Comments added

This commit is contained in:
Muaz Ahmad 2023-08-03 13:37:46 +05:00
parent c31db1b65f
commit ae24570c19
4 changed files with 62 additions and 4 deletions

7
api.py
View file

@ -1,5 +1,6 @@
import requests, json import requests, json
# API request handler and data access
class WorldState(): class WorldState():
def __init__(self): def __init__(self):
self.client = requests.Session() self.client = requests.Session()
@ -12,6 +13,12 @@ class WorldState():
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
return False return False
# aribtrary mapping, some skipped, some not-standard anyway
# better way is probably to do setattr in a loop, but then need to
# change code and handle baro.
# not willing to change it on the off chance much of this is replaced if
# content API becomes useful and names change again
self.fissures = self.ws.get('fissures') self.fissures = self.ws.get('fissures')
self.invasions = self.ws.get('invasions') self.invasions = self.ws.get('invasions')
self.sorties = self.ws.get('sortie') self.sorties = self.ws.get('sortie')

View file

@ -1,8 +1,14 @@
# custom widgets, code is largely ripped from placeholders from
# a generated gui_base.py file and additional bits slapped on
# and some minor changes in create_gui, mostly in naming of
# widgets including indexing and subobjects as well with self.i
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
from datetime import datetime, timedelta from datetime import datetime, timedelta
import time import time
# util for clocks
utcoffset = time.time() - time.mktime(time.gmtime()) utcoffset = time.time() - time.mktime(time.gmtime())
class Fissure(QtWidgets.QWidget): class Fissure(QtWidgets.QWidget):
@ -53,6 +59,7 @@ class Fissure(QtWidgets.QWidget):
self.gridLayout_3.addWidget(self.FissureType, 1, 1, 1, 1) self.gridLayout_3.addWidget(self.FissureType, 1, 1, 1, 1)
def update_gui(self): def update_gui(self):
# attempt an update, will fail during initial pass before worldstate init so try-except
try: try:
self.FissureTier.setText(f"{self.fissure_info['tier']} - T{self.fissure_info['tierNum']}") self.FissureTier.setText(f"{self.fissure_info['tier']} - T{self.fissure_info['tierNum']}")
self.update_timer() self.update_timer()
@ -62,6 +69,7 @@ class Fissure(QtWidgets.QWidget):
pass pass
def update_timer(self): def update_timer(self):
# update timer, same as global timers in main
eta = round(time.mktime(time.strptime(self.fissure_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset) eta = round(time.mktime(time.strptime(self.fissure_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset)
if eta >= 0: if eta >= 0:
self.FissureTimer.setText(f"{str(eta // 3600) + 'h' if eta // 3600 > 0 else ''} {(eta // 60) % 60}m {eta % 60}s") self.FissureTimer.setText(f"{str(eta // 3600) + 'h' if eta // 3600 > 0 else ''} {(eta // 60) % 60}m {eta % 60}s")
@ -113,6 +121,7 @@ class Invasion(QtWidgets.QWidget):
self.gridLayout_4.addWidget(self.Reward1, 0, 0, 1, 1) self.gridLayout_4.addWidget(self.Reward1, 0, 0, 1, 1)
def update_gui(self): def update_gui(self):
# same as Fissures, progress bars are colored according to factions involved, update css
try: try:
faction_colors = {'Grineer': 'red', 'Corpus': 'blue', 'Infested': 'green'} faction_colors = {'Grineer': 'red', 'Corpus': 'blue', 'Infested': 'green'}
self.Reward1.setText(f"{self.invasion_info['attackerReward']['itemString']}") self.Reward1.setText(f"{self.invasion_info['attackerReward']['itemString']}")
@ -123,6 +132,7 @@ class Invasion(QtWidgets.QWidget):
pass pass
def update_progress(self): def update_progress(self):
# invasion progerss tracked with progressbar, set here as psuedo-timer
self.InvasionProgress.setProperty('value', self.invasion_info['completion']) self.InvasionProgress.setProperty('value', self.invasion_info['completion'])
class Alert(QtWidgets.QWidget): class Alert(QtWidgets.QWidget):
@ -162,6 +172,7 @@ class Alert(QtWidgets.QWidget):
self.horizontalLayout_6.addWidget(self.AlertTimer) self.horizontalLayout_6.addWidget(self.AlertTimer)
def update_gui(self): def update_gui(self):
# same as fissure
try: try:
self.AlertReward.setText(self.alert_info['mission']['reward']['itemString']) self.AlertReward.setText(self.alert_info['mission']['reward']['itemString'])
self.update_timer() self.update_timer()
@ -169,6 +180,7 @@ class Alert(QtWidgets.QWidget):
pass pass
def update_timer(self): def update_timer(self):
# same as fissure
eta = round(time.mktime(time.strptime(self.alert_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset) eta = round(time.mktime(time.strptime(self.alert_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset)
if eta > 0: if eta > 0:
self.AlertTimer.setText(f'{str(eta // 86400) + "d " if eta // 86400 > 0 else ""}{str((eta // 3600) % 24) + "h" if eta // 3600 > 0 else ""} {(eta // 60) % 60}m {eta % 60}s') self.AlertTimer.setText(f'{str(eta // 86400) + "d " if eta // 86400 > 0 else ""}{str((eta // 3600) % 24) + "h" if eta // 3600 > 0 else ""} {(eta // 60) % 60}m {eta % 60}s')
@ -198,6 +210,7 @@ class BaroItem(QtWidgets.QWidget):
self.gridLayout_7.addWidget(self.ItemName, 0, 0, 1, 1) self.gridLayout_7.addWidget(self.ItemName, 0, 0, 1, 1)
def update_gui(self): def update_gui(self):
# same as fissure, except no dynamic timer needing updates
try: try:
self.ItemName.setText(self.item_info['item']) self.ItemName.setText(self.item_info['item'])
except: except:
@ -239,6 +252,7 @@ class Event(QtWidgets.QWidget):
self.horizontalLayout_11.addWidget(self.EventTimer) self.horizontalLayout_11.addWidget(self.EventTimer)
def update_gui(self): def update_gui(self):
# same as fissure
try: try:
self.EventName.setText(self.event_info['description']) self.EventName.setText(self.event_info['description'])
self.update_timer() self.update_timer()
@ -246,6 +260,7 @@ class Event(QtWidgets.QWidget):
pass pass
def update_timer(self): def update_timer(self):
# same as fissure
eta = round(time.mktime(time.strptime(self.event_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset) eta = round(time.mktime(time.strptime(self.event_info['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset)
if eta > 0: if eta > 0:
self.EventTimer.setText(f'{str(eta // 86400) + "d " if eta // 86400 > 0 else ""}{(eta // 3600) % 24}h') self.EventTimer.setText(f'{str(eta // 86400) + "d " if eta // 86400 > 0 else ""}{(eta // 3600) % 24}h')
@ -295,6 +310,7 @@ class NewsBlurb(QtWidgets.QWidget):
self.horizontalLayout_12.addWidget(self.NewsBlurbRelTimer) self.horizontalLayout_12.addWidget(self.NewsBlurbRelTimer)
def update_gui(self): def update_gui(self):
# same as fissure, except populate hyperlink instead of setting labels.
try: try:
self.NewsBlurbHyperLink.setText(f'<a href=\"{self.news_info["link"]}\">{self.news_info["message"]}</a>') self.NewsBlurbHyperLink.setText(f'<a href=\"{self.news_info["link"]}\">{self.news_info["message"]}</a>')
self.update_timer() self.update_timer()
@ -302,6 +318,16 @@ class NewsBlurb(QtWidgets.QWidget):
pass pass
def update_timer(self): def update_timer(self):
# timers are wonkier than fissure since there can be both start and end dates
# chosen strat:
# if event starts in the future:
# starts in
# elif event has started and end date not reached:
# ends in
# else if no end date and start date past if it even existed:
# just display time difference to date, as in 1d ago
#
# if time delta is > 1d, only display day, else h and min
prefix = '' prefix = ''
if self.news_info.get('startDate'): if self.news_info.get('startDate'):
eta = round(time.mktime(time.strptime(self.news_info.get('startDate'), '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset) eta = round(time.mktime(time.strptime(self.news_info.get('startDate'), '%Y-%m-%dT%H:%M:%S.%fZ')) - time.time() + utcoffset)

6
gui.py
View file

@ -1,14 +1,18 @@
import gui_base
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
import sys import sys
import gui_base
# GUI constructor from generated gui_base file
# doesn't really need to exist but its here now
class GUI(QtWidgets.QMainWindow, gui_base.Ui_MainWindow): class GUI(QtWidgets.QMainWindow, gui_base.Ui_MainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.setupUi(self) self.setupUi(self)
# test code
def main(): def main():
app = QApplication(sys.argv) app = QApplication(sys.argv)
gui = ExampleApp() gui = ExampleApp()

27
main.py
View file

@ -1,3 +1,5 @@
# central controller, main loop
from gui import GUI from gui import GUI
from api import WorldState from api import WorldState
from extra_widgets import * from extra_widgets import *
@ -11,25 +13,32 @@ import sys
class App(GUI): class App(GUI):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
# fetch world state info from API
self.ws = WorldState() self.ws = WorldState()
# if bad fetch, error for retry until quit or fetched
while self.ws.ws == {}: while self.ws.ws == {}:
self.network_error() self.network_error()
sys.exit(1) sys.exit(1)
# remove placeholder templates for given widgets, replaced with actual data later in redraw
[widget.setParent(None) for widget in [self.Fissure, self.Invasion, self.Alert, self.BaroItem, self.Event, self.NewsBlurb]] [widget.setParent(None) for widget in [self.Fissure, self.Invasion, self.Alert, self.BaroItem, self.Event, self.NewsBlurb]]
# update interval for clocks
self.timers_timer = QTimer(self) self.timers_timer = QTimer(self)
self.timers_timer.timeout.connect(self.update_timers) self.timers_timer.timeout.connect(self.update_timers)
self.timers_timer.start(1000) self.timers_timer.start(1000)
# update interval for data refresh
self.ws_update_timer = QTimer(self) self.ws_update_timer = QTimer(self)
self.ws_update_timer.timeout.connect(self.update_world_state) self.ws_update_timer.timeout.connect(self.update_world_state)
self.ws_update_timer.start(1000 * 60 * 5) self.ws_update_timer.start(1000 * 60 * 5)
# largely just creating custom widgets, and mapping to existing parent widgets
self.redraw_content() self.redraw_content()
def redraw_content(self): def redraw_content(self):
self.redraw_content_dynamic() self.redraw_content_dynamic() # content that varies in number, invasions, fissures, etc
self.redraw_content_static() self.redraw_content_static() # static content that won't change/only one, arbi, archons, etc
def redraw_content_dynamic(self): def redraw_content_dynamic(self):
self.Fissure_list = [Fissure(self.FissureHolder, fissure_info, fissure_i) for (fissure_i, fissure_info) in enumerate(self.ws.fissures)] self.Fissure_list = [Fissure(self.FissureHolder, fissure_info, fissure_i) for (fissure_i, fissure_info) in enumerate(self.ws.fissures)]
@ -41,6 +50,7 @@ class App(GUI):
self.Alert_list = [Alert(self.AlertHolder, alert_info, alert_i) for (alert_i, alert_info) in enumerate(self.ws.alerts)] self.Alert_list = [Alert(self.AlertHolder, alert_info, alert_i) for (alert_i, alert_info) in enumerate(self.ws.alerts)]
[self.AlertList.addWidget(i) for i in self.Alert_list] [self.AlertList.addWidget(i) for i in self.Alert_list]
# if baro key is [], no baro, switch tab to inactive, else populate grid
if len(self.ws.baro_items) == 0: if len(self.ws.baro_items) == 0:
self.BaroTabs.setCurrentIndex(0) self.BaroTabs.setCurrentIndex(0)
else: else:
@ -56,13 +66,14 @@ class App(GUI):
def redraw_content_static(self): def redraw_content_static(self):
for i in range(1, 4): for i in range(1, 4):
getattr(self, 'SortieM'+str(i)).setText(self.ws.sorties['variants'][i - 1]['missionType']) getattr(self, 'SortieM' + str(i)).setText(self.ws.sorties['variants'][i - 1]['missionType'])
getattr(self, 'SortieM' + str(i) + 'Mod').setText(self.ws.sorties['variants'][i-1]['modifier']) getattr(self, 'SortieM' + str(i) + 'Mod').setText(self.ws.sorties['variants'][i-1]['modifier'])
self.ArchonHuntStr.setText('Archon Hunt: ' + self.ws.archon_hunt['boss']) self.ArchonHuntStr.setText('Archon Hunt: ' + self.ws.archon_hunt['boss'])
for i in range(1, 4): for i in range(1, 4):
getattr(self, 'ArchonHuntM' + str(i)).setText(self.ws.archon_hunt['missions'][i - 1]['type']) getattr(self, 'ArchonHuntM' + str(i)).setText(self.ws.archon_hunt['missions'][i - 1]['type'])
# warframestat.us arbi jank fix until content API adds arbis and can use that directly
if not self.ws.arbitration: if not self.ws.arbitration:
self.ArbitrationTabs.setCurrentIndex(0) self.ArbitrationTabs.setCurrentIndex(0)
else: else:
@ -70,6 +81,7 @@ class App(GUI):
self.ArbitrationMT.setText(self.ws.arbitration['type']) self.ArbitrationMT.setText(self.ws.arbitration['type'])
self.ArbitrationFaction.setText(self.ws.arbitration['enemy']) self.ArbitrationFaction.setText(self.ws.arbitration['enemy'])
# nightwave mission mapping if active
daily_i = 1 daily_i = 1
weekly_i = 1 weekly_i = 1
elite_i = 1 elite_i = 1
@ -94,25 +106,33 @@ class App(GUI):
self.NightwaveTabs.setCurrentIndex(0) self.NightwaveTabs.setCurrentIndex(0)
def update_timers(self): def update_timers(self):
# call timer updates and invasion progress changes
[i.update_timer() for i in self.Fissure_list] [i.update_timer() for i in self.Fissure_list]
[i.update_progress() for i in self.Invasion_list] [i.update_progress() for i in self.Invasion_list]
[i.update_timer() for i in self.Alert_list] [i.update_timer() for i in self.Alert_list]
[i.update_timer() for i in self.events_list] [i.update_timer() for i in self.events_list]
[i.update_timer() for i in self.newsblurb_list] [i.update_timer() for i in self.newsblurb_list]
# parse expiry datestring and calc sortie expiry time delta from now to listed expiry
sortie_eta = round(time.mktime(time.strptime(self.ws.sorties['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime())) sortie_eta = round(time.mktime(time.strptime(self.ws.sorties['expiry'], '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()))
if sortie_eta >= 0: if sortie_eta >= 0:
self.SortieResetTimer.setText(f'{str(sortie_eta // 3600) + "h " if sortie_eta // 3600 > 0 else ""}{(sortie_eta // 60) % 60}m {sortie_eta % 60}s') self.SortieResetTimer.setText(f'{str(sortie_eta // 3600) + "h " if sortie_eta // 3600 > 0 else ""}{(sortie_eta // 60) % 60}m {sortie_eta % 60}s')
else: else:
self.SortieResetTimer.setText('Expired') self.SortieResetTimer.setText('Expired')
# same as sortie, except expiry happens at Monday 00:00 UTC), 3 days for epoch adjust from Wed
# % week for weekly timer diff since last Monday
# day str listed separately for display formatting
weekly_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) - 3 * 86400) % (7 * 86400) weekly_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) - 3 * 86400) % (7 * 86400)
self.WeeklyResetTimeDayStr.setText(str(weekly_eta // 86400) + 'd') self.WeeklyResetTimeDayStr.setText(str(weekly_eta // 86400) + 'd')
self.WeeklyResetTimeStr.setText(f'{(weekly_eta // 3600) % 24}h {(weekly_eta // 60) % 60}m {weekly_eta % 60}s') self.WeeklyResetTimeStr.setText(f'{(weekly_eta // 3600) % 24}h {(weekly_eta // 60) % 60}m {weekly_eta % 60}s')
# same as above, bounties reset at given time adjust, 2.5hr cycle
bounty_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) + 120) % (9000) bounty_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) + 120) % (9000)
self.BountyTimeStr.setText(f'{bounty_eta // 3600}h {(bounty_eta // 60) % 60}m {bounty_eta % 60}s') self.BountyTimeStr.setText(f'{bounty_eta // 3600}h {(bounty_eta // 60) % 60}m {bounty_eta % 60}s')
# baro reset adjust, 2 week cycle in full.
# arrives at 2 days left, present < 2 days.
baro_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) + (10*86400 + 13 * 3600)) % (14 * 86400) baro_eta = round(time.mktime(time.strptime('1970-1-1T00:00:00.000Z', '%Y-%m-%dT%H:%M:%S.%fZ')) - time.mktime(time.gmtime()) + (10*86400 + 13 * 3600)) % (14 * 86400)
if baro_eta >= 2 * 86400: if baro_eta >= 2 * 86400:
self.BaroStateStr.setText('Baro Arrives in:') self.BaroStateStr.setText('Baro Arrives in:')
@ -129,6 +149,7 @@ class App(GUI):
self.network_error() self.network_error()
def network_error(self): def network_error(self):
# slapped on later, just a dialog box for network error
msg = QMessageBox() msg = QMessageBox()
msg.setIcon(QMessageBox.Critical) msg.setIcon(QMessageBox.Critical)
msg.setText('Network Error') msg.setText('Network Error')