Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c8f9c80
Update .gitignore
itsjust-vy Dec 9, 2025
5bd08a6
Update versions.json and requirements.txt
itsjust-vy Dec 9, 2025
6934765
Update TSHWebServerActions.py
itsjust-vy Dec 9, 2025
6d1d3db
Update TSHTournamentDataProvider.py
itsjust-vy Dec 9, 2025
9849ff2
Comments about Parry.gg url matching
itsjust-vy Dec 9, 2025
4ccf1b9
Create ParryGGDataProvider.py
itsjust-vy Dec 9, 2025
3d66da6
Initialisation work
itsjust-vy Dec 11, 2025
71fef6b
ParryGG: GetIconURL
itsjust-vy Dec 12, 2025
a70f2ae
_create_service is now _setup_service
itsjust-vy Dec 12, 2025
d4339d4
ParryGG: GetEntrants
itsjust-vy Dec 12, 2025
f8957a8
ParryGG: GetTournamentData
itsjust-vy Dec 12, 2025
d908bbc
ParryGG: GetTournamentPhases
itsjust-vy Dec 12, 2025
92e6d92
Bugfixes and Cleaning
itsjust-vy Dec 15, 2025
a7f723e
Further Misc Bugfixes and Cleaning
itsjust-vy Dec 16, 2025
befa4dd
Basic Support in TSHTournamentDataProvider.py
itsjust-vy Dec 16, 2025
b285759
Get API Key from Settings, rather than .env
itsjust-vy Dec 16, 2025
c117dc8
Merge branch 'main' into feature/parry.gg
itsjust-vy Dec 16, 2025
ff96158
Bugfix for image.type comparison
itsjust-vy Dec 16, 2025
7c8b22d
Better Errors
itsjust-vy Dec 16, 2025
6be9c5d
Merge branch 'main' into feature/parry.gg
itsjust-vy Dec 18, 2025
e011886
Bring imports in line with StartGGDataProvider
itsjust-vy Dec 18, 2025
ff83e04
Merge branch 'main' into feature/parry.gg
itsjust-vy Feb 11, 2026
c9e7fd8
Update .gitignore
itsjust-vy Feb 11, 2026
27fde5c
Merge branch 'main' into feature/parry.gg
itsjust-vy Mar 1, 2026
48b8b9d
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 1, 2026
67d9e61
Fix crash on defaulting some settings
itsjust-vy Apr 1, 2026
836cc34
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 1, 2026
c219d1b
Basic Game IDs from parry.gg
itsjust-vy Apr 1, 2026
c864cc3
Use parry.gg game slugs rather than ids
itsjust-vy Apr 1, 2026
464ab3d
Renamed parrygg_game_id to parrygg_game_slug
itsjust-vy Apr 1, 2026
5b0495e
Check validity of StartGG-specific buttons
itsjust-vy Apr 1, 2026
87590be
Disable Player Tracking for parry.gg
itsjust-vy Apr 1, 2026
c899471
Return empty lists to avoid crashes
itsjust-vy Apr 1, 2026
9c686cc
seed works now
itsjust-vy Apr 5, 2026
34dde67
Implement GetStationMatchId
itsjust-vy Apr 5, 2026
7f52186
Only initialize get_slugs_and_ids once
itsjust-vy Apr 5, 2026
0e79172
Merge remote-tracking branch 'upstream/main'
itsjust-vy Apr 5, 2026
f44bb58
Merge remote-tracking branch 'upstream/main'
itsjust-vy Apr 6, 2026
b8bb3d5
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 6, 2026
8ee76ce
Merge remote-tracking branch 'upstream/main'
itsjust-vy Apr 7, 2026
6348fb0
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 7, 2026
d021f3b
Require parrygg >= 0.1.4
itsjust-vy Apr 8, 2026
63f55b3
Implement GetMatches
itsjust-vy Apr 8, 2026
9476cc8
Clearer errors for unimplemented functions
itsjust-vy Apr 8, 2026
6e31153
(poorly) Implement GetMatch
itsjust-vy Apr 8, 2026
7b8132f
Fix Sponsor Name
itsjust-vy Apr 8, 2026
ff5979e
Misc Fixes
itsjust-vy Apr 8, 2026
879b79c
Square Tournament Image/Icon
itsjust-vy Apr 8, 2026
65c263f
Merge remote-tracking branch 'upstream/main'
itsjust-vy Apr 10, 2026
1dc5abf
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 10, 2026
7b56ebb
Merge remote-tracking branch 'upstream/main'
itsjust-vy Apr 14, 2026
a93e1b0
Merge branch 'main' into feature/parry.gg
itsjust-vy Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"game_tracker"
],
"supported_providers": [
"StartGG"
"StartGG",
"ParryGG"
]
}
3 changes: 3 additions & 0 deletions dependencies/requirements.txt
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ tqdm==2.2.3
tzdata
zstd==1.5.7.3
countryflag==1.1.1
grpcio
parrygg>=0.1.4
python-dotenv
18 changes: 18 additions & 0 deletions src/Settings/TSHSettingsWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,24 @@ def UiMounted(self):

