diff --git a/RGSX.sh b/RGSX.sh new file mode 100644 index 0000000..58fc295 --- /dev/null +++ b/RGSX.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# Supprimer SDL_VIDEODRIVER=fbcon pour laisser SDL choisir le pilote +# export SDL_VIDEODRIVER=fbcon +/usr/bin/python3 /userdata/roms/ports/RGSX \ No newline at end of file diff --git a/__main__.py b/__main__.py index 949b925..6a8eeba 100644 --- a/__main__.py +++ b/__main__.py @@ -9,7 +9,7 @@ import logging import requests import sys import json -from display import init_display, draw_loading_screen, draw_error_screen, draw_platform_grid, draw_progress_screen, draw_scrollbar, draw_confirm_dialog, draw_controls, draw_gradient, draw_virtual_keyboard, draw_popup_message, draw_extension_warning, draw_pause_menu, draw_controls_help +from display import init_display, draw_loading_screen, draw_error_screen, draw_platform_grid, draw_progress_screen, draw_scrollbar, draw_confirm_dialog, draw_controls, draw_gradient, draw_virtual_keyboard, draw_popup_message, draw_extension_warning, draw_pause_menu, draw_controls_help, draw_game_list from network import test_internet, download_rom, check_extension_before_download, extract_zip from controls import handle_controls from controls_mapper import load_controls_config, map_controls, draw_controls_mapping, ACTIONS @@ -158,6 +158,7 @@ def load_sources(): except Exception as e: logger.error(f"Erreur lors du chargement de sources.json : {str(e)}") return [] + # Fonction pour vérifier et appliquer les mises à jour OTA async def check_for_updates(): try: @@ -245,7 +246,6 @@ async def check_for_updates(): return False, f"Erreur lors de la vérification des mises à jour : {str(e)}" # Boucle principale - async def main(): logger.debug("Début main") running = True @@ -477,54 +477,11 @@ async def main(): draw_error_screen(screen) logger.debug("Rendu de draw_error_screen") elif config.menu_state == "platform": - platform = config.platforms[config.selected_platform] - platform_name = config.platform_names.get(platform, platform) - game_count = config.games_count.get(platform, 0) - title_text = f"{platform_name} ({game_count} jeux)" - title_surface = config.title_font.render(title_text, True, (255, 255, 255)) - title_rect = title_surface.get_rect(center=(config.screen_width // 2, 60)) - pygame.draw.rect(screen, (50, 50, 50, 200), title_rect.inflate(40, 20)) - pygame.draw.rect(screen, (255, 255, 255), title_rect.inflate(40, 20), 2) - screen.blit(title_surface, title_rect) draw_platform_grid(screen) + logger.debug("Rendu de draw_platform_grid") elif config.menu_state == "game": - platform = config.platforms[config.current_platform] - platform_name = config.platform_names.get(platform, platform) - games = config.filtered_games if config.filter_active or config.search_mode else config.games - game_count = len(games) - if not config.search_mode: - title_text = f"{platform_name} ({game_count} jeux)" - title_surface = config.title_font.render(title_text, True, (255, 255, 255)) - title_rect = title_surface.get_rect(center=(config.screen_width // 2, 60)) - pygame.draw.rect(screen, (50, 50, 50, 200), title_rect.inflate(40, 20)) - pygame.draw.rect(screen, (255, 255, 255), title_rect.inflate(40, 20), 2) - screen.blit(title_surface, title_rect) - margin_top = 150 - line_height = config.font.get_height() + 10 - for i in range(config.scroll_offset, min(config.scroll_offset + config.visible_games, len(games))): - game_name = games[i][0] if isinstance(games[i], (list, tuple)) else games[i] - color = (0, 150, 255) if i == config.current_game else (255, 255, 255) - game_text = truncate_text_end(game_name, config.font, config.screen_width - 40) - text_surface = config.font.render(game_text, True, color) - text_rect = text_surface.get_rect(center=(config.screen_width // 2, margin_top + (i - config.scroll_offset) * line_height)) - screen.blit(text_surface, text_rect) - draw_scrollbar(screen) - if config.search_mode: - search_text = f"Filtrer : {config.search_query}_" - search_surface = config.search_font.render(search_text, True, (255, 255, 255)) - search_rect = search_surface.get_rect(center=(config.screen_width // 2, 60)) - pygame.draw.rect(screen, (50, 50, 50, 200), search_rect.inflate(40, 20)) - pygame.draw.rect(screen, (255, 255, 255), search_rect.inflate(40, 20), 2) - screen.blit(search_surface, search_rect) - if config.is_non_pc: - draw_virtual_keyboard(screen) - elif config.filter_active: - filter_text = f"Filtre actif : {config.search_query}" - filter_surface = config.small_font.render(filter_text, True, (255, 255, 255)) - filter_rect = filter_surface.get_rect(center=(config.screen_width // 2, 100)) - pygame.draw.rect(screen, (50, 50, 50, 200), filter_rect.inflate(40, 20)) - pygame.draw.rect(screen, (255, 255, 255), filter_rect.inflate(40, 20), 2) - screen.blit(filter_surface, filter_rect) + draw_game_list(screen) + logger.debug("Rendu de draw_game_list") elif config.menu_state == "download_progress": draw_progress_screen(screen) logger.debug("Rendu de draw_progress_screen") @@ -711,7 +668,6 @@ async def main(): pygame.quit() logger.debug("Application terminée") - # Fonction pour vérifier si un événement correspond à une action def is_input_matched(event, action_name): if not config.controls_config.get(action_name): diff --git a/__pycache__/__main__.cpython-311.pyc b/__pycache__/__main__.cpython-311.pyc new file mode 100644 index 0000000..3134985 Binary files /dev/null and b/__pycache__/__main__.cpython-311.pyc differ diff --git a/__pycache__/config.cpython-311.pyc b/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000..40ff317 Binary files /dev/null and b/__pycache__/config.cpython-311.pyc differ diff --git a/__pycache__/controls.cpython-311.pyc b/__pycache__/controls.cpython-311.pyc new file mode 100644 index 0000000..f1dbd22 Binary files /dev/null and b/__pycache__/controls.cpython-311.pyc differ diff --git a/__pycache__/controls_mapper.cpython-311.pyc b/__pycache__/controls_mapper.cpython-311.pyc new file mode 100644 index 0000000..7dfcb22 Binary files /dev/null and b/__pycache__/controls_mapper.cpython-311.pyc differ diff --git a/__pycache__/display.cpython-311.pyc b/__pycache__/display.cpython-311.pyc new file mode 100644 index 0000000..be6182f Binary files /dev/null and b/__pycache__/display.cpython-311.pyc differ diff --git a/__pycache__/network.cpython-311.pyc b/__pycache__/network.cpython-311.pyc new file mode 100644 index 0000000..64ce5ab Binary files /dev/null and b/__pycache__/network.cpython-311.pyc differ diff --git a/__pycache__/utils.cpython-311.pyc b/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000..355f339 Binary files /dev/null and b/__pycache__/utils.cpython-311.pyc differ diff --git a/assets/Pixel-UniCode.ttf b/assets/Pixel-UniCode.ttf new file mode 100644 index 0000000..5b4d3cb Binary files /dev/null and b/assets/Pixel-UniCode.ttf differ diff --git a/assets/music/8bit.mp3 b/assets/music/8bit.mp3 new file mode 100644 index 0000000..93107de Binary files /dev/null and b/assets/music/8bit.mp3 differ diff --git a/assets/music/90s.mp3 b/assets/music/90s.mp3 new file mode 100644 index 0000000..91d9907 Binary files /dev/null and b/assets/music/90s.mp3 differ diff --git a/assets/music/fantasia.mp3 b/assets/music/fantasia.mp3 new file mode 100644 index 0000000..b104334 Binary files /dev/null and b/assets/music/fantasia.mp3 differ diff --git a/assets/music/game_mode.mp3 b/assets/music/game_mode.mp3 new file mode 100644 index 0000000..a81b62f Binary files /dev/null and b/assets/music/game_mode.mp3 differ diff --git a/assets/music/pixel_racer.mp3 b/assets/music/pixel_racer.mp3 new file mode 100644 index 0000000..ba6fcc7 Binary files /dev/null and b/assets/music/pixel_racer.mp3 differ diff --git a/assets/music/return_8bit.mp3 b/assets/music/return_8bit.mp3 new file mode 100644 index 0000000..f271737 Binary files /dev/null and b/assets/music/return_8bit.mp3 differ diff --git a/assets/music/stranger.mp3 b/assets/music/stranger.mp3 new file mode 100644 index 0000000..a321333 Binary files /dev/null and b/assets/music/stranger.mp3 differ diff --git a/backup.rar b/backup.rar new file mode 100644 index 0000000..053ad2b Binary files /dev/null and b/backup.rar differ diff --git a/display.py b/display.py index 97990f6..7301f42 100644 --- a/display.py +++ b/display.py @@ -104,10 +104,26 @@ def draw_error_screen(screen): screen.blit(retry_text, retry_rect) def draw_platform_grid(screen): - """Affiche la grille des plateformes.""" + """Affiche la grille des plateformes avec un titre en haut.""" + # Configuration du titre + platform = config.platforms[config.current_platform] + platform_name = config.platform_names.get(platform, platform) + + title_text = f"{platform_name}" + title_surface = config.title_font.render(title_text, True, (255, 255, 255)) + title_rect = title_surface.get_rect(center=(config.screen_width // 2, title_surface.get_height() // 2 + 10)) + title_rect_inflated = title_rect.inflate(40, 20) + title_rect_inflated.topleft = ((config.screen_width - title_rect_inflated.width) // 2, 0) + + # Dessiner le rectangle de fond du titre + pygame.draw.rect(screen, (50, 50, 50, 200), title_rect_inflated, border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), title_rect_inflated, 2, border_radius=10) + screen.blit(title_surface, title_rect) + + # Configuration de la grille margin_left = int(config.screen_width * 0.026) # ~50px pour 1920p margin_right = int(config.screen_width * 0.026) - margin_top = int(config.screen_height * 0.111) # ~120px pour 1080p + margin_top = int(config.screen_height * 0.140) # ~120px pour 1080p margin_bottom = int(config.screen_height * 0.0648) # ~70px pour 1080p num_cols = 3 num_rows = 3 @@ -170,6 +186,106 @@ def draw_platform_grid(screen): screen.blit(image, image_rect) +def draw_game_list(screen): + """Affiche la liste des jeux avec défilement et rectangle de fond.""" + logger.debug("Début de draw_game_list") + + platform = config.platforms[config.current_platform] + platform_name = config.platform_names.get(platform, platform) + games = config.filtered_games if config.filter_active or config.search_mode else config.games + game_count = len(games) + + if not games: + logger.debug("Aucune liste de jeux disponible") + message = "Aucun jeu disponible" + lines = wrap_text(message, config.font, config.screen_width - 80) + line_height = config.font.get_height() + 5 + text_height = len(lines) * line_height + margin_top_bottom = 20 + rect_height = text_height + 2 * margin_top_bottom + max_text_width = max([config.font.size(line)[0] for line in lines], default=300) + rect_width = max_text_width + 40 + rect_x = (config.screen_width - rect_width) // 2 + rect_y = (config.screen_height - rect_height) // 2 + + screen.blit(OVERLAY, (0, 0)) + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) + + for i, line in enumerate(lines): + text_surface = config.small_font.render(line, True, (255, 255, 255)) + text_rect = text_surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2)) + screen.blit(text_surface, text_rect) + return + + line_height = config.small_font.get_height() + 10 + margin_top_bottom = 10 + extra_margin_top = 5 # Marge supplémentaire pour éviter le chevauchement avec le titre + extra_margin_bottom = 40 # Marge supplémentaire en bas pour éloigner du texte des contrôles + title_height = max(config.title_font.get_height(), config.search_font.get_height(), config.small_font.get_height()) + 20 # Hauteur du titre avec padding réduit + available_height = config.screen_height - title_height - extra_margin_top - extra_margin_bottom - 2 * margin_top_bottom + games_per_page = available_height // line_height + max_text_width = max([config.font.size(truncate_text_end(game[0] if isinstance(game, (list, tuple)) else game, config.font, config.screen_width - 80))[0] for game in games], default=300) + rect_width = max_text_width + 40 + rect_height = games_per_page * line_height + 2 * margin_top_bottom + rect_x = (config.screen_width - rect_width) // 2 + rect_y = title_height + extra_margin_top + (config.screen_height - title_height - extra_margin_top - extra_margin_bottom - rect_height) // 2 + + # Limiter scroll_offset pour éviter l'espace vide + config.scroll_offset = max(0, min(config.scroll_offset, max(0, len(games) - games_per_page))) + if config.current_game < config.scroll_offset: + config.scroll_offset = config.current_game + elif config.current_game >= config.scroll_offset + games_per_page: + config.scroll_offset = config.current_game - games_per_page + 1 + + screen.blit(OVERLAY, (0, 0)) + + # Afficher le titre ou le texte de recherche/filtre + if config.search_mode: + search_text = f"Filtrer : {config.search_query}_" + title_surface = config.search_font.render(search_text, True, (255, 255, 255)) + title_rect = title_surface.get_rect(center=(config.screen_width // 2, title_surface.get_height() // 2 + 10)) + title_rect_inflated = title_rect.inflate(40, 20) + title_rect_inflated.topleft = ((config.screen_width - title_rect_inflated.width) // 2, 0) + pygame.draw.rect(screen, (50, 50, 50, 200), title_rect_inflated, border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), title_rect_inflated, 2, border_radius=10) + screen.blit(title_surface, title_rect) + elif config.filter_active: + filter_text = f"Filtre actif : {config.search_query}" + title_surface = config.small_font.render(filter_text, True, (255, 255, 255)) + title_rect = title_surface.get_rect(center=(config.screen_width // 2, title_surface.get_height() // 2 + 10)) + title_rect_inflated = title_rect.inflate(40, 20) + title_rect_inflated.topleft = ((config.screen_width - title_rect_inflated.width) // 2, 0) + pygame.draw.rect(screen, (50, 50, 50, 200), title_rect_inflated, border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), title_rect_inflated, 2, border_radius=10) + screen.blit(title_surface, title_rect) + else: + title_text = f"{platform_name} ({game_count} jeux)" + title_surface = config.title_font.render(title_text, True, (255, 255, 255)) + title_rect = title_surface.get_rect(center=(config.screen_width // 2, title_surface.get_height() // 2 + 10)) + title_rect_inflated = title_rect.inflate(40, 20) + title_rect_inflated.topleft = ((config.screen_width - title_rect_inflated.width) // 2, 0) + pygame.draw.rect(screen, (50, 50, 50, 200), title_rect_inflated, border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), title_rect_inflated, 2, border_radius=10) + screen.blit(title_surface, title_rect) + + # Afficher le rectangle de fond et la liste des jeux + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) + + for i in range(config.scroll_offset, min(config.scroll_offset + games_per_page, len(games))): + game_name = games[i][0] if isinstance(games[i], (list, tuple)) else games[i] + color = (0, 150, 255) if i == config.current_game else (255, 255, 255) + game_text = truncate_text_end(game_name, config.small_font, config.screen_width - 80) + 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)) + screen.blit(text_surface, text_rect) + logger.debug(f"Jeu affiché : texte={game_text}, position={text_rect}, selected={i == config.current_game}") + + draw_scrollbar(screen) + if config.search_mode and config.is_non_pc: + draw_virtual_keyboard(screen) + def draw_virtual_keyboard(screen): """Affiche un clavier virtuel pour la saisie dans search_mode, centré verticalement.""" keyboard_layout = [ @@ -185,7 +301,7 @@ def draw_virtual_keyboard(screen): keyboard_height = len(keyboard_layout) * (key_height + key_spacing) - key_spacing start_x = (config.screen_width - keyboard_width) // 2 search_bottom_y = int(config.screen_height * 0.111) + (config.search_font.get_height() + 40) // 2 # ~120px pour 1080p - controls_y = config.screen_height - int(config.screen_height * 0.0185) # ~20px pour 1080p + controls_y = config.screen_height - int(config.screen_height * 0.037) # ~40px pour 1080p available_height = controls_y - search_bottom_y start_y = search_bottom_y + (available_height - keyboard_height - 40) // 2 @@ -208,7 +324,7 @@ def draw_virtual_keyboard(screen): screen.blit(text, text_rect) def draw_progress_screen(screen): - """Affiche l'écran de progression des téléchargements avec taille en Mo, et un message spécifique pour la conversion ISO.""" + """Affiche l'écran de progression des téléchargements avec taille en Mo.""" logger.debug("Début de draw_progress_screen") if not config.download_tasks: @@ -227,51 +343,50 @@ def draw_progress_screen(screen): screen.blit(OVERLAY, (0, 0)) - if status == "Converting ISO": - title_text = f"Converting : {truncate_text_end(game_name, config.font, config.screen_width - 200)}" - else: - title_text = f"{status} : {truncate_text_end(game_name, config.font, config.screen_width - 200)}" + title_text = f"{status} : {truncate_text_end(game_name, config.font, config.screen_width - 200)}" title_lines = wrap_text(title_text, config.font, config.screen_width - 80) line_height = config.font.get_height() + 5 + text_height = len(title_lines) * line_height + margin_top_bottom = 20 + bar_height = int(config.screen_height * 0.0278) # ~30px pour 1080p + percent_height = line_height # Hauteur pour le texte de progression + rect_height = text_height + bar_height + percent_height + 3 * margin_top_bottom + max_text_width = max([config.font.size(line)[0] for line in title_lines], default=300) + bar_width = max_text_width # Ajuster la barre à la largeur du texte + rect_width = max_text_width + 40 + rect_x = (config.screen_width - rect_width) // 2 + rect_y = (config.screen_height - rect_height) // 2 + + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) + for i, line in enumerate(title_lines): title_render = config.font.render(line, True, (255, 255, 255)) - title_rect = title_render.get_rect(center=(config.screen_width // 2, config.screen_height // 2 - 100 - (len(title_lines) // 2 - i) * line_height)) + title_rect = title_render.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2)) screen.blit(title_render, title_rect) logger.debug(f"Titre affiché : texte={line}, position={title_rect}, taille={title_render.get_size()}") - if status == "Converting ISO": - conversion_text = "Conversion de l'ISO en dossier .ps3 en cours..." - conversion_lines = wrap_text(conversion_text, config.font, config.screen_width - 80) - for i, line in enumerate(conversion_lines): - conversion_render = config.font.render(line, True, (255, 255, 255)) - conversion_rect = conversion_render.get_rect(center=(config.screen_width // 2, config.screen_height // 2 - (len(conversion_lines) // 2 - i) * line_height)) - screen.blit(conversion_render, conversion_rect) - logger.debug(f"Message de conversion affiché : texte={line}, position={conversion_rect}, taille={conversion_render.get_size()}") - else: - bar_width = config.screen_width // 2 - bar_height = int(config.screen_height * 0.0278) # ~30px pour 1080p - bar_x = (config.screen_width - bar_width) // 2 - bar_y = config.screen_height // 2 - progress_width = 0 - pygame.draw.rect(screen, (100, 100, 100), (bar_x, bar_y, bar_width, bar_height)) - if total_size > 0: - progress_width = int(bar_width * (progress_percent / 100)) - pygame.draw.rect(screen, (0, 150, 255), (bar_x, bar_y, progress_width, bar_height)) - pygame.draw.rect(screen, (255, 255, 255), (bar_x, bar_y, bar_width, bar_height), 2) - logger.debug(f"Barre de progression affichée : position=({bar_x}, {bar_y}), taille=({bar_width}, {bar_height}), progress_width={progress_width}") - - downloaded_mb = downloaded_size / (1024 * 1024) - total_mb = total_size / (1024 * 1024) - size_text = f"{downloaded_mb:.1f} Mo / {total_mb:.1f} Mo" - percent_text = f"{int(progress_percent)}% {size_text}" - percent_lines = wrap_text(percent_text, config.font, config.screen_width - 80) - text_y = bar_y + bar_height // 2 + config.font.get_height() + 20 - for i, line in enumerate(percent_lines): - percent_render = config.font.render(line, True, (255, 255, 255)) - percent_rect = percent_render.get_rect(center=(config.screen_width // 2, text_y + i * line_height)) - screen.blit(percent_render, percent_rect) - logger.debug(f"Texte de progression affiché : texte={line}, position={percent_rect}, taille={percent_render.get_size()}") + bar_y = rect_y + text_height + margin_top_bottom + progress_width = 0 + pygame.draw.rect(screen, (100, 100, 100), (rect_x + 20, bar_y, bar_width, bar_height)) + if total_size > 0: + progress_width = int(bar_width * (progress_percent / 100)) + pygame.draw.rect(screen, (0, 150, 255), (rect_x + 20, bar_y, progress_width, bar_height)) + pygame.draw.rect(screen, (255, 255, 255), (rect_x + 20, bar_y, bar_width, bar_height), 2) + logger.debug(f"Barre de progression affichée : position=({rect_x + 20}, {bar_y}), taille=({bar_width}, {bar_height}), progress_width={progress_width}") + downloaded_mb = downloaded_size / (1024 * 1024) + total_mb = total_size / (1024 * 1024) + size_text = f"{downloaded_mb:.1f} Mo / {total_mb:.1f} Mo" + percent_text = f"{int(progress_percent)}% {size_text}" + percent_lines = wrap_text(percent_text, config.font, config.screen_width - 80) + text_y = bar_y + bar_height + margin_top_bottom + for i, line in enumerate(percent_lines): + percent_render = config.font.render(line, True, (255, 255, 255)) + percent_rect = percent_render.get_rect(center=(config.screen_width // 2, text_y + i * line_height + line_height // 2)) + screen.blit(percent_render, percent_rect) + logger.debug(f"Texte de progression affiché : texte={line}, position={percent_rect}, taille={percent_render.get_size()}") + def draw_scrollbar(screen): """Affiche la barre de défilement à droite de l’écran.""" if len(config.filtered_games) <= config.visible_games: @@ -289,20 +404,27 @@ def draw_confirm_dialog(screen): message = "Voulez-vous vraiment quitter ?" 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 = line_height + 20 + 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 + 40 + rect_x = (config.screen_width - rect_width) // 2 + rect_y = (config.screen_height - rect_height) // 2 + + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) + for i, line in enumerate(wrapped_message): text = config.font.render(line, True, (255, 255, 255)) - text_rect = text.get_rect(center=(config.screen_width // 2, config.screen_height // 2 - 50 - (len(wrapped_message) // 2 - i) * line_height)) + 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) - yes_text = config.font.render("Oui", True, (255, 255, 255)) - no_text = config.font.render("Non", True, (255, 255, 255)) - yes_rect = yes_text.get_rect(center=(config.screen_width // 2 - 100, config.screen_height // 2 + 50)) - no_rect = no_text.get_rect(center=(config.screen_width // 2 + 100, config.screen_height // 2 + 50)) - - if config.confirm_selection == 1: - pygame.draw.rect(screen, (0, 150, 255, 150), yes_rect.inflate(40, 20)) - else: - pygame.draw.rect(screen, (0, 150, 255, 150), no_rect.inflate(40, 20)) + yes_text = config.font.render("Oui", True, (0, 150, 255) if config.confirm_selection == 1 else (255, 255, 255)) + no_text = config.font.render("Non", True, (0, 150, 255) if config.confirm_selection == 0 else (255, 255, 255)) + yes_rect = yes_text.get_rect(center=(config.screen_width // 2 - 100, rect_y + text_height + margin_top_bottom + line_height // 2)) + no_rect = no_text.get_rect(center=(config.screen_width // 2 + 100, rect_y + text_height + margin_top_bottom + line_height // 2)) screen.blit(yes_text, yes_rect) screen.blit(no_text, no_rect) @@ -356,15 +478,14 @@ def draw_extension_warning(screen): rect_y = (config.screen_height - rect_height) // 2 screen.blit(OVERLAY, (0, 0)) + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) - text_surfaces = [config.font.render(line, True, (255, 255, 255)) for line in lines] - text_rects = [ - surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2)) - for i, surface in enumerate(text_surfaces) - ] - for surface, rect in zip(text_surfaces, text_rects): - screen.blit(surface, rect) - logger.debug(f"Lignes affichées : {[(rect.center, surface.get_size()) for rect, surface in zip(text_rects, text_surfaces)]}") + for i, line in enumerate(lines): + text_surface = config.font.render(line, True, (255, 255, 255)) + text_rect = text_surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2)) + screen.blit(text_surface, text_rect) + logger.debug(f"Lignes affichées : {[(rect.center, text_surface.get_size()) for rect, text_surface in zip([text_surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + i * line_height + line_height // 2)) for i in range(len(lines))], [config.font.render(line, True, (255, 255, 255)) for line in lines])]}") yes_text = "[Oui]" if config.extension_confirm_selection == 1 else "Oui" no_text = "[Non]" if config.extension_confirm_selection == 0 else "Non" @@ -383,23 +504,34 @@ def draw_extension_warning(screen): logger.error(f"Erreur lors du rendu de extension_warning : {str(e)}") error_message = "Erreur d'affichage de l'avertissement." wrapped_error = wrap_text(error_message, config.font, config.screen_width - 80) + line_height = config.font.get_height() + 5 + rect_height = len(wrapped_error) * line_height + 2 * 20 + max_text_width = max([config.font.size(line)[0] for line in wrapped_error], default=300) + rect_width = max_text_width + 40 + rect_x = (config.screen_width - rect_width) // 2 + rect_y = (config.screen_height - rect_height) // 2 + + screen.blit(OVERLAY, (0, 0)) + pygame.draw.rect(screen, (50, 50, 50, 200), (rect_x, rect_y, rect_width, rect_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (rect_x, rect_y, rect_width, rect_height), 2, border_radius=10) + for i, line in enumerate(wrapped_error): error_surface = config.font.render(line, True, (255, 0, 0)) - error_rect = error_surface.get_rect(center=(config.screen_width // 2, config.screen_height // 2 - (len(wrapped_error) // 2 - i) * line_height)) + error_rect = error_surface.get_rect(center=(config.screen_width // 2, rect_y + 20 + i * line_height + line_height // 2)) screen.blit(error_surface, error_rect) def draw_controls(screen, menu_state): """Affiche les contrôles sur une seule ligne en bas de l’écran pour tous les états du menu.""" start_button = get_control_display('start', 'START') - control_text = f"{start_button} : Menu - Controls" + control_text = f"Menu {config.menu_state} - {start_button} : Options - Controls" max_width = config.screen_width - 40 - wrapped_controls = wrap_text(control_text, config.font, max_width) - line_height = config.font.get_height() + 5 + wrapped_controls = wrap_text(control_text, config.small_font, max_width) + line_height = config.small_font.get_height() + 5 rect_height = len(wrapped_controls) * line_height + 20 - rect_y = config.screen_height - rect_height - 20 + rect_y = config.screen_height - rect_height - 5 # Augmenter la marge inférieure de 20px à 40px for i, line in enumerate(wrapped_controls): - text_surface = config.font.render(line, True, (255, 255, 255)) + text_surface = config.small_font.render(line, True, (255, 255, 255)) text_rect = text_surface.get_rect(center=(config.screen_width // 2, rect_y + 10 + i * line_height + line_height // 2)) screen.blit(text_surface, text_rect) @@ -437,14 +569,19 @@ def draw_pause_menu(screen, selected_option): menu_width = int(config.screen_width * 0.2083) # ~400px pour 1920p line_height = config.font.get_height() + 10 - menu_height = len(options) * line_height + 40 + text_height = len(options) * line_height + margin_top_bottom = 20 + menu_height = text_height + 2 * margin_top_bottom menu_x = (config.screen_width - menu_width) // 2 menu_y = (config.screen_height - menu_height) // 2 + pygame.draw.rect(screen, (50, 50, 50, 200), (menu_x, menu_y, menu_width, menu_height), border_radius=10) + pygame.draw.rect(screen, (255, 255, 255), (menu_x, menu_y, menu_width, menu_height), 2, border_radius=10) + for i, option in enumerate(options): color = (0, 150, 255) if i == selected_option else (255, 255, 255) text_surface = config.font.render(option, True, color) - text_rect = text_surface.get_rect(center=(config.screen_width // 2, menu_y + 20 + i * line_height)) + text_rect = text_surface.get_rect(center=(config.screen_width // 2, menu_y + margin_top_bottom + i * line_height + line_height // 2)) screen.blit(text_surface, text_rect) def get_control_display(action, default): diff --git a/network.py b/network.py index f648359..03efd15 100644 --- a/network.py +++ b/network.py @@ -181,7 +181,7 @@ def extract_rar(rar_path, dest_dir, url): config.download_progress[url]["total_size"] = total_size config.download_progress[url]["status"] = "Extracting" config.download_progress[url]["progress_percent"] = 0 - config.needs_redraw = True # Forcer le redraw + config.needs_redraw = True escaped_rar_path = rar_path.replace(" ", "\\ ") escaped_dest_dir = dest_dir.replace(" ", "\\ ") @@ -195,30 +195,27 @@ def extract_rar(rar_path, dest_dir, url): extracted_size = 0 extracted_files = [] - for root, _, files in os.walk(dest_dir): - for file in files: - file_path = os.path.join(root, file) - rel_path = os.path.relpath(file_path, dest_dir).replace(os.sep, '/') - for expected_file, file_size in files_to_extract: - if rel_path == expected_file: - extracted_size += file_size - extracted_files.append(expected_file) - os.chmod(file_path, 0o644) - logger.debug(f"Fichier extrait: {expected_file}, taille: {file_size}, chemin: {file_path}") - break + total_files = len(files_to_extract) + for i, (expected_file, file_size) in enumerate(files_to_extract): + file_path = os.path.join(dest_dir, expected_file) + if os.path.exists(file_path): + extracted_size += file_size + extracted_files.append(expected_file) + os.chmod(file_path, 0o644) + logger.debug(f"Fichier extrait: {expected_file}, taille: {file_size}, chemin: {file_path}") + with lock: + config.download_progress[url]["downloaded_size"] = extracted_size + config.download_progress[url]["status"] = "Extracting" + config.download_progress[url]["progress_percent"] = ((i + 1) / total_files * 100) if total_files > 0 else 0 + config.needs_redraw = True + else: + logger.warning(f"Fichier non trouvé après extraction: {expected_file}") missing_files = [f for f, _ in files_to_extract if f not in extracted_files] if missing_files: logger.warning(f"Fichiers non extraits: {', '.join(missing_files)}") return False, f"Fichiers non extraits: {', '.join(missing_files)}" - with lock: - config.download_progress[url]["downloaded_size"] = extracted_size - config.download_progress[url]["total_size"] = total_size - config.download_progress[url]["status"] = "Extracting" - config.download_progress[url]["progress_percent"] = 100 if total_size > 0 else 0 - config.needs_redraw = True # Forcer le redraw - if dest_dir == "/userdata/roms/ps3" and len(root_dirs) == 1: root_dir = root_dirs.pop() old_path = os.path.join(dest_dir, root_dir) diff --git a/rom_extensions.json b/rom_extensions.json new file mode 100644 index 0000000..bdf3fb8 --- /dev/null +++ b/rom_extensions.json @@ -0,0 +1,2317 @@ +[ + { + "system": "3DO INTERACTIVE MULTIPLAYER", + "folder": "/userdata/roms/3do", + "extensions": [ + ".iso", + ".chd", + ".cue" + ] + }, + { + "system": "3DS", + "folder": "/userdata/roms/3ds", + "extensions": [ + ".3ds", + ".3dsx", + ".cxi", + ".axf", + ".elf", + ".app", + ".squashfs" + ] + }, + { + "system": "ABUSE", + "folder": "/userdata/roms/abuse", + "extensions": [ + ".game" + ] + }, + { + "system": "ADAM", + "folder": "/userdata/roms/adam", + "extensions": [ + ".wav", + ".ddp", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".rom", + ".col", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "ADVENTURE VISION", + "folder": "/userdata/roms/advision", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "AMIGA AGA", + "folder": "/userdata/roms/amiga1200", + "extensions": [ + ".adf", + ".uae", + ".ipf", + ".dms", + ".dmz", + ".adz", + ".lha", + ".hdf", + ".exe", + ".m3u", + ".zip", + ".raw", + ".scp" + ] + }, + { + "system": "AMIGA OCS/ECS", + "folder": "/userdata/roms/amiga500", + "extensions": [ + ".adf", + ".uae", + ".ipf", + ".dms", + ".dmz", + ".adz", + ".lha", + ".hdf", + ".exe", + ".m3u", + ".zip", + ".raw", + ".scp" + ] + }, + { + "system": "AMIGA CD32", + "folder": "/userdata/roms/amigacd32", + "extensions": [ + ".bin", + ".cue", + ".iso", + ".chd" + ] + }, + { + "system": "AMIGA CDTV", + "folder": "/userdata/roms/amigacdtv", + "extensions": [ + ".bin", + ".cue", + ".iso", + ".chd", + ".m3u" + ] + }, + { + "system": "AMSTRAD CPC", + "folder": "/userdata/roms/amstradcpc", + "extensions": [ + ".dsk", + ".sna", + ".tap", + ".cdt", + ".voc", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "M-1000", + "folder": "/userdata/roms/apfm1000", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "APPLE II", + "folder": "/userdata/roms/apple2", + "extensions": [ + ".nib", + ".do", + ".po", + ".dsk", + ".mfi", + ".dfi", + ".rti", + ".edd", + ".woz", + ".wav", + ".zip", + ".7z", + ".chd", + ".hdv", + ".2mg" + ] + }, + { + "system": "APPLE IIGS", + "folder": "/userdata/roms/apple2gs", + "extensions": [ + ".2mg", + ".do", + ".nib", + ".po", + ".dsk", + ".mfi", + ".dfi", + ".rti", + ".edd", + ".woz", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqui", + ".ima", + ".img", + ".ufi", + ".360", + ".ipf", + ".dc42", + ".zip", + ".7z" + ] + }, + { + "system": "ARCADIA 2001", + "folder": "/userdata/roms/arcadia", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "ARCHIMEDES", + "folder": "/userdata/roms/archimedes", + "extensions": [ + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".ima", + ".img", + ".ufi", + ".360", + ".ipf", + ".adf", + ".apd", + ".jfd", + ".ads", + ".adm", + ".adl", + ".ssd", + ".bbc", + ".dsd", + ".st", + ".msa", + ".chd", + ".zip", + ".7z" + ] + }, + { + "system": "ARDUBOY", + "folder": "/userdata/roms/arduboy", + "extensions": [ + ".hex", + ".zip", + ".7z" + ] + }, + { + "system": "ASTROCADE", + "folder": "/userdata/roms/astrocde", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "ATARI 2600", + "folder": "/userdata/roms/atari2600", + "extensions": [ + ".a26", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "ATARI 5200", + "folder": "/userdata/roms/atari5200", + "extensions": [ + ".rom", + ".xfd", + ".atr", + ".atx", + ".cdm", + ".cas", + ".car", + ".bin", + ".a52", + ".xex", + ".zip", + ".7z" + ] + }, + { + "system": "ATARI 7800", + "folder": "/userdata/roms/atari7800", + "extensions": [ + ".a78", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "ATARI 800", + "folder": "/userdata/roms/atari800", + "extensions": [ + ".rom", + ".xfd", + ".atr", + ".atx", + ".cdm", + ".cas", + ".car", + ".bin", + ".a52", + ".xex", + ".zip", + ".7z", + ".m3u" + ] + }, + { + "system": "ATARI ST", + "folder": "/userdata/roms/atarist", + "extensions": [ + ".st", + ".msa", + ".stx", + ".dim", + ".ipf", + ".m3u", + ".zip", + ".7z", + ".hd", + ".gemdos" + ] + }, + { + "system": "ATOM", + "folder": "/userdata/roms/atom", + "extensions": [ + ".wav", + ".tap", + ".csw", + ".uef", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".40t", + ".atm", + ".bin", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "ATOMISWAVE", + "folder": "/userdata/roms/atomiswave", + "extensions": [ + ".lst", + ".bin", + ".dat", + ".zip", + ".7z" + ] + }, + { + "system": "BBC MICRO", + "folder": "/userdata/roms/bbc", + "extensions": [ + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".ima", + ".img", + ".ufi", + ".360", + ".ipf", + ".ssd", + ".bbc", + ".dsd", + ".adf", + ".ads", + ".adm", + ".adl", + ".fsd", + ".wav", + ".tap", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "COMMODORE 128", + "folder": "/userdata/roms/c128", + "extensions": [ + ".d64", + ".d81", + ".prg", + ".lnx", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "COMMODORE VIC-20", + "folder": "/userdata/roms/c20", + "extensions": [ + ".20", + ".40", + ".60", + ".rom", + ".a0", + ".b0", + ".crt", + ".d64", + ".d81", + ".prg", + ".tap", + ".t64", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "COMMODORE 64", + "folder": "/userdata/roms/c64", + "extensions": [ + ".d64", + ".d71", + ".d81", + ".crt", + ".prg", + ".tap", + ".t64", + ".m3u", + ".zip", + ".7z", + ".nib", + ".g64" + ] + }, + { + "system": "CAMPUTERS LYNX", + "folder": "/userdata/roms/camplynx", + "extensions": [ + ".wav", + ".tap", + ".ldf", + ".zip", + ".7z" + ] + }, + { + "system": "CANNONBALL", + "folder": "/userdata/roms/cannonball", + "extensions": [ + ".cannonball" + ] + }, + { + "system": "CAVE STORY", + "folder": "/userdata/roms/cavestory", + "extensions": [ + ".exe" + ] + }, + { + "system": "CD-I", + "folder": "/userdata/roms/cdi", + "extensions": [ + ".chd", + ".cue", + ".toc", + ".nrg", + ".gdi", + ".iso", + ".cdr" + ] + }, + { + "system": "C-DOGS SDL", + "folder": "/userdata/roms/cdogs", + "extensions": [ + ".game" + ] + }, + { + "system": "COMMANDER GENIUS", + "folder": "/userdata/roms/cgenius", + "extensions": [ + ".cgenius" + ] + }, + { + "system": "CHANNEL-F", + "folder": "/userdata/roms/channelf", + "extensions": [ + ".zip", + ".rom", + ".bin", + ".chf" + ] + }, + { + "system": "SEGA CHIHIRO", + "folder": "/userdata/roms/chihiro", + "extensions": [ + ".iso" + ] + }, + { + "system": "COLOR COMPUTER", + "folder": "/userdata/roms/coco", + "extensions": [ + ".wav", + ".cas", + ".dsk", + ".ccc", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "COLECOVISION", + "folder": "/userdata/roms/colecovision", + "extensions": [ + ".bin", + ".col", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "COMMANDER X16", + "folder": "/userdata/roms/commanderx16", + "extensions": [ + ".bas", + ".img", + ".prg" + ] + }, + { + "system": "CORSIXTH", + "folder": "/userdata/roms/corsixth", + "extensions": [ + ".game" + ] + }, + { + "system": "COMMODORE PLUS4", + "folder": "/userdata/roms/cplus4", + "extensions": [ + ".d64", + ".prg", + ".tap", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "CREATIVISION", + "folder": "/userdata/roms/crvision", + "extensions": [ + ".bin", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "DAPHNE", + "folder": "/userdata/roms/daphne", + "extensions": [ + ".daphne", + ".squashfs" + ] + }, + { + "system": "DIABLO", + "folder": "/userdata/roms/devilutionx", + "extensions": [ + ".mpq" + ] + }, + { + "system": "DOOM 3", + "folder": "/userdata/roms/doom3", + "extensions": [ + ".d3" + ] + }, + { + "system": "DOS (X86)", + "folder": "/userdata/roms/dos", + "extensions": [ + ".pc", + ".dos", + ".zip", + ".squashfs", + ".dosz", + ".m3u", + ".iso", + ".cue" + ] + }, + { + "system": "DREAMCAST", + "folder": "/userdata/roms/dreamcast", + "extensions": [ + ".cdi", + ".cue", + ".gdi", + ".chd", + ".m3u" + ] + }, + { + "system": "DXX REBIRTH", + "folder": "/userdata/roms/dxx-rebirth", + "extensions": [ + ".d1x", + ".d2x" + ] + }, + { + "system": "EASYRPG", + "folder": "/userdata/roms/easyrpg", + "extensions": [ + ".easyrpg", + ".squashfs", + ".zip" + ] + }, + { + "system": "ECWOLF", + "folder": "/userdata/roms/ecwolf", + "extensions": [ + ".ecwolf", + ".pk3", + ".squashfs" + ] + }, + { + "system": "EDUKE32", + "folder": "/userdata/roms/eduke32", + "extensions": [ + ".eduke32" + ] + }, + { + "system": "ELECTRON", + "folder": "/userdata/roms/electron", + "extensions": [ + ".wav", + ".csw", + ".uef", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".ssd", + ".bbc", + ".img", + ".dsd", + ".adf", + ".ads", + ".adm", + ".adl", + ".rom", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "WOLFENSTEIN - ENEMY TERRITORY", + "folder": "/userdata/roms/etlegacy", + "extensions": [ + ".etl" + ] + }, + { + "system": "FALLOUT COMMUNITY EDITION", + "folder": "/userdata/roms/fallout1-ce", + "extensions": [ + ".f1ce" + ] + }, + { + "system": "FALLOUT 2 COMMUNITY EDITION", + "folder": "/userdata/roms/fallout2-ce", + "extensions": [ + ".f2ce" + ] + }, + { + "system": "FINAL BURN NEO", + "folder": "/userdata/roms/fbneo", + "extensions": [ + ".zip", + ".7z" + ] + }, + { + "system": "FAMILY COMPUTER DISK SYSTEM", + "folder": "/userdata/roms/fds", + "extensions": [ + ".fds", + ".zip", + ".7z" + ] + }, + { + "system": "FLASH PLAYER", + "folder": "/userdata/roms/flash", + "extensions": [ + ".swf" + ] + }, + { + "system": "APPLICATIONS", + "folder": "/userdata/roms/flatpak", + "extensions": [ + ".flatpak" + ] + }, + { + "system": "FM-7", + "folder": "/userdata/roms/fm7", + "extensions": [ + ".wav", + ".t77", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".zip", + ".7z" + ] + }, + { + "system": "FM-TOWNS", + "folder": "/userdata/roms/fmtowns", + "extensions": [ + ".bin", + ".m3u", + ".cue", + ".d88", + ".d77", + ".xdf", + ".iso", + ".chd", + ".toc", + ".nrg", + ".gdi", + ".cdr", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".zip", + ".7z" + ] + }, + { + "system": "FUTURE PINBALL", + "folder": "/userdata/roms/fpinball", + "extensions": [ + ".fpt" + ] + }, + { + "system": "ION FURY", + "folder": "/userdata/roms/fury", + "extensions": [ + ".grp" + ] + }, + { + "system": "GAMATE", + "folder": "/userdata/roms/gamate", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "GAME AND WATCH", + "folder": "/userdata/roms/gameandwatch", + "extensions": [ + ".mgw", + ".zip", + ".7z" + ] + }, + { + "system": "GAME.COM", + "folder": "/userdata/roms/gamecom", + "extensions": [ + ".bin", + ".tgc", + ".zip", + ".7z" + ] + }, + { + "system": "GAMECUBE", + "folder": "/userdata/roms/gamecube", + "extensions": [ + ".gcm", + ".iso", + ".gcz", + ".ciso", + ".wbfs", + ".rvz", + ".elf", + ".dol", + ".m3u", + ".json" + ] + }, + { + "system": "GAME GEAR", + "folder": "/userdata/roms/gamegear", + "extensions": [ + ".bin", + ".gg", + ".zip", + ".7z" + ] + }, + { + "system": "GAME POCKET COMPUTER", + "folder": "/userdata/roms/gamepock", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "GAME BOY", + "folder": "/userdata/roms/gb", + "extensions": [ + ".gb", + ".zip", + ".7z" + ] + }, + { + "system": "GAME BOY (2 PLAYERS)", + "folder": "/userdata/roms/gb2players", + "extensions": [ + ".gb", + ".gb2", + ".gbc2", + ".zip", + ".7z" + ] + }, + { + "system": "GAME BOY ADVANCE", + "folder": "/userdata/roms/gba", + "extensions": [ + ".gba", + ".zip", + ".7z" + ] + }, + { + "system": "GAME BOY COLOR", + "folder": "/userdata/roms/gbc", + "extensions": [ + ".gbc", + ".zip", + ".7z" + ] + }, + { + "system": "GAME BOY COLOR (2 PLAYERS)", + "folder": "/userdata/roms/gbc2players", + "extensions": [ + ".gbc", + ".gb2", + ".gbc2", + ".zip", + ".7z" + ] + }, + { + "system": "GAME MASTER", + "folder": "/userdata/roms/gmaster", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "GP32", + "folder": "/userdata/roms/gp32", + "extensions": [ + ".smc", + ".zip", + ".7z" + ] + }, + { + "system": "GX4000", + "folder": "/userdata/roms/gx4000", + "extensions": [ + ".dsk", + ".m3u", + ".cpr", + ".zip", + ".7z" + ] + }, + { + "system": "GZDOOM", + "folder": "/userdata/roms/gzdoom", + "extensions": [ + ".wad", + ".iwad", + ".pwad", + ".gzdoom" + ] + }, + { + "system": "HYDRA CASTLE LABYRINTH", + "folder": "/userdata/roms/hcl", + "extensions": [ + ".game" + ] + }, + { + "system": "HURRICAN", + "folder": "/userdata/roms/hurrican", + "extensions": [ + ".game" + ] + }, + { + "system": "IKEMEN", + "folder": "/userdata/roms/ikemen", + "extensions": [ + ".ikemen", + ".pc" + ] + }, + { + "system": "MATTEL INTELLIVISION", + "folder": "/userdata/roms/intellivision", + "extensions": [ + ".int", + ".bin", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "RETURN TO CASTLE WOLFENSTEIN", + "folder": "/userdata/roms/iortcw", + "extensions": [ + ".rtcw" + ] + }, + { + "system": "JAGUAR", + "folder": "/userdata/roms/jaguar", + "extensions": [ + ".j64", + ".jag", + ".cof", + ".abs", + ".rom", + ".zip", + ".7z" + ] + }, + { + "system": "JAGUAR CD", + "folder": "/userdata/roms/jaguarcd", + "extensions": [ + ".cue", + ".cdi" + ] + }, + { + "system": "JAZZ JACKRABBIT 2", + "folder": "/userdata/roms/jazz2", + "extensions": [ + ".game" + ] + }, + { + "system": "LASER 310", + "folder": "/userdata/roms/laser310", + "extensions": [ + ".vz", + ".wav", + ".cas", + ".zip", + ".7z" + ] + }, + { + "system": "LCD GAMES", + "folder": "/userdata/roms/lcdgames", + "extensions": [ + ".mgw", + ".zip", + ".7z" + ] + }, + { + "system": "LOWRES NX", + "folder": "/userdata/roms/lowresnx", + "extensions": [ + ".nx", + ".zip", + ".7z" + ] + }, + { + "system": "LUTRO", + "folder": "/userdata/roms/lutro", + "extensions": [ + ".lutro", + ".zip", + ".7z" + ] + }, + { + "system": "ATARI LYNX", + "folder": "/userdata/roms/lynx", + "extensions": [ + ".bll", + ".lnx", + ".lyx", + ".o", + ".zip", + ".7z" + ] + }, + { + "system": "MACINTOSH", + "folder": "/userdata/roms/macintosh", + "extensions": [ + ".dsk", + ".zip", + ".7z", + ".mfi", + ".dfi", + ".hfe", + ".mfm", + ".td0", + ".imd", + ".d77", + ".d88", + ".1dd", + ".cqm", + ".cqi", + ".dsk", + ".ima", + ".img", + ".ufi", + ".ipf", + ".dc42", + ".woz", + ".2mg", + ".360", + ".chd", + ".cue", + ".toc", + ".nrg", + ".gdi", + ".iso", + ".cdr", + ".hd", + ".hdv", + ".2mg", + ".hdi" + ] + }, + { + "system": "MAME", + "folder": "/userdata/roms/mame", + "extensions": [ + ".zip", + ".7z" + ] + }, + { + "system": "MASTER SYSTEM", + "folder": "/userdata/roms/mastersystem", + "extensions": [ + ".bin", + ".sms", + ".zip", + ".7z" + ] + }, + { + "system": "MEGA DRIVE", + "folder": "/userdata/roms/megadrive", + "extensions": [ + ".bin", + ".gen", + ".md", + ".sg", + ".smd", + ".zip", + ".7z" + ] + }, + { + "system": "MEGA DUCK / COUGAR BOY", + "folder": "/userdata/roms/megaduck", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "MODEL 2", + "folder": "/userdata/roms/model2", + "extensions": [ + ".zip" + ] + }, + { + "system": "MODEL 3", + "folder": "/userdata/roms/model3", + "extensions": [ + ".zip" + ] + }, + { + "system": "MOONLIGHT EMBEDDED", + "folder": "/userdata/roms/moonlight", + "extensions": [ + ".moonlight" + ] + }, + { + "system": "MRBOOM", + "folder": "/userdata/roms/mrboom", + "extensions": [ + ".libretro" + ] + }, + { + "system": "MSU-MD", + "folder": "/userdata/roms/msu-md", + "extensions": [ + ".md", + ".zip", + ".7z", + ".squashfs" + ] + }, + { + "system": "MSX1", + "folder": "/userdata/roms/msx1", + "extensions": [ + ".dsk", + ".mx1", + ".rom", + ".zip", + ".7z", + ".cas", + ".m3u", + ".ogv", + ".openmsx" + ] + }, + { + "system": "MSX2", + "folder": "/userdata/roms/msx2", + "extensions": [ + ".dsk", + ".mx2", + ".rom", + ".zip", + ".7z", + ".cas", + ".m3u", + ".ogv", + ".openmsx" + ] + }, + { + "system": "MSX2+", + "folder": "/userdata/roms/msx2+", + "extensions": [ + ".dsk", + ".mx2", + ".rom", + ".zip", + ".7z", + ".cas", + ".m3u", + ".openmsx" + ] + }, + { + "system": "MSX TURBO-R", + "folder": "/userdata/roms/msxturbor", + "extensions": [ + ".dsk", + ".mx2", + ".rom", + ".zip", + ".7z", + ".openmsx", + ".m3u" + ] + }, + { + "system": "MUGEN", + "folder": "/userdata/roms/mugen", + "extensions": [ + ".pc" + ] + }, + { + "system": "OTHELLO MULTIVISION", + "folder": "/userdata/roms/multivision", + "extensions": [ + ".bin", + ".sg", + ".zip", + ".7z" + ] + }, + { + "system": "NINTENDO 64", + "folder": "/userdata/roms/n64", + "extensions": [ + ".z64", + ".n64", + ".v64", + ".zip", + ".7z" + ] + }, + { + "system": "NINTENDO 64 DISK DRIVE", + "folder": "/userdata/roms/n64dd", + "extensions": [ + ".z64", + ".n64", + ".ndd", + ".zip", + ".7z" + ] + }, + { + "system": "NAMCO 246/256", + "folder": "/userdata/roms/namco2x6", + "extensions": [ + ".zip" + ] + }, + { + "system": "NAOMI", + "folder": "/userdata/roms/naomi", + "extensions": [ + ".lst", + ".bin", + ".dat", + ".zip", + ".7z" + ] + }, + { + "system": "NAOMI 2", + "folder": "/userdata/roms/naomi2", + "extensions": [ + ".zip", + ".7z" + ] + }, + { + "system": "NINTENDO DS", + "folder": "/userdata/roms/nds", + "extensions": [ + ".nds", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "NEO-GEO", + "folder": "/userdata/roms/neogeo", + "extensions": [ + ".7z", + ".zip" + ] + }, + { + "system": "NEO-GEO CD", + "folder": "/userdata/roms/neogeocd", + "extensions": [ + ".cue", + ".iso", + ".chd" + ] + }, + { + "system": "NINTENDO ENTERTAINMENT SYSTEM", + "folder": "/userdata/roms/nes", + "extensions": [ + ".nes", + ".unif", + ".unf", + ".zip", + ".7z" + ] + }, + { + "system": "NEO-GEO POCKET", + "folder": "/userdata/roms/ngp", + "extensions": [ + ".ngp", + ".zip", + ".7z" + ] + }, + { + "system": "NEO-GEO POCKET COLOR", + "folder": "/userdata/roms/ngpc", + "extensions": [ + ".ngc", + ".zip", + ".7z" + ] + }, + { + "system": "ODYSSEY2", + "folder": "/userdata/roms/o2em", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "OD-COMMANDER", + "folder": "/userdata/roms/odcommander", + "extensions": [ + ".odc" + ] + }, + { + "system": "OPENBOR", + "folder": "/userdata/roms/openbor", + "extensions": [ + ".pak" + ] + }, + { + "system": "JAZZ JACKRABBIT", + "folder": "/userdata/roms/openjazz", + "extensions": [ + ".game" + ] + }, + { + "system": "OPENLARA", + "folder": "/userdata/roms/openlara", + "extensions": [ + ".croft" + ] + }, + { + "system": "PC-8800", + "folder": "/userdata/roms/pc88", + "extensions": [ + ".cmt", + ".d88", + ".u88", + ".m3u" + ] + }, + { + "system": "PC-9800", + "folder": "/userdata/roms/pc98", + "extensions": [ + ".d98", + ".zip", + ".98d", + ".fdi", + ".fdd", + ".2hd", + ".tfd", + ".d88", + ".88d", + ".hdm", + ".xdf", + ".dup", + ".cmd", + ".hdi", + ".thd", + ".nhd", + ".hdd", + ".hdn", + ".m3u" + ] + }, + { + "system": "PC ENGINE", + "folder": "/userdata/roms/pcengine", + "extensions": [ + ".pce", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "PC ENGINE CD", + "folder": "/userdata/roms/pcenginecd", + "extensions": [ + ".pce", + ".cue", + ".ccd", + ".iso", + ".img", + ".chd" + ] + }, + { + "system": "PC-FX", + "folder": "/userdata/roms/pcfx", + "extensions": [ + ".cue", + ".ccd", + ".toc", + ".chd", + ".zip", + ".7z", + ".m3u" + ] + }, + { + "system": "PDP-1", + "folder": "/userdata/roms/pdp1", + "extensions": [ + ".zip", + ".7z", + ".tap", + ".rim", + ".drm" + ] + }, + { + "system": "COMMODORE PET", + "folder": "/userdata/roms/pet", + "extensions": [ + ".a0", + ".b0", + ".crt", + ".d64", + ".d81", + ".prg", + ".tap", + ".t64", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "SEGA PICO", + "folder": "/userdata/roms/pico", + "extensions": [ + ".bin", + ".md", + ".zip", + ".7z" + ] + }, + { + "system": "PICO-8", + "folder": "/userdata/roms/pico8", + "extensions": [ + ".p8", + ".png", + ".m3u" + ] + }, + { + "system": "PLUG AND PLAY TV GAMES", + "folder": "/userdata/roms/plugnplay", + "extensions": [ + ".zip", + ".7z" + ] + }, + { + "system": "POKEMON MINI", + "folder": "/userdata/roms/pokemini", + "extensions": [ + ".min", + ".zip", + ".7z" + ] + }, + { + "system": "PRBOOM", + "folder": "/userdata/roms/prboom", + "extensions": [ + ".wad", + ".iwad", + ".pwad" + ] + }, + { + "system": "PLAYSTATION 2", + "folder": "/userdata/roms/ps2", + "extensions": [ + ".iso", + ".mdf", + ".nrg", + ".bin", + ".img", + ".dump", + ".gz", + ".cso", + ".chd", + ".m3u" + ] + }, + { + "system": "PLAYSTATION 3", + "folder": "/userdata/roms/ps3", + "extensions": [ + ".ps3", + ".psn", + ".squashfs" + ] + }, + { + "system": "PLAYSTATION PORTABLE", + "folder": "/userdata/roms/psp", + "extensions": [ + ".iso", + ".cso", + ".pbp", + ".chd" + ] + }, + { + "system": "PLAYSTATION VITA", + "folder": "/userdata/roms/psvita", + "extensions": [ + ".zip", + ".psvita" + ] + }, + { + "system": "PLAYSTATION", + "folder": "/userdata/roms/psx", + "extensions": [ + ".cue", + ".img", + ".mdf", + ".pbp", + ".toc", + ".cbn", + ".m3u", + ".ccd", + ".chd", + ".iso" + ] + }, + { + "system": "PV-1000", + "folder": "/userdata/roms/pv1000", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "PYGAME", + "folder": "/userdata/roms/pygame", + "extensions": [ + ".pygame" + ] + }, + { + "system": "PYXEL", + "folder": "/userdata/roms/pyxel", + "extensions": [ + ".py", + ".pyxapp" + ] + }, + { + "system": "QUAKE III", + "folder": "/userdata/roms/quake3", + "extensions": [ + ".quake3" + ] + }, + { + "system": "RAZE", + "folder": "/userdata/roms/raze", + "extensions": [ + ".raze" + ] + }, + { + "system": "REMINISCENCE", + "folder": "/userdata/roms/reminiscence", + "extensions": [ + ".rem" + ] + }, + { + "system": "RISE OF THE TRIAD", + "folder": "/userdata/roms/rott", + "extensions": [ + ".rott" + ] + }, + { + "system": "SAM COUPÉ", + "folder": "/userdata/roms/samcoupe", + "extensions": [ + ".cpm", + ".dsk", + ".sad", + ".mgt", + ".sdf", + ".td0", + ".sbt", + ".zip" + ] + }, + { + "system": "SATELLAVIEW", + "folder": "/userdata/roms/satellaview", + "extensions": [ + ".bs", + ".smc", + ".sfc", + ".zip", + ".7z", + ".squashfs" + ] + }, + { + "system": "SATURN", + "folder": "/userdata/roms/saturn", + "extensions": [ + ".cue", + ".ccd", + ".m3u", + ".chd", + ".iso", + ".zip", + ".mds" + ] + }, + { + "system": "SCUMMVM", + "folder": "/userdata/roms/scummvm", + "extensions": [ + ".scummvm", + ".squashfs" + ] + }, + { + "system": "SUPER CASSETTE VISION", + "folder": "/userdata/roms/scv", + "extensions": [ + ".bin", + ".zip", + ".0" + ] + }, + { + "system": "SDLPOP", + "folder": "/userdata/roms/sdlpop", + "extensions": [ + ".sdlpop" + ] + }, + { + "system": "32X", + "folder": "/userdata/roms/sega32x", + "extensions": [ + ".32x", + ".chd", + ".smd", + ".bin", + ".md", + ".zip", + ".7z" + ] + }, + { + "system": "SEGA CD", + "folder": "/userdata/roms/segacd", + "extensions": [ + ".cue", + ".iso", + ".chd", + ".m3u" + ] + }, + { + "system": "SG-1000", + "folder": "/userdata/roms/sg1000", + "extensions": [ + ".bin", + ".sg", + ".zip", + ".7z" + ] + }, + { + "system": "SUPER GAME BOY", + "folder": "/userdata/roms/sgb", + "extensions": [ + ".gb", + ".gbc", + ".zip", + ".7z" + ] + }, + { + "system": "SINGE", + "folder": "/userdata/roms/singe", + "extensions": [ + ".daphne", + ".squashfs" + ] + }, + { + "system": "SUPER NINTENDO ENTERTAINMENT SYSTEM", + "folder": "/userdata/roms/snes", + "extensions": [ + ".smc", + ".fig", + ".sfc", + ".gd3", + ".gd7", + ".dx2", + ".bsx", + ".swc", + ".zip", + ".7z" + ] + }, + { + "system": "SUPER DISC (MSU1)", + "folder": "/userdata/roms/snes-msu1", + "extensions": [ + ".smc", + ".sfc", + ".squashfs" + ] + }, + { + "system": "SOCRATES", + "folder": "/userdata/roms/socrates", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "SOLARUS", + "folder": "/userdata/roms/solarus", + "extensions": [ + ".zip", + ".solarus" + ] + }, + { + "system": "SONIC MANIA", + "folder": "/userdata/roms/sonic-mania", + "extensions": [ + ".sman" + ] + }, + { + "system": "SONIC 3 A.I.R.", + "folder": "/userdata/roms/sonic3-air", + "extensions": [ + ".s3air" + ] + }, + { + "system": "SONIC RETRO ENGINE", + "folder": "/userdata/roms/sonicretro", + "extensions": [ + ".son", + ".scd" + ] + }, + { + "system": "SPECTRAVIDEO SV-328", + "folder": "/userdata/roms/spectravideo", + "extensions": [ + ".zip", + ".7z", + ".cas" + ] + }, + { + "system": "STEAM", + "folder": "/userdata/roms/steam", + "extensions": [ + ".steam" + ] + }, + { + "system": "SUFAMI TURBO", + "folder": "/userdata/roms/sufami", + "extensions": [ + ".st", + ".fig", + ".bs", + ".smc", + ".sfc", + ".zip", + ".7z" + ] + }, + { + "system": "SUPER MARIO WAR", + "folder": "/userdata/roms/superbroswar", + "extensions": [ + ".game" + ] + }, + { + "system": "SUPERGRAFX", + "folder": "/userdata/roms/supergrafx", + "extensions": [ + ".pce", + ".sgx", + ".cue", + ".ccd", + ".chd", + ".zip", + ".7z" + ] + }, + { + "system": "SUPERVISION", + "folder": "/userdata/roms/supervision", + "extensions": [ + ".sv", + ".zip", + ".7z" + ] + }, + { + "system": "SUPER A'CAN", + "folder": "/userdata/roms/supracan", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "SEGA SP", + "folder": "/userdata/roms/systemsp", + "extensions": [ + ".lst", + ".bin", + ".dat", + ".zip", + ".7z" + ] + }, + { + "system": "THE FORCE ENGINE", + "folder": "/userdata/roms/theforceengine", + "extensions": [ + ".tfe" + ] + }, + { + "system": "THEXTECH", + "folder": "/userdata/roms/thextech", + "extensions": [ + ".smbx", + ".squashfs" + ] + }, + { + "system": "THOMSON - MO/TO (THEODORE)", + "folder": "/userdata/roms/thomson", + "extensions": [ + ".fd", + ".sap", + ".k7", + ".m7", + ".m5", + ".rom", + ".zip" + ] + }, + { + "system": "TI-99", + "folder": "/userdata/roms/ti99", + "extensions": [ + ".rpk", + ".wav", + ".zip", + ".7z" + ] + }, + { + "system": "TIC-80", + "folder": "/userdata/roms/tic80", + "extensions": [ + ".tic" + ] + }, + { + "system": "TRIFORCE", + "folder": "/userdata/roms/triforce", + "extensions": [ + ".gcm", + ".iso", + ".gcz", + ".ciso", + ".wbfs", + ".elf", + ".dol", + ".m3u" + ] + }, + { + "system": "TUTOR", + "folder": "/userdata/roms/tutor", + "extensions": [ + ".bin", + ".wav", + ".zip", + ".7z" + ] + }, + { + "system": "TYRIAN", + "folder": "/userdata/roms/tyrian", + "extensions": [ + ".game" + ] + }, + { + "system": "TYRQUAKE", + "folder": "/userdata/roms/tyrquake", + "extensions": [ + ".pak" + ] + }, + { + "system": "UZEBOX", + "folder": "/userdata/roms/uzebox", + "extensions": [ + ".uze" + ] + }, + { + "system": "VC 4000", + "folder": "/userdata/roms/vc4000", + "extensions": [ + ".bin", + ".rom", + ".pgm", + ".tvc", + ".zip", + ".7z" + ] + }, + { + "system": "VECTREX", + "folder": "/userdata/roms/vectrex", + "extensions": [ + ".bin", + ".gam", + ".vec", + ".zip", + ".7z" + ] + }, + { + "system": "VIDEO GAME MUSIC PLAYER", + "folder": "/userdata/roms/vgmplay", + "extensions": [ + ".vgm", + ".vgz", + ".zip", + ".7z" + ] + }, + { + "system": "VIDEOPAC+ G7400", + "folder": "/userdata/roms/videopacplus", + "extensions": [ + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "VIRCON32", + "folder": "/userdata/roms/vircon32", + "extensions": [ + ".v32", + ".zip" + ] + }, + { + "system": "VIRTUAL BOY", + "folder": "/userdata/roms/virtualboy", + "extensions": [ + ".vb", + ".zip", + ".7z" + ] + }, + { + "system": "TANDY VIDEO INFORMATION SYSTEM", + "folder": "/userdata/roms/vis", + "extensions": [ + ".chd", + ".cue", + ".toc", + ".nrg", + ".gdi", + ".iso", + ".cdr" + ] + }, + { + "system": "QUAKE II", + "folder": "/userdata/roms/vitaquake2", + "extensions": [ + ".pak", + ".zip", + ".7zip" + ] + }, + { + "system": "VISUAL PINBALL X", + "folder": "/userdata/roms/vpinball", + "extensions": [ + ".vpx" + ] + }, + { + "system": "V.SMILE", + "folder": "/userdata/roms/vsmile", + "extensions": [ + ".u1", + ".u3", + ".bin", + ".zip", + ".7z" + ] + }, + { + "system": "WASM4", + "folder": "/userdata/roms/wasm4", + "extensions": [ + ".wasm" + ] + }, + { + "system": "WII", + "folder": "/userdata/roms/wii", + "extensions": [ + ".gcm", + ".iso", + ".gcz", + ".ciso", + ".wbfs", + ".wad", + ".rvz", + ".elf", + ".dol", + ".m3u", + ".json" + ] + }, + { + "system": "WII U", + "folder": "/userdata/roms/wiiu", + "extensions": [ + ".wua", + ".wup", + ".wud", + ".wux", + ".rpx", + ".squashfs", + ".wuhb" + ] + }, + { + "system": "WINDOWS", + "folder": "/userdata/roms/windows", + "extensions": [ + ".pc", + ".exe", + ".wine", + ".wsquashfs", + ".wtgz" + ] + }, + { + "system": "INSTALL A NEW WINDOWS GAME", + "folder": "/userdata/roms/windows_installers", + "extensions": [ + ".exe", + ".iso" + ] + }, + { + "system": "WONDERSWAN", + "folder": "/userdata/roms/wswan", + "extensions": [ + ".ws", + ".zip", + ".7z" + ] + }, + { + "system": "WONDERSWAN COLOR", + "folder": "/userdata/roms/wswanc", + "extensions": [ + ".wsc", + ".zip", + ".7z" + ] + }, + { + "system": "SHARP X1", + "folder": "/userdata/roms/x1", + "extensions": [ + ".dx1", + ".zip", + ".2d", + ".2hd", + ".tfd", + ".d88", + ".88d", + ".hdm", + ".xdf", + ".dup", + ".cmd", + ".7z" + ] + }, + { + "system": "SHARP X68000", + "folder": "/userdata/roms/x68000", + "extensions": [ + ".dim", + ".img", + ".d88", + ".88d", + ".hdm", + ".dup", + ".2hd", + ".xdf", + ".hdf", + ".cmd", + ".m3u", + ".zip", + ".7z" + ] + }, + { + "system": "HALF-LIFE 1", + "folder": "/userdata/roms/xash3d_fwgs", + "extensions": [ + ".game" + ] + }, + { + "system": "XBOX", + "folder": "/userdata/roms/xbox", + "extensions": [ + ".iso", + ".squashfs" + ] + }, + { + "system": "XBOX 360", + "folder": "/userdata/roms/xbox360", + "extensions": [ + ".iso", + ".xex", + ".xbox360", + ".zar" + ] + }, + { + "system": "ATARI XE GAME SYSTEM", + "folder": "/userdata/roms/xegs", + "extensions": [ + ".atr", + ".dsk", + ".xfd", + ".bin", + ".rom", + ".car", + ".zip", + ".7z" + ] + }, + { + "system": "XRICK", + "folder": "/userdata/roms/xrick", + "extensions": [ + ".zip" + ] + }, + { + "system": "ZELDA CLASSIC", + "folder": "/userdata/roms/zc210", + "extensions": [ + ".qst" + ] + }, + { + "system": "ZX81", + "folder": "/userdata/roms/zx81", + "extensions": [ + ".tzx", + ".p", + ".zip", + ".7z" + ] + }, + { + "system": "ZX SPECTRUM", + "folder": "/userdata/roms/zxspectrum", + "extensions": [ + ".tzx", + ".tap", + ".z80", + ".rzx", + ".scl", + ".trd", + ".dsk", + ".zip", + ".7z" + ] + } +] \ No newline at end of file diff --git a/update/run.update b/update/run.update new file mode 100644 index 0000000..bd8f1a0 --- /dev/null +++ b/update/run.update @@ -0,0 +1,40 @@ +#!/bin/bash +# Script wrapper pour exécuter rgsx-update.sh et quitter RGSX +RGSX_UPDATE_SCRIPT="/userdata/roms/ports/rgsx-update.sh" +LOG_DIR="/userdata/roms/ports/logs" +LOG_FILE="$LOG_DIR/rgsx_update.log" + +# Créer le répertoire de logs s'il n'existe pas +mkdir -p "$LOG_DIR" +if [ ! -d "$LOG_DIR" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Erreur : Impossible de créer $LOG_DIR" >&2 + exit 1 +fi + +# Journaliser l'exécution +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Exécution de run-update.sh" >> "$LOG_FILE" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Vérification de l'existence de $RGSX_UPDATE_SCRIPT" >> "$LOG_FILE" +if [ ! -f "$RGSX_UPDATE_SCRIPT" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Erreur : $RGSX_UPDATE_SCRIPT n'existe pas" >> "$LOG_FILE" + exit 1 +fi +if [ ! -x "$RGSX_UPDATE_SCRIPT" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Rendre $RGSX_UPDATE_SCRIPT exécutable" >> "$LOG_FILE" + chmod +x "$RGSX_UPDATE_SCRIPT" +fi + +# Tuer les processus RGSX existants +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Terminaison des processus RGSX" >> "$LOG_FILE" +ps aux | grep '[p]ython3.*RGSX' | awk '{print $2}' >> "$LOG_FILE" +ps aux | grep '[p]ython3.*RGSX' | awk '{print $2}' | xargs kill -15 2>> "$LOG_FILE" +sleep 1 +ps aux | grep '[p]ython3.*RGSX' | awk '{print $2}' >> "$LOG_FILE" +ps aux | grep '[p]ython3.*RGSX' | awk '{print $2}' | xargs kill -9 2>> "$LOG_FILE" + +# Exécuter rgsx-update.sh +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Exécution de $RGSX_UPDATE_SCRIPT" >> "$LOG_FILE" +bash "$RGSX_UPDATE_SCRIPT" CONSOLE >> "$LOG_FILE" 2>&1 +exit_code=$? +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Code de retour de $RGSX_UPDATE_SCRIPT : $exit_code" >> "$LOG_FILE" + +exit $exit_code \ No newline at end of file