mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-24 08:52:39 +01:00
v1.9.9.4 - implement custom source mode (test)
This commit is contained in:
@@ -27,6 +27,7 @@ from utils import (
|
||||
)
|
||||
from history import load_history, save_history
|
||||
from config import OTA_data_ZIP
|
||||
from rgsx_settings import get_sources_mode, get_custom_sources_url, get_sources_zip_url
|
||||
from accessibility import load_accessibility_settings
|
||||
|
||||
# Configuration du logging
|
||||
@@ -64,6 +65,10 @@ for i, scale in enumerate(config.font_scale_options):
|
||||
# Chargement et initialisation de la langue
|
||||
from language import initialize_language
|
||||
initialize_language()
|
||||
# Initialiser le mode sources et URL personnalisée
|
||||
config.sources_mode = get_sources_mode()
|
||||
config.custom_sources_url = get_custom_sources_url()
|
||||
logger.debug(f"Mode sources initial: {config.sources_mode}, URL custom: {config.custom_sources_url}")
|
||||
|
||||
# Détection du système non-PC
|
||||
config.is_non_pc = detect_non_pc()
|
||||
@@ -624,6 +629,10 @@ async def main():
|
||||
config.needs_redraw = True
|
||||
logger.error(f"État de menu non valide détecté: {config.menu_state}, retour à platform")
|
||||
draw_controls(screen, config.menu_state, getattr(config, 'current_music_name', None), getattr(config, 'music_popup_start_time', 0))
|
||||
|
||||
# Popup générique (affiché dans n'importe quel état si timer actif), sauf si un état popup dédié déjà l'affiche
|
||||
if config.popup_timer > 0 and config.popup_message and config.menu_state not in ["update_result", "restart_popup"]:
|
||||
draw_popup(screen)
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
@@ -722,45 +731,60 @@ async def main():
|
||||
try:
|
||||
zip_path = os.path.join(config.SAVE_FOLDER, "data_download.zip")
|
||||
headers = {'User-Agent': 'Mozilla/5.0'}
|
||||
with requests.get(OTA_data_ZIP, stream=True, headers=headers, timeout=30) as response:
|
||||
response.raise_for_status()
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
logger.debug(f"Taille totale du ZIP : {total_size} octets")
|
||||
downloaded = 0
|
||||
os.makedirs(os.path.dirname(zip_path), exist_ok=True)
|
||||
with open(zip_path, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
downloaded += len(chunk)
|
||||
config.download_progress[OTA_data_ZIP] = {
|
||||
"downloaded_size": downloaded,
|
||||
"total_size": total_size,
|
||||
"status": "Téléchargement",
|
||||
"progress_percent": (downloaded / total_size * 100) if total_size > 0 else 0
|
||||
}
|
||||
config.loading_progress = 15.0 + (35.0 * downloaded / total_size) if total_size > 0 else 15.0
|
||||
config.needs_redraw = True
|
||||
await asyncio.sleep(0)
|
||||
logger.debug(f"ZIP téléchargé : {zip_path}")
|
||||
|
||||
config.current_loading_system = _("loading_extracting_data")
|
||||
config.loading_progress = 60.0
|
||||
config.needs_redraw = True
|
||||
dest_dir = config.SAVE_FOLDER
|
||||
success, message = extract_zip_data(zip_path, dest_dir, OTA_data_ZIP)
|
||||
if success:
|
||||
logger.debug(f"Extraction réussie : {message}")
|
||||
config.loading_progress = 70.0
|
||||
config.needs_redraw = True
|
||||
# Déterminer l'URL à utiliser selon le mode (RGSX ou custom)
|
||||
sources_zip_url = get_sources_zip_url(OTA_data_ZIP)
|
||||
if sources_zip_url is None:
|
||||
# Mode custom sans URL valide -> pas de téléchargement, jeux vides
|
||||
logger.warning("Mode custom actif mais aucune URL valide fournie. Liste de jeux vide.")
|
||||
config.popup_message = _("sources_mode_custom_missing_url").format(config.RGSX_SETTINGS_PATH)
|
||||
config.popup_timer = 5000
|
||||
else:
|
||||
raise Exception(f"Échec de l'extraction : {message}")
|
||||
try:
|
||||
with requests.get(sources_zip_url, stream=True, headers=headers, timeout=30) as response:
|
||||
response.raise_for_status()
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
logger.debug(f"Taille totale du ZIP : {total_size} octets")
|
||||
downloaded = 0
|
||||
os.makedirs(os.path.dirname(zip_path), exist_ok=True)
|
||||
with open(zip_path, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
downloaded += len(chunk)
|
||||
config.download_progress[sources_zip_url] = {
|
||||
"downloaded_size": downloaded,
|
||||
"total_size": total_size,
|
||||
"status": "Téléchargement",
|
||||
"progress_percent": (downloaded / total_size * 100) if total_size > 0 else 0
|
||||
}
|
||||
config.loading_progress = 15.0 + (35.0 * downloaded / total_size) if total_size > 0 else 15.0
|
||||
config.needs_redraw = True
|
||||
await asyncio.sleep(0)
|
||||
logger.debug(f"ZIP téléchargé : {zip_path}")
|
||||
|
||||
config.current_loading_system = _("loading_extracting_data")
|
||||
config.loading_progress = 60.0
|
||||
config.needs_redraw = True
|
||||
dest_dir = config.SAVE_FOLDER
|
||||
success, message = extract_zip_data(zip_path, dest_dir, sources_zip_url)
|
||||
if success:
|
||||
logger.debug(f"Extraction réussie : {message}")
|
||||
config.loading_progress = 70.0
|
||||
config.needs_redraw = True
|
||||
else:
|
||||
raise Exception(f"Échec de l'extraction : {message}")
|
||||
except Exception as de:
|
||||
logger.error(f"Erreur téléchargement custom source: {de}")
|
||||
config.popup_message = _("sources_mode_custom_download_error")
|
||||
config.popup_timer = 5000
|
||||
# Pas d'arrêt : continuer avec jeux vides
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du téléchargement/extraction du Dossier Data : {str(e)}")
|
||||
config.menu_state = "error"
|
||||
# Message UI générique (les détails restent dans les logs)
|
||||
config.error_message = _("error_extract_data_failed")
|
||||
config.needs_redraw = True
|
||||
# En mode custom on ne bloque pas le chargement ; en mode RGSX (sources_zip_url non None et OTA) on affiche une erreur
|
||||
if sources_zip_url is not None:
|
||||
config.menu_state = "error"
|
||||
config.error_message = _("error_extract_data_failed")
|
||||
config.needs_redraw = True
|
||||
loading_step = "load_sources"
|
||||
if os.path.exists(zip_path):
|
||||
os.remove(zip_path)
|
||||
@@ -797,6 +821,17 @@ async def main():
|
||||
config.needs_redraw = True
|
||||
logger.debug("Transition terminée, passage à game")
|
||||
|
||||
# Mise à jour du timer popup générique (en dehors des états spéciaux) AVANT mise à jour last_frame_time
|
||||
if config.popup_timer > 0 and config.popup_message and config.menu_state not in ["update_result", "restart_popup"]:
|
||||
delta = current_time - config.last_frame_time
|
||||
if delta > 0:
|
||||
config.popup_timer -= delta
|
||||
# Forcer redraw pour mettre à jour le compte à rebours
|
||||
config.needs_redraw = True
|
||||
if config.popup_timer <= 0:
|
||||
config.popup_timer = 0
|
||||
config.popup_message = ""
|
||||
# Mettre à jour last_frame_time après tous les calculs dépendants
|
||||
config.last_frame_time = current_time
|
||||
clock.tick(60)
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
@@ -5,7 +5,7 @@ import platform
|
||||
from rgsx_settings import load_rgsx_settings, save_rgsx_settings, migrate_old_settings
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "1.9.9.3"
|
||||
app_version = "1.9.9.4"
|
||||
|
||||
def get_operating_system():
|
||||
"""Renvoie le nom du système d'exploitation."""
|
||||
@@ -147,6 +147,8 @@ transition_duration = 18
|
||||
games_count = {}
|
||||
music_enabled = True # Par défaut la musique est activée
|
||||
API_KEY_1FICHIER = "" # Initialisation de la variable globale pour la clé API
|
||||
sources_mode = "rgsx" # Mode des sources de jeux (rgsx/custom)
|
||||
custom_sources_url = "" # URL personnalisée si mode custom
|
||||
|
||||
# Variables pour la sélection de langue
|
||||
selected_language_index = 0
|
||||
|
||||
@@ -994,7 +994,9 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.selected_option = max(0, config.selected_option - 1)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "down"):
|
||||
config.selected_option = min(8, config.selected_option + 1) # 9 options maintenant (0-8)
|
||||
# Nombre d'options dynamique (inclut éventuellement l'option source des jeux)
|
||||
total = getattr(config, 'pause_menu_total_options', 9) # fallback 9
|
||||
config.selected_option = min(total - 1, config.selected_option + 1)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "confirm"):
|
||||
if config.selected_option == 0: # Controls
|
||||
@@ -1034,18 +1036,32 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.menu_state = "accessibility_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug("Passage au menu accessibilité")
|
||||
elif config.selected_option == 5: # Redownload game cache
|
||||
elif config.selected_option == 5: # Source toggle
|
||||
try:
|
||||
from rgsx_settings import get_sources_mode, set_sources_mode
|
||||
current_mode = get_sources_mode()
|
||||
new_mode = set_sources_mode('custom' if current_mode == 'rgsx' else 'rgsx')
|
||||
config.sources_mode = new_mode
|
||||
if new_mode == 'custom':
|
||||
config.popup_message = _("sources_mode_custom_select_info").format(config.RGSX_SETTINGS_PATH)
|
||||
config.popup_timer = 10000
|
||||
else:
|
||||
config.popup_message = _("sources_mode_rgsx_select_info")
|
||||
config.popup_timer = 4000
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Changement du mode des sources vers {new_mode}")
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur changement mode sources: {e}")
|
||||
elif config.selected_option == 6: # Redownload game cache
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "redownload_game_cache"
|
||||
config.redownload_confirm_selection = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Passage à redownload_game_cache depuis pause_menu")
|
||||
elif config.selected_option == 6: # Music toggle
|
||||
elif config.selected_option == 7: # Music toggle
|
||||
config.music_enabled = not config.music_enabled
|
||||
save_music_config()
|
||||
if config.music_enabled:
|
||||
# Relancer la musique si activée
|
||||
# Utilise les variables globales si elles existent
|
||||
music_files = getattr(config, "music_files", None)
|
||||
music_folder = getattr(config, "music_folder", None)
|
||||
if music_files and music_folder:
|
||||
@@ -1054,7 +1070,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
pygame.mixer.music.stop()
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Musique {'activée' if config.music_enabled else 'désactivée'} via menu pause")
|
||||
elif config.selected_option == 7: # Symlink option
|
||||
elif config.selected_option == 8: # Symlink option
|
||||
from rgsx_settings import set_symlink_option, get_symlink_option
|
||||
current_status = get_symlink_option()
|
||||
success, message = set_symlink_option(not current_status)
|
||||
@@ -1062,7 +1078,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.popup_timer = 3000 if success else 5000
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Symlink option {'activée' if not current_status else 'désactivée'} via menu pause")
|
||||
elif config.selected_option == 8: # Quit
|
||||
elif config.selected_option == 9: # Quit
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "confirm_exit"
|
||||
config.confirm_selection = 0
|
||||
|
||||
@@ -1187,33 +1187,27 @@ def draw_language_menu(screen):
|
||||
def draw_pause_menu(screen, selected_option):
|
||||
"""Dessine le menu pause avec un style moderne."""
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
# Option musique dynamique
|
||||
from rgsx_settings import get_symlink_option, get_sources_mode
|
||||
mode = get_sources_mode()
|
||||
source_label = _("games_source_rgsx") if mode == "rgsx" else _("games_source_custom")
|
||||
if config.music_enabled:
|
||||
music_name = config.current_music_name or ""
|
||||
music_option = _("menu_music_enabled").format(music_name)
|
||||
else:
|
||||
music_option = _("menu_music_disabled")
|
||||
|
||||
# Option symlink dynamique
|
||||
from rgsx_settings import get_symlink_option
|
||||
if get_symlink_option():
|
||||
symlink_option = _("symlink_option_enabled")
|
||||
else:
|
||||
symlink_option = _("symlink_option_disabled")
|
||||
|
||||
symlink_option = _("symlink_option_enabled") if get_symlink_option() else _("symlink_option_disabled")
|
||||
options = [
|
||||
_("menu_controls"),
|
||||
_("menu_remap_controls"),
|
||||
_("menu_history"),
|
||||
_("menu_language"),
|
||||
_("menu_accessibility"),
|
||||
_("menu_redownload_cache"),
|
||||
music_option, # Ici l'option dynamique
|
||||
symlink_option,
|
||||
_("menu_quit")
|
||||
_("menu_controls"), # 0
|
||||
_("menu_remap_controls"), # 1
|
||||
_("menu_history"), # 2
|
||||
_("menu_language"), # 3
|
||||
_("menu_accessibility"), # 4
|
||||
f"{_('menu_games_source_prefix')}: {source_label}", # 5
|
||||
_("menu_redownload_cache"), # 6
|
||||
music_option, # 7
|
||||
symlink_option, # 8
|
||||
_("menu_quit") # 9
|
||||
]
|
||||
|
||||
menu_width = int(config.screen_width * 0.8)
|
||||
line_height = config.font.get_height() + 10
|
||||
button_height = int(config.screen_height * 0.0463)
|
||||
@@ -1235,6 +1229,8 @@ def draw_pause_menu(screen, selected_option):
|
||||
button_height,
|
||||
selected=i == selected_option
|
||||
)
|
||||
# Stocker le nombre total d'options pour la navigation dynamique
|
||||
config.pause_menu_total_options = len(options)
|
||||
|
||||
# Menu aide contrôles
|
||||
def draw_controls_help(screen, previous_state):
|
||||
@@ -1313,6 +1309,9 @@ def draw_controls_help(screen, previous_state):
|
||||
else:
|
||||
if cur:
|
||||
line_surf = font.render(cur, True, THEME_COLORS["text"])
|
||||
|
||||
|
||||
|
||||
wrapped.append((False, line_surf))
|
||||
total_height += line_surf.get_height() + line_spacing
|
||||
max_width = max(max_width, line_surf.get_width())
|
||||
|
||||
@@ -187,4 +187,13 @@
|
||||
"symlink_option_disabled": "Symlink-Option deaktiviert",
|
||||
"symlink_settings_saved_successfully": "Symlink-Einstellungen erfolgreich gespeichert",
|
||||
"symlink_settings_save_error": "Fehler beim Speichern der Symlink-Einstellungen"
|
||||
,
|
||||
"menu_games_source_prefix": "Spielquelle",
|
||||
"games_source_rgsx": "RGSX",
|
||||
"sources_mode_rgsx_select_info": "RGSX: Spieleliste aktualisieren",
|
||||
"games_source_custom": "Benutzerdefiniert"
|
||||
,
|
||||
"sources_mode_custom_select_info": "Benutzerdefiniert: URL in {0} setzen und Spieleliste aktualisieren",
|
||||
"sources_mode_custom_missing_url": "Keine benutzerdefinierte URL gesetzt (bearbeite {0})",
|
||||
"sources_mode_custom_download_error": "Download der benutzerdefinierten Quelle fehlgeschlagen"
|
||||
}
|
||||
@@ -187,4 +187,13 @@
|
||||
"symlink_option_disabled": "Symlink option disabled",
|
||||
"symlink_settings_saved_successfully": "Symlink settings saved successfully",
|
||||
"symlink_settings_save_error": "Error saving symlink settings"
|
||||
,
|
||||
"menu_games_source_prefix": "Game source",
|
||||
"games_source_rgsx": "RGSX",
|
||||
"sources_mode_rgsx_select_info": "RGSX: update the games list",
|
||||
"games_source_custom": "Custom"
|
||||
,
|
||||
"sources_mode_custom_select_info": "Custom mode: set URL in {0} then update games list",
|
||||
"sources_mode_custom_missing_url": "No custom URL set (edit {0})",
|
||||
"sources_mode_custom_download_error": "Custom source download failed"
|
||||
}
|
||||
@@ -188,4 +188,13 @@
|
||||
"symlink_option_disabled": "Opción symlink deshabilitada",
|
||||
"symlink_settings_saved_successfully": "Configuración symlink guardada con éxito",
|
||||
"symlink_settings_save_error": "Error al guardar la configuración symlink"
|
||||
,
|
||||
"menu_games_source_prefix": "Origen de juegos",
|
||||
"games_source_rgsx": "RGSX",
|
||||
"sources_mode_rgsx_select_info": "RGSX: actualizar la lista de juegos",
|
||||
"games_source_custom": "Personalizado"
|
||||
,
|
||||
"sources_mode_custom_select_info": "Modo personalizado: define la URL en {0} y actualiza la lista de juegos",
|
||||
"sources_mode_custom_missing_url": "No se ha establecido URL personalizada (editar {0})",
|
||||
"sources_mode_custom_download_error": "Fallo en la descarga de la fuente personalizada"
|
||||
}
|
||||
@@ -188,4 +188,12 @@
|
||||
"symlink_option_disabled": "Option symlink désactivée",
|
||||
"symlink_settings_saved_successfully": "Paramètres symlink sauvegardés avec succès",
|
||||
"symlink_settings_save_error": "Erreur lors de la sauvegarde des paramètres symlink"
|
||||
,
|
||||
"menu_games_source_prefix": "Source des jeux",
|
||||
"games_source_rgsx": "RGSX",
|
||||
"sources_mode_rgsx_select_info": "RGSX : mettre à jour la liste des jeux",
|
||||
"games_source_custom": "Personnalisée",
|
||||
"sources_mode_custom_select_info": "Mode personnalisé : définir l'URL dans {0} puis mettre à jour la liste des jeux",
|
||||
"sources_mode_custom_missing_url": "Aucune URL personnalisée définie (modifier {0})",
|
||||
"sources_mode_custom_download_error": "Échec du téléchargement de la source personnalisée"
|
||||
}
|
||||
@@ -28,6 +28,10 @@ def load_rgsx_settings():
|
||||
"symlink": {
|
||||
"enabled": False,
|
||||
"target_directory": ""
|
||||
},
|
||||
"sources": { # Nouvelle section pour la source des jeux
|
||||
"mode": "rgsx", # "rgsx" ou "custom"
|
||||
"custom_url": "" # URL personnalisée pour le ZIP des sources
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,3 +221,38 @@ def apply_symlink_path(base_path, platform_folder):
|
||||
else:
|
||||
# Return original path
|
||||
return os.path.join(base_path, platform_folder)
|
||||
|
||||
# ----------------------- Sources (RGSX / Custom) ----------------------- #
|
||||
|
||||
def get_sources_mode(settings=None):
|
||||
"""Retourne le mode des sources: 'rgsx' (par défaut) ou 'custom'."""
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("sources", {}).get("mode", "rgsx")
|
||||
|
||||
def set_sources_mode(mode):
|
||||
"""Définit le mode des sources et sauvegarde le fichier."""
|
||||
if mode not in ("rgsx", "custom"):
|
||||
mode = "rgsx"
|
||||
settings = load_rgsx_settings()
|
||||
sources = settings.setdefault("sources", {})
|
||||
sources["mode"] = mode
|
||||
save_rgsx_settings(settings)
|
||||
return mode
|
||||
|
||||
def get_custom_sources_url(settings=None):
|
||||
"""Retourne l'URL personnalisée configurée (ou chaîne vide)."""
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("sources", {}).get("custom_url", "").strip()
|
||||
|
||||
def get_sources_zip_url(fallback_url):
|
||||
"""Retourne l'URL ZIP à utiliser selon le mode. Fallback sur l'URL standard si custom invalide."""
|
||||
settings = load_rgsx_settings()
|
||||
if get_sources_mode(settings) == "custom":
|
||||
custom = get_custom_sources_url(settings)
|
||||
if custom.startswith("http://") or custom.startswith("https://"):
|
||||
return custom
|
||||
# Pas de fallback : retourner None pour signaler une source vide
|
||||
return None
|
||||
return fallback_url
|
||||
|
||||
Reference in New Issue
Block a user