import requests import re, json, math from datetime import datetime, timezone, timedelta import functions JST = timezone(timedelta(hours = 9)) LOCALTIME = timezone(timedelta(hours = 10)) # TODO: allow for customisation class YahooAuctionsItem: """ A class for handling items on Yahoo! Auctions Japan Attributes ---------- name : str The name given to the auction item by the user. original_name : str The name as it appears on Y!A, favourite : bool Whether or not the user has "favourited" this item. url : bool The URL this item was added from. If not provided, defaults to https://buyee.jp/item/yahoo/auction/{id}. id : str The ID of the item, found at the end of the URL. last_checked : datetime The time that the item's status was last checked by buypeeb. available : bool Whether or not the item is still available (if the auction is still available) ready : bool Whether or not the object is ready. If not, some of the data (price, available, etc.) may be out of date or unset. updating : bool If true, the object is currently being updated. Should never be true if ready is true. price : float The price of the item in yen. bids : int The number of bids that have been placed on the item. start_date : datetime The start date and time of the item in JST. end_date : datetime The end date and time of the item in JST. """ def __init__(self, url: str, id: str, name: str = "", from_json: dict = None): # note - incoming url is not validated in any way! self.name = name self.price = 0 self.win_price = 0 self.original_name = "" self.favourite = None self.end_date = datetime.fromisoformat('1970-01-01').replace(tzinfo = JST) self.start_date = datetime.fromisoformat('1970-01-01').replace(tzinfo = JST) self.bids = 0 self.auto_extension = None self.rate = 75.0 if url == None and from_json != None and id != None: self.id = id self.name = from_json['name'] self.original_name = from_json['original_name'] if self.name == "": self.name = self.original_name self.favourite = from_json['favourite'] self.url = f"https://buyee.jp/item/yahoo/auction/{self.id}" elif url != None and id != None: self.url = url self.id = id else: raise RuntimeError self.last_checked = datetime.fromisoformat('1970-01-01') self.available = True self.ready = False self.updating = False def update(self): self.updating = True try: # the good news is, yahoo japan returns all the data we need in handy json format # the bad news is that the only way to get that json format is to download the whole auction page and grep it r = requests.get(f"https://page.auctions.yahoo.co.jp/jp/auction/{self.id}").text # r = open("yahoo.html").read() j = json.loads(re.match(r'.*var pageData ?= ?(\{.*?\});', r, re.DOTALL).group(1)) ae = re.search(r'自動延長.+\n.+>(.+)<.+', r) if ae != None: ae = ae.group(1) self.auto_extension = (ae == "あり") except: raise j = j['items'] self.price = float(j['price']) self.win_price = float(j['winPrice']) self.bids = j['bids'] self.start_date = datetime.fromisoformat(j['starttime']).replace(tzinfo = JST) self.end_date = datetime.fromisoformat(j['endtime']).replace(tzinfo = JST) self.last_checked = datetime.now(JST) self.original_name = j['productName'] if self.name == None or self.name == "": self.name = j['productName'] self.available = (self.end_date_local() >= datetime.now(LOCALTIME)) self.ready = True self.updating = False return self.id, self def price_jpy(self, win = False): p = self.price if win: p = self.win_price return f"¥{p:.0f}" def price_aud(self, rate = 0, win = False): if rate == 0: rate = self.rate else: self.rate = rate p = self.price if win: p = self.win_price return f"${self.price / rate:.2f}" def end_date_local(self): return self.end_date.astimezone(LOCALTIME) def start_date_local(self): return self.start_date.astimezone(LOCALTIME) def ending_in(self, local = False): if local: difference = self.end_date_local() - datetime.now(tz = LOCALTIME) else: difference = self.end_date - datetime.now(tz = JST) ds = int(difference.total_seconds()) seconds = ds % 60 minutes = math.floor(ds / 60) % 60 hours = math.floor(ds / (60 * 60)) % 24 days = math.floor(ds / (60 * 60 * 24)) out = "" if days > 0: out += f"{days}d " if hours > 0: out += f"{hours}h " if minutes > 0: out += f"{minutes}m " return f"{out}{seconds}s" def ending_at(self, local = False): now = datetime.now(tz = LOCALTIME) ndate = now.strftime("%d %b") if self.end_date != None: ed = self.end_date_local() if local else self.end_date idate, itime = ed.strftime("%d %b"), ed.strftime("%H:%M") if idate == ndate: return itime else: return f"{idate} {itime}"