2023-08-03 13:37:46 +05:00
|
|
|
# central controller, main loop
|
|
|
|
|
2022-11-10 16:26:28 +05:00
|
|
|
from gui import GUI
|
|
|
|
from api import WorldState
|
|
|
|
from extra_widgets import *
|
|
|
|
|
|
|
|
from PyQt5.QtWidgets import QApplication, QMessageBox
|
2022-11-10 23:03:50 +05:00
|
|
|
from PyQt5.QtCore import QTimer
|
2022-11-10 16:26:28 +05:00
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
class App(GUI):
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__()
|
2023-08-03 13:37:46 +05:00
|
|
|
# fetch world state info from API
|
2022-11-10 16:26:28 +05:00
|
|
|
self.ws = WorldState()
|
2023-08-03 13:37:46 +05:00
|
|
|
# if bad fetch, error for retry until quit or fetched
|
2022-11-10 16:26:28 +05:00
|
|
|
while self.ws.ws == {}:
|
|
|
|
self.network_error()
|
|
|
|
sys.exit(1)
|
2023-08-03 13:37:46 +05:00
|
|
|
|
|
|
|
# remove placeholder templates for given widgets, replaced with actual data later in redraw
|
2022-11-10 23:03:50 +05:00
|
|
|
[widget.setParent(None) for widget in [self.Fissure, self.Invasion, self.Alert, self.BaroItem, self.Event, self.NewsBlurb]]
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# update interval for clocks
|
2022-11-10 23:03:50 +05:00
|
|
|
self.timers_timer = QTimer(self)
|
|
|
|
self.timers_timer.timeout.connect(self.update_timers)
|
|
|
|
self.timers_timer.start(1000)
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# update interval for data refresh
|
2022-11-10 23:03:50 +05:00
|
|
|
self.ws_update_timer = QTimer(self)
|
|
|
|
self.ws_update_timer.timeout.connect(self.update_world_state)
|
|
|
|
self.ws_update_timer.start(1000 * 60 * 5)
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# largely just creating custom widgets, and mapping to existing parent widgets
|
2022-11-10 16:26:28 +05:00
|
|
|
self.redraw_content()
|
|
|
|
|
2022-11-10 23:03:50 +05:00
|
|
|
def redraw_content(self):
|
2023-08-03 13:37:46 +05:00
|
|
|
self.redraw_content_dynamic() # content that varies in number, invasions, fissures, etc
|
|
|
|
self.redraw_content_static() # static content that won't change/only one, arbi, archons, etc
|
2022-11-10 16:26:28 +05:00
|
|
|
|
2022-11-10 23:03:50 +05:00
|
|
|
def redraw_content_dynamic(self):
|
2022-11-10 23:19:30 +05:00
|
|
|
self.Fissure_list = [Fissure(self.FissureHolder, fissure_info, fissure_i) for (fissure_i, fissure_info) in enumerate(self.ws.fissures)]
|
|
|
|
[self.FissureList.addWidget(i) for i in self.Fissure_list]
|
2022-11-10 23:03:50 +05:00
|
|
|
|
2022-11-10 23:19:30 +05:00
|
|
|
self.Invasion_list = [Invasion(self.InvasionHolder, invasion_info, invasion_i) for (invasion_i, invasion_info) in enumerate(self.ws.invasions)]
|
|
|
|
[self.InvasionList.addWidget(i) for i in self.Invasion_list]
|
2022-11-10 23:03:50 +05:00
|
|
|
|
2022-11-10 23:19:30 +05:00
|
|
|
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]
|
2022-11-10 23:03:50 +05:00
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# if baro key is [], no baro, switch tab to inactive, else populate grid
|
2022-11-10 23:03:50 +05:00
|
|
|
if len(self.ws.baro_items) == 0:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.BaroTabs.setCurrentIndex(0)
|
2022-11-10 23:03:50 +05:00
|
|
|
else:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.BaroTabs.setCurrentIndex(1)
|
2022-11-10 23:03:50 +05:00
|
|
|
self.baro_items_list = [BaroItem(self.BaroData, item_info, item_i) for (item_i, item_info) in enumerate(self.ws.baro_items)]
|
|
|
|
[self.gridLayout_6.addWidget(i, index // 7, index % 7, 1, 1) for (index, i) in enumerate(self.baro_items_list)]
|
|
|
|
|
2022-11-10 23:19:30 +05:00
|
|
|
self.events_list = [Event(self.EventHolder, event_info, event_i) for (event_i, event_info) in enumerate(self.ws.events)]
|
|
|
|
[self.EventsList.addWidget(i) for i in self.events_list]
|
2022-11-10 23:03:50 +05:00
|
|
|
|
2022-11-10 23:19:30 +05:00
|
|
|
self.newsblurb_list = [NewsBlurb(self.NewsHolder, newsblurb_info, newsblurb_i) for (newsblurb_i, newsblurb_info) in enumerate(self.ws.news)]
|
|
|
|
[self.NewsList.addWidget(i) for i in self.newsblurb_list]
|
2022-11-10 23:03:50 +05:00
|
|
|
|
|
|
|
def redraw_content_static(self):
|
|
|
|
for i in range(1, 4):
|
2023-08-03 13:37:46 +05:00
|
|
|
getattr(self, 'SortieM' + str(i)).setText(self.ws.sorties['variants'][i - 1]['missionType'])
|
2022-11-10 23:03:50 +05:00
|
|
|
getattr(self, 'SortieM' + str(i) + 'Mod').setText(self.ws.sorties['variants'][i-1]['modifier'])
|
|
|
|
|
|
|
|
self.ArchonHuntStr.setText('Archon Hunt: ' + self.ws.archon_hunt['boss'])
|
|
|
|
for i in range(1, 4):
|
|
|
|
getattr(self, 'ArchonHuntM' + str(i)).setText(self.ws.archon_hunt['missions'][i - 1]['type'])
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# warframestat.us arbi jank fix until content API adds arbis and can use that directly
|
2022-11-10 23:03:50 +05:00
|
|
|
if not self.ws.arbitration:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.ArbitrationTabs.setCurrentIndex(0)
|
2022-11-10 23:03:50 +05:00
|
|
|
else:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.ArbitrationTabs.setCurrentIndex(1)
|
2022-11-10 23:03:50 +05:00
|
|
|
self.ArbitrationMT.setText(self.ws.arbitration['type'])
|
|
|
|
self.ArbitrationFaction.setText(self.ws.arbitration['enemy'])
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# nightwave mission mapping if active
|
2022-11-10 23:03:50 +05:00
|
|
|
daily_i = 1
|
|
|
|
weekly_i = 1
|
|
|
|
elite_i = 1
|
|
|
|
if self.ws.nightwave:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.NightwaveTabs.setCurrentIndex(1)
|
2022-11-10 23:03:50 +05:00
|
|
|
for challenge in self.ws.nightwave['activeChallenges']:
|
|
|
|
if challenge.get('isDaily'):
|
|
|
|
challenge_type = 'Daily'
|
|
|
|
challenge_i = daily_i
|
|
|
|
daily_i += 1
|
|
|
|
elif challenge.get('isElite'):
|
|
|
|
challenge_type = 'Elite'
|
|
|
|
challenge_i = weekly_i
|
|
|
|
weekly_i += 1
|
|
|
|
else:
|
|
|
|
challenge_type = 'Weekly'
|
|
|
|
challenge_i = elite_i
|
|
|
|
elite_i += 1
|
|
|
|
getattr(self, challenge_type + str(challenge_i) + 'Name').setText(challenge['title'])
|
|
|
|
getattr(self, challenge_type + str(challenge_i) + 'Desc').setText(challenge['desc'])
|
|
|
|
else:
|
2022-11-10 23:19:30 +05:00
|
|
|
self.NightwaveTabs.setCurrentIndex(0)
|
2022-11-10 23:03:50 +05:00
|
|
|
|
|
|
|
def update_timers(self):
|
2023-08-03 13:37:46 +05:00
|
|
|
# call timer updates and invasion progress changes
|
2022-11-10 23:03:50 +05:00
|
|
|
[i.update_timer() for i in self.Fissure_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.events_list]
|
|
|
|
[i.update_timer() for i in self.newsblurb_list]
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# parse expiry datestring and calc sortie expiry time delta from now to listed expiry
|
2022-11-10 23:03:50 +05:00
|
|
|
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:
|
|
|
|
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:
|
|
|
|
self.SortieResetTimer.setText('Expired')
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# 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
|
2022-11-10 23:03:50 +05:00
|
|
|
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.WeeklyResetTimeStr.setText(f'{(weekly_eta // 3600) % 24}h {(weekly_eta // 60) % 60}m {weekly_eta % 60}s')
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# same as above, bounties reset at given time adjust, 2.5hr cycle
|
2022-11-10 23:03:50 +05:00
|
|
|
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')
|
|
|
|
|
2023-08-03 13:37:46 +05:00
|
|
|
# baro reset adjust, 2 week cycle in full.
|
|
|
|
# arrives at 2 days left, present < 2 days.
|
2022-11-10 23:03:50 +05:00
|
|
|
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:
|
|
|
|
self.BaroStateStr.setText('Baro Arrives in:')
|
|
|
|
baro_eta = baro_eta - 2 * 86400
|
|
|
|
else:
|
|
|
|
self.BaroStateStr.setText('Baro Leaves in:')
|
|
|
|
self.BaroTimeStr.setText(f'{str(baro_eta // 86400) + "d " if baro_eta // 86400 > 0 else ""}{(baro_eta // 3600) % 24}h {(baro_eta // 60) % 60}m {baro_eta % 60}s')
|
|
|
|
|
|
|
|
|
|
|
|
def update_world_state(self):
|
|
|
|
if self.ws.get_ws():
|
|
|
|
self.redraw_content()
|
|
|
|
else:
|
|
|
|
self.network_error()
|
2022-11-10 16:26:28 +05:00
|
|
|
|
|
|
|
def network_error(self):
|
2023-08-03 13:37:46 +05:00
|
|
|
# slapped on later, just a dialog box for network error
|
2022-11-10 16:26:28 +05:00
|
|
|
msg = QMessageBox()
|
|
|
|
msg.setIcon(QMessageBox.Critical)
|
|
|
|
msg.setText('Network Error')
|
|
|
|
msg.setInformativeText('Could not connect to api.warframestat.us')
|
|
|
|
msg.setWindowTitle('Error')
|
|
|
|
msg.exec_()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app_handle = QApplication(sys.argv)
|
|
|
|
app = App()
|
|
|
|
app.show()
|
|
|
|
app_handle.exec_()
|
|
|
|
|