mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-19 16:26:00 +01:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4913a5fc2 | ||
|
|
bf9d3d2de5 | ||
|
|
9979949bdc | ||
|
|
9ed264544f | ||
|
|
779c060927 | ||
|
|
88400e538f | ||
|
|
cbab067dd6 | ||
|
|
b4ed0b355d |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -23,3 +23,4 @@ pygame/
|
||||
data/
|
||||
docker-compose.test.yml
|
||||
config/
|
||||
pyrightconfig.json
|
||||
|
||||
@@ -526,7 +526,7 @@ async def main():
|
||||
# Appui long détecté, ouvrir le scraper
|
||||
games = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
if games:
|
||||
game_name = games[config.current_game][0]
|
||||
game_name = games[config.current_game].name
|
||||
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
|
||||
|
||||
config.previous_menu_state = "game"
|
||||
@@ -835,12 +835,9 @@ async def main():
|
||||
logger.debug("Action quit détectée, arrêt de l'application")
|
||||
elif action == "download" and config.menu_state == "game" and config.filtered_games:
|
||||
game = config.filtered_games[config.current_game]
|
||||
if isinstance(game, (list, tuple)):
|
||||
game_name = game[0]
|
||||
url = game[1] if len(game) > 1 else None
|
||||
else: # fallback str
|
||||
game_name = str(game)
|
||||
url = None
|
||||
game_name = game.name
|
||||
url = game.url
|
||||
|
||||
# Nouveau schéma: config.platforms contient déjà platform_name (string)
|
||||
platform_name = config.platforms[config.current_platform]
|
||||
if url:
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
import os
|
||||
import logging
|
||||
import platform
|
||||
from typing import Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(slots=True)
|
||||
class Game:
|
||||
name: str
|
||||
url: str
|
||||
size: str
|
||||
display_name: str # name withou file extension or platform prefix
|
||||
|
||||
# Headless mode for CLI: set env RGSX_HEADLESS=1 to avoid pygame and noisy prints
|
||||
HEADLESS = os.environ.get("RGSX_HEADLESS") == "1"
|
||||
@@ -14,7 +23,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "2.5.0.4"
|
||||
app_version = "2.5.0.5"
|
||||
|
||||
# Nombre de jours avant de proposer la mise à jour de la liste des jeux
|
||||
GAMELIST_UPDATE_DAYS = 7
|
||||
@@ -364,7 +373,8 @@ filter_platforms_dirty = False # indique si modifications non sauvegardées
|
||||
filter_platforms_selection = [] # copie de travail des plateformes visibles (bool masque?) structure: list of (name, hidden_bool)
|
||||
|
||||
# Affichage des jeux et sélection
|
||||
games = [] # Liste des jeux pour la plateforme actuelle
|
||||
games: list[Game] = [] # Liste des jeux pour la plateforme actuelle
|
||||
fbneo_games = {}
|
||||
current_game = 0 # Index du jeu actuellement sélectionné
|
||||
menu_state = "loading" # État actuel de l'interface menu
|
||||
scroll_offset = 0 # Offset de défilement pour la liste des jeux
|
||||
@@ -389,7 +399,7 @@ selected_language_index = 0 # Index de la langue sélectionnée dans la liste
|
||||
|
||||
|
||||
# Recherche et filtres
|
||||
filtered_games = [] # Liste des jeux filtrés par recherche ou filtre
|
||||
filtered_games: list[Game] = [] # Liste des jeux filtrés par recherche ou filtre
|
||||
search_mode = False # Indicateur si le mode recherche est actif
|
||||
search_query = "" # Chaîne de recherche saisie par l'utilisateur
|
||||
filter_active = False # Indicateur si un filtre est appliqué
|
||||
|
||||
@@ -8,7 +8,7 @@ import datetime
|
||||
import threading
|
||||
import logging
|
||||
import config
|
||||
from config import REPEAT_DELAY, REPEAT_INTERVAL, REPEAT_ACTION_DEBOUNCE, CONTROLS_CONFIG_PATH
|
||||
from config import REPEAT_DELAY, REPEAT_INTERVAL, REPEAT_ACTION_DEBOUNCE, CONTROLS_CONFIG_PATH, Game
|
||||
from display import draw_validation_transition, show_toast
|
||||
from network import download_rom, download_from_1fichier, is_1fichier_url, request_cancel
|
||||
from utils import (
|
||||
@@ -31,6 +31,8 @@ from rgsx_settings import (
|
||||
from accessibility import save_accessibility_settings
|
||||
from scraper import get_game_metadata, download_image_to_surface
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Extensions d'archives pour lesquelles on ignore l'avertissement d'extension non supportée
|
||||
@@ -326,6 +328,20 @@ def _launch_next_queued_download():
|
||||
if config.download_queue:
|
||||
_launch_next_queued_download()
|
||||
|
||||
def filter_games_by_search_query() -> list[Game]:
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
|
||||
filtered_games = []
|
||||
for game in base_games:
|
||||
game_name = game.display_name
|
||||
if config.search_query.lower() in game_name.lower():
|
||||
filtered_games.append(game)
|
||||
|
||||
return filtered_games
|
||||
...
|
||||
|
||||
def handle_controls(event, sources, joystick, screen):
|
||||
"""Gère un événement clavier/joystick/souris et la répétition automatique.
|
||||
Retourne 'quit', 'download', 'redownload', ou None."""
|
||||
@@ -509,7 +525,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
|
||||
# Jeux
|
||||
elif config.menu_state == "game":
|
||||
games = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
games: list[Game] = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
if config.search_mode and getattr(config, 'joystick', False):
|
||||
keyboard_layout = [
|
||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
|
||||
@@ -563,10 +579,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
elif is_input_matched(event, "confirm"):
|
||||
config.search_query += keyboard_layout[row][col]
|
||||
# Appliquer d'abord les filtres avancés si actifs, puis le filtre par nom
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
config.filtered_games = [game for game in base_games if config.search_query.lower() in game[0].lower()]
|
||||
config.filtered_games = filter_games_by_search_query()
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
@@ -575,10 +588,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
if config.search_query:
|
||||
config.search_query = config.search_query[:-1]
|
||||
# Appliquer d'abord les filtres avancés si actifs, puis le filtre par nom
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
config.filtered_games = [game for game in base_games if config.search_query.lower() in game[0].lower()]
|
||||
config.filtered_games = filter_games_by_search_query()
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
@@ -586,10 +596,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
elif is_input_matched(event, "space"):
|
||||
config.search_query += " "
|
||||
# Appliquer d'abord les filtres avancés si actifs, puis le filtre par nom
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
config.filtered_games = [game for game in base_games if config.search_query.lower() in game[0].lower()]
|
||||
config.filtered_games = filter_games_by_search_query()
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
@@ -642,10 +649,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
if event.unicode.isalnum() or event.unicode == ' ':
|
||||
config.search_query += event.unicode
|
||||
# Appliquer d'abord les filtres avancés si actifs, puis le filtre par nom
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
config.filtered_games = [game for game in base_games if config.search_query.lower() in game[0].lower()]
|
||||
config.filtered_games = filter_games_by_search_query()
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
@@ -655,10 +659,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
if config.search_query:
|
||||
config.search_query = config.search_query[:-1]
|
||||
# Appliquer d'abord les filtres avancés si actifs, puis le filtre par nom
|
||||
base_games = config.games
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active():
|
||||
base_games = config.game_filter_obj.apply_filters(config.games)
|
||||
config.filtered_games = [game for game in base_games if config.search_query.lower() in game[0].lower()]
|
||||
config.filtered_games = filter_games_by_search_query()
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
@@ -726,8 +727,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
if games:
|
||||
idx = config.current_game
|
||||
game = games[idx]
|
||||
url = game[1]
|
||||
game_name = game[0]
|
||||
url = game.url
|
||||
game_name = game.name
|
||||
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
|
||||
|
||||
pending_download = check_extension_before_download(url, platform, game_name)
|
||||
@@ -3184,8 +3185,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Déclencher le téléchargement normal
|
||||
games = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
if games:
|
||||
url = games[config.current_game][1]
|
||||
game_name = games[config.current_game][0]
|
||||
url = games[config.current_game].url
|
||||
game_name = games[config.current_game].name
|
||||
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
|
||||
logger.debug(f"Appui court sur confirm ({press_duration}ms), téléchargement pour {game_name}, URL: {url}")
|
||||
|
||||
@@ -3316,8 +3317,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Déclencher le téléchargement normal (même code que pour KEYUP)
|
||||
games = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
if games:
|
||||
url = games[config.current_game][1]
|
||||
game_name = games[config.current_game][0]
|
||||
url = games[config.current_game].url
|
||||
game_name = games[config.current_game].name
|
||||
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
|
||||
logger.debug(f"Appui court sur confirm ({press_duration}ms), téléchargement pour {game_name}, URL: {url}")
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@ from rgsx_settings import (load_rgsx_settings, get_light_mode, get_show_unsuppor
|
||||
get_hide_premium_systems, get_symlink_option)
|
||||
from game_filters import GameFilters
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
import urllib.request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
OVERLAY = None # Initialisé dans init_display()
|
||||
@@ -1154,12 +1159,70 @@ def draw_platform_grid(screen):
|
||||
for key in keys_to_remove:
|
||||
del platform_images_cache[key]
|
||||
|
||||
|
||||
|
||||
FBNEO_GAME_LIST = "fbneo_gamelist.txt"
|
||||
|
||||
def download_fbneo_list(path_to_save: str) -> None:
|
||||
url = "https://raw.githubusercontent.com/libretro/FBNeo/master/gamelist.txt"
|
||||
path = Path(path_to_save)
|
||||
|
||||
if not path.exists():
|
||||
logger.debug("Downloading fbneo gamelist.txt from github ...")
|
||||
urllib.request.urlretrieve(url, path)
|
||||
|
||||
logger.debug("Download finished:", path)
|
||||
...
|
||||
|
||||
def parse_fbneo_list(path: str) -> Dict[str, Any]:
|
||||
games : Dict[str, Any] = {}
|
||||
headers = None
|
||||
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.rstrip()
|
||||
|
||||
if line.startswith("+"):
|
||||
continue
|
||||
|
||||
if "|" not in line:
|
||||
continue
|
||||
|
||||
parts = [p.strip() for p in line.split("|")[1:-1]]
|
||||
|
||||
if headers is None:
|
||||
headers = parts
|
||||
continue
|
||||
|
||||
row = dict(zip(headers, parts))
|
||||
|
||||
name = row["name"]
|
||||
games[name] = row
|
||||
|
||||
return games
|
||||
|
||||
# Liste des jeux
|
||||
def draw_game_list(screen):
|
||||
"""Affiche la liste des jeux avec un style moderne."""
|
||||
#logger.debug(f"[DRAW_GAME_LIST] Called - platform={config.current_platform}, search_mode={config.search_mode}, filter_active={config.filter_active}")
|
||||
platform = config.platforms[config.current_platform]
|
||||
platform_name = config.platform_names.get(platform, platform)
|
||||
|
||||
fbneo_selected = platform_name == 'Final Burn Neo'
|
||||
if fbneo_selected:
|
||||
fbneo_game_list_path = os.path.join(config.SAVE_FOLDER, FBNEO_GAME_LIST)
|
||||
download_fbneo_list(fbneo_game_list_path) # download the fbneo game list if necessary - 10 MB file
|
||||
config.fbneo_games = parse_fbneo_list(fbneo_game_list_path)
|
||||
for game in config.games:
|
||||
clean_name = game.display_name
|
||||
if clean_name in config.fbneo_games:
|
||||
fbneo_game = config.fbneo_games[clean_name]
|
||||
game.display_name = fbneo_game["full name"]
|
||||
...
|
||||
|
||||
if config.game_filter_obj and config.game_filter_obj.is_active() and not config.search_query:
|
||||
config.filtered_games = config.game_filter_obj.apply_filters(config.games)
|
||||
|
||||
games = config.filtered_games if config.filter_active or config.search_mode else config.games
|
||||
game_count = len(games)
|
||||
#logger.debug(f"[DRAW_GAME_LIST] Games count={game_count}, current_game={config.current_game}, filtered_games={len(config.filtered_games) if config.filtered_games else 0}, config.games={len(config.games) if config.games else 0}")
|
||||
@@ -1310,13 +1373,9 @@ def draw_game_list(screen):
|
||||
|
||||
for i in range(config.scroll_offset, min(config.scroll_offset + items_per_page, len(games))):
|
||||
item = games[i]
|
||||
if isinstance(item, (list, tuple)) and item:
|
||||
game_name = item[0]
|
||||
size_val = item[2] if len(item) > 2 else None
|
||||
else:
|
||||
game_name = str(item)
|
||||
size_val = None
|
||||
|
||||
game_name = item.display_name
|
||||
size_val = item.size
|
||||
|
||||
# Vérifier si le jeu est déjà téléchargé
|
||||
is_downloaded = is_game_downloaded(platform_name, game_name)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import re
|
||||
import logging
|
||||
from typing import List, Tuple, Dict, Any
|
||||
|
||||
from config import Game
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -156,9 +158,7 @@ class GameFilters:
|
||||
r'\([^\)]*PRERELEASE[^\)]*\)',
|
||||
r'\([^\)]*UNFINISHED[^\)]*\)',
|
||||
r'\([^\)]*WIP[^\)]*\)',
|
||||
r'\[[^\]]*BETA[^\]]*\]',
|
||||
r'\[[^\]]*DEMO[^\]]*\]',
|
||||
r'\[[^\]]*TEST[^\]]*\]'
|
||||
r'\([^\)]*BOOTLEG[^\)]*\)',
|
||||
]
|
||||
return any(re.search(pattern, name) for pattern in non_release_patterns)
|
||||
|
||||
@@ -211,7 +211,7 @@ class GameFilters:
|
||||
|
||||
return best_priority
|
||||
|
||||
def apply_filters(self, games: List[Tuple]) -> List[Tuple]:
|
||||
def apply_filters(self, games: list[Game]) -> list[Game]:
|
||||
"""
|
||||
Applique les filtres à une liste de jeux
|
||||
games: Liste de tuples (game_name, game_url, size)
|
||||
@@ -224,7 +224,7 @@ class GameFilters:
|
||||
|
||||
# Filtrage par région
|
||||
for game in games:
|
||||
game_name = game[0]
|
||||
game_name = game.display_name
|
||||
|
||||
# Vérifier les filtres de région
|
||||
if self.region_filters:
|
||||
@@ -255,12 +255,12 @@ class GameFilters:
|
||||
|
||||
return filtered_games
|
||||
|
||||
def _apply_one_rom_per_game(self, games: List[Tuple]) -> List[Tuple]:
|
||||
def _apply_one_rom_per_game(self, games: List[Game]) -> List[Game]:
|
||||
"""Garde seulement une ROM par jeu selon la priorité de région"""
|
||||
games_by_base = {}
|
||||
|
||||
for game in games:
|
||||
game_name = game[0]
|
||||
game_name = game.display_name
|
||||
base_name = self.get_base_game_name(game_name)
|
||||
|
||||
if base_name not in games_by_base:
|
||||
@@ -276,7 +276,7 @@ class GameFilters:
|
||||
else:
|
||||
# Trier par priorité de région
|
||||
sorted_games = sorted(game_list,
|
||||
key=lambda g: self.get_region_priority(g[0]))
|
||||
key=lambda g: self.get_region_priority(g.display_name))
|
||||
result.append(sorted_games[0])
|
||||
|
||||
return result
|
||||
|
||||
@@ -17,7 +17,7 @@ import re
|
||||
import config # paths, settings, SAVE_FOLDER, etc.
|
||||
from utils import load_api_keys as _prime_api_keys # ensure API key files are created
|
||||
import network as network_mod # for progress_queues access
|
||||
from utils import load_sources, load_games, is_extension_supported, load_extensions_json, sanitize_filename, extract_zip_data
|
||||
from utils import load_sources, load_games, is_extension_supported, load_extensions_json, sanitize_filename
|
||||
from history import load_history, save_history, add_to_history
|
||||
from network import download_rom, download_from_1fichier, is_1fichier_url
|
||||
from rgsx_settings import get_sources_zip_url
|
||||
@@ -277,7 +277,7 @@ def cmd_games(args):
|
||||
suggestions = [] # (priority, score, game_obj)
|
||||
# 1) Substring match (full or sans extension) priority 0, score = position
|
||||
for g in games:
|
||||
title = g[0] if isinstance(g, (list, tuple)) and g else None
|
||||
title = g.name
|
||||
if not title:
|
||||
continue
|
||||
t_lower = title.lower()
|
||||
@@ -303,7 +303,7 @@ def cmd_games(args):
|
||||
# 2) Ordered non-contiguous tokens (priority 1)
|
||||
if q_tokens:
|
||||
for g in games:
|
||||
title = g[0] if isinstance(g, (list, tuple)) and g else None
|
||||
title = g.name
|
||||
if not title:
|
||||
continue
|
||||
tt = _tokens(title)
|
||||
@@ -313,7 +313,7 @@ def cmd_games(args):
|
||||
# 3) All tokens present, any order (priority 2), score = token set size
|
||||
if q_tokens:
|
||||
for g in games:
|
||||
title = g[0] if isinstance(g, (list, tuple)) and g else None
|
||||
title = g.name
|
||||
if not title:
|
||||
continue
|
||||
t_tokens = set(_tokens(title))
|
||||
@@ -322,12 +322,12 @@ def cmd_games(args):
|
||||
# Deduplicate by title keeping best (lowest priority, then score)
|
||||
best = {}
|
||||
for prio, score, g in suggestions:
|
||||
title = g[0] if isinstance(g, (list, tuple)) and g else str(g)
|
||||
title = g.name
|
||||
key = title.lower()
|
||||
cur = best.get(key)
|
||||
if cur is None or (prio, score) < (cur[0], cur[1]):
|
||||
best[key] = (prio, score, g)
|
||||
ranked = sorted(best.values(), key=lambda x: (x[0], x[1], (x[2][0] if isinstance(x[2], (list, tuple)) and x[2] else str(x[2])).lower()))
|
||||
ranked = sorted(best.values(), key=lambda x: (x[0], x[1], (x[2].name if isinstance(x[2], (list, config.Game)) and x[2] else str(x[2])).lower()))
|
||||
games = [g for _, _, g in ranked]
|
||||
# Table: Name (60) | Size (12) to allow "xxxx.xx MiB"
|
||||
NAME_W = 60
|
||||
@@ -344,7 +344,7 @@ def cmd_games(args):
|
||||
print(header)
|
||||
print(border)
|
||||
for g in games:
|
||||
title = g[0] if isinstance(g, (list, tuple)) and g else str(g)
|
||||
title = g.name
|
||||
size_val = ''
|
||||
if isinstance(g, (list, tuple)) and len(g) >= 3:
|
||||
size_val = display_size(g[2])
|
||||
@@ -447,11 +447,11 @@ def cmd_download(args):
|
||||
def _tokens(s: str) -> list[str]:
|
||||
return re.findall(r"[a-z0-9]+", s.lower())
|
||||
|
||||
def _game_title(g) -> str | None:
|
||||
return g[0] if isinstance(g, (list, tuple)) and g else None
|
||||
def _game_title(g: config.Game) -> str | None:
|
||||
return g.name
|
||||
|
||||
def _game_url(g) -> str | None:
|
||||
return g[1] if isinstance(g, (list, tuple)) and len(g) > 1 else None
|
||||
def _game_url(g: config.Game) -> str | None:
|
||||
return g.url
|
||||
|
||||
# 1) Exact match (case-insensitive), with and without extension
|
||||
match = None
|
||||
@@ -561,8 +561,8 @@ def cmd_download(args):
|
||||
size_val = ''
|
||||
size_raw = None
|
||||
for g in games:
|
||||
if isinstance(g, (list, tuple)) and g and g[0] == title and len(g) >= 3:
|
||||
size_raw = g[2]
|
||||
if g.name == title:
|
||||
size_raw = g.size
|
||||
break
|
||||
if size_raw is not None:
|
||||
size_val = display_size(size_raw)
|
||||
|
||||
@@ -25,6 +25,7 @@ from utils import load_sources, load_games, extract_data
|
||||
from network import download_rom, download_from_1fichier
|
||||
from pathlib import Path
|
||||
from rgsx_settings import get_language
|
||||
from config import Game
|
||||
|
||||
try:
|
||||
from watchdog.observers import Observer # type: ignore
|
||||
@@ -161,7 +162,7 @@ def get_cached_sources() -> tuple[list[dict], str, datetime]:
|
||||
return copy.deepcopy(platforms), etag, last_modified
|
||||
|
||||
|
||||
def get_cached_games(platform: str) -> tuple[list[tuple], str, datetime]:
|
||||
def get_cached_games(platform: str) -> tuple[list[Game], str, datetime]:
|
||||
"""Return cached games list for platform with metadata."""
|
||||
now = time.time()
|
||||
with cache_lock:
|
||||
@@ -696,14 +697,14 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
elif games_last_modified:
|
||||
latest_modified = games_last_modified
|
||||
for game in games:
|
||||
game_name = game[0] if isinstance(game, (list, tuple)) else str(game)
|
||||
game_name = game.name
|
||||
game_name_lower = game_name.lower()
|
||||
if all(word in game_name_lower for word in search_words):
|
||||
matching_games.append({
|
||||
'game_name': game_name,
|
||||
'platform': platform_name,
|
||||
'url': game[1] if len(game) > 1 and isinstance(game, (list, tuple)) else None,
|
||||
'size': normalize_size(game[2] if len(game) > 2 and isinstance(game, (list, tuple)) else None, self._get_language_from_cookies())
|
||||
'url': game.url,
|
||||
'size': normalize_size(game.size, self._get_language_from_cookies())
|
||||
})
|
||||
except Exception as e:
|
||||
logger.debug(f"Erreur lors de la recherche dans {platform_name}: {e}")
|
||||
@@ -750,9 +751,9 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
games, _, games_last_modified = get_cached_games(platform_name)
|
||||
games_formatted = [
|
||||
{
|
||||
'name': g[0],
|
||||
'url': g[1] if len(g) > 1 else None,
|
||||
'size': normalize_size(g[2] if len(g) > 2 else None, lang)
|
||||
'name': g.name,
|
||||
'url': g.url,
|
||||
'size': normalize_size(g.size, lang)
|
||||
}
|
||||
for g in games
|
||||
]
|
||||
@@ -1134,7 +1135,7 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
if game_name_param and game_index is None:
|
||||
game_index = None
|
||||
for idx, game in enumerate(games):
|
||||
current_game_name = game[0] if isinstance(game, (list, tuple)) else str(game)
|
||||
current_game_name = game.name
|
||||
if current_game_name == game_name_param:
|
||||
game_index = idx
|
||||
break
|
||||
@@ -1155,8 +1156,8 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
return
|
||||
|
||||
game = games[game_index]
|
||||
game_name = game[0]
|
||||
game_url = game[1] if len(game) > 1 else None
|
||||
game_name = game.name
|
||||
game_url = game.url
|
||||
|
||||
if not game_url:
|
||||
self._send_json({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import requests # type: ignore
|
||||
import re
|
||||
@@ -7,7 +8,7 @@ import logging
|
||||
import platform
|
||||
import subprocess
|
||||
import config
|
||||
from config import HEADLESS
|
||||
from config import HEADLESS, Game
|
||||
try:
|
||||
if not HEADLESS:
|
||||
import pygame # type: ignore
|
||||
@@ -1166,7 +1167,7 @@ def load_sources():
|
||||
logger.error(f"Erreur fusion systèmes + détection jeux: {e}")
|
||||
return []
|
||||
|
||||
def load_games(platform_id):
|
||||
def load_games(platform_id:str) -> list[Game]:
|
||||
try:
|
||||
# Retrouver l'objet plateforme pour accéder éventuellement à 'folder'
|
||||
platform_dict = None
|
||||
@@ -1235,7 +1236,13 @@ def load_games(platform_id):
|
||||
|
||||
if getattr(config, "games_count_log_verbose", False):
|
||||
logger.debug(f"{os.path.basename(game_file)}: {len(normalized)} jeux")
|
||||
return normalized
|
||||
|
||||
games_list: list[Game] = []
|
||||
for name, url, size in normalized:
|
||||
display_name = Path(name).stem
|
||||
display_name = display_name.replace(platform_id, "")
|
||||
games_list.append(Game(name=name, url=url, size=size, display_name=display_name))
|
||||
return games_list
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement des jeux pour {platform_id}: {e}")
|
||||
return []
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2.5.0.4"
|
||||
"version": "2.5.0.5"
|
||||
}
|
||||
Reference in New Issue
Block a user