4 Commits

Author SHA1 Message Date
8e34c92385 chore(changelog): update
All checks were successful
Code check / Check code (push) Successful in 1m33s
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-08-03 20:36:12 +05:00
d50b63bca7 fix(steam_api): re-download json lists if it is broken
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-08-03 20:33:00 +05:00
6966253e9b fix(add_game_dialog): check exe path before add game
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-08-03 20:14:02 +05:00
13f3af7a42 fix(hltb): return None if all time zero
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-08-03 20:03:15 +05:00
4 changed files with 43 additions and 9 deletions

View File

@@ -12,10 +12,13 @@
- Уменьшена длительность анимации открытия карточки с 800 до 350мс
- Контекстное меню при открытие теперь сразу фокусируется на первом элементе
- Анимации теперь можно настраивать через темы (за подробностями в документацию)
- Общие json (steam_apps и anticheat_games) теперь перекачиваются если сломаны
### Fixed
- legendary list теперь не вызывается если вход в EGS не был произведён
- Скриншоты тем теперь не теряют в качестве при масштабе отличном от 100%
- Данные от HLTB теперь не отображаются в карточке если нет данных о времени прохождения
- Диалог добавления игры теперь не добавляет игру если exe не существует
### Contributors

View File

@@ -677,7 +677,10 @@ class AddGameDialog(QDialog):
exe_path = self.exeEdit.text().strip()
name = self.nameEdit.text().strip()
if not exe_path or not name:
if not exe_path or not os.path.isfile(exe_path):
return None, None
if not name:
return None, None
portproton_path = get_portproton_location()

View File

@@ -219,9 +219,11 @@ class ResultParser:
("comp_plus", "main_extra"),
("comp_100", "completionist")
]
all_zero = all(game_data.get(json_field, 0) == 0 for json_field, _ in time_fields)
for json_field, attr_name in time_fields:
if json_field in game_data:
time_hours = round(game_data[json_field] / 3600, 2)
time_seconds = game_data[json_field]
time_hours = None if all_zero else round(time_seconds / 3600, 2)
setattr(game, attr_name, time_hours)
game.similarity = self._calculate_similarity(game)
return game

View File

@@ -291,7 +291,7 @@ def load_steam_apps_async(callback: Callable[[list], None]):
if os.path.exists(cache_tar):
os.remove(cache_tar)
logger.info("Archive %s deleted after extraction", cache_tar)
steam_apps = data.get("applist", {}).get("apps", []) if isinstance(data, dict) else data or []
steam_apps = data if isinstance(data, list) else []
logger.info("Loaded %d apps from archive", len(steam_apps))
callback(steam_apps)
except Exception as e:
@@ -303,12 +303,25 @@ def load_steam_apps_async(callback: Callable[[list], None]):
try:
with open(cache_json, "rb") as f:
data = orjson.loads(f.read())
steam_apps = data.get("applist", {}).get("apps", []) if isinstance(data, dict) else data or []
# Validate JSON structure
if not isinstance(data, list):
logger.error("Cached JSON %s has invalid format (not a list), re-downloading", cache_json)
raise ValueError("Invalid JSON structure")
# Validate each app entry
for app in data:
if not isinstance(app, dict) or "appid" not in app or "normalized_name" not in app:
logger.error("Cached JSON %s contains invalid app entry, re-downloading", cache_json)
raise ValueError("Invalid app entry structure")
steam_apps = data
logger.info("Loaded %d apps from cache", len(steam_apps))
callback(steam_apps)
except Exception as e:
logger.error("Error reading cached JSON: %s", e)
callback([])
logger.error("Error reading or validating cached JSON %s: %s", cache_json, e)
# Attempt to re-download if cache is invalid or corrupted
app_list_url = (
"https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/data/games_appid.tar.xz"
)
downloader.download_async(app_list_url, cache_tar, timeout=5, callback=process_tar)
else:
app_list_url = (
"https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/data/games_appid.tar.xz"
@@ -448,12 +461,25 @@ def load_weanticheatyet_data_async(callback: Callable[[list], None]):
try:
with open(cache_json, "rb") as f:
data = orjson.loads(f.read())
anti_cheat_data = data or []
# Validate JSON structure
if not isinstance(data, list):
logger.error("Cached JSON %s has invalid format (not a list), re-downloading", cache_json)
raise ValueError("Invalid JSON structure")
# Validate each anti-cheat entry
for entry in data:
if not isinstance(entry, dict) or "normalized_name" not in entry or "status" not in entry:
logger.error("Cached JSON %s contains invalid anti-cheat entry, re-downloading", cache_json)
raise ValueError("Invalid anti-cheat entry structure")
anti_cheat_data = data
logger.info("Loaded %d anti-cheat entries from cache", len(anti_cheat_data))
callback(anti_cheat_data)
except Exception as e:
logger.error("Error reading cached WeAntiCheatYet JSON: %s", e)
callback([])
logger.error("Error reading or validating cached WeAntiCheatYet JSON %s: %s", cache_json, e)
# Attempt to re-download if cache is invalid or corrupted
app_list_url = (
"https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/data/anticheat_games.tar.xz"
)
downloader.download_async(app_list_url, cache_tar, timeout=5, callback=process_tar)
else:
app_list_url = (
"https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/data/anticheat_games.tar.xz"