From 7facc2579b2c33774f57f02fdc18137708abad17 Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Sun, 24 Sep 2023 12:35:44 -0400 Subject: [PATCH 1/6] Address some issues with web server actions and disable SocketIO logging for dev only --- src/TSHWebServer.py | 8 +++++++- src/TSHWebServerActions.py | 40 ++++++++++---------------------------- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/TSHWebServer.py b/src/TSHWebServer.py index b19490cc1..36b771835 100644 --- a/src/TSHWebServer.py +++ b/src/TSHWebServer.py @@ -20,7 +20,13 @@ class WebServer(QThread): app = Flask(__name__, static_folder=os.path.curdir) cors = CORS(app) - socketio = SocketIO(app, cors_allowed_origins='*', logger=logger, async_mode='threading') + socketio = SocketIO( + app, + cors_allowed_origins='*', + #Uncomment to enable SocketIO logging (As logging is unuseful, we'll make this a dev flag) + #logger=logger, + async_mode='threading' + ) app.config['CORS_HEADERS'] = 'Content-Type' actions = None diff --git a/src/TSHWebServerActions.py b/src/TSHWebServerActions.py index 3282571ee..d7bd9d72d 100644 --- a/src/TSHWebServerActions.py +++ b/src/TSHWebServerActions.py @@ -131,15 +131,14 @@ def post_score(self, data): return "OK" def team_scoreup(self, scoreboard, team): - logger.info(team) - if team == 1 or team == "1": + if str(team) == "1": self.scoreboard.GetScoreboard(scoreboard).signals.CommandScoreChange.emit(0, 1) else: self.scoreboard.GetScoreboard(scoreboard).signals.CommandScoreChange.emit(1, 1) return "OK" def team_scoredown(self, scoreboard, team): - if team == 1 or team == "1": + if str(team) == "1": self.scoreboard.GetScoreboard(scoreboard).signals.CommandScoreChange.emit(0, -1) else: self.scoreboard.GetScoreboard(scoreboard).signals.CommandScoreChange.emit(1, -1) @@ -157,21 +156,15 @@ def set_route(self, # Best Of argument # best-of= if bestOf is not None: - if not isinstance(bestOf, int): - bestOf = 0 - self.scoreboard.GetScoreboard(scoreboard).signals.ChangeSetData.emit( json.loads( - json.dumps({'bestOf': bestOf}) + json.dumps({'bestOf': int(bestOf)}) ) ) # Phase argument # phase= if phase is not None: - if not isinstance(phase, str): - phase = 'Pools' - self.scoreboard.GetScoreboard(scoreboard).signals.ChangeSetData.emit( json.loads( json.dumps({'tournament_phase': phase}) @@ -181,9 +174,6 @@ def set_route(self, # Match argument # match= if match is not None: - if not isinstance(match, str): - match = 'Pools' - self.scoreboard.GetScoreboard(scoreboard).signals.ChangeSetData.emit( json.loads( json.dumps({'round_name': match}) @@ -193,29 +183,19 @@ def set_route(self, # Players argument # players= if players is not None: - if not isinstance(players, int): - players = 1 - - self.scoreboard.GetScoreboard(scoreboard).playerNumber.setValue(players) + self.scoreboard.GetScoreboard(scoreboard).playerNumber.setValue(int(players)) # Characters argument # characters= if characters is not None: - if not isinstance(characters, int): - characters = 1 - - self.scoreboard.GetScoreboard(scoreboard).charNumber.setValue(characters) + self.scoreboard.GetScoreboard(scoreboard).charNumber.setValue(int(characters)) # Losers argument # losers=&team= if losers is not None: - losers = bool(losers) - if not isinstance(team, str): - team = '1' - self.scoreboard.GetScoreboard(scoreboard).signals.ChangeSetData.emit( json.loads( - json.dumps({'team' + team + 'losers': losers}) + json.dumps({'team' + str(team) + 'losers': bool(losers)}) ) ) return "OK" @@ -264,10 +244,10 @@ def stats_upset_factor(self, scoreboard): return "OK" def stats_last_sets(self, scoreboard, player): - if player == 1 or player == "1": + if str(player) == "1": self.scoreboard.GetScoreboard( scoreboard).stats.signals.LastSetsP1Signal.emit() - elif player == 2 or player == "2": + elif str(player) == "2": self.scoreboard.GetScoreboard( scoreboard).stats.signals.LastSetsP2Signal.emit() elif player == "both": @@ -281,10 +261,10 @@ def stats_last_sets(self, scoreboard, player): return "OK" def stats_history_sets(self, scoreboard, player): - if player == 1 or player == "1": + if str(player) == "1": self.scoreboard.GetScoreboard( scoreboard).stats.signals.PlayerHistoryStandingsP1Signal.emit() - elif player == 2 or player == "2": + elif str(player) == "2": self.scoreboard.GetScoreboard( scoreboard).stats.signals.PlayerHistoryStandingsP2Signal.emit() elif player == "both": From bf587f1fe490b1ef51264f3b4c29cbc5b83f80ed Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Sun, 24 Sep 2023 16:08:43 -0400 Subject: [PATCH 2/6] Address Stats applying across scoreboards and a few other issues --- src/TSHStatsUtil.py | 19 +++++++++++-------- src/TSHTournamentDataProvider.py | 17 ++++++----------- .../StartGGDataProvider.py | 5 ++++- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/TSHStatsUtil.py b/src/TSHStatsUtil.py index 9e782e5ab..2a4f61859 100644 --- a/src/TSHStatsUtil.py +++ b/src/TSHStatsUtil.py @@ -18,6 +18,9 @@ class TSHStatsSignals(QObject): PlayerHistoryStandingsP2Signal = Signal() UpsetFactorCalculation = Signal() + recent_sets_updated = Signal(dict) + last_sets_updated = Signal(dict) + history_sets_updated = Signal(dict) class TSHStatsUtil: instance: "TSHStatsUtil" = None @@ -41,11 +44,11 @@ def __init__(self, scoreboardNumber, scoreboard): self.signals.UpsetFactorCalculation.connect( self.GetSetUpsetFactor) - TSHTournamentDataProvider.instance.signals.history_sets_updated.connect( + self.signals.history_sets_updated.connect( self.UpdateHistorySets) - TSHTournamentDataProvider.instance.signals.last_sets_updated.connect( + self.signals.last_sets_updated.connect( self.UpdateLastSets) - TSHTournamentDataProvider.instance.signals.recent_sets_updated.connect( + self.signals.recent_sets_updated.connect( self.UpdateRecentSets) TSHTournamentDataProvider.instance.signals.stream_queue_loaded.connect( self.UpdateStreamQueue) @@ -61,7 +64,7 @@ def GetRecentSets(self): "state": "loading", "sets": [] }) - TSHTournamentDataProvider.instance.GetRecentSets(p1id, p2id) + TSHTournamentDataProvider.instance.GetRecentSets(self.signals.recent_sets_updated, p1id, p2id) updated = True if not updated: @@ -86,7 +89,7 @@ def GetLastSetsP1(self): p1id = StateManager.Get(f"score.{self.scoreboardNumber}.team.1.player.1.id") logger.info(f"Player 1 ID: {p1id}") if p1id: - TSHTournamentDataProvider.instance.GetLastSets(p1id, "1") + TSHTournamentDataProvider.instance.GetLastSets(self.signals.last_sets_updated, p1id, "1") else: StateManager.Set(f"score.{self.scoreboardNumber}.last_sets.1", {}) @@ -96,7 +99,7 @@ def GetLastSetsP2(self): p2id = StateManager.Get(f"score.{self.scoreboardNumber}.team.2.player.1.id") logger.info(f"Player 2 ID: {p2id}") if p2id: - TSHTournamentDataProvider.instance.GetLastSets(p2id, "2") + TSHTournamentDataProvider.instance.GetLastSets(self.signals.last_sets_updated, p2id, "2") else: StateManager.Set(f"score.{self.scoreboardNumber}.last_sets.2", {}) @@ -124,7 +127,7 @@ def GetPlayerHistoryStandingsP1(self): p1id = StateManager.Get(f"score.{self.scoreboardNumber}.team.1.player.1.id") if p1id: TSHTournamentDataProvider.instance.GetPlayerHistoryStandings( - p1id, "1", StateManager.Get(f"game.smashgg_id")) + self.signals.history_sets_updated, p1id, "1", StateManager.Get(f"game.smashgg_id")) else: StateManager.Set(f"score.{self.scoreboardNumber}.history_sets.1", {}) @@ -134,7 +137,7 @@ def GetPlayerHistoryStandingsP2(self): p2id = StateManager.Get(f"score.{self.scoreboardNumber}.team.2.player.1.id") if p2id: TSHTournamentDataProvider.instance.GetPlayerHistoryStandings( - p2id, "2", StateManager.Get(f"game.smashgg_id")) + self.signals.history_sets_updated, p2id, "2", StateManager.Get(f"game.smashgg_id")) else: StateManager.Set(f"score.{self.scoreboardNumber}.history_sets.2", {}) diff --git a/src/TSHTournamentDataProvider.py b/src/TSHTournamentDataProvider.py index 24e9a429f..3015b62bb 100644 --- a/src/TSHTournamentDataProvider.py +++ b/src/TSHTournamentDataProvider.py @@ -23,16 +23,12 @@ class TSHTournamentDataProviderSignals(QObject): tournament_data_updated = Signal(dict) twitch_username_updated = Signal() user_updated = Signal() - recent_sets_updated = Signal(dict) - last_sets_updated = Signal(dict) - history_sets_updated = Signal(dict) get_sets_finished = Signal(list) tournament_phases_updated = Signal(list) tournament_phasegroup_updated = Signal(dict) game_changed = Signal(int) stream_queue_loaded = Signal(dict) - class TSHTournamentDataProvider: instance: "TSHTournamentDataProvider" = None @@ -244,9 +240,9 @@ def GetMatch(self, mainWindow, setId, overwrite=True): ]) self.threadPool.start(worker) - def GetRecentSets(self, id1, id2): + def GetRecentSets(self, callback, id1, id2): worker = Worker(self.provider.GetRecentSets, **{ - "id1": id1, "id2": id2, "callback": self.signals.recent_sets_updated, "requestTime": time.time_ns() + "id1": id1, "id2": id2, "callback": callback, "requestTime": time.time_ns() }) self.threadPool.start(worker) @@ -259,25 +255,24 @@ def GetStandings(self, playerNumber, callback): ]) self.threadPool.start(worker) - def GetLastSets(self, playerId, playerNumber): + def GetLastSets(self, callback, playerId, playerNumber): worker = Worker(self.provider.GetLastSets, **{ "playerID": playerId[0], "playerNumber": playerNumber, - "callback": self.signals.last_sets_updated + "callback": callback }) self.threadPool.start(worker) - def GetPlayerHistoryStandings(self, playerId, playerNumber, gameType): + def GetPlayerHistoryStandings(self, callback, playerId, playerNumber, gameType): worker = Worker(self.provider.GetPlayerHistoryStandings, **{ "playerID": playerId[0], "playerNumber": playerNumber, "gameType": gameType, - "callback": self.signals.history_sets_updated + "callback": callback }) self.threadPool.start(worker) def GetStreamQueue(self): - worker = Worker(self.provider.GetStreamQueue) worker.signals.result.connect(lambda streamQueue: [ TSHTournamentDataProvider.instance.signals.stream_queue_loaded.emit( diff --git a/src/TournamentDataProvider/StartGGDataProvider.py b/src/TournamentDataProvider/StartGGDataProvider.py index 30c0f2810..6e0e99af7 100644 --- a/src/TournamentDataProvider/StartGGDataProvider.py +++ b/src/TournamentDataProvider/StartGGDataProvider.py @@ -379,6 +379,9 @@ def GetMatch(self, setId, progress_callback): return finalResult def _GetMatchTasks(self, setId, progress_callback): + if "preview" in str(setId): + return self.ParseMatchDataOldApi({}) + data = self.QueryRequests( f'https://www.start.gg/api/-/gg_api./set/{setId};bustCache=true;expand=["setTask"];fetchMostRecentCached=true', type=requests.get, @@ -963,9 +966,9 @@ def GetStreamQueue(self, progress_callback=None): stateCode = playerData.get("state_code", "") countryData = TSHCountryHelper.countries.get( countryCode) + stateData = {} if countryData: states = countryData.get("states") - stateData = {} if stateCode: stateData = states[stateCode] From d2f46ef22a63f02c2992702d50d16ce2fae2e9a2 Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Thu, 28 Sep 2023 18:01:39 -0400 Subject: [PATCH 3/6] Change over commentary widget to use the player widget, UI changes, and stage pull fix --- src/TSHCommentaryWidget.py | 205 +++++++++++------------------- src/TSHScoreboardPlayerWidget.py | 23 ++-- src/TSHScoreboardStageWidget.py | 32 ++--- src/layout/TSHScoreboardPlayer.ui | 191 ++++++++++++++-------------- 4 files changed, 200 insertions(+), 251 deletions(-) diff --git a/src/TSHCommentaryWidget.py b/src/TSHCommentaryWidget.py index dd0218381..92e453ab3 100644 --- a/src/TSHCommentaryWidget.py +++ b/src/TSHCommentaryWidget.py @@ -5,8 +5,10 @@ from qtpy import uic from loguru import logger -from .TSHScoreboardPlayerWidget import * +from .TSHScoreboardPlayerWidget import TSHScoreboardPlayerWidget from .Helpers.TSHBadWordFilter import TSHBadWordFilter +from .TSHPlayerDB import TSHPlayerDB +from .StateManager import StateManager class TSHCommentaryWidget(QDockWidget): @@ -32,10 +34,54 @@ def __init__(self, *args): col.setLayout(QVBoxLayout()) topOptions.layout().addWidget(col) self.commentatorNumber = QSpinBox() - col.layout().addWidget(QLabel(QApplication.translate("app", "Number of commentators"))) - col.layout().addWidget(self.commentatorNumber) + row = QWidget() + row.setLayout(QHBoxLayout()) + commsNumber = QLabel(QApplication.translate("app", "Number of commentators")) + commsNumber.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum) + row.layout().addWidget(commsNumber) + row.layout().addWidget(self.commentatorNumber) self.commentatorNumber.valueChanged.connect( lambda val: self.SetCommentatorNumber(val)) + + characterNumber = QSpinBox() + charNumber = QLabel(QApplication.translate("app", "Characters per player")) + charNumber.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum) + row.layout().addWidget(charNumber) + row.layout().addWidget(characterNumber) + characterNumber.valueChanged.connect(self.SetCharacterNumber) + + self.eyeBt = QToolButton() + self.eyeBt.setIcon(QIcon('assets/icons/eye.svg')) + self.eyeBt.setSizePolicy( + QSizePolicy.Maximum, QSizePolicy.Fixed) + col.layout().addWidget(self.eyeBt, Qt.AlignmentFlag.AlignRight) + self.eyeBt.setPopupMode(QToolButton.InstantPopup) + menu = QMenu() + self.eyeBt.setMenu(menu) + + menu.addSection("Players") + + self.elements = [ + ["Real Name", ["real_name", "real_nameLabel"]], + ["Twitter", ["twitter", "twitterLabel"]], + ["Location", ["locationLabel", "state", "country"]], + ["Characters", ["characters"]], + ["Pronouns", ["pronoun", "pronounLabel"]], + ] + self.elements[0][0] = QApplication.translate("app", "Real Name") + self.elements[1][0] = QApplication.translate("app", "Twitter") + self.elements[2][0] = QApplication.translate("app", "Location") + self.elements[3][0] = QApplication.translate("app", "Characters") + self.elements[4][0] = QApplication.translate("app", "Pronouns") + for element in self.elements: + action: QAction = self.eyeBt.menu().addAction(element[0]) + action.setCheckable(True) + action.setChecked(True) + action.toggled.connect( + lambda toggled, action=action, element=element: self.ToggleElements(action, element[1])) + + row.layout().addWidget(self.eyeBt) + col.layout().addWidget(row) scrollArea = QScrollArea() scrollArea.setFrameShadow(QFrame.Shadow.Plain) @@ -54,40 +100,23 @@ def __init__(self, *args): StateManager.Set("commentary", {}) self.commentatorNumber.setValue(2) - - TSHPlayerDB.signals.db_updated.connect(self.SetupAutocomplete) - self.SetupAutocomplete() + characterNumber.setValue(1) def SetCommentatorNumber(self, number): while len(self.commentaryWidgets) < number: - comm = QGroupBox() - uic.loadUi("src/layout/TSHCommentator.ui", comm) - comm.setTitle(QApplication.translate( - "app", "Commentator {0}").format(len(self.commentaryWidgets)+1)) - - for c in comm.findChildren(QLineEdit): - c.editingFinished.connect( - lambda element=c, index=len(self.commentaryWidgets)+1: [ - StateManager.Set( - f"commentary.{index}.{element.objectName()}", element.text()) - ]) - c.editingFinished.emit() - - comm.findChild(QPushButton, "btUp").setIcon( - QIcon("./assets/icons/arrow_up.svg")) - comm.findChild(QPushButton, "btUp").clicked.connect( + comm = TSHScoreboardPlayerWidget( + index=len(self.commentaryWidgets)+1, + teamNumber=0, + path=f'commentary.{len(self.commentaryWidgets)+1}', + customName="Commentator" + ) + + comm.btMoveUp.clicked.connect( lambda x=None, index=len(self.commentaryWidgets): self.MoveUp(index)) - comm.findChild(QPushButton, "btDown").setIcon( - QIcon("./assets/icons/arrow_down.svg")) - comm.findChild(QPushButton, "btDown").clicked.connect( + comm.btMoveDown.clicked.connect( lambda x=None, index=len(self.commentaryWidgets): self.MoveDown(index)) - comm.findChild(QLineEdit, "name").editingFinished.connect( - lambda c=comm, index=len(self.commentaryWidgets)+1: self.ExportMergedName(c, index)) - comm.findChild(QLineEdit, "team").editingFinished.connect( - lambda c=comm, index=len(self.commentaryWidgets)+1: self.ExportMergedName(c, index)) - self.commentaryWidgets.append(comm) self.widgetArea.layout().addWidget(comm) @@ -96,115 +125,27 @@ def SetCommentatorNumber(self, number): comm.setParent(None) self.commentaryWidgets.remove(comm) - self.SetupAutocomplete() - if StateManager.Get(f'commentary'): for k in list(StateManager.Get(f'commentary').keys()): if not k.isnumeric() or (k.isnumeric() and int(k) > number): StateManager.Unset(f'commentary.{k}') def MoveUp(self, index): - try: - StateManager.BlockSaving() - if index > 0: - self.SwapComms(index, index-1) - finally: - StateManager.ReleaseSaving() + if index > 0: + self.SwapComms(index, index-1) def MoveDown(self, index): - try: - StateManager.BlockSaving() - if index < len(self.commentaryWidgets)-1: - self.SwapComms(index, index+1) - finally: - StateManager.ReleaseSaving() + if index < len(self.commentaryWidgets)-1: + self.SwapComms(index, index+1) def SwapComms(self, index1, index2): - saveState = {c.objectName(): c.text() - for c in self.commentaryWidgets[index1].findChildren(QLineEdit)} - - for c in self.commentaryWidgets[index2].findChildren(QLineEdit): - for c2 in self.commentaryWidgets[index2].findChildren(QLineEdit): - self.commentaryWidgets[index1].findChild( - QLineEdit, c.objectName()).setText(c.text()) - self.commentaryWidgets[index1].findChild( - QLineEdit, c.objectName()).editingFinished.emit() - - c.setText(saveState[c.objectName()]) - c.editingFinished.emit() - - def ExportMergedName(self, comm, index): - team = comm.findChild(QLineEdit, "team").text() - name = comm.findChild(QLineEdit, "name").text() - merged = "" - - if team != "": - merged += team+" | " - - merged += name - - StateManager.Set( - f"commentary.{index}.mergedName", merged) - - def SetupAutocomplete(self): - if TSHPlayerDB.model: - for c in self.commentaryWidgets: - c.findChild(QLineEdit, "name").setCompleter(QCompleter()) - c.findChild(QLineEdit, "name").completer().setCaseSensitivity( - Qt.CaseSensitivity.CaseInsensitive) - c.findChild(QLineEdit, "name").completer( - ).setFilterMode(Qt.MatchFlag.MatchContains) - c.findChild(QLineEdit, "name").completer().setModel( - TSHPlayerDB.model) - c.findChild(QLineEdit, "name").completer().activated[QModelIndex].connect( - lambda x, c=c: self.SetData( - c, - x.data(Qt.ItemDataRole.UserRole)), Qt.QueuedConnection - ) - c.pronoun_completer = QCompleter() - c.findChild(QLineEdit, "pronoun").setCompleter( - c.pronoun_completer) - c.pronoun_list = [] - for file in ['./user_data/pronouns_list.txt']: - try: - with open(file, 'r') as f: - for l in f.readlines(): - processed_line = l.replace("\n", "").strip() - if processed_line and processed_line not in c.pronoun_list: - c.pronoun_list.append(processed_line) - except Exception as e: - logger.error(f"ERROR: Did not find {file}") - logger.error(traceback.format_exc()) - c.pronoun_model = QStringListModel() - c.pronoun_completer.setModel(c.pronoun_model) - c.pronoun_model.setStringList(c.pronoun_list) - - def SetData(self, widget, data): - if data.get("gamerTag"): - data["gamerTag"] = TSHBadWordFilter.Censor( - data["gamerTag"], data.get("country_code")) - widget.findChild(QLineEdit, "name").setText(data.get("gamerTag", "")) - widget.findChild(QLineEdit, "name").editingFinished.emit() - - if data.get("team"): - data["team"] = TSHBadWordFilter.Censor( - data["team"], data.get("country_code")) - widget.findChild(QLineEdit, "team").setText(data.get("prefix")) - widget.findChild(QLineEdit, "team").editingFinished.emit() - - if data.get("real_name"): - data["real_name"] = TSHBadWordFilter.Censor( - data["real_name"], data.get("country_code")) - widget.findChild(QLineEdit, "real_name").setText(data.get("name", "")) - widget.findChild(QLineEdit, "real_name").editingFinished.emit() - - if data.get("twitter"): - data["twitter"] = TSHBadWordFilter.Censor( - data["twitter"], data.get("country_code")) - widget.findChild(QLineEdit, "twitter").setText(data.get("twitter", "")) - widget.findChild(QLineEdit, "twitter").editingFinished.emit() - - if data.get("pronoun"): - data["pronoun"] = TSHBadWordFilter.Censor(data["pronoun"]) - widget.findChild(QLineEdit, "pronoun").setText(data.get("pronoun", "")) - widget.findChild(QLineEdit, "pronoun").editingFinished.emit() + self.commentaryWidgets[index1].SwapWith(self.commentaryWidgets[index2]) + + def ToggleElements(self, action: QAction, elements): + for pw in self.commentaryWidgets: + for element in elements: + pw.findChild(QWidget, element).setVisible(action.isChecked()) + + def SetCharacterNumber(self, value): + for pw in self.commentaryWidgets: + pw.SetCharactersPerPlayer(value) \ No newline at end of file diff --git a/src/TSHScoreboardPlayerWidget.py b/src/TSHScoreboardPlayerWidget.py index 443cb8719..ee561b922 100644 --- a/src/TSHScoreboardPlayerWidget.py +++ b/src/TSHScoreboardPlayerWidget.py @@ -37,7 +37,7 @@ class TSHScoreboardPlayerWidget(QGroupBox): dataLock = threading.RLock() - def __init__(self, index=0, teamNumber=0, path="", scoreboardNumber=1, *args): + def __init__(self, index=0, teamNumber=0, path="", scoreboardNumber=1, customName="", *args): super().__init__(*args) self.instanceSignals = TSHScoreboardPlayerWidgetSignals() @@ -47,6 +47,7 @@ def __init__(self, index=0, teamNumber=0, path="", scoreboardNumber=1, *args): self.index = index self.teamNumber = teamNumber self.scoreboardNumber = scoreboardNumber + self.customName = customName self.losers = False @@ -284,11 +285,12 @@ def ExportPlayerId(self, id=None): if StateManager.Get(f"{self.path}.id") != id: StateManager.Set( f"{self.path}.id", id) - self.instanceSignals.playerId_changed.emit() - if self.path.startswith(f"score.{self.scoreboardNumber}.team.1"): - self.instanceSignals.player1Id_changed.emit() - else: - self.instanceSignals.player2Id_changed.emit() + if "score" in self.path: + self.instanceSignals.playerId_changed.emit() + if "team.1" in self.path: + self.instanceSignals.player1Id_changed.emit() + else: + self.instanceSignals.player2Id_changed.emit() def ExportPlayerSeed(self, seed=None): with self.dataLock: @@ -340,8 +342,13 @@ def SwapWith(self, other: "TSHScoreboardPlayerWidget"): StateManager.ReleaseSaving() def SetIndex(self, index: int, team: int): - self.findChild(QWidget, "title").setText( - QApplication.translate("app", "Player {0}").format(index)) + if self.customName == "": + self.findChild(QWidget, "title").setText( + QApplication.translate("app", "Player {0}").format(index)) + else: + title = self.customName + " {0}" + self.findChild(QWidget, "title").setText( + QApplication.translate("app", title).format(index)) self.index = index self.teamNumber = team diff --git a/src/TSHScoreboardStageWidget.py b/src/TSHScoreboardStageWidget.py index af1a3c81c..cbae5d91e 100644 --- a/src/TSHScoreboardStageWidget.py +++ b/src/TSHScoreboardStageWidget.py @@ -510,32 +510,34 @@ def GetCurrentRuleset(self, forSaving=False): return ruleset + def QueryRequests(self, url=None, type=None, headers=None, jsonParams=None, params=None): + requestCode = 0 + data = None + while requestCode != 200: + data = type( + url, + headers=headers, + json=jsonParams, + params=params + ) + requestCode = data.status_code + return json.loads(data.text) + def LoadStartggRulesets(self): try: class DownloadThread(QThread): + query = self.QueryRequests def run(self): - try: - data = requests.get( - "https://www.start.gg/api/-/gg_api./rulesets" + data = self.query( + "https://www.start.gg/api/-/gg_api./rulesets", + type=requests.get ) - data = json.loads(data.text) rulesets = deep_get(data, "entities.ruleset") open('./assets/rulesets.json', 'w').write(json.dumps(rulesets)) self.parent().startggRulesets = rulesets logger.info("startgg Rulesets downloaded from startgg") self.parent().signals.rulesets_changed.emit() - except: - logger.error(traceback.format_exc()) - - try: - rulesets = json.loads( - open('./assets/rulesets.json').read()) - self.parent().startggRulesets = rulesets - logger.info("startgg Rulesets loaded from local file") - self.parent().signals.rulesets_changed.emit() - except: - logger.error(traceback.format_exc()) downloadThread = DownloadThread(self) downloadThread.start() except Exception as e: diff --git a/src/layout/TSHScoreboardPlayer.ui b/src/layout/TSHScoreboardPlayer.ui index 458040896..46c015cd6 100644 --- a/src/layout/TSHScoreboardPlayer.ui +++ b/src/layout/TSHScoreboardPlayer.ui @@ -7,7 +7,7 @@ 0 0 393 - 267 + 345 @@ -28,19 +28,54 @@ - - + + - 9 + 8 + true - - Real Name + + CHARACTERS + - + + + + + + + 10 + true + + + + PLAYER + + + Qt::AlignCenter + + + + + + + + + + 8 + true + + + + SPONSOR/TAG + + + + @@ -92,64 +127,39 @@ - - - - - 9 - - - - - - - - - - - - 8 - 75 - true - - - - SPONSOR/TAG - - - - - - - - 8 - 75 - true - - - - TWITTER - - - - - - - - 9 - - - - Handle Only - - + + + + + + + 9 + + + + Handle Only + + + + + + + + 9 + + + + + + + + - + 8 - 75 true @@ -158,32 +168,15 @@ - - - - - 8 - 75 - true - - - - CHARACTERS - - - - - - + + - 8 - 75 - true + 9 - - REAL NAME + + Real Name @@ -224,36 +217,44 @@ - - + + 8 - 75 true - PRONOUNS + REAL NAME - - + + - + - 10 - 75 + 8 true - PLAYER + TWITTER - - Qt::AlignCenter + + + + + + + 8 + true + + + + PRONOUNS @@ -263,8 +264,6 @@ real_name - twitter - pronoun From 7dadbe1399313f33220471f80d30e266ebdc909a Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Thu, 5 Oct 2023 17:55:28 -0400 Subject: [PATCH 4/6] Fix some more layout items missed and lock scoreboard amount to not allow manual edits --- layout/last_sets/index.js | 4 ++-- layout/map/index.js | 8 ++++---- layout/map_world_fighters/index.js | 8 ++++---- layout/recent_sets_full/index.js | 4 ++-- layout/scoreboard_JinTracker/index.js | 16 ++++++++-------- layout/scoreboard_mainstagy/index.js | 2 +- layout/scoreboard_topleft/index.js | 2 +- layout/scoreboard_vgbootcampy_classic/index.js | 2 +- src/TournamentStreamHelper.py | 1 + 9 files changed, 24 insertions(+), 23 deletions(-) diff --git a/layout/last_sets/index.js b/layout/last_sets/index.js index 0e3c5dbeb..0d322ace6 100644 --- a/layout/last_sets/index.js +++ b/layout/last_sets/index.js @@ -19,8 +19,8 @@ LoadEverything().then(() => { if ( !oldData.score || - JSON.stringify(data.score.last_sets) != - JSON.stringify(oldData.score.last_sets) + JSON.stringify(data.score[scoreboardNumber].last_sets) != + JSON.stringify(oldData.score[scoreboardNumber].last_sets) ) { sets_html = ""; Object.values(data.score[scoreboardNumber].last_sets[window.PLAYER]) diff --git a/layout/map/index.js b/layout/map/index.js index d28880a1e..0dc3c16ac 100755 --- a/layout/map/index.js +++ b/layout/map/index.js @@ -292,10 +292,10 @@ LoadEverything().then(() => { if ( Object.keys(oldData).length == 0 || - JSON.stringify(oldData.score.team["1"].player) != - JSON.stringify(data.score.team["1"].player) || - JSON.stringify(oldData.score.team["2"].player) != - JSON.stringify(data.score.team["2"].player) + JSON.stringify(oldData.score[scoreboardNumber].team["1"].player) != + JSON.stringify(data.score[scoreboardNumber].team["1"].player) || + JSON.stringify(oldData.score[scoreboardNumber].team["2"].player) != + JSON.stringify(data.score[scoreboardNumber].team["2"].player) ) { UpdateMap(); } diff --git a/layout/map_world_fighters/index.js b/layout/map_world_fighters/index.js index 773d10ce1..1c5e7ba30 100755 --- a/layout/map_world_fighters/index.js +++ b/layout/map_world_fighters/index.js @@ -335,10 +335,10 @@ LoadEverything().then(() => { if ( Object.keys(oldData).length == 0 || - JSON.stringify(oldData.score.team["1"].player) != - JSON.stringify(data.score.team["1"].player) || - JSON.stringify(oldData.score.team["2"].player) != - JSON.stringify(data.score.team["2"].player) + JSON.stringify(oldData.score[scoreboardNumber].team["1"].player) != + JSON.stringify(data.score[scoreboardNumber].team["1"].player) || + JSON.stringify(oldData.score[scoreboardNumber].team["2"].player) != + JSON.stringify(data.score[scoreboardNumber].team["2"].player) ) { UpdateMap(); } diff --git a/layout/recent_sets_full/index.js b/layout/recent_sets_full/index.js index d25d3cb01..54c61fd37 100644 --- a/layout/recent_sets_full/index.js +++ b/layout/recent_sets_full/index.js @@ -46,8 +46,8 @@ LoadEverything().then(() => { } else { if ( !oldData.score || - JSON.stringify(oldData.score.recent_sets) != - JSON.stringify(data.score.recent_sets) + JSON.stringify(oldData.score[scoreboardNumber].recent_sets) != + JSON.stringify(data.score[scoreboardNumber].recent_sets) ) { playersRecentSets = data.score[scoreboardNumber].recent_sets; diff --git a/layout/scoreboard_JinTracker/index.js b/layout/scoreboard_JinTracker/index.js index 68366e97f..8ee845007 100644 --- a/layout/scoreboard_JinTracker/index.js +++ b/layout/scoreboard_JinTracker/index.js @@ -205,7 +205,7 @@ LoadEverything().then(() => { * The result of game 1 is held in index 0, game 2 in index 1, and so on. */ function colorInBoxes() { - for (let i = 0; i < data.score.best_of; i++) { + for (let i = 0; i < data.score[scoreboardNumber].best_of; i++) { const redGameBox = document.querySelector(`.game${i + 1}.p1_won`); const blueGameBox = document.querySelector(`.game${i + 1}.p2_won`); const darkGameBox = document.querySelector(`.game${i + 1}.neither_won`); @@ -372,7 +372,7 @@ function updateGameArray( if (p1Score < 100) { for (let i = 0; i < p1Score - newP1Score; i++) { let index = -1; - for (let j = 0; j < data.score.best_of; j++) { + for (let j = 0; j < data.score[scoreboardNumber].best_of; j++) { if (gameArray[j] == 1) { index = j; // Locate the index of the most recent win } @@ -389,7 +389,7 @@ function updateGameArray( if (p2Score < 100) { for (let i = 0; i < p2Score - newP2Score; i++) { let index = -1; - for (let j = 0; j < data.score.best_of; j++) { + for (let j = 0; j < data.score[scoreboardNumber].best_of; j++) { if (gameArray[j] == 2) { index = j; // Locate the index of the most recent win } @@ -412,7 +412,7 @@ function updateGameArray( function scoreBoxDisplayToggle() { const scoreBoxes = document.querySelector(`.score_boxes`); - if (data.score.best_of > 0) { + if (data.score[scoreboardNumber].best_of > 0) { // Show the box(es) when Best Of is greater than 0 scoreBoxes.classList.add("unhidden"); } else { @@ -433,9 +433,9 @@ function createGameBoxes(savedBestOf) { let darkGameDivText = ""; // If Best Of is not 0 and Best Of has been updated - if (data.score.best_of > 0 && data.score.best_of != savedBestOf) { + if (data.score[scoreboardNumber].best_of > 0 && data.score[scoreboardNumber].best_of != savedBestOf) { // The number of boxes should equal Best Of - for (let i = 1; i <= data.score.best_of; i++) { + for (let i = 1; i <= data.score[scoreboardNumber].best_of; i++) { gameDivText += `
GAME ${i}
\n`; redGameDivText += `\n`; blueGameDivText += `\n`; @@ -445,13 +445,13 @@ function createGameBoxes(savedBestOf) { SetInnerHtml($(".red.score_boxes"), redGameDivText); // Create the red game boxes SetInnerHtml($(".blue.score_boxes"), blueGameDivText); // Create the blue game boxes SetInnerHtml($(".dark.score_boxes"), darkGameDivText); // Create the dark game boxes - } else if (data.score.best_of === 0) { + } else if (data.score[scoreboardNumber].best_of === 0) { SetInnerHtml($(".word.score_boxes"), ""); // The game boxes with words disappear SetInnerHtml($(".red.score_boxes"), ""); // The red game boxes disappear SetInnerHtml($(".blue.score_boxes"), ""); // The blue game boxes disappear SetInnerHtml($(".dark.score_boxes"), ""); // The dark game boxes disappear } - savedBestOf = data.score.best_of; // The new Best Of is saved so it can be used to detect change later + savedBestOf = data.score[scoreboardNumber].best_of; // The new Best Of is saved so it can be used to detect change later return savedBestOf; } diff --git a/layout/scoreboard_mainstagy/index.js b/layout/scoreboard_mainstagy/index.js index 5c40833c9..6d7cb9e17 100644 --- a/layout/scoreboard_mainstagy/index.js +++ b/layout/scoreboard_mainstagy/index.js @@ -212,7 +212,7 @@ LoadEverything().then(() => { async function UpdateMatch() { const tournamentContainer = document.querySelector(".tournament_container"); - if (!(data.score.best_of || data.score.match)) { + if (!(data.score[scoreboardNumber].best_of || data.score[scoreboardNumber].match)) { tournamentContainer.classList.add("hidden"); tournamentContainer.classList.remove("unhidden"); } else { diff --git a/layout/scoreboard_topleft/index.js b/layout/scoreboard_topleft/index.js index 1b7cda64b..8346789f3 100755 --- a/layout/scoreboard_topleft/index.js +++ b/layout/scoreboard_topleft/index.js @@ -220,7 +220,7 @@ LoadEverything().then(() => { : "" ); - let score = [data.score.score_left, data.score.score_right]; + let score = [data.score[scoreboardNumber].score_left, data.score[scoreboardNumber].score_right]; SetInnerHtml($(`.p${t + 1}.container .score`), String(team.score)); diff --git a/layout/scoreboard_vgbootcampy_classic/index.js b/layout/scoreboard_vgbootcampy_classic/index.js index f7c963f43..98a9eaa3c 100644 --- a/layout/scoreboard_vgbootcampy_classic/index.js +++ b/layout/scoreboard_vgbootcampy_classic/index.js @@ -170,7 +170,7 @@ LoadEverything().then(() => { if (!data.score[scoreboardNumber].best_of && data.score[scoreboardNumber].match) { SetInnerHtml($(".match"), data.score[scoreboardNumber].match.toUpperCase()); - } else if (data.score.best_of && !data.score[scoreboardNumber].match) { + } else if (data.score[scoreboardNumber].best_of && !data.score[scoreboardNumber].match) { SetInnerHtml($(".match"), data.score[scoreboardNumber].best_of_text.toUpperCase()); } else if (savedMatch != data.score[scoreboardNumber].match) { SetInnerHtml($(".match"), data.score[scoreboardNumber].match.toUpperCase()); diff --git a/src/TournamentStreamHelper.py b/src/TournamentStreamHelper.py index 674c63e53..003a48385 100755 --- a/src/TournamentStreamHelper.py +++ b/src/TournamentStreamHelper.py @@ -651,6 +651,7 @@ def __init__(self): self.scoreboardAmount = QSpinBox() self.scoreboardAmount.setMaximumWidth(100) + self.scoreboardAmount.lineEdit().setReadOnly(True) self.scoreboardAmount.setMinimum(1) self.scoreboardAmount.setMaximum(10) From 233ca735842dfac8a38e2bb81186f1244512abc0 Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Sun, 26 Nov 2023 15:41:57 -0500 Subject: [PATCH 5/6] Add file export setting --- src/Settings/TSHSettingsWindow.py | 8 ++++++++ src/StateManager.py | 1 + 2 files changed, 9 insertions(+) diff --git a/src/Settings/TSHSettingsWindow.py b/src/Settings/TSHSettingsWindow.py index f836114f8..01852c3c6 100644 --- a/src/Settings/TSHSettingsWindow.py +++ b/src/Settings/TSHSettingsWindow.py @@ -62,6 +62,14 @@ def UiMounted(self): False )) + generalSettings.append(( + QApplication.translate( + "settings.disable_export", "Disable TSH file exporting"), + "disable_export", + "checkbox", + False + )) + self.add_setting_widget(QApplication.translate( "settings", "General"), SettingsWidget("general", generalSettings)) diff --git a/src/StateManager.py b/src/StateManager.py index 8cd701468..089f38a79 100755 --- a/src/StateManager.py +++ b/src/StateManager.py @@ -10,6 +10,7 @@ import time from loguru import logger from .Helpers.TSHDictHelper import deep_get, deep_set, deep_unset, deep_clone +from .SettingsManager import SettingsManager class StateManager: From e417e13f0fa0f33978b095d3ca66491043222e7c Mon Sep 17 00:00:00 2001 From: Eion Dailey Date: Sun, 26 Nov 2023 15:42:46 -0500 Subject: [PATCH 6/6] Add Setting check for file exporting --- src/StateManager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/StateManager.py b/src/StateManager.py index 089f38a79..0908f44ce 100755 --- a/src/StateManager.py +++ b/src/StateManager.py @@ -47,7 +47,8 @@ def ExportAll(ref_diff): file.write(orjson.dumps(StateManager.state, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_INDENT_2)) StateManager.state.pop("timestamp") - StateManager.ExportText(StateManager.lastSavedState, ref_diff) + if not SettingsManager.Get("general.disable_export", False): + StateManager.ExportText(StateManager.lastSavedState, ref_diff) StateManager.lastSavedState = deep_clone(StateManager.state) diff = DeepDiff(StateManager.lastSavedState,