self.add_setting_widget(QApplication.translate(
"settings", "Bluesky"), SettingsWidget("bsky_account", bskySettings))

# Add API Key settings
APIKeySettings = []
APIKeySettings.append((
QApplication.translate(
"settings.api_keys", "parry.gg"),
"parrygg",
"password",
"",
None,
QApplication.translate(
"settings.api_keys", "You can get an API Key from parry.gg/api-keys") + "\n" +
QApplication.translate(
"settings.api_keys", "Please note that the API Key will be stored in plain text on your computer")
))

self.add_setting_widget(QApplication.translate(
"settings", "API Keys"), SettingsWidget("api_keys", APIKeySettings))

self.resize(1000, 500)
QApplication.processEvents()
Expand Down
21 changes: 21 additions & 0 deletions src/TSHGameAssetManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,27 @@ def detect_smashgg_id_match(game, id):
if detect_smashgg_id_match(game, gameid):
self.LoadGameAssets(i+1)
break

def SetGameFromParryGGId(self, gameid):
def detect_parrygg_id_match(game, id):
result = str(game.get("parrygg_game_slug", "")) == str(id)
if not result:
alternates = game.get("alternate_versions", [])
alternates_ids = []
for alternate in alternates:
if alternate.get("parrygg_game_slug"):
alternates_ids.append(
str(alternate.get("parrygg_game_slug")))
result = str(id) in alternates_ids
return (result)

if len(self.games.keys()) == 0:
return

for i, game in enumerate(self.games.values()):
if detect_parrygg_id_match(game, gameid):
self.LoadGameAssets(i+1)
break

def CopyCSS(self, game):
# Make dir if doesn't exists
Expand Down
9 changes: 7 additions & 2 deletions src/TSHScoreboardWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,12 +681,17 @@ def UpdateBottomButtons(self):
self.btSelectSet.setText(
QApplication.translate("app", "Load set from {0}").format(TSHTournamentDataProvider.instance.provider.url))
self.btSelectSet.setEnabled(True)
if self.scoreboardNumber <= 1 and not SettingsManager.Get("general.hide_track_player", False):
self.btLoadPlayerSet.setEnabled(True)
self.btLoadStationSet.setEnabled(True)
if TSHTournamentDataProvider.instance.provider.name == "StartGG":
if self.scoreboardNumber <= 1 and not SettingsManager.Get("general.hide_track_player", False):
self.btLoadPlayerSet.setEnabled(True)
elif TSHTournamentDataProvider.instance.provider.name == "ParryGG":
self.btLoadPlayerSet.setEnabled(False)
else:
self.btSelectSet.setText(
QApplication.translate("app", "Load set"))
self.btSelectSet.setEnabled(False)
self.btLoadStationSet.setEnabled(False)

def SetCharacterNumber(self, value):
# logger.info(f"TSHScoreboardWidget#SetCharacterNumber({value})")
Expand Down
43 changes: 42 additions & 1 deletion src/TSHTournamentDataProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .TSHGameAssetManager import TSHGameAssetManager
from .TournamentDataProvider.TournamentDataProvider import TournamentDataProvider
from .TournamentDataProvider.StartGGDataProvider import StartGGDataProvider
from .TournamentDataProvider.ParryGGDataProvider import ParryGGDataProvider
from .Helpers.TSHVersionHelper import get_supported_providers
from loguru import logger

Expand Down Expand Up @@ -63,6 +64,9 @@ def SetGameFromProvider(self):
if "start.gg" in self.provider.url:
TSHGameAssetManager.instance.SetGameFromStartGGId(
self.provider.videogame)
elif "parry.gg" in self.provider.url:
TSHGameAssetManager.instance.SetGameFromParryGGId(
self.provider.videogame)
else:
logger.error("Unsupported provider...")

