Compare commits

...

4 Commits

Author SHA1 Message Date
skymike03
0915a90fbe Merge branch 'main' of https://github.com/RetroGameSets/RGSX 2026-03-17 23:24:33 +01:00
skymike03
3ae3c151eb v2.6.0.3 (2025.03.17)
- Add support and donation information to release notes
- Add normalize game name for roms scanning (ie. Game (USA).ext will be shown owned for a rom named only "Game.ext"
- Add fulscreen/windowed mode in Settings > Display with auto resize window
2026-03-17 23:24:31 +01:00
RGS
7460b12d71 Delete snes directory error 2026-03-17 23:16:49 +01:00
skymike03
2f437c1aa4 v2.6.0.2 (2025.03.17)
- Add support and donation information to release notes
- Add normalize game name for roms scanning (ie. Game (USA).ext will be shown owned for a rom named only "Game.ext"
2026-03-17 23:12:50 +01:00
8 changed files with 137 additions and 35 deletions

View File

@@ -119,6 +119,16 @@ jobs:
### 📖 Documentation
[README.md](https://github.com/${{ github.repository }}/blob/main/README.md)
## SUPPORT US
Donate , Buy me a beer or a coffee :
if you want to support my project you can look here 🙂 https://bit.ly/donate-to-rgsx
Affiliate links :
hi all if you want to buy a premium account, you can use affiliated links here to support dev of RGSX without donate anything :
DEBRID-LINK.FR : https://debrid-link.fr/id/ow1DD
1FICHIER.COM : https://1fichier.com/?af=3186111
REAL-DEBRID.FR : http://real-debrid.com/?id=8441
RELEASE_EOF
echo "✓ Release notes generated"

View File

@@ -32,7 +32,7 @@ from display import (
draw_display_menu, draw_filter_menu_choice, draw_filter_advanced, draw_filter_priority_config,
draw_history_list, draw_clear_history_dialog, draw_cancel_download_dialog,
draw_confirm_dialog, draw_reload_games_data_dialog, draw_popup, draw_gradient,
draw_toast, show_toast, THEME_COLORS
draw_toast, show_toast, THEME_COLORS, sync_display_metrics
)
from language import _
from network import test_internet, download_rom, is_1fichier_url, download_from_1fichier, check_for_updates, cancel_all_downloads, download_queue_worker
@@ -45,7 +45,7 @@ from utils import (
)
from history import load_history, save_history, load_downloaded_games
from config import OTA_data_ZIP
from rgsx_settings import get_sources_mode, get_custom_sources_url, get_sources_zip_url
from rgsx_settings import get_sources_mode, get_custom_sources_url, get_sources_zip_url, get_display_fullscreen
from accessibility import load_accessibility_settings
# Configuration du logging
@@ -430,7 +430,7 @@ def stop_web_server():
# Boucle principale
async def main():
global current_music, music_files, music_folder, joystick
global current_music, music_files, music_folder, joystick, screen
logger.debug("Début main")
# Charger les filtres de jeux sauvegardés
@@ -610,6 +610,27 @@ async def main():
current_music = play_random_music(music_files, music_folder, current_music)
continue
resize_events = {
getattr(pygame, 'VIDEORESIZE', -1),
getattr(pygame, 'WINDOWSIZECHANGED', -2),
getattr(pygame, 'WINDOWRESIZED', -3),
}
if event.type in resize_events and not get_display_fullscreen():
try:
if event.type == getattr(pygame, 'VIDEORESIZE', -1):
new_width = max(640, int(getattr(event, 'w', config.screen_width)))
new_height = max(360, int(getattr(event, 'h', config.screen_height)))
screen = pygame.display.set_mode((new_width, new_height), pygame.RESIZABLE)
else:
screen = pygame.display.get_surface() or screen
sync_display_metrics(screen)
config.needs_redraw = True
logger.debug(f"Fenêtre redimensionnée: {config.screen_width}x{config.screen_height}")
except Exception as e:
logger.error(f"Erreur lors du redimensionnement de la fenêtre: {e}")
continue
if event.type == pygame.QUIT:
config.menu_state = "confirm_exit"
config.confirm_selection = 0

View File

@@ -26,7 +26,7 @@ except Exception:
pygame = None # type: ignore
# Version actuelle de l'application
app_version = "2.6.0.1"
app_version = "2.6.0.3"
# Nombre de jours avant de proposer la mise à jour de la liste des jeux
GAMELIST_UPDATE_DAYS = 7

View File

@@ -2212,11 +2212,27 @@ def handle_controls(event, sources, joystick, screen):
# Sous-menu Display
elif config.menu_state == "pause_display_menu":
sel = getattr(config, 'pause_display_selection', 0)
# layout, font submenu, family, [monitor if multi], light, unknown, back
# layout, font submenu, family, [monitor if multi], [display mode on Windows], light, unknown, back
from rgsx_settings import get_available_monitors
monitors = get_available_monitors()
show_monitor = len(monitors) > 1
total = 7 if show_monitor else 6 # dynamic total based on monitor count
show_display_mode = getattr(config, 'OPERATING_SYSTEM', '') == "Windows"
monitor_index = 3 if show_monitor else None
display_mode_index = 4 if show_monitor else 3
if not show_display_mode:
display_mode_index = None
next_index = 3
if show_monitor:
next_index += 1
if show_display_mode:
next_index += 1
light_index = next_index
unknown_index = light_index + 1
back_index = unknown_index + 1
total = back_index + 1
if is_input_matched(event, "up"):
config.pause_display_selection = (sel - 1) % total
config.needs_redraw = True
@@ -2274,8 +2290,8 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur changement font family: {e}")
# 3 monitor selection (only if multiple monitors)
elif sel == 3 and show_monitor and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
# Monitor selection (only if multiple monitors)
elif monitor_index is not None and sel == monitor_index and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
from rgsx_settings import get_display_monitor, set_display_monitor
current = get_display_monitor()
@@ -2286,8 +2302,19 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur changement moniteur: {e}")
# light mode toggle (index 4 if show_monitor, else 3)
elif ((sel == 4 and show_monitor) or (sel == 3 and not show_monitor)) and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
# Display mode toggle (Windows only)
elif display_mode_index is not None and sel == display_mode_index and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
from rgsx_settings import get_display_fullscreen, set_display_fullscreen
current = get_display_fullscreen()
set_display_fullscreen(not current)
config.popup_message = _("display_mode_restart_required") if _ else "Restart required to apply screen mode"
config.popup_timer = 3000
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur toggle fullscreen/windowed: {e}")
# Light mode toggle
elif sel == light_index and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
from rgsx_settings import get_light_mode, set_light_mode
current = get_light_mode()
@@ -2297,8 +2324,8 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur toggle light mode: {e}")
# allow unknown extensions (index 5 if show_monitor, else 4)
elif ((sel == 5 and show_monitor) or (sel == 4 and not show_monitor)) and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
# Allow unknown extensions
elif sel == unknown_index and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
current = get_allow_unknown_extensions()
new_val = set_allow_unknown_extensions(not current)
@@ -2307,8 +2334,8 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur toggle allow_unknown_extensions: {e}")
# back (index 6 if show_monitor, else 5)
elif ((sel == 6 and show_monitor) or (sel == 5 and not show_monitor)) and is_input_matched(event, "confirm"):
# Back
elif sel == back_index and is_input_matched(event, "confirm"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True

View File

@@ -30,6 +30,24 @@ logger = logging.getLogger(__name__)
OVERLAY = None # Initialisé dans init_display()
def sync_display_metrics(screen=None):
"""Synchronise les dimensions globales et l'overlay avec la fenêtre courante."""
global OVERLAY
if screen is None:
screen = pygame.display.get_surface()
if screen is None:
return None
screen_width, screen_height = screen.get_size()
config.screen_width = screen_width
config.screen_height = screen_height
OVERLAY = pygame.Surface((screen_width, screen_height), pygame.SRCALPHA)
OVERLAY.fill((5, 10, 20, 160))
return screen
# --- Helpers: SVG icons for controls (local cache, optional cairosvg) ---
_HELP_ICON_CACHE = {}
@@ -280,6 +298,7 @@ def init_display():
settings = load_rgsx_settings()
logger.debug(f"Settings chargés: display={settings.get('display', {})}")
target_monitor = settings.get("display", {}).get("monitor", 0)
is_fullscreen = get_display_fullscreen(settings)
# Vérifier les variables d'environnement (priorité sur les settings)
@@ -328,14 +347,24 @@ def init_display():
screen_width = display_info.current_w
screen_height = display_info.current_h
# Créer la fenêtre en plein écran
flags = pygame.FULLSCREEN
# Sur Linux/Batocera, utiliser SCALED pour respecter la résolution forcée d'EmulationStation
if platform.system() == "Linux":
flags |= pygame.SCALED
# Sur certains systèmes Windows, NOFRAME aide pour le multi-écran
elif platform.system() == "Windows":
flags |= pygame.NOFRAME
# Créer la fenêtre selon le mode d'affichage configuré.
if is_fullscreen:
flags = pygame.FULLSCREEN
# Sur Linux/Batocera, utiliser SCALED pour respecter la résolution forcée d'EmulationStation
if platform.system() == "Linux":
flags |= pygame.SCALED
# Sur certains systèmes Windows, NOFRAME aide pour le multi-écran
elif platform.system() == "Windows":
flags |= pygame.NOFRAME
else:
flags = pygame.RESIZABLE
if platform.system() == "Windows":
os.environ["SDL_VIDEO_CENTERED"] = "1"
desktop_width = screen_width
desktop_height = screen_height
screen_width = min(desktop_width, max(960, int(desktop_width * 0.9)))
screen_height = min(desktop_height, max(540, int(desktop_height * 0.9)))
try:
screen = pygame.display.set_mode((screen_width, screen_height), flags, display=target_monitor)
@@ -345,15 +374,16 @@ def init_display():
except Exception as e:
logger.error(f"Error creating display on monitor {target_monitor}: {e}")
screen = pygame.display.set_mode((screen_width, screen_height), flags)
config.screen_width = screen_width
config.screen_height = screen_height
screen = sync_display_metrics(screen)
screen_width, screen_height = screen.get_size()
config.current_monitor = target_monitor
# Initialisation de OVERLAY avec effet glassmorphism
OVERLAY = pygame.Surface((screen_width, screen_height), pygame.SRCALPHA)
OVERLAY.fill((5, 10, 20, 160)) # Bleu très foncé semi-transparent pour effet verre
logger.debug(f"Écran initialisé: {screen_width}x{screen_height} sur moniteur {target_monitor}")
logger.debug(
f"Écran initialisé: {screen_width}x{screen_height} sur moniteur {target_monitor} "
f"({'fullscreen' if is_fullscreen else 'windowed'})"
)
return screen
# Fond d'écran dégradé
@@ -2995,6 +3025,13 @@ def draw_pause_display_menu(screen, selected_index):
monitor_info = monitors[current_monitor] if current_monitor < num_monitors else monitors[0]
monitor_value = f"{monitor_info['name']} ({monitor_info['resolution']})"
monitor_txt = f"{_('display_monitor') if _ else 'Monitor'}: < {monitor_value} >"
# Display mode - Windows only
show_display_mode_option = getattr(config, 'OPERATING_SYSTEM', '') == "Windows"
if show_display_mode_option:
is_fullscreen = get_display_fullscreen()
display_mode_value = _("display_fullscreen") if is_fullscreen else _("display_windowed")
display_mode_txt = f"{_('display_mode') if _ else 'Screen mode'}: < {display_mode_value} >"
# Allow unknown extensions
allow_unknown = get_allow_unknown_extensions()
@@ -3011,8 +3048,7 @@ def draw_pause_display_menu(screen, selected_index):
back_txt = _("menu_back") if _ else "Back"
# Build options list - conditional monitor option
# layout, font submenu, family, [monitor if multi], light, unknown, back
# Build options list - conditional monitor and display mode options
font_submenu_txt = f"{_('submenu_display_font_size') if _ else 'Font Size'} >"
options = [layout_txt, font_submenu_txt, font_family_txt]
instruction_keys = [
@@ -3024,6 +3060,10 @@ def draw_pause_display_menu(screen, selected_index):
if show_monitor_option:
options.append(monitor_txt)
instruction_keys.append("instruction_display_monitor")
if show_display_mode_option:
options.append(display_mode_txt)
instruction_keys.append("instruction_display_mode")
options.extend([light_txt, unknown_txt, back_txt])
instruction_keys.extend([

View File

@@ -1,6 +1,7 @@
import json
import os
import logging
import re
import config
from datetime import datetime
@@ -168,7 +169,7 @@ IGNORED_ROM_SCAN_EXTENSIONS = {
def normalize_downloaded_game_name(game_name):
"""Normalise un nom de jeu pour les comparaisons en ignorant l'extension."""
"""Normalise un nom de jeu pour les comparaisons en ignorant extension et tags."""
if not isinstance(game_name, str):
return ""
@@ -176,7 +177,10 @@ def normalize_downloaded_game_name(game_name):
if not normalized:
return ""
return os.path.splitext(normalized)[0].strip().lower()
normalized = os.path.splitext(normalized)[0]
normalized = re.sub(r'\s*[\[(][^\])]*[\])]', '', normalized)
normalized = re.sub(r'\s+', ' ', normalized)
return normalized.strip().lower()
def _normalize_downloaded_games_dict(downloaded):

View File

@@ -1,3 +1,3 @@
{
"version": "2.6.0.1"
"version": "2.6.0.3"
}