retrieve data in a separate thread from the UI
This commit is contained in:
parent
1e2b3902f2
commit
277fbd6311
4 changed files with 73 additions and 11 deletions
49
buypeeb.py
49
buypeeb.py
|
@ -20,14 +20,15 @@
|
||||||
|
|
||||||
import requests, gi
|
import requests, gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, Gio, Gdk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
import functions
|
|
||||||
from listing import YahooAuctionsItem
|
|
||||||
from settings import BuypeebSettings
|
|
||||||
|
|
||||||
import json, sys
|
import json, sys
|
||||||
from os import path
|
from os import path
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
import functions
|
||||||
|
from listing import YahooAuctionsItem, JST
|
||||||
|
from settings import BuypeebSettings
|
||||||
|
|
||||||
isWindows = sys.platform.startswith('win')
|
isWindows = sys.platform.startswith('win')
|
||||||
|
|
||||||
|
@ -36,6 +37,25 @@ if isWindows:
|
||||||
else:
|
else:
|
||||||
settingsLocation = path.expanduser("~/.config/Lynnear Software/buypeeb/") # dotfiles in ~ need to die. begone dot
|
settingsLocation = path.expanduser("~/.config/Lynnear Software/buypeeb/") # dotfiles in ~ need to die. begone dot
|
||||||
|
|
||||||
|
class WatchlistUpdater(Thread):
|
||||||
|
def __init__(self, app, update_all: bool = False):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.app = app
|
||||||
|
self.update_all = update_all
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# TODO: make this happen in parallel
|
||||||
|
if self.update_all:
|
||||||
|
for id, item in self.app.settings.watchlist.items():
|
||||||
|
if not (item.ready or item.updating):
|
||||||
|
item.update()
|
||||||
|
|
||||||
|
else:
|
||||||
|
for item in self.app.settings.outdated_items():
|
||||||
|
if not(item.ready or item.updating):
|
||||||
|
item.update()
|
||||||
|
|
||||||
|
self.app.renderList()
|
||||||
class BuypeebApp:
|
class BuypeebApp:
|
||||||
|
|
||||||
# SETUP
|
# SETUP
|
||||||
|
@ -69,6 +89,7 @@ class BuypeebApp:
|
||||||
|
|
||||||
def activate(self, app):
|
def activate(self, app):
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
self.updateItems()
|
||||||
|
|
||||||
def shutdown(self, app):
|
def shutdown(self, app):
|
||||||
self.settings.save()
|
self.settings.save()
|
||||||
|
@ -123,11 +144,26 @@ class BuypeebApp:
|
||||||
def setExchangeRate(self):
|
def setExchangeRate(self):
|
||||||
self.rate = functions.get_exchange_rate()
|
self.rate = functions.get_exchange_rate()
|
||||||
|
|
||||||
|
def updateItems(self, update_all: bool = False):
|
||||||
|
updater = WatchlistUpdater(self, update_all)
|
||||||
|
updater.start()
|
||||||
|
|
||||||
def renderList(self):
|
def renderList(self):
|
||||||
self.items.clear()
|
self.items.clear()
|
||||||
print(self.settings.watchlist)
|
print(self.settings.watchlist)
|
||||||
for id, item in self.settings.watchlist.items():
|
for id, item in self.settings.watchlist.items():
|
||||||
self.items.append([item.name, item.price_aud(self.rate), "heenlo", id])
|
if item.ready:
|
||||||
|
self.items.append([item.name, item.price_aud(self.rate), "heenlo", id])
|
||||||
|
else:
|
||||||
|
self.items.append([item.name, "...", "...", id])
|
||||||
|
|
||||||
|
self.updateListTimes()
|
||||||
|
|
||||||
|
def updateListTimes(self):
|
||||||
|
now = datetime.now()
|
||||||
|
for item in self.items:
|
||||||
|
id = item[3]
|
||||||
|
|
||||||
|
|
||||||
# BUTTON CLICKS
|
# BUTTON CLICKS
|
||||||
|
|
||||||
|
@ -141,6 +177,7 @@ class BuypeebApp:
|
||||||
self.msgBox("Invalid URL", "The provided URL was invalid.", Gtk.MessageType.ERROR)
|
self.msgBox("Invalid URL", "The provided URL was invalid.", Gtk.MessageType.ERROR)
|
||||||
|
|
||||||
self.renderList()
|
self.renderList()
|
||||||
|
self.updateItems()
|
||||||
|
|
||||||
def btnClearEndedClicked(self, widget):
|
def btnClearEndedClicked(self, widget):
|
||||||
if self.msgBox("Clear ended?", "Are you sure you want to clear all ended items from the watchlist?", buttons = Gtk.ButtonsType.OK_CANCEL):
|
if self.msgBox("Clear ended?", "Are you sure you want to clear all ended items from the watchlist?", buttons = Gtk.ButtonsType.OK_CANCEL):
|
||||||
|
|
13
listing.py
13
listing.py
|
@ -56,6 +56,10 @@ class YahooAuctionsItem:
|
||||||
def __init__(self, url: str, id: str, name: str = None, from_json: dict = None):
|
def __init__(self, url: str, id: str, name: str = None, from_json: dict = None):
|
||||||
# note - incoming url is not validated in any way!
|
# note - incoming url is not validated in any way!
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.price = 0
|
||||||
|
self.original_name = None
|
||||||
|
self.favourite = None
|
||||||
|
|
||||||
if url == None and from_json != None and id != None:
|
if url == None and from_json != None and id != None:
|
||||||
self.id = id
|
self.id = id
|
||||||
self.name = from_json['name']
|
self.name = from_json['name']
|
||||||
|
@ -74,15 +78,15 @@ class YahooAuctionsItem:
|
||||||
self.available = True
|
self.available = True
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.updating = False
|
self.updating = False
|
||||||
self.update()
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
self.updating = True
|
||||||
try:
|
try:
|
||||||
# the good news is, yahoo japan returns all the data we need in handy json format
|
# 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
|
# 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 = requests.get(f"https://page.auctions.yahoo.co.jp/jp/auction/{self.id}").text
|
||||||
r = open("yahoo.html").read()
|
# r = open("yahoo.html").read()
|
||||||
j = json.loads(re.match(r'.*var pageData ?= ?(\{.*?\});', r, re.DOTALL).group(1))
|
j = json.loads(re.match(r'.*var pageData ?= ?(\{.*?\});', r, re.DOTALL).group(1))
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
@ -97,6 +101,9 @@ class YahooAuctionsItem:
|
||||||
if self.name == None:
|
if self.name == None:
|
||||||
self.name = j['productName']
|
self.name = j['productName']
|
||||||
|
|
||||||
|
self.ready = True
|
||||||
|
self.updating = False
|
||||||
|
|
||||||
def price_jpy(self):
|
def price_jpy(self):
|
||||||
return f"¥{self.price:.2f}"
|
return f"¥{self.price:.2f}"
|
||||||
|
|
||||||
|
|
19
settings.py
19
settings.py
|
@ -1,9 +1,12 @@
|
||||||
import json, os, pickle
|
import json, os, pickle
|
||||||
from os import path
|
from os import path
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
import functions
|
import functions
|
||||||
from listing import YahooAuctionsItem
|
from listing import YahooAuctionsItem
|
||||||
|
|
||||||
|
JST = timezone(timedelta(hours = 9))
|
||||||
|
|
||||||
class BuypeebSettings:
|
class BuypeebSettings:
|
||||||
def __init__(self, location: str):
|
def __init__(self, location: str):
|
||||||
self.updateInterval = 10 * 60
|
self.updateInterval = 10 * 60
|
||||||
|
@ -50,3 +53,19 @@ class BuypeebSettings:
|
||||||
self.watchlist[id] = YahooAuctionsItem(url, id, name)
|
self.watchlist[id] = YahooAuctionsItem(url, id, name)
|
||||||
for item in self.watchlist.values():
|
for item in self.watchlist.values():
|
||||||
print(item.name, item.price)
|
print(item.name, item.price)
|
||||||
|
|
||||||
|
def outdated_items(self):
|
||||||
|
out = []
|
||||||
|
now = datetime.now(tz = JST).timestamp()
|
||||||
|
for item in self.watchlist.values():
|
||||||
|
time_difference = now - item.last_checked.timestamp()
|
||||||
|
ending_soon = False # TODO: this
|
||||||
|
|
||||||
|
if \
|
||||||
|
(item.favourite and time_difference >= self.favouriteUpdateInterval) or \
|
||||||
|
(item.favourite and ending_soon and time_difference >= self.favouriteUpdateIntervalCritical) or \
|
||||||
|
(time_difference >= self.updateInterval) or \
|
||||||
|
(ending_soon and time_difference >= self.updateIntervalCritical):
|
||||||
|
out.append(item)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
|
@ -285,7 +285,6 @@
|
||||||
<property name="title" translatable="yes">Name</property>
|
<property name="title" translatable="yes">Name</property>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
<property name="clickable">True</property>
|
<property name="clickable">True</property>
|
||||||
<property name="sort_indicator">True</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCellRendererText"/>
|
<object class="GtkCellRendererText"/>
|
||||||
<attributes>
|
<attributes>
|
||||||
|
@ -309,7 +308,7 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTreeViewColumn">
|
<object class="GtkTreeViewColumn">
|
||||||
<property name="resizable">True</property>
|
<property name="resizable">True</property>
|
||||||
<property name="title" translatable="yes">Ending in</property>
|
<property name="title" translatable="yes">Ending at</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCellRendererText"/>
|
<object class="GtkCellRendererText"/>
|
||||||
<attributes>
|
<attributes>
|
||||||
|
|
Loading…
Reference in a new issue