Expand All @@ -76,6 +80,17 @@ def SetTournament(self, url, initialLoading=False):
TSHTournamentDataProvider.instance.provider = StartGGDataProvider(
url, self.threadPool, self)
url = TSHTournamentDataProvider.instance.provider.GetRealEventURL(url)
elif url is not None and "parry.gg" in url:
if not SettingsManager.Get("api_keys.parrygg"):
logger.error("ParryGG API key not set")
TSHTournamentDataProvider.instance.provider = None
else:
try:
TSHTournamentDataProvider.instance.provider = ParryGGDataProvider(
url, self.threadPool, self, SettingsManager.Get("api_keys.parrygg"))
except Exception as e:
logger.error(f"Failed to initialize ParryGG provider: {e}")
TSHTournamentDataProvider.instance.provider = None
else:
logger.error("Unsupported provider...")
TSHTournamentDataProvider.instance.provider = None
Expand Down Expand Up @@ -105,6 +120,9 @@ def SetTournamentSignal(self, url, initialLoading=False):
if url is not None and "start.gg" in url:
TSHTournamentDataProvider.instance.provider = StartGGDataProvider(
url, self.threadPool, self)
elif url is not None and "parry.gg" in url:
TSHTournamentDataProvider.instance.provider = ParryGGDataProvider(
url, self.threadPool, self)
else:
logger.error("Unsupported provider...")
TSHTournamentDataProvider.instance.provider = None
Expand Down Expand Up @@ -139,7 +157,16 @@ def SetStartggEventSlug(self, mainWindow):
okButton = QPushButton("OK")
validators = [
QRegularExpression("start.gg/tournament/[^/]+/event[s]?/[^/]+"),
QRegularExpression("start.gg/admin/tournament/[^/]+/brackets/[^/]+")
QRegularExpression("start.gg/admin/tournament/[^/]+/brackets/[^/]+"),

# This could maybe become just "parry.gg/[^/]+/[^/]+"
#
# But that form of url directs to the /main/bracket page anyway,
# so it's rare to see it shortened unless typing the url manually.
#
# Only downside is that the tournament management page would match
# (parry.gg/tournamentname/_manage) which doesn't include the event slug.
QRegularExpression("parry.gg/[^/]+/[^/]+/[^/]+")
]

def validateText():
Expand Down Expand Up @@ -173,6 +200,16 @@ def validateText():
# Some URLs in startgg have eventS but the API doesn't work with that format
url = url.replace("/events/", "/event/")

elif "parry.gg" in url:
# Remove the "_manage" part of admin urls first
url = url.replace("/_manage", "")

matches = re.match(
"(.*parry.gg/[^/]*/[^/]*)", url)

if matches:
url = matches.group()

SettingsManager.Set("TOURNAMENT_URL", url)
TSHTournamentDataProvider.instance.SetTournament(
SettingsManager.Get("TOURNAMENT_URL"))
Expand All @@ -193,6 +230,10 @@ def SetUserAccount(self, window, startgg=False):
if (self.provider and self.provider.url and "start.gg" in self.provider.url) or startgg:
window_text = QApplication.translate(
"app", "Paste the URL to the player's StartGG profile")
# TODO
# elif (self.provider and self.provider.url and "parry.gg" in self.provider.url):
# window_text = QApplication.translate(
# "app", "Paste the URL to the player's ParryGG profile")
else:
logger.error(QApplication.translate(
"app", "Invalid tournament data provider"))
Expand Down
18 changes: 17 additions & 1 deletion src/TSHWebServerActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,12 @@ def load_tournament(self, url=None):
return "OK"
else:
validators = [
QRegularExpression("start.gg/tournament/[^/]+/event[s]?/[^/]+")
QRegularExpression("start.gg/tournament/[^/]+/event[s]?/[^/]+"),

# This could maybe become just "parry.gg/[^/]+/[^/]+"
# But that form of url directs to the /main/bracket page anyway,
# so it's rare to see it shortened unless typing the url manually.
QRegularExpression("parry.gg/[^/]+/[^/]+/[^/]+")
]

for validator in validators:
Expand All @@ -548,6 +553,17 @@ def load_tournament(self, url=None):
# Some URLs in startgg have eventS but the API doesn't work with that format
url = url.replace("/events/", "/event/")

elif "parry.gg" in url:
# Remove the "_manage" part of admin urls first
url = url.replace("/_manage", "")

matches = re.match(
"(.*parry.gg/[^/]*/[^/]*)", url)

if matches:
url = matches.group()


SettingsManager.Set("TOURNAMENT_URL", url)
TSHTournamentDataProvider.instance.signals.tournament_url_update.emit(url)

Expand Down
Loading