mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-27 01:44:46 +01:00
v1.9.7.7 - Corrrection de bugs de téléchargements, bug detection clé 1fichier, ajout options d'accessibilité pour agrandir/reduire la taille des polices
This commit is contained in:
58
__main__.py
58
__main__.py
@@ -7,7 +7,7 @@ import logging
|
||||
import requests
|
||||
import queue
|
||||
import datetime
|
||||
from display import init_display, draw_loading_screen, draw_error_screen, draw_platform_grid, draw_progress_screen, draw_controls, draw_virtual_keyboard, draw_popup_result_download, draw_extension_warning, draw_pause_menu, draw_controls_help, draw_game_list, draw_history_list, draw_clear_history_dialog, draw_confirm_dialog, draw_redownload_game_cache_dialog, draw_popup, draw_gradient, draw_language_menu, THEME_COLORS
|
||||
from display import init_display, draw_loading_screen, draw_error_screen, draw_platform_grid, draw_progress_screen, draw_controls, draw_virtual_keyboard, draw_popup_result_download, draw_extension_warning, draw_pause_menu, draw_controls_help, draw_game_list, draw_history_list, draw_clear_history_dialog, draw_cancel_download_dialog, draw_confirm_dialog, draw_redownload_game_cache_dialog, draw_popup, draw_gradient, THEME_COLORS
|
||||
from language import handle_language_menu_events, _
|
||||
from network import test_internet, download_rom, is_1fichier_url, download_from_1fichier, check_for_updates
|
||||
from controls import handle_controls, validate_menu_state, process_key_repeats
|
||||
@@ -38,8 +38,19 @@ logger = logging.getLogger(__name__)
|
||||
pygame.init()
|
||||
config.init_font()
|
||||
pygame.joystick.init()
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
logger.debug("---------------------------DEBUT LOG--------------------------------")
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
|
||||
|
||||
# Chargement des paramètres d'accessibilité
|
||||
from utils import load_accessibility_settings
|
||||
config.accessibility_settings = load_accessibility_settings()
|
||||
for i, scale in enumerate(config.font_scale_options):
|
||||
if scale == config.accessibility_settings.get("font_scale", 1.0):
|
||||
config.current_font_scale_index = i
|
||||
break
|
||||
|
||||
# Chargement et initialisation de la langue
|
||||
from language import initialize_language
|
||||
initialize_language()
|
||||
@@ -53,22 +64,8 @@ clock = pygame.time.Clock()
|
||||
|
||||
pygame.display.set_caption("RGSX")
|
||||
|
||||
# Initialisation des polices
|
||||
try:
|
||||
font_path = os.path.join(config.APP_FOLDER, "assets", "Pixel-UniCode.ttf")
|
||||
config.font = pygame.font.Font(font_path, 36) # Police principale
|
||||
config.title_font = pygame.font.Font(font_path, 48) # Police pour les titres
|
||||
config.search_font = pygame.font.Font(font_path, 48) # Police pour la recherche
|
||||
config.progress_font = pygame.font.Font(font_path, 36) # Police pour l'affichage de la progression
|
||||
config.small_font = pygame.font.Font(font_path, 28) # Police pour les petits textes
|
||||
#logger.debug("Police Pixel-UniCode chargée")
|
||||
except:
|
||||
config.font = pygame.font.SysFont("arial", 48) # Police fallback
|
||||
config.title_font = pygame.font.SysFont("arial", 60) # Police fallback pour les titres
|
||||
config.search_font = pygame.font.SysFont("arial", 60) # Police fallback pour la recherche
|
||||
config.progress_font = pygame.font.SysFont("arial", 36) # Police fallback pour l'affichage de la progression
|
||||
config.small_font = pygame.font.SysFont("arial", 28) # Police fallback pour les petits textes
|
||||
#logger.debug("Police Arial chargée")
|
||||
# Initialisation des polices via config
|
||||
config.init_font()
|
||||
|
||||
# Mise à jour de la résolution dans config
|
||||
config.screen_width, config.screen_height = pygame.display.get_surface().get_size()
|
||||
@@ -190,8 +187,10 @@ async def main():
|
||||
events = pygame.event.get()
|
||||
for event in events:
|
||||
# Gestion directe des événements pour le menu de langue
|
||||
if config.menu_state == "language_select" and event.type == pygame.KEYDOWN:
|
||||
handle_language_menu_events(event, screen)
|
||||
if config.menu_state == "language_select":
|
||||
from language import handle_language_menu_events
|
||||
if handle_language_menu_events(event, screen):
|
||||
config.needs_redraw = True
|
||||
continue
|
||||
|
||||
if event.type == pygame.USEREVENT + 1: # Événement de fin de musique
|
||||
@@ -228,6 +227,12 @@ async def main():
|
||||
#logger.debug(f"Événement transmis à handle_controls dans pause_menu: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "accessibility_menu":
|
||||
from accessibility import handle_accessibility_events
|
||||
if handle_accessibility_events(event):
|
||||
config.needs_redraw = True
|
||||
continue
|
||||
|
||||
if config.menu_state == "controls_help":
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
@@ -237,7 +242,11 @@ async def main():
|
||||
if config.menu_state == "confirm_clear_history":
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
#logger.debug(f"Événement transmis à handle_controls dans confirm_clear_history: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "confirm_cancel_download":
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
continue
|
||||
|
||||
if config.menu_state == "redownload_game_cache":
|
||||
@@ -298,6 +307,7 @@ async def main():
|
||||
"game_name": game_name,
|
||||
"status": "downloading",
|
||||
"progress": 0,
|
||||
"message": _("download_initializing"),
|
||||
"url": url,
|
||||
"timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
})
|
||||
@@ -559,10 +569,18 @@ async def main():
|
||||
# logger.debug("Screen updated with draw_history_list")
|
||||
elif config.menu_state == "confirm_clear_history":
|
||||
draw_clear_history_dialog(screen)
|
||||
elif config.menu_state == "confirm_cancel_download":
|
||||
draw_cancel_download_dialog(screen)
|
||||
elif config.menu_state == "redownload_game_cache":
|
||||
draw_redownload_game_cache_dialog(screen)
|
||||
elif config.menu_state == "restart_popup":
|
||||
draw_popup(screen)
|
||||
elif config.menu_state == "accessibility_menu":
|
||||
from accessibility import draw_accessibility_menu
|
||||
draw_accessibility_menu(screen)
|
||||
elif config.menu_state == "language_select":
|
||||
from display import draw_language_menu
|
||||
draw_language_menu(screen)
|
||||
else:
|
||||
config.menu_state = "platform"
|
||||
draw_platform_grid(screen)
|
||||
|
||||
129
accessibility.py
Normal file
129
accessibility.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import pygame #type:ignore
|
||||
import config
|
||||
from utils import save_accessibility_settings
|
||||
from language import _
|
||||
|
||||
def draw_accessibility_menu(screen):
|
||||
"""Affiche le menu d'accessibilité avec curseur pour la taille de police."""
|
||||
from display import OVERLAY, THEME_COLORS, draw_stylized_button
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
# Titre
|
||||
title_text = _("menu_accessibility")
|
||||
title_surface = config.title_font.render(title_text, True, THEME_COLORS["text"])
|
||||
title_rect = title_surface.get_rect(center=(config.screen_width // 2, config.screen_height // 4))
|
||||
|
||||
# Fond du titre
|
||||
title_bg_rect = title_rect.inflate(40, 20)
|
||||
pygame.draw.rect(screen, THEME_COLORS["button_idle"], title_bg_rect, border_radius=10)
|
||||
pygame.draw.rect(screen, THEME_COLORS["border"], title_bg_rect, 2, border_radius=10)
|
||||
screen.blit(title_surface, title_rect)
|
||||
|
||||
# Curseur de taille de police
|
||||
current_scale = config.font_scale_options[config.current_font_scale_index]
|
||||
font_text = _("accessibility_font_size").format(f"{current_scale:.1f}")
|
||||
|
||||
# Position du curseur
|
||||
cursor_y = config.screen_height // 2
|
||||
cursor_width = 400
|
||||
cursor_height = 60
|
||||
cursor_x = (config.screen_width - cursor_width) // 2
|
||||
|
||||
# Fond du curseur
|
||||
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (cursor_x, cursor_y, cursor_width, cursor_height), border_radius=10)
|
||||
pygame.draw.rect(screen, THEME_COLORS["border"], (cursor_x, cursor_y, cursor_width, cursor_height), 2, border_radius=10)
|
||||
|
||||
# Flèches gauche/droite
|
||||
arrow_size = 30
|
||||
left_arrow_x = cursor_x + 20
|
||||
right_arrow_x = cursor_x + cursor_width - arrow_size - 20
|
||||
arrow_y = cursor_y + (cursor_height - arrow_size) // 2
|
||||
|
||||
# Flèche gauche
|
||||
left_color = THEME_COLORS["fond_lignes"] if config.current_font_scale_index > 0 else THEME_COLORS["border"]
|
||||
pygame.draw.polygon(screen, left_color, [
|
||||
(left_arrow_x + arrow_size, arrow_y),
|
||||
(left_arrow_x, arrow_y + arrow_size // 2),
|
||||
(left_arrow_x + arrow_size, arrow_y + arrow_size)
|
||||
])
|
||||
|
||||
# Flèche droite
|
||||
right_color = THEME_COLORS["fond_lignes"] if config.current_font_scale_index < len(config.font_scale_options) - 1 else THEME_COLORS["border"]
|
||||
pygame.draw.polygon(screen, right_color, [
|
||||
(right_arrow_x, arrow_y),
|
||||
(right_arrow_x + arrow_size, arrow_y + arrow_size // 2),
|
||||
(right_arrow_x, arrow_y + arrow_size)
|
||||
])
|
||||
|
||||
# Texte au centre
|
||||
text_surface = config.font.render(font_text, True, THEME_COLORS["text"])
|
||||
text_rect = text_surface.get_rect(center=(cursor_x + cursor_width // 2, cursor_y + cursor_height // 2))
|
||||
screen.blit(text_surface, text_rect)
|
||||
|
||||
# Instructions
|
||||
instruction_text = _("language_select_instruction")
|
||||
instruction_surface = config.small_font.render(instruction_text, True, THEME_COLORS["text"])
|
||||
instruction_rect = instruction_surface.get_rect(center=(config.screen_width // 2, config.screen_height - 100))
|
||||
screen.blit(instruction_surface, instruction_rect)
|
||||
|
||||
def handle_accessibility_events(event):
|
||||
"""Gère les événements du menu d'accessibilité avec support clavier et manette."""
|
||||
# Gestion des touches du clavier
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT and config.current_font_scale_index > 0:
|
||||
config.current_font_scale_index -= 1
|
||||
update_font_scale()
|
||||
return True
|
||||
elif event.key == pygame.K_RIGHT and config.current_font_scale_index < len(config.font_scale_options) - 1:
|
||||
config.current_font_scale_index += 1
|
||||
update_font_scale()
|
||||
return True
|
||||
elif event.key == pygame.K_RETURN or event.key == pygame.K_ESCAPE:
|
||||
config.menu_state = "pause_menu"
|
||||
return True
|
||||
|
||||
# Gestion des boutons de la manette
|
||||
elif event.type == pygame.JOYBUTTONDOWN:
|
||||
if event.button == 0: # Bouton A (valider)
|
||||
config.menu_state = "pause_menu"
|
||||
return True
|
||||
elif event.button == 1: # Bouton B (annuler)
|
||||
config.menu_state = "pause_menu"
|
||||
return True
|
||||
|
||||
# Gestion du D-pad
|
||||
elif event.type == pygame.JOYHATMOTION:
|
||||
if event.value == (-1, 0): # Gauche
|
||||
if config.current_font_scale_index > 0:
|
||||
config.current_font_scale_index -= 1
|
||||
update_font_scale()
|
||||
return True
|
||||
elif event.value == (1, 0): # Droite
|
||||
if config.current_font_scale_index < len(config.font_scale_options) - 1:
|
||||
config.current_font_scale_index += 1
|
||||
update_font_scale()
|
||||
return True
|
||||
|
||||
# Gestion du joystick analogique (axe horizontal)
|
||||
elif event.type == pygame.JOYAXISMOTION:
|
||||
if event.axis == 0 and abs(event.value) > 0.5: # Joystick gauche horizontal
|
||||
if event.value < -0.5 and config.current_font_scale_index > 0: # Gauche
|
||||
config.current_font_scale_index -= 1
|
||||
update_font_scale()
|
||||
return True
|
||||
elif event.value > 0.5 and config.current_font_scale_index < len(config.font_scale_options) - 1: # Droite
|
||||
config.current_font_scale_index += 1
|
||||
update_font_scale()
|
||||
return True
|
||||
|
||||
return False
|
||||
def update_font_scale():
|
||||
"""Met à jour l'échelle de police et sauvegarde."""
|
||||
new_scale = config.font_scale_options[config.current_font_scale_index]
|
||||
config.accessibility_settings["font_scale"] = new_scale
|
||||
save_accessibility_settings(config.accessibility_settings)
|
||||
|
||||
# Réinitialiser les polices
|
||||
config.init_font()
|
||||
config.needs_redraw = True
|
||||
49
config.py
49
config.py
@@ -3,7 +3,7 @@ import os
|
||||
import logging
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "1.9.7.6"
|
||||
app_version = "1.9.7.7"
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ REPEAT_ACTION_DEBOUNCE = 150 # Délai anti-rebond pour répétitions (ms) - aug
|
||||
platforms = []
|
||||
current_platform = 0
|
||||
accessibility_mode = False # Mode accessibilité pour les polices agrandies
|
||||
accessibility_settings = {"font_scale": 1.0}
|
||||
font_scale_options = [0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
|
||||
current_font_scale_index = 3 # Index pour 1.0
|
||||
platform_names = {} # {platform_id: platform_name}
|
||||
games = []
|
||||
current_game = 0
|
||||
@@ -89,6 +92,7 @@ current_history_item = 0
|
||||
history_scroll_offset = 0 # Offset pour le défilement de l'historique
|
||||
visible_history_items = 15 # Nombre d'éléments d'historique visibles (ajusté dynamiquement)
|
||||
confirm_clear_selection = 0 # confirmation clear historique
|
||||
confirm_cancel_selection = 0 # confirmation annulation téléchargement
|
||||
last_state_change_time = 0 # Temps du dernier changement d'état pour debounce
|
||||
debounce_delay = 200 # Délai de debounce en millisecondes
|
||||
platform_dicts = [] # Liste des dictionnaires de plateformes
|
||||
@@ -126,27 +130,32 @@ small_font = None
|
||||
|
||||
def init_font():
|
||||
"""Initialise les polices après pygame.init()."""
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
logger.debug("---------------------------DEBUT LOG--------------------------------")
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
|
||||
global FONT, progress_font, title_font, search_font, small_font
|
||||
multiplier = 1.5 if accessibility_mode else 1.0
|
||||
global font, progress_font, title_font, search_font, small_font
|
||||
font_scale = accessibility_settings.get("font_scale", 1.0)
|
||||
try:
|
||||
FONT = pygame.font.Font(None, int(36 * multiplier))
|
||||
progress_font = pygame.font.Font(None, int(28 * multiplier))
|
||||
title_font = pygame.font.Font(None, int(48 * multiplier))
|
||||
search_font = pygame.font.Font(None, int(36 * multiplier))
|
||||
small_font = pygame.font.Font(None, int(24 * multiplier))
|
||||
logger.debug(f"Polices initialisées avec succès (mode accessibilité: {accessibility_mode})")
|
||||
# amazonq-ignore-next-line
|
||||
except pygame.error as e:
|
||||
logger.error(f"Erreur lors de l'initialisation des polices : {e}")
|
||||
FONT = None
|
||||
progress_font = None
|
||||
title_font = None
|
||||
search_font = None
|
||||
small_font = None
|
||||
font_path = os.path.join(APP_FOLDER, "assets", "Pixel-UniCode.ttf")
|
||||
font = pygame.font.Font(font_path, int(36 * font_scale))
|
||||
title_font = pygame.font.Font(font_path, int(48 * font_scale))
|
||||
search_font = pygame.font.Font(font_path, int(48 * font_scale))
|
||||
progress_font = pygame.font.Font(font_path, int(36 * font_scale))
|
||||
small_font = pygame.font.Font(font_path, int(28 * font_scale))
|
||||
logger.debug(f"Polices Pixel-UniCode initialisées (font_scale: {font_scale})")
|
||||
except Exception as e:
|
||||
try:
|
||||
font = pygame.font.SysFont("arial", int(48 * font_scale))
|
||||
title_font = pygame.font.SysFont("arial", int(60 * font_scale))
|
||||
search_font = pygame.font.SysFont("arial", int(60 * font_scale))
|
||||
progress_font = pygame.font.SysFont("arial", int(36 * font_scale))
|
||||
small_font = pygame.font.SysFont("arial", int(28 * font_scale))
|
||||
logger.debug(f"Polices Arial initialisées (font_scale: {font_scale})")
|
||||
except Exception as e2:
|
||||
logger.error(f"Erreur lors de l'initialisation des polices : {e2}")
|
||||
font = None
|
||||
progress_font = None
|
||||
title_font = None
|
||||
search_font = None
|
||||
small_font = None
|
||||
|
||||
def validate_resolution():
|
||||
"""Valide la résolution de l'écran par rapport aux capacités de l'écran."""
|
||||
|
||||
64
controls.py
64
controls.py
@@ -9,7 +9,7 @@ import json
|
||||
import os
|
||||
from display import draw_validation_transition
|
||||
from network import download_rom, download_from_1fichier, is_1fichier_url
|
||||
from utils import load_games, check_extension_before_download, is_extension_supported, load_extensions_json, sanitize_filename
|
||||
from utils import load_games, check_extension_before_download, is_extension_supported, load_extensions_json, sanitize_filename, load_api_key_1fichier
|
||||
from history import load_history, clear_history, add_to_history, save_history
|
||||
import logging
|
||||
from language import _ # Import de la fonction de traduction
|
||||
@@ -504,6 +504,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.current_history_item = len(config.history) - 1
|
||||
# Vérifier d'abord si c'est un lien 1fichier
|
||||
if is_1fichier_url(url):
|
||||
config.API_KEY_1FICHIER = load_api_key_1fichier()
|
||||
if not config.API_KEY_1FICHIER:
|
||||
config.previous_menu_state = config.menu_state
|
||||
config.menu_state = "error"
|
||||
@@ -739,13 +740,50 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
logger.error(f"config.pending_download est None pour {game_name}")
|
||||
break
|
||||
elif is_input_matched(event, "cancel"):
|
||||
elif is_input_matched(event, "cancel") or is_input_matched(event, "history"):
|
||||
if config.history and config.current_history_item < len(config.history):
|
||||
entry = config.history[config.current_history_item]
|
||||
if entry.get("status") in ["downloading", "Téléchargement", "Extracting"] and is_input_matched(event, "cancel"):
|
||||
config.menu_state = "confirm_cancel_download"
|
||||
config.confirm_cancel_selection = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug("Demande d'annulation de téléchargement")
|
||||
return action
|
||||
config.menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.current_history_item = 0
|
||||
config.history_scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Retour à {config.menu_state} depuis history")
|
||||
|
||||
# Confirmation annulation téléchargement
|
||||
elif config.menu_state == "confirm_cancel_download":
|
||||
if is_input_matched(event, "confirm"):
|
||||
if config.confirm_cancel_selection == 1: # Oui
|
||||
entry = config.history[config.current_history_item]
|
||||
url = entry.get("url")
|
||||
# Annuler la tâche correspondante
|
||||
for task_id, (task, task_url, game_name, platform) in list(config.download_tasks.items()):
|
||||
if task_url == url:
|
||||
task.cancel()
|
||||
del config.download_tasks[task_id]
|
||||
entry["status"] = "Canceled"
|
||||
entry["progress"] = 0
|
||||
entry["message"] = "Téléchargement annulé"
|
||||
save_history(config.history)
|
||||
logger.debug(f"Téléchargement annulé: {game_name}")
|
||||
break
|
||||
config.menu_state = "history"
|
||||
config.needs_redraw = True
|
||||
else: # Non
|
||||
config.menu_state = "history"
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "left") or is_input_matched(event, "right"):
|
||||
config.confirm_cancel_selection = 1 - config.confirm_cancel_selection
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "cancel"):
|
||||
config.menu_state = "history"
|
||||
config.needs_redraw = True
|
||||
|
||||
# Confirmation vider l'historique"
|
||||
elif config.menu_state == "confirm_clear_history":
|
||||
logger.debug(f"État confirm_clear_history, confirm_clear_selection={config.confirm_clear_selection}, événement={event.type}, valeur={getattr(event, 'value', None)}")
|
||||
@@ -866,26 +904,10 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Passage à language_select depuis pause_menu")
|
||||
elif config.selected_option == 4: # Accessibility
|
||||
config.accessibility_mode = not config.accessibility_mode
|
||||
config.init_font()
|
||||
# Reinitialiser les polices dans le main
|
||||
font_path = os.path.join(config.APP_FOLDER, "assets", "Pixel-UniCode.ttf")
|
||||
multiplier = 1.5 if config.accessibility_mode else 1.0
|
||||
try:
|
||||
config.font = pygame.font.Font(font_path, int(36 * multiplier))
|
||||
config.title_font = pygame.font.Font(font_path, int(48 * multiplier))
|
||||
config.search_font = pygame.font.Font(font_path, int(48 * multiplier))
|
||||
config.progress_font = pygame.font.Font(font_path, int(36 * multiplier))
|
||||
config.small_font = pygame.font.Font(font_path, int(28 * multiplier))
|
||||
except:
|
||||
config.font = pygame.font.SysFont("arial", int(48 * multiplier))
|
||||
config.title_font = pygame.font.SysFont("arial", int(60 * multiplier))
|
||||
config.search_font = pygame.font.SysFont("arial", int(60 * multiplier))
|
||||
config.progress_font = pygame.font.SysFont("arial", int(36 * multiplier))
|
||||
config.small_font = pygame.font.SysFont("arial", int(28 * multiplier))
|
||||
config.menu_state = config.previous_menu_state
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "accessibility_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Mode accessibilité {'activé' if config.accessibility_mode else 'désactivé'}")
|
||||
logger.debug("Passage au menu accessibilité")
|
||||
elif config.selected_option == 5: # Redownload game cache
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "redownload_game_cache"
|
||||
|
||||
76
display.py
76
display.py
@@ -530,7 +530,7 @@ def draw_game_list(screen):
|
||||
for i in range(config.scroll_offset, min(config.scroll_offset + items_per_page, len(games))):
|
||||
game_name = games[i][0] if isinstance(games[i], (list, tuple)) else games[i]
|
||||
color = THEME_COLORS["fond_lignes"] if i == config.current_game else THEME_COLORS["text"]
|
||||
game_text = truncate_text_middle(game_name, config.small_font, rect_width - 40)
|
||||
game_text = truncate_text_middle(game_name, config.small_font, rect_width - 40, is_filename=False)
|
||||
text_surface = config.small_font.render(game_text, True, color)
|
||||
text_rect = text_surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + (i - config.scroll_offset) * line_height + line_height // 2))
|
||||
if i == config.current_game:
|
||||
@@ -680,7 +680,8 @@ def draw_history_list(screen):
|
||||
# logger.debug(f"Affichage terminé: {game_name}, status={status_text}")
|
||||
elif status == "Erreur":
|
||||
status_text = _("history_status_error").format(entry.get('message', 'Échec'))
|
||||
#logger.debug(f"Affichage erreur: {game_name}, status={status_text}")
|
||||
elif status == "Canceled":
|
||||
status_text = _("history_status_canceled")
|
||||
else:
|
||||
status_text = status
|
||||
#logger.debug(f"Affichage statut inconnu: {game_name}, status={status_text}")
|
||||
@@ -757,8 +758,37 @@ def draw_clear_history_dialog(screen):
|
||||
text_rect = text.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2))
|
||||
screen.blit(text, text_rect)
|
||||
|
||||
draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - 180, rect_y + text_height + margin_top_bottom, 160, button_height, selected=config.confirm_clear_selection == 1)
|
||||
draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 20, rect_y + text_height + margin_top_bottom, 160, button_height, selected=config.confirm_clear_selection == 0)
|
||||
button_width = min(160, (rect_width - 60) // 2)
|
||||
draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - button_width - 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_clear_selection == 1)
|
||||
draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_clear_selection == 0)
|
||||
|
||||
def draw_cancel_download_dialog(screen):
|
||||
"""Affiche la boîte de dialogue de confirmation pour annuler un téléchargement."""
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
message = _("confirm_cancel_download")
|
||||
wrapped_message = wrap_text(message, config.font, config.screen_width - 80)
|
||||
line_height = config.font.get_height() + 5
|
||||
text_height = len(wrapped_message) * line_height
|
||||
button_height = int(config.screen_height * 0.0463)
|
||||
margin_top_bottom = 20
|
||||
rect_height = text_height + button_height + 2 * margin_top_bottom
|
||||
max_text_width = max([config.font.size(line)[0] for line in wrapped_message], default=300)
|
||||
rect_width = max_text_width + 150
|
||||
rect_x = (config.screen_width - rect_width) // 2
|
||||
rect_y = (config.screen_height - rect_height) // 2
|
||||
|
||||
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (rect_x, rect_y, rect_width, rect_height), border_radius=12)
|
||||
pygame.draw.rect(screen, THEME_COLORS["border"], (rect_x, rect_y, rect_width, rect_height), 2, border_radius=12)
|
||||
|
||||
for i, line in enumerate(wrapped_message):
|
||||
text = config.font.render(line, True, THEME_COLORS["text"])
|
||||
text_rect = text.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2))
|
||||
screen.blit(text, text_rect)
|
||||
|
||||
button_width = min(160, (rect_width - 60) // 2)
|
||||
draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - button_width - 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_cancel_selection == 1)
|
||||
draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_cancel_selection == 0)
|
||||
|
||||
# Affichage du clavier virtuel sur non-PC
|
||||
def draw_virtual_keyboard(screen):
|
||||
@@ -960,7 +990,6 @@ def draw_controls(screen, menu_state, current_music_name=None, music_popup_start
|
||||
current_time = pygame.time.get_ticks() / 1000
|
||||
if current_time - config.music_popup_start_time < 3.0: # Afficher pendant 3 secondes
|
||||
control_text += f" | {config.current_music_name}"
|
||||
logger.debug(f"config.current_music_name")
|
||||
max_width = config.screen_width - 40
|
||||
wrapped_controls = wrap_text(control_text, config.small_font, max_width)
|
||||
line_height = config.small_font.get_height() + 5
|
||||
@@ -1124,22 +1153,30 @@ def draw_controls_help(screen, previous_state):
|
||||
}
|
||||
|
||||
# Catégories de contrôles
|
||||
nav_text = _("controls_navigation")
|
||||
pages_text = _("controls_pages")
|
||||
confirm_select_text = _("controls_confirm_select")
|
||||
cancel_back_text = _("controls_cancel_back")
|
||||
history_text = _("controls_history")
|
||||
clear_history_text = _("controls_clear_history")
|
||||
filter_search_text = _("controls_filter_search")
|
||||
|
||||
control_categories = {
|
||||
"Navigation": [
|
||||
f"{get_control_display('up', '↑')} {get_control_display('down', '↓')} {get_control_display('left', '←')} {get_control_display('right', '→')} : Navigation",
|
||||
f"{get_control_display('page_up', 'LB')} {get_control_display('page_down', 'RB')} : Pages"
|
||||
_("controls_category_navigation"): [
|
||||
f"{get_control_display('up', '↑')} {get_control_display('down', '↓')} {get_control_display('left', '←')} {get_control_display('right', '→')} : {nav_text}",
|
||||
f"{get_control_display('page_up', 'LB')} {get_control_display('page_down', 'RB')} : {pages_text}"
|
||||
],
|
||||
"Actions principales": [
|
||||
f"{get_control_display('confirm', 'A')} : Confirmer/Sélectionner",
|
||||
f"{get_control_display('cancel', 'B')} : Annuler/Retour",
|
||||
_("controls_category_main_actions"): [
|
||||
f"{get_control_display('confirm', 'A')} : {confirm_select_text}",
|
||||
f"{get_control_display('cancel', 'B')} : {cancel_back_text}",
|
||||
f"{get_control_display('start', 'Start')} : {start_text}"
|
||||
],
|
||||
"Téléchargements": [
|
||||
f"{get_control_display('history', 'Y')} : Historique",
|
||||
f"{get_control_display('progress', 'X')} : Effacer historique"
|
||||
_("controls_category_downloads"): [
|
||||
f"{get_control_display('history', 'Y')} : {history_text}",
|
||||
f"{get_control_display('progress', 'X')} : {clear_history_text}"
|
||||
],
|
||||
"Recherche": [
|
||||
f"{get_control_display('filter', 'Select')} : Filtrer/Rechercher",
|
||||
_("controls_category_search"): [
|
||||
f"{get_control_display('filter', 'Select')} : {filter_search_text}",
|
||||
f"{get_control_display('delete', 'Suppr')} : {delete_text}",
|
||||
f"{get_control_display('space', 'Espace')} : {space_text}"
|
||||
]
|
||||
@@ -1185,7 +1222,7 @@ def draw_controls_help(screen, previous_state):
|
||||
pygame.draw.rect(screen, THEME_COLORS["border"], (popup_x, popup_y, popup_width, popup_height), 2, border_radius=12)
|
||||
|
||||
# Titre
|
||||
title_text = "Aide des contrôles"
|
||||
title_text = _("controls_help_title")
|
||||
title_surface = config.title_font.render(title_text, True, THEME_COLORS["text"])
|
||||
title_rect = title_surface.get_rect(center=(config.screen_width // 2, popup_y + 25))
|
||||
screen.blit(title_surface, title_rect)
|
||||
@@ -1257,8 +1294,9 @@ def draw_confirm_dialog(screen):
|
||||
text_rect = text.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2))
|
||||
screen.blit(text, text_rect)
|
||||
|
||||
draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - 180, rect_y + text_height + margin_top_bottom, 160, button_height, selected=config.confirm_selection == 1)
|
||||
draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 20, rect_y + text_height + margin_top_bottom, 160, button_height, selected=config.confirm_selection == 0)
|
||||
button_width = min(160, (rect_width - 60) // 2)
|
||||
draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - button_width - 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_selection == 1)
|
||||
draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_selection == 0)
|
||||
|
||||
# draw_redownload_game_cache_dialog
|
||||
def draw_redownload_game_cache_dialog(screen):
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"history_status_extracting": "Extracting: {0}%",
|
||||
"history_status_completed": "Completed",
|
||||
"history_status_error": "Error: {0}",
|
||||
"history_status_canceled": "Canceled",
|
||||
|
||||
"download_status": "{0}: {1}",
|
||||
"download_progress": "{0}% {1} MB / {2} MB",
|
||||
@@ -66,6 +67,7 @@
|
||||
"menu_remap_controls": "Remap controls",
|
||||
"menu_history": "History",
|
||||
"menu_language": "Language",
|
||||
"menu_accessibility": "Accessibility",
|
||||
"menu_redownload_cache": "Redownload Games cache",
|
||||
"menu_quit": "Quit",
|
||||
|
||||
@@ -155,5 +157,20 @@
|
||||
"utils_permission_denied": "Permission denied during extraction: {0}",
|
||||
"utils_extraction_failed": "Extraction failed: {0}",
|
||||
"utils_unrar_unavailable": "Unrar command not available",
|
||||
"utils_rar_list_failed": "Failed to list RAR files: {0}"
|
||||
"utils_rar_list_failed": "Failed to list RAR files: {0}",
|
||||
"download_initializing": "Initializing...",
|
||||
"accessibility_font_size": "Font size: {0}",
|
||||
"confirm_cancel_download": "Cancel current download?",
|
||||
"controls_help_title": "Controls Help",
|
||||
"controls_category_navigation": "Navigation",
|
||||
"controls_category_main_actions": "Main Actions",
|
||||
"controls_category_downloads": "Downloads",
|
||||
"controls_category_search": "Search",
|
||||
"controls_navigation": "Navigation",
|
||||
"controls_pages": "Pages",
|
||||
"controls_confirm_select": "Confirm/Select",
|
||||
"controls_cancel_back": "Cancel/Back",
|
||||
"controls_history": "History",
|
||||
"controls_clear_history": "Clear History",
|
||||
"controls_filter_search": "Filter/Search"
|
||||
}
|
||||
@@ -42,6 +42,7 @@
|
||||
"history_status_extracting": "Extraction : {0}%",
|
||||
"history_status_completed": "Terminé",
|
||||
"history_status_error": "Erreur : {0}",
|
||||
"history_status_canceled": "Annulé",
|
||||
|
||||
"download_status": "{0} : {1}",
|
||||
"download_progress": "{0}% {1} Mo / {2} Mo",
|
||||
@@ -66,6 +67,7 @@
|
||||
"menu_remap_controls": "Remapper les contrôles",
|
||||
"menu_history": "Historique",
|
||||
"menu_language": "Langue",
|
||||
"menu_accessibility": "Accessibilité",
|
||||
"menu_redownload_cache": "Retélécharger le cache des jeux",
|
||||
"menu_quit": "Quitter",
|
||||
|
||||
@@ -144,7 +146,22 @@
|
||||
"network_permission_error": "Pas de permission d'écriture dans {0}",
|
||||
"network_file_not_found": "Le fichier {0} n'existe pas",
|
||||
"network_cannot_get_filename": "Impossible de récupérer le nom du fichier",
|
||||
"network_cannot_get_download_url": "Impossible de récupérer l'URL de téléchargement",
|
||||
"network_cannot_get_download_url": "Impossible de récupérer l'URL de téléchargement",
|
||||
"download_initializing": "Initialisation en cours...",
|
||||
"accessibility_font_size": "Taille de police : {0}",
|
||||
"confirm_cancel_download": "Annuler le téléchargement en cours ?",
|
||||
"controls_help_title": "Aide des contrôles",
|
||||
"controls_category_navigation": "Navigation",
|
||||
"controls_category_main_actions": "Actions principales",
|
||||
"controls_category_downloads": "Téléchargements",
|
||||
"controls_category_search": "Recherche",
|
||||
"controls_navigation": "Navigation",
|
||||
"controls_pages": "Pages",
|
||||
"controls_confirm_select": "Confirmer/Sélectionner",
|
||||
"controls_cancel_back": "Annuler/Retour",
|
||||
"controls_history": "Historique",
|
||||
"controls_clear_history": "Effacer historique",
|
||||
"controls_filter_search": "Filtrer/Rechercher",
|
||||
"network_download_failed": "Échec du téléchargement après {0} tentatives",
|
||||
"network_api_error": "Erreur lors de la requête API, la clé est peut-être incorrecte: {0}",
|
||||
"network_download_error": "Erreur téléchargement {0}: {1}",
|
||||
|
||||
284
network.py
284
network.py
@@ -10,6 +10,7 @@ from config import OTA_VERSION_ENDPOINT,APP_FOLDER, UPDATE_FOLDER, OTA_UPDATE_ZI
|
||||
from utils import sanitize_filename, extract_zip, extract_rar, load_api_key_1fichier
|
||||
from history import save_history
|
||||
import logging
|
||||
import datetime
|
||||
import queue
|
||||
import time
|
||||
import os
|
||||
@@ -152,9 +153,8 @@ def extract_update(zip_path, dest_dir, source_url):
|
||||
logger.error(f"Erreur critique lors de l'extraction du ZIP {source_url}: {str(e)}")
|
||||
return False, _("network_zip_extraction_error").format(source_url, str(e))
|
||||
|
||||
# File d'attente pour la progression
|
||||
import queue
|
||||
progress_queue = queue.Queue()
|
||||
# File d'attente pour la progression - une par tâche
|
||||
progress_queues = {}
|
||||
|
||||
|
||||
|
||||
@@ -162,13 +162,9 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
logger.debug(f"Début téléchargement: {game_name} depuis {url}, is_zip_non_supported={is_zip_non_supported}, task_id={task_id}")
|
||||
result = [None, None]
|
||||
|
||||
# Vider la file d'attente avant de commencer
|
||||
while not progress_queue.empty():
|
||||
try:
|
||||
progress_queue.get_nowait()
|
||||
logger.debug(f"File progress_queue vidée pour {game_name}")
|
||||
except queue.Empty:
|
||||
break
|
||||
# Créer une queue spécifique pour cette tâche
|
||||
if task_id not in progress_queues:
|
||||
progress_queues[task_id] = queue.Queue()
|
||||
|
||||
def download_thread():
|
||||
logger.debug(f"Thread téléchargement démarré pour {url}, task_id={task_id}")
|
||||
@@ -178,7 +174,6 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
if platform_dict["platform"] == platform:
|
||||
dest_dir = os.path.join(config.ROMS_FOLDER, platform_dict.get("folder", platform.lower().replace(" ", "")))
|
||||
logger.debug(f"Répertoire de destination trouvé pour {platform}: {dest_dir}")
|
||||
#dest_dir = platform_dict.get("folder")
|
||||
break
|
||||
if not dest_dir:
|
||||
dest_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), platform.lower().replace(" ", ""))
|
||||
@@ -201,47 +196,27 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
'Upgrade-Insecure-Requests': '1'
|
||||
}
|
||||
|
||||
# Utiliser une session pour gérer les cookies
|
||||
session = requests.Session()
|
||||
session.headers.update(headers)
|
||||
|
||||
# Première requête HEAD pour obtenir la vraie URL
|
||||
#logger.debug(f"Première requête HEAD vers {url}")
|
||||
head_response = session.head(url, timeout=30, allow_redirects=False)
|
||||
#logger.debug(f"HEAD Status: {head_response.status_code}, Headers: {dict(head_response.headers)}")
|
||||
|
||||
# Suivre la redirection manuellement si nécessaire
|
||||
final_url = url
|
||||
if head_response.status_code in [301, 302, 303, 307, 308]:
|
||||
final_url = head_response.headers.get('Location', url)
|
||||
#logger.debug(f"Redirection détectée vers: {final_url}")
|
||||
|
||||
# Requête GET vers l'URL finale avec en-têtes spécifiques
|
||||
download_headers = headers.copy()
|
||||
download_headers['Accept'] = 'application/octet-stream, */*'
|
||||
download_headers['Referer'] = 'https://myrient.erista.me/'
|
||||
response = session.get(final_url, stream=True, timeout=30, allow_redirects=False, headers=download_headers)
|
||||
response = session.get(url, stream=True, timeout=30, allow_redirects=True, headers=download_headers)
|
||||
logger.debug(f"Status code: {response.status_code}")
|
||||
logger.debug(f"Headers: {dict(response.headers)}")
|
||||
response.raise_for_status()
|
||||
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
logger.debug(f"Taille totale: {total_size} octets")
|
||||
|
||||
if total_size == 0:
|
||||
logger.warning(f"Taille de fichier 0, possible redirection ou erreur. URL finale: {response.url}")
|
||||
# Vérifier si c'est une redirection
|
||||
if response.url != url:
|
||||
logger.debug(f"Redirection détectée: {url} -> {response.url}")
|
||||
|
||||
# Initialiser la progression avec task_id
|
||||
progress_queue.put((task_id, 0, total_size))
|
||||
progress_queues[task_id].put((task_id, 0, total_size))
|
||||
logger.debug(f"Progression initiale envoyée: 0% pour {game_name}, task_id={task_id}")
|
||||
|
||||
downloaded = 0
|
||||
chunk_size = 4096
|
||||
last_update_time = time.time()
|
||||
update_interval = 0.5 # Mettre à jour toutes les 0,5 secondes
|
||||
update_interval = 0.1 # Mettre à jour toutes les 0,1 secondes
|
||||
with open(dest_path, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=chunk_size):
|
||||
if chunk:
|
||||
@@ -250,24 +225,17 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
downloaded += size_received
|
||||
current_time = time.time()
|
||||
if current_time - last_update_time >= update_interval:
|
||||
# Calculer le pourcentage correctement et le limiter entre 0 et 100
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
progress_queue.put((task_id, downloaded, total_size))
|
||||
progress_queues[task_id].put((task_id, downloaded, total_size))
|
||||
last_update_time = current_time
|
||||
else:
|
||||
logger.debug("Chunk vide reçu")
|
||||
|
||||
os.chmod(dest_path, 0o644)
|
||||
logger.debug(f"Téléchargement terminé: {dest_path}")
|
||||
|
||||
# Vérifier si l'extraction est nécessaire pour les archives non supportées
|
||||
if is_zip_non_supported:
|
||||
logger.debug(f"Extraction automatique nécessaire pour {dest_path}")
|
||||
extension = os.path.splitext(dest_path)[1].lower()
|
||||
if extension == ".zip":
|
||||
try:
|
||||
# Mettre à jour le statut avant l'extraction
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement"]:
|
||||
@@ -319,7 +287,7 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
result[1] = _("network_download_error").format(game_name, str(e))
|
||||
finally:
|
||||
logger.debug(f"Thread téléchargement terminé pour {url}, task_id={task_id}")
|
||||
progress_queue.put((task_id, result[0], result[1]))
|
||||
progress_queues[task_id].put((task_id, result[0], result[1]))
|
||||
logger.debug(f"Final result sent to queue: success={result[0]}, message={result[1]}, task_id={task_id}")
|
||||
|
||||
thread = threading.Thread(target=download_thread)
|
||||
@@ -328,68 +296,63 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
# Boucle principale pour mettre à jour la progression
|
||||
while thread.is_alive():
|
||||
try:
|
||||
while not progress_queue.empty():
|
||||
data = progress_queue.get()
|
||||
logger.debug(f"Progress queue data received: {data}")
|
||||
if len(data) != 3 or data[0] != task_id: # Ignorer les données d'une autre tâche
|
||||
logger.debug(f"Ignoring queue data for task_id={data[0]}, expected={task_id}")
|
||||
continue
|
||||
if isinstance(data[1], bool): # Fin du téléchargement
|
||||
success, message = data[1], data[2]
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement", "Extracting"]:
|
||||
entry["status"] = "Download_OK" if success else "Erreur"
|
||||
entry["progress"] = 100 if success else 0
|
||||
# Utiliser une variable intermédiaire pour stocker le message
|
||||
message_text = message
|
||||
entry["message"] = message_text
|
||||
save_history(config.history)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Final update in history: status={entry['status']}, progress={entry['progress']}%, message={message}, task_id={task_id}")
|
||||
break
|
||||
else:
|
||||
downloaded, total_size = data[1], data[2]
|
||||
# Calculer le pourcentage correctement et le limiter entre 0 et 100
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement"]:
|
||||
entry["progress"] = progress_percent
|
||||
entry["status"] = "Téléchargement"
|
||||
entry["downloaded_size"] = downloaded
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
break
|
||||
await asyncio.sleep(0.2)
|
||||
task_queue = progress_queues.get(task_id)
|
||||
if task_queue:
|
||||
while not task_queue.empty():
|
||||
data = task_queue.get()
|
||||
#logger.debug(f"Progress queue data received: {data}")
|
||||
if isinstance(data[1], bool): # Fin du téléchargement
|
||||
success, message = data[1], data[2]
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement", "Extracting"]:
|
||||
entry["status"] = "Download_OK" if success else "Erreur"
|
||||
entry["progress"] = 100 if success else 0
|
||||
entry["message"] = message
|
||||
save_history(config.history)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Final update in history: status={entry['status']}, progress={entry['progress']}%, message={message}, task_id={task_id}")
|
||||
break
|
||||
else:
|
||||
downloaded, total_size = data[1], data[2]
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement"]:
|
||||
entry["progress"] = progress_percent
|
||||
entry["status"] = "Téléchargement"
|
||||
entry["downloaded_size"] = downloaded
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
break
|
||||
await asyncio.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur mise à jour progression: {str(e)}")
|
||||
|
||||
thread.join()
|
||||
#logger.debug(f"Thread joined for {url}, task_id={task_id}")
|
||||
# Nettoyer la queue
|
||||
if task_id in progress_queues:
|
||||
del progress_queues[task_id]
|
||||
return result[0], result[1]
|
||||
|
||||
async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=False, task_id=None):
|
||||
load_api_key_1fichier()
|
||||
config.API_KEY_1FICHIER = load_api_key_1fichier()
|
||||
logger.debug(f"Début téléchargement 1fichier: {game_name} depuis {url}, is_zip_non_supported={is_zip_non_supported}, task_id={task_id}")
|
||||
logger.debug(f"Clé API 1fichier: {'présente' if config.API_KEY_1FICHIER else 'absente'}")
|
||||
result = [None, None]
|
||||
|
||||
# Vider la file d'attente avant de commencer
|
||||
while not progress_queue.empty():
|
||||
try:
|
||||
progress_queue.get_nowait()
|
||||
logger.debug(f"File progress_queue vidée pour {game_name}")
|
||||
except queue.Empty:
|
||||
break
|
||||
# Créer une queue spécifique pour cette tâche
|
||||
logger.debug(f"Création queue pour task_id={task_id}")
|
||||
if task_id not in progress_queues:
|
||||
progress_queues[task_id] = queue.Queue()
|
||||
|
||||
def download_thread():
|
||||
logger.debug(f"Thread téléchargement 1fichier démarré pour {url}, task_id={task_id}")
|
||||
try:
|
||||
link = url.split('&af=')[0]
|
||||
logger.debug(f"URL nettoyée: {link}")
|
||||
dest_dir = None
|
||||
for platform_dict in config.platform_dicts:
|
||||
if platform_dict["platform"] == platform:
|
||||
@@ -398,10 +361,13 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
if not dest_dir:
|
||||
logger.warning(f"Aucun dossier 'folder' trouvé pour la plateforme {platform}")
|
||||
dest_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), platform)
|
||||
logger.debug(f"Répertoire destination déterminé: {dest_dir}")
|
||||
|
||||
logger.debug(f"Vérification répertoire destination: {dest_dir}")
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
logger.debug(f"Répertoire créé ou existant: {dest_dir}")
|
||||
if not os.access(dest_dir, os.W_OK):
|
||||
logger.error(f"Pas de permission d'écriture dans {dest_dir}")
|
||||
raise PermissionError(f"Pas de permission d'écriture dans {dest_dir}")
|
||||
|
||||
headers = {
|
||||
@@ -412,10 +378,9 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
"url": link,
|
||||
"pretty": 1
|
||||
}
|
||||
|
||||
#logger.debug(f"Envoi requête POST à https://api.1fichier.com/v1/file/info.cgi pour {url}")
|
||||
logger.debug(f"Préparation requête file/info pour {link}")
|
||||
response = requests.post("https://api.1fichier.com/v1/file/info.cgi", headers=headers, json=payload, timeout=30)
|
||||
#logger.debug(f"Réponse reçue, status: {response.status_code}")
|
||||
logger.debug(f"Réponse file/info reçue, code: {response.status_code}")
|
||||
response.raise_for_status()
|
||||
file_info = response.json()
|
||||
|
||||
@@ -427,7 +392,7 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
|
||||
filename = file_info.get("filename", "").strip()
|
||||
if not filename:
|
||||
logger.error("Impossible de récupérer le nom du fichier")
|
||||
logger.error(f"Impossible de récupérer le nom du fichier")
|
||||
result[0] = False
|
||||
result[1] = _("network_cannot_get_filename")
|
||||
return
|
||||
@@ -435,50 +400,48 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
sanitized_filename = sanitize_filename(filename)
|
||||
dest_path = os.path.join(dest_dir, sanitized_filename)
|
||||
logger.debug(f"Chemin destination: {dest_path}")
|
||||
|
||||
#logger.debug(f"Envoi requête POST à https://api.1fichier.com/v1/download/get_token.cgi pour {url}")
|
||||
logger.debug(f"Envoi requête get_token pour {link}")
|
||||
response = requests.post("https://api.1fichier.com/v1/download/get_token.cgi", headers=headers, json=payload, timeout=30)
|
||||
#logger.debug(f"Réponse reçue, status: {response.status_code}")
|
||||
logger.debug(f"Réponse get_token reçue, code: {response.status_code}")
|
||||
response.raise_for_status()
|
||||
download_info = response.json()
|
||||
|
||||
final_url = download_info.get("url")
|
||||
if not final_url:
|
||||
logger.error("Impossible de récupérer l'URL de téléchargement")
|
||||
logger.error(f"Impossible de récupérer l'URL de téléchargement")
|
||||
result[0] = False
|
||||
result[1] = _("network_cannot_get_download_url")
|
||||
return
|
||||
|
||||
logger.debug(f"URL de téléchargement obtenue: {final_url}")
|
||||
lock = threading.Lock()
|
||||
retries = 10
|
||||
retry_delay = 10
|
||||
# Initialiser la progression avec task_id
|
||||
progress_queue.put((task_id, 0, 0)) # Taille initiale inconnue
|
||||
#logger.debug(f"Progression initiale envoyée: 0% pour {game_name}, task_id={task_id}")
|
||||
logger.debug(f"Initialisation progression avec taille inconnue pour task_id={task_id}")
|
||||
progress_queues[task_id].put((task_id, 0, 0)) # Taille initiale inconnue
|
||||
for attempt in range(retries):
|
||||
logger.debug(f"Début tentative {attempt + 1} pour télécharger {final_url}")
|
||||
try:
|
||||
#logger.debug(f"Tentative {attempt + 1} : Envoi requête GET à {final_url}")
|
||||
with requests.get(final_url, stream=True, headers={'User-Agent': 'Mozilla/5.0'}, timeout=30) as response:
|
||||
#logger.debug(f"Réponse reçue, status: {response.status_code}")
|
||||
logger.debug(f"Réponse GET reçue, code: {response.status_code}")
|
||||
response.raise_for_status()
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
logger.debug(f"Taille totale: {total_size} octets")
|
||||
with lock:
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] == "downloading":
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
break
|
||||
progress_queue.put((task_id, 0, total_size)) # Mettre à jour la taille totale
|
||||
progress_queues[task_id].put((task_id, 0, total_size)) # Mettre à jour la taille totale
|
||||
|
||||
downloaded = 0
|
||||
chunk_size = 8192
|
||||
last_update_time = time.time()
|
||||
update_interval = 0.5 # Mettre à jour toutes les 0,5 secondes
|
||||
update_interval = 0.1 # Mettre à jour toutes les 0,1 secondes
|
||||
logger.debug(f"Ouverture fichier: {dest_path}")
|
||||
with open(dest_path, 'wb') as f:
|
||||
logger.debug(f"Ouverture fichier: {dest_path}")
|
||||
for chunk in response.iter_content(chunk_size=chunk_size):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
@@ -486,11 +449,9 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
current_time = time.time()
|
||||
if current_time - last_update_time >= update_interval:
|
||||
with lock:
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] == "downloading":
|
||||
# Calculer le pourcentage correctement et le limiter entre 0 et 100
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
entry["progress"] = progress_percent
|
||||
@@ -498,14 +459,12 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
entry["downloaded_size"] = downloaded
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
#logger.debug(f"Progression mise à jour: {entry['progress']:.1f}% pour {game_name}")
|
||||
break
|
||||
progress_queue.put((task_id, downloaded, total_size))
|
||||
progress_queues[task_id].put((task_id, downloaded, total_size))
|
||||
last_update_time = current_time
|
||||
|
||||
if is_zip_non_supported:
|
||||
with lock:
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] == "Téléchargement":
|
||||
@@ -514,11 +473,12 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
config.needs_redraw = True
|
||||
break
|
||||
extension = os.path.splitext(dest_path)[1].lower()
|
||||
logger.debug(f"Début extraction, type d'archive: {extension}")
|
||||
if extension == ".zip":
|
||||
try:
|
||||
success, msg = extract_zip(dest_path, dest_dir, url)
|
||||
logger.debug(f"Extraction ZIP terminée: {msg}")
|
||||
if success:
|
||||
logger.debug(f"Extraction ZIP réussie: {msg}")
|
||||
result[0] = True
|
||||
result[1] = _("network_download_extract_ok").format(game_name)
|
||||
else:
|
||||
@@ -526,14 +486,14 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
result[0] = False
|
||||
result[1] = _("network_extraction_failed").format(msg)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception lors de l'extraction: {str(e)}")
|
||||
logger.error(f"Exception lors de l'extraction ZIP: {str(e)}")
|
||||
result[0] = False
|
||||
result[1] = f"Erreur téléchargement {game_name}: {str(e)}"
|
||||
elif extension == ".rar":
|
||||
try:
|
||||
success, msg = extract_rar(dest_path, dest_dir, url)
|
||||
logger.debug(f"Extraction RAR terminée: {msg}")
|
||||
if success:
|
||||
logger.debug(f"Extraction RAR réussie: {msg}")
|
||||
result[0] = True
|
||||
result[1] = _("network_download_extract_ok").format(game_name)
|
||||
else:
|
||||
@@ -549,6 +509,7 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
result[0] = True
|
||||
result[1] = _("network_download_ok").format(game_name)
|
||||
else:
|
||||
logger.debug(f"Application des permissions sur {dest_path}")
|
||||
os.chmod(dest_path, 0o644)
|
||||
logger.debug(f"Téléchargement terminé: {dest_path}")
|
||||
result[0] = True
|
||||
@@ -556,78 +517,77 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
|
||||
return
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Tentative {attempt + 1} échouée : {e}")
|
||||
logger.error(f"Tentative {attempt + 1} échouée: {e}")
|
||||
if attempt < retries - 1:
|
||||
logger.debug(f"Attente de {retry_delay} secondes avant nouvelle tentative")
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
logger.error("Nombre maximum de tentatives atteint")
|
||||
logger.error(f"Nombre maximum de tentatives atteint")
|
||||
result[0] = False
|
||||
result[1] = _("network_download_failed").format(retries)
|
||||
return
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Erreur API 1fichier : {e}")
|
||||
logger.error(f"Erreur API 1fichier: {e}")
|
||||
result[0] = False
|
||||
result[1] = _("network_api_error").format(str(e))
|
||||
|
||||
finally:
|
||||
logger.debug(f"Thread téléchargement 1fichier terminé pour {url}, task_id={task_id}")
|
||||
progress_queue.put((task_id, result[0], result[1]))
|
||||
logger.debug(f"Final result sent to queue: success={result[0]}, message={result[1]}, task_id={task_id}")
|
||||
progress_queues[task_id].put((task_id, result[0], result[1]))
|
||||
logger.debug(f"Résultat final envoyé à la queue: success={result[0]}, message={result[1]}, task_id={task_id}")
|
||||
|
||||
thread = threading.Thread(target=download_thread)
|
||||
logger.debug(f"Démarrage thread pour {url}, task_id={task_id}")
|
||||
thread = threading.Thread(target=download_thread)
|
||||
thread.start()
|
||||
|
||||
# Boucle principale pour mettre à jour la progression
|
||||
logger.debug(f"Début boucle de progression pour task_id={task_id}")
|
||||
while thread.is_alive():
|
||||
try:
|
||||
while not progress_queue.empty():
|
||||
data = progress_queue.get()
|
||||
logger.debug(f"Progress queue data received: {data}")
|
||||
if len(data) != 3 or data[0] != task_id: # Ignorer les données d'une autre tâche
|
||||
logger.debug(f"Ignoring queue data for task_id={data[0]}, expected={task_id}")
|
||||
continue
|
||||
if isinstance(data[1], bool): # Fin du téléchargement
|
||||
success, message = data[1], data[2]
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement", "Extracting"]:
|
||||
entry["status"] = "Download_OK" if success else "Erreur"
|
||||
entry["progress"] = 100 if success else 0
|
||||
# Utiliser une variable intermédiaire pour stocker le message
|
||||
message_text = message
|
||||
entry["message"] = message_text
|
||||
save_history(config.history)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Final update in history: status={entry['status']}, progress={entry['progress']}%, message={message}, task_id={task_id}")
|
||||
break
|
||||
else:
|
||||
downloaded, total_size = data[1], data[2]
|
||||
# Calculer le pourcentage correctement et le limiter entre 0 et 100
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
|
||||
# Vérifier si config.history est une liste avant d'itérer
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement"]:
|
||||
entry["progress"] = progress_percent
|
||||
entry["status"] = "Téléchargement"
|
||||
entry["downloaded_size"] = downloaded
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
break
|
||||
await asyncio.sleep(0.2)
|
||||
task_queue = progress_queues.get(task_id)
|
||||
if task_queue:
|
||||
while not task_queue.empty():
|
||||
data = task_queue.get()
|
||||
logger.debug(f"Données queue progression reçues: {data}")
|
||||
if isinstance(data[1], bool): # Fin du téléchargement
|
||||
success, message = data[1], data[2]
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement", "Extracting"]:
|
||||
entry["status"] = "Download_OK" if success else "Erreur"
|
||||
entry["progress"] = 100 if success else 0
|
||||
entry["message"] = message
|
||||
save_history(config.history)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Mise à jour finale historique: status={entry['status']}, progress={entry['progress']}%, message={message}, task_id={task_id}")
|
||||
break
|
||||
else:
|
||||
downloaded, total_size = data[1], data[2]
|
||||
progress_percent = int(downloaded / total_size * 100) if total_size > 0 else 0
|
||||
progress_percent = max(0, min(100, progress_percent))
|
||||
|
||||
if isinstance(config.history, list):
|
||||
for entry in config.history:
|
||||
if "url" in entry and entry["url"] == url and entry["status"] in ["downloading", "Téléchargement"]:
|
||||
entry["progress"] = progress_percent
|
||||
entry["status"] = "Téléchargement"
|
||||
entry["downloaded_size"] = downloaded
|
||||
entry["total_size"] = total_size
|
||||
config.needs_redraw = True
|
||||
break
|
||||
await asyncio.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur mise à jour progression: {str(e)}")
|
||||
|
||||
logger.debug(f"Fin boucle de progression, attente fin thread pour task_id={task_id}")
|
||||
thread.join()
|
||||
logger.debug(f"Thread joined for {url}, task_id={task_id}")
|
||||
logger.debug(f"Thread terminé, nettoyage queue pour task_id={task_id}")
|
||||
# Nettoyer la queue
|
||||
if task_id in progress_queues:
|
||||
del progress_queues[task_id]
|
||||
logger.debug(f"Fin download_from_1fichier, résultat: success={result[0]}, message={result[1]}")
|
||||
return result[0], result[1]
|
||||
|
||||
|
||||
def is_1fichier_url(url):
|
||||
"""Détecte si l'URL est un lien 1fichier."""
|
||||
return "1fichier.com" in url
|
||||
67
utils.py
67
utils.py
@@ -13,6 +13,28 @@ import time
|
||||
import random
|
||||
import random
|
||||
from config import JSON_EXTENSIONS, SAVE_FOLDER
|
||||
|
||||
def load_accessibility_settings():
|
||||
"""Charge les paramètres d'accessibilité depuis accessibility.json."""
|
||||
accessibility_path = os.path.join(SAVE_FOLDER, "accessibility.json")
|
||||
try:
|
||||
if os.path.exists(accessibility_path):
|
||||
with open(accessibility_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement de accessibility.json: {str(e)}")
|
||||
return {"font_scale": 1.0}
|
||||
|
||||
def save_accessibility_settings(settings):
|
||||
"""Sauvegarde les paramètres d'accessibilité dans accessibility.json."""
|
||||
accessibility_path = os.path.join(SAVE_FOLDER, "accessibility.json")
|
||||
try:
|
||||
os.makedirs(SAVE_FOLDER, exist_ok=True)
|
||||
with open(accessibility_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(settings, f, indent=2)
|
||||
logger.debug(f"Paramètres d'accessibilité sauvegardés: {settings}")
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors de la sauvegarde de accessibility.json: {str(e)}")
|
||||
from history import save_history
|
||||
from language import _ # Import de la fonction de traduction
|
||||
from datetime import datetime
|
||||
@@ -85,17 +107,23 @@ def check_extension_before_download(url, platform, game_name):
|
||||
def is_extension_supported(filename, platform, extensions_data):
|
||||
"""Vérifie si l'extension du fichier est supportée pour la plateforme donnée."""
|
||||
extension = os.path.splitext(filename)[1].lower()
|
||||
|
||||
dest_dir = None
|
||||
for platform_dict in config.platform_dicts:
|
||||
if platform_dict["platform"] == platform:
|
||||
dest_dir = os.path.join(config.ROMS_FOLDER, platform_dict.get("folder", platform.lower().replace(" ", "")))
|
||||
dest_dir = os.path.join(config.ROMS_FOLDER, platform_dict.get("folder"))
|
||||
break
|
||||
|
||||
if not dest_dir:
|
||||
logger.warning(f"Aucun dossier 'folder' trouvé pour la plateforme {platform}")
|
||||
dest_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), platform)
|
||||
for system in extensions_data:
|
||||
if system["folder"] == dest_dir:
|
||||
return extension in system["extensions"]
|
||||
|
||||
dest_folder_name = os.path.basename(dest_dir)
|
||||
for i, system in enumerate(extensions_data):
|
||||
if system["folder"] == dest_folder_name:
|
||||
result = extension in system["extensions"]
|
||||
return result
|
||||
|
||||
logger.warning(f"Aucun système trouvé pour le dossier {dest_dir}")
|
||||
return False
|
||||
|
||||
@@ -388,7 +416,7 @@ def extract_zip(zip_path, dest_dir, url):
|
||||
if current_time - last_save_time >= save_interval:
|
||||
save_history(config.history)
|
||||
last_save_time = current_time
|
||||
logger.debug(f"Extraction en cours: {info.filename}, file_extracted={file_extracted}/{file_size}, total_extracted={extracted_size}/{total_size}, progression={progress_percent:.1f}%")
|
||||
# logger.debug(f"Extraction en cours: {info.filename}, file_extracted={file_extracted}/{file_size}, total_extracted={extracted_size}/{total_size}, progression={progress_percent:.1f}%")
|
||||
|
||||
config.needs_redraw = True
|
||||
break
|
||||
@@ -574,7 +602,7 @@ def extract_rar(rar_path, dest_dir, url):
|
||||
logger.error(f"Erreur lors de la suppression de {rar_path}: {str(e)}")
|
||||
|
||||
def play_random_music(music_files, music_folder, current_music=None):
|
||||
"""Joue une musique aléatoire et configure l'événement de fin."""
|
||||
"""Joue une musique aléatoire et configure l'événement de fin de manière non-bloquante."""
|
||||
if music_files:
|
||||
# Éviter de rejouer la même musique consécutivement
|
||||
available_music = [f for f in music_files if f != current_music]
|
||||
@@ -583,11 +611,21 @@ def play_random_music(music_files, music_folder, current_music=None):
|
||||
music_file = random.choice(available_music)
|
||||
music_path = os.path.join(music_folder, music_file)
|
||||
logger.debug(f"Lecture de la musique : {music_path}")
|
||||
pygame.mixer.music.load(music_path)
|
||||
pygame.mixer.music.set_volume(0.5)
|
||||
pygame.mixer.music.play(loops=0) # Jouer une seule fois
|
||||
pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) # Événement de fin
|
||||
set_music_popup(music_file) # Afficher le nom de la musique dans la popup
|
||||
|
||||
def load_and_play_music():
|
||||
try:
|
||||
pygame.mixer.music.load(music_path)
|
||||
pygame.mixer.music.set_volume(0.5)
|
||||
pygame.mixer.music.play(loops=0) # Jouer une seule fois
|
||||
pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) # Événement de fin
|
||||
set_music_popup(music_file) # Afficher le nom de la musique dans la popup
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement de la musique {music_path}: {str(e)}")
|
||||
|
||||
# Charger et jouer la musique dans un thread séparé pour éviter le blocage
|
||||
music_thread = threading.Thread(target=load_and_play_music, daemon=True)
|
||||
music_thread.start()
|
||||
|
||||
return music_file # Retourner la nouvelle musique pour mise à jour
|
||||
else:
|
||||
logger.debug("Aucune musique trouvée dans /RGSX/assets/music")
|
||||
@@ -602,13 +640,17 @@ def set_music_popup(music_name):
|
||||
def load_api_key_1fichier():
|
||||
"""Charge la clé API 1fichier depuis le dossier de sauvegarde, crée le fichier si absent."""
|
||||
api_path = os.path.join(SAVE_FOLDER, "1fichierAPI.txt")
|
||||
logger.debug(f"Tentative de chargement de la clé API depuis: {api_path}")
|
||||
try:
|
||||
# Vérifie si le fichier existe déjà
|
||||
if not os.path.exists(api_path):
|
||||
# Crée le dossier parent si nécessaire
|
||||
os.makedirs(SAVE_FOLDER, exist_ok=True)
|
||||
# Crée le fichier vide si absent
|
||||
with open(api_path, "w") as f:
|
||||
f.write("")
|
||||
logger.info(f"Fichier de clé API créé : {api_path}")
|
||||
return ""
|
||||
except OSError as e:
|
||||
logger.error(f"Erreur lors de la création du fichier de clé API : {e}")
|
||||
return ""
|
||||
@@ -616,9 +658,10 @@ def load_api_key_1fichier():
|
||||
try:
|
||||
with open(api_path, "r", encoding="utf-8") as f:
|
||||
api_key = f.read().strip()
|
||||
logger.debug(f"Clé API 1fichier chargée : {api_key}")
|
||||
logger.debug(f"Clé API 1fichier lue: '{api_key}' (longueur: {len(api_key)})")
|
||||
if not api_key:
|
||||
logger.warning("Clé API 1fichier vide, veuillez la renseigner dans le fichier pour pouvoir utiliser les fonctionnalités de téléchargement sur 1fichier.")
|
||||
config.API_KEY_1FICHIER = api_key
|
||||
return api_key
|
||||
except OSError as e:
|
||||
logger.error(f"Erreur lors de la lecture de la clé API : {e}")
|
||||
|
||||
Reference in New Issue
Block a user