Find the IGDB ID by searching on igdb.com.
- The ID is in the URL (e.g., igdb.com/games/slug/123 → ID is 123).
+ The ID is displayed in a box to the right of the metadata pane (e.g. IGDB ID: 12345).
From 1bf29180e2e3cf028c704c44de4ac2c262205d81 Mon Sep 17 00:00:00 2001
From: Ohad Schneider
Date: Fri, 13 Feb 2026 13:03:47 +0200
Subject: [PATCH 08/12] fix xbox store URL
---
web/utils/helpers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/web/utils/helpers.py b/web/utils/helpers.py
index 75e84cd..aca9b2d 100644
--- a/web/utils/helpers.py
+++ b/web/utils/helpers.py
@@ -56,7 +56,7 @@ def get_store_url(store, store_id, extra_data=None):
elif store == "xbox":
# Xbox Store URL
if store_id:
- return f"https://www.xbox.com/games/store/{store_id}"
+ return f"https://www.xbox.com/games/store/game/{store_id}"
return None
return None
From de9dcfd49f7c674fce08a9e20287d6c14af85dd5 Mon Sep 17 00:00:00 2001
From: Ohad Schneider
Date: Fri, 13 Feb 2026 22:52:47 +0200
Subject: [PATCH 09/12] default game pass plan should be `none`
---
web/sources/xbox.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/web/sources/xbox.py b/web/sources/xbox.py
index 35eecfa..f161c3f 100644
--- a/web/sources/xbox.py
+++ b/web/sources/xbox.py
@@ -47,7 +47,7 @@ def get_resolved_xbox_gamepass_settings():
"""Get Xbox Game Pass settings."""
gamepass_settings = get_xbox_gamepass_settings()
return {
- "plan": gamepass_settings.get("plan", "ultimate"),
+ "plan": gamepass_settings.get("plan", "none"),
"market": gamepass_settings.get("market", "US")
}
From 950fb72061b5590add7ad294518d3e3f9df3d594 Mon Sep 17 00:00:00 2001
From: Ohad Schneider
Date: Fri, 13 Feb 2026 22:53:50 +0200
Subject: [PATCH 10/12] fix var naming conventions
---
web/sources/xbox.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/web/sources/xbox.py b/web/sources/xbox.py
index f161c3f..bc0b2f5 100644
--- a/web/sources/xbox.py
+++ b/web/sources/xbox.py
@@ -341,11 +341,15 @@ def get_gamepass_catalog(plan, market):
all_games = []
- planInfo = GAMEPASS_PLAN_MAP[plan]
- collectionId = planInfo['collection']
- subscriptionId = planInfo['subscription']
+ plan_info = GAMEPASS_PLAN_MAP.get(plan)
+ if not plan_info:
+ print(f" Invalid Game Pass plan: {plan}")
+ return []
+
+ collection_id = plan_info['collection']
+ subscription_id = plan_info['subscription']
# Fetch Game Pass catalog
- url = f"{GAMEPASS_CATALOG_ENDPOINT}?id={collectionId}&language=en-US&market={market}&platformContext=pc&subscriptionContext={subscriptionId}"
+ url = f"{GAMEPASS_CATALOG_ENDPOINT}?id={collection_id}&language=en-US&market={market}&platformContext=pc&subscriptionContext={subscription_id}"
print(f" Fetching Game Pass catalog for plan: {plan} (market: {market})...")
response = requests.get(url, headers=REQUIRED_HEADERS)
From 5752b38c19ddea6b77589cde8aec0e327fc1d44e Mon Sep 17 00:00:00 2001
From: Ohad Schneider
Date: Fri, 13 Feb 2026 23:02:05 +0200
Subject: [PATCH 11/12] propagate config to inner methods via params
---
web/sources/xbox.py | 33 ++++++++++++++-------------------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/web/sources/xbox.py b/web/sources/xbox.py
index bc0b2f5..c7585a7 100644
--- a/web/sources/xbox.py
+++ b/web/sources/xbox.py
@@ -164,7 +164,7 @@ def get_xuid_from_token(token):
return None
-def get_owned_games(token, xuid=None):
+def get_owned_games(token, market, xuid=None):
"""Fetch owned games from Xbox TitleHub API."""
try:
auth_header, userhash = parse_xsts_token(token)
@@ -179,7 +179,7 @@ def get_owned_games(token, xuid=None):
if not xuid:
print(" Could not determine XUID - trying alternative API")
# Fall back to Collections API which doesn't need XUID
- return get_owned_games_from_collections(token)
+ return get_owned_games_from_collections(token, market)
headers = {
**REQUIRED_HEADERS,
@@ -204,7 +204,7 @@ def get_owned_games(token, xuid=None):
if response.status_code != 200:
print(f" TitleHub error: {response.status_code} - {response.text[:200]}")
# Try Collections API as fallback
- return get_owned_games_from_collections(token)
+ return get_owned_games_from_collections(token, market)
try:
data = response.json()
@@ -262,7 +262,7 @@ def get_owned_games(token, xuid=None):
return []
-def get_owned_games_from_collections(token):
+def get_owned_games_from_collections(token, market):
"""Fetch owned games using Collections API (alternative method)."""
try:
auth_header, _ = parse_xsts_token(token)
@@ -276,13 +276,12 @@ def get_owned_games_from_collections(token):
}
# Query for owned products
- planInfo = get_resolved_xbox_gamepass_settings()
payload = {
"productIds": [],
"productSkuIds": [],
"idType": "ProductId",
"beneficiaries": [],
- "market": planInfo["market"],
+ "market": market,
"languages": ["en-US"],
"maxPageSize": 1000,
}
@@ -341,11 +340,7 @@ def get_gamepass_catalog(plan, market):
all_games = []
- plan_info = GAMEPASS_PLAN_MAP.get(plan)
- if not plan_info:
- print(f" Invalid Game Pass plan: {plan}")
- return []
-
+ plan_info = GAMEPASS_PLAN_MAP[plan]
collection_id = plan_info['collection']
subscription_id = plan_info['subscription']
# Fetch Game Pass catalog
@@ -374,7 +369,7 @@ def get_gamepass_catalog(plan, market):
batch_size = 20
for i in range(0, len(product_ids), batch_size):
batch = product_ids[i:i + batch_size]
- details = get_product_details(batch)
+ details = get_product_details(batch, market)
all_games.extend(details)
return all_games
@@ -386,7 +381,7 @@ def get_gamepass_catalog(plan, market):
return []
-def get_product_details(product_ids):
+def get_product_details(product_ids, market):
"""Fetch product details from Display Catalog API."""
if not product_ids:
return []
@@ -394,8 +389,7 @@ def get_product_details(product_ids):
try:
# Build the products query
ids_param = ",".join(product_ids)
- planInfo = get_resolved_xbox_gamepass_settings()
- url = f"{DISPLAY_CATALOG_ENDPOINT}?bigIds={ids_param}&market={planInfo['market']}&languages=en-US"
+ url = f"{DISPLAY_CATALOG_ENDPOINT}?bigIds={ids_param}&market={market}&languages=en-US"
response = requests.get(url, headers=REQUIRED_HEADERS)
@@ -467,7 +461,8 @@ def get_xbox_library():
"""Fetch all games from Xbox - owned games + Game Pass catalog."""
token = get_xsts_token()
gamepass_settings = get_resolved_xbox_gamepass_settings()
-
+ plan = gamepass_settings["plan"]
+ market = gamepass_settings["market"]
print("Fetching Xbox library...")
all_games = []
@@ -475,7 +470,7 @@ def get_xbox_library():
# First, try to get owned games if token is available
if token:
- owned_games = get_owned_games(token)
+ owned_games = get_owned_games(token, market)
print(f" Found {len(owned_games)} owned Xbox games")
for game in owned_games:
@@ -488,7 +483,7 @@ def get_xbox_library():
print(" To import owned games, add your XSTS token in Settings")
# Then fetch Game Pass catalog (public API)
- gamepass_games = get_gamepass_catalog(gamepass_settings["plan"], gamepass_settings["market"])
+ gamepass_games = get_gamepass_catalog(plan, market)
print(f" Found {len(gamepass_games)} Game Pass games")
# Add Game Pass games that aren't already owned
@@ -538,7 +533,7 @@ def main():
elif args.token:
# Use provided token for testing
print("Using provided token...")
- games = get_owned_games(args.token)
+ games = get_owned_games(args.token, args.market)
else:
games = get_xbox_library()
From 85e8a5a6f5d22642a47aeb2b6ae675aa4059bb68 Mon Sep 17 00:00:00 2001
From: Ohad Schneider
Date: Fri, 13 Feb 2026 23:06:01 +0200
Subject: [PATCH 12/12] raise error on invalid game pass plan
---
web/sources/xbox.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/web/sources/xbox.py b/web/sources/xbox.py
index c7585a7..cfdfdc0 100644
--- a/web/sources/xbox.py
+++ b/web/sources/xbox.py
@@ -340,7 +340,10 @@ def get_gamepass_catalog(plan, market):
all_games = []
- plan_info = GAMEPASS_PLAN_MAP[plan]
+ plan_info = GAMEPASS_PLAN_MAP.get(plan)
+ if not plan_info:
+ raise ValueError(f"Invalid Game Pass plan: {plan}")
+
collection_id = plan_info['collection']
subscription_id = plan_info['subscription']
# Fetch Game Pass catalog