mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-19 08:16:49 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
217392dcd1 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -17,9 +17,9 @@ ports/RGSX.bat
|
||||
audit_i18n.py
|
||||
prune_i18n.py
|
||||
Info.txt
|
||||
pygame/
|
||||
|
||||
# Docker test data
|
||||
data/
|
||||
|
||||
docker-compose.test.yml
|
||||
config/
|
||||
|
||||
@@ -238,11 +238,12 @@ except Exception as e:
|
||||
|
||||
# Initialisation du mixer Pygame (déférée/évitable si musique désactivée)
|
||||
if getattr(config, 'music_enabled', True):
|
||||
pygame.mixer.pre_init(44100, -16, 2, 4096)
|
||||
try:
|
||||
pygame.mixer.pre_init(44100, -16, 2, 4096)
|
||||
pygame.mixer.init()
|
||||
except Exception as e:
|
||||
logger.warning(f"Échec init mixer: {e}")
|
||||
except (NotImplementedError, AttributeError, Exception) as e:
|
||||
logger.warning(f"Mixer non disponible ou échec init: {e}")
|
||||
config.music_enabled = False # Désactiver la musique si mixer non disponible
|
||||
|
||||
# Dossier musique Batocera
|
||||
music_folder = os.path.join(config.APP_FOLDER, "assets", "music")
|
||||
@@ -1368,7 +1369,11 @@ async def main():
|
||||
clock.tick(60)
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
pygame.mixer.music.stop()
|
||||
try:
|
||||
if pygame.mixer.get_init() is not None:
|
||||
pygame.mixer.music.stop()
|
||||
except (AttributeError, NotImplementedError):
|
||||
pass
|
||||
# Cancel any ongoing downloads to prevent lingering background threads
|
||||
try:
|
||||
cancel_all_downloads()
|
||||
|
||||
133
ports/RGSX/assets/progs/custom_dns
Normal file
133
ports/RGSX/assets/progs/custom_dns
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
# BATOCERA SERVICE
|
||||
# name: Custom DNS Service for RGSX
|
||||
# description: Force custom DNS servers (Cloudflare 1.1.1.1)
|
||||
# author: RetroGameSets
|
||||
# depends:
|
||||
# version: 1.0
|
||||
|
||||
RESOLV_CONF="/tmp/resolv.conf"
|
||||
PIDFILE="/var/run/custom_dns.pid"
|
||||
LOGFILE="/userdata/roms/ports/RGSX/logs/custom_dns_service.log"
|
||||
SERVICE_NAME="custom_dns"
|
||||
|
||||
# Fonction utilitaire : vérifie si le service est activé dans batocera-settings
|
||||
is_enabled() {
|
||||
local enabled_services
|
||||
enabled_services="$(/usr/bin/batocera-settings-get system.services 2>/dev/null)"
|
||||
for s in $enabled_services; do
|
||||
if [ "$s" = "$SERVICE_NAME" ]; then
|
||||
echo "enabled"
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo "disabled"
|
||||
}
|
||||
|
||||
# Fonction pour appliquer les DNS personnalisés
|
||||
apply_custom_dns() {
|
||||
echo "[${SERVICE_NAME}] Applying custom DNS servers..."
|
||||
mkdir -p "$(dirname "$LOGFILE")"
|
||||
{
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - Applying custom DNS"
|
||||
# Retirer la protection si elle existe
|
||||
chattr -i "$RESOLV_CONF" 2>/dev/null || true
|
||||
# Écrire la nouvelle configuration DNS
|
||||
echo "# Generated by RGSX Custom DNS Service" > "$RESOLV_CONF"
|
||||
echo "nameserver 1.1.1.1" >> "$RESOLV_CONF"
|
||||
echo "nameserver 1.0.0.1" >> "$RESOLV_CONF"
|
||||
# Protéger le fichier contre les modifications
|
||||
chattr +i "$RESOLV_CONF" 2>/dev/null || true
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - Custom DNS applied successfully"
|
||||
} >> "$LOGFILE" 2>&1
|
||||
echo "[${SERVICE_NAME}] Custom DNS applied (1.1.1.1, 1.0.0.1)"
|
||||
}
|
||||
|
||||
# Fonction pour restaurer les DNS par défaut
|
||||
restore_default_dns() {
|
||||
echo "[${SERVICE_NAME}] Restoring default DNS..."
|
||||
mkdir -p "$(dirname "$LOGFILE")"
|
||||
{
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - Restoring default DNS"
|
||||
# Retirer la protection
|
||||
chattr -i "$RESOLV_CONF" 2>/dev/null || true
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - DNS protection removed"
|
||||
} >> "$LOGFILE" 2>&1
|
||||
echo "[${SERVICE_NAME}] Default DNS restored"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
echo "[${SERVICE_NAME}] Already running (PID $(cat "$PIDFILE"))"
|
||||
exit 0
|
||||
fi
|
||||
apply_custom_dns
|
||||
echo $$ > "$PIDFILE"
|
||||
echo "[${SERVICE_NAME}] Started (PID $(cat "$PIDFILE"))"
|
||||
;;
|
||||
|
||||
stop)
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
echo "[${SERVICE_NAME}] Stopping..."
|
||||
restore_default_dns
|
||||
rm -f "$PIDFILE"
|
||||
echo "[${SERVICE_NAME}] Stopped"
|
||||
else
|
||||
echo "[${SERVICE_NAME}] Not running"
|
||||
fi
|
||||
;;
|
||||
|
||||
restart)
|
||||
echo "[${SERVICE_NAME}] Restarting..."
|
||||
"$0" stop
|
||||
sleep 1
|
||||
"$0" start
|
||||
;;
|
||||
|
||||
status)
|
||||
ENABLE_STATE=$(is_enabled)
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
if chattr -i "$RESOLV_CONF" 2>/dev/null; then
|
||||
chattr +i "$RESOLV_CONF" 2>/dev/null
|
||||
echo "[${SERVICE_NAME}] Running (DNS protected) - ${ENABLE_STATE} on boot"
|
||||
exit 0
|
||||
else
|
||||
echo "[${SERVICE_NAME}] Running (DNS not protected) - ${ENABLE_STATE} on boot"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo "[${SERVICE_NAME}] Not running - ${ENABLE_STATE} on boot"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
enable)
|
||||
current=$(/usr/bin/batocera-settings-get system.services 2>/dev/null)
|
||||
if echo "$current" | grep -qw "$SERVICE_NAME"; then
|
||||
echo "[${SERVICE_NAME}] Already enabled on boot"
|
||||
else
|
||||
new_value="$current $SERVICE_NAME"
|
||||
/usr/bin/batocera-settings-set system.services "$new_value"
|
||||
echo "[${SERVICE_NAME}] Enabled on boot"
|
||||
fi
|
||||
;;
|
||||
|
||||
disable)
|
||||
current=$(/usr/bin/batocera-settings-get system.services 2>/dev/null)
|
||||
if echo "$current" | grep -qw "$SERVICE_NAME"; then
|
||||
new_value=$(echo "$current" | sed "s/\b$SERVICE_NAME\b//g" | xargs)
|
||||
/usr/bin/batocera-settings-set system.services "$new_value"
|
||||
echo "[${SERVICE_NAME}] Disabled on boot"
|
||||
else
|
||||
echo "[${SERVICE_NAME}] Already disabled"
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|enable|disable}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -13,7 +13,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "2.3.2.0"
|
||||
app_version = "2.3.2.1"
|
||||
|
||||
|
||||
def get_application_root():
|
||||
|
||||
@@ -15,7 +15,9 @@ from utils import (
|
||||
load_games, check_extension_before_download, is_extension_supported,
|
||||
load_extensions_json, play_random_music, sanitize_filename,
|
||||
save_music_config, load_api_keys, _get_dest_folder_name,
|
||||
extract_zip, extract_rar, find_file_with_or_without_extension, toggle_web_service_at_boot, check_web_service_status,
|
||||
extract_zip, extract_rar, find_file_with_or_without_extension,
|
||||
toggle_web_service_at_boot, check_web_service_status,
|
||||
toggle_custom_dns_at_boot, check_custom_dns_status,
|
||||
restart_application, generate_support_zip, load_sources,
|
||||
ensure_download_provider_keys, missing_all_provider_keys, build_provider_paths_string
|
||||
)
|
||||
@@ -593,31 +595,31 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "page_up"):
|
||||
config.current_game = max(0, config.current_game - config.visible_games)
|
||||
config.repeat_action = None
|
||||
config.repeat_key = None
|
||||
config.repeat_start_time = 0
|
||||
config.repeat_last_action = current_time
|
||||
update_key_state("page_up", True, event.type, event.key if event.type == pygame.KEYDOWN else
|
||||
event.button if event.type == pygame.JOYBUTTONDOWN else
|
||||
(event.axis, event.value) if event.type == pygame.JOYAXISMOTION else
|
||||
event.value)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "left"):
|
||||
config.current_game = max(0, config.current_game - config.visible_games)
|
||||
config.repeat_action = None
|
||||
config.repeat_key = None
|
||||
config.repeat_start_time = 0
|
||||
config.repeat_last_action = current_time
|
||||
update_key_state("left", True, event.type, event.key if event.type == pygame.KEYDOWN else
|
||||
event.button if event.type == pygame.JOYBUTTONDOWN else
|
||||
(event.axis, event.value) if event.type == pygame.JOYAXISMOTION else
|
||||
event.value)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "page_down"):
|
||||
config.current_game = min(len(games) - 1, config.current_game + config.visible_games)
|
||||
config.repeat_action = None
|
||||
config.repeat_key = None
|
||||
config.repeat_start_time = 0
|
||||
config.repeat_last_action = current_time
|
||||
update_key_state("page_down", True, event.type, event.key if event.type == pygame.KEYDOWN else
|
||||
event.button if event.type == pygame.JOYBUTTONDOWN else
|
||||
(event.axis, event.value) if event.type == pygame.JOYAXISMOTION else
|
||||
event.value)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "right"):
|
||||
config.current_game = min(len(games) - 1, config.current_game + config.visible_games)
|
||||
config.repeat_action = None
|
||||
config.repeat_key = None
|
||||
config.repeat_start_time = 0
|
||||
config.repeat_last_action = current_time
|
||||
update_key_state("right", True, event.type, event.key if event.type == pygame.KEYDOWN else
|
||||
event.button if event.type == pygame.JOYBUTTONDOWN else
|
||||
(event.axis, event.value) if event.type == pygame.JOYAXISMOTION else
|
||||
event.value)
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "filter"):
|
||||
config.search_mode = True
|
||||
@@ -1620,9 +1622,11 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Calculer le nombre total d'options selon le système
|
||||
total = 4 # music, symlink, api keys, back
|
||||
web_service_index = -1
|
||||
custom_dns_index = -1
|
||||
if config.OPERATING_SYSTEM == "Linux":
|
||||
total = 5 # music, symlink, web_service, api keys, back
|
||||
total = 6 # music, symlink, web_service, custom_dns, api keys, back
|
||||
web_service_index = 2
|
||||
custom_dns_index = 3
|
||||
|
||||
if is_input_matched(event, "up"):
|
||||
config.pause_settings_selection = (sel - 1) % total
|
||||
@@ -1642,7 +1646,11 @@ def handle_controls(event, sources, joystick, screen):
|
||||
if music_files and music_folder:
|
||||
config.current_music = play_random_music(music_files, music_folder, getattr(config, "current_music", None))
|
||||
else:
|
||||
pygame.mixer.music.stop()
|
||||
try:
|
||||
if pygame.mixer.get_init() is not None:
|
||||
pygame.mixer.music.stop()
|
||||
except (AttributeError, NotImplementedError):
|
||||
pass
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Musique {'activée' if config.music_enabled else 'désactivée'} via settings")
|
||||
# Option 1: Symlink toggle
|
||||
@@ -1655,7 +1663,6 @@ def handle_controls(event, sources, joystick, screen):
|
||||
logger.info(f"Symlink option {'activée' if not current_status else 'désactivée'} via settings")
|
||||
# Option 2: Web Service toggle (seulement si Linux)
|
||||
elif sel == web_service_index and web_service_index >= 0 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
|
||||
current_status = check_web_service_status()
|
||||
# Afficher un message de chargement
|
||||
config.popup_message = _("settings_web_service_enabling") if not current_status else _("settings_web_service_disabling")
|
||||
@@ -1672,8 +1679,26 @@ def handle_controls(event, sources, joystick, screen):
|
||||
else:
|
||||
logger.error(f"Erreur toggle service web: {message}")
|
||||
threading.Thread(target=toggle_service, daemon=True).start()
|
||||
# Option 3: Custom DNS toggle (seulement si Linux)
|
||||
elif sel == custom_dns_index and custom_dns_index >= 0 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
current_status = check_custom_dns_status()
|
||||
# Afficher un message de chargement
|
||||
config.popup_message = _("settings_custom_dns_enabling") if not current_status else _("settings_custom_dns_disabling")
|
||||
config.popup_timer = 1000
|
||||
config.needs_redraw = True
|
||||
# Exécuter en thread pour ne pas bloquer l'UI
|
||||
def toggle_dns():
|
||||
success, message = toggle_custom_dns_at_boot(not current_status)
|
||||
config.popup_message = message
|
||||
config.popup_timer = 5000 if success else 7000
|
||||
config.needs_redraw = True
|
||||
if success:
|
||||
logger.info(f"Service custom DNS {'activé' if not current_status else 'désactivé'} au démarrage")
|
||||
else:
|
||||
logger.error(f"Erreur toggle service custom DNS: {message}")
|
||||
threading.Thread(target=toggle_dns, daemon=True).start()
|
||||
# Option API Keys (index varie selon Linux ou pas)
|
||||
elif sel == (web_service_index + 1 if web_service_index >= 0 else 2) and is_input_matched(event, "confirm"):
|
||||
elif sel == (custom_dns_index + 1 if custom_dns_index >= 0 else 2) and is_input_matched(event, "confirm"):
|
||||
config.menu_state = "pause_api_keys_status"
|
||||
config.needs_redraw = True
|
||||
# Option Back (dernière option)
|
||||
@@ -2000,7 +2025,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Gestion des relâchements de touches
|
||||
if event.type == pygame.KEYUP:
|
||||
# Vérifier quelle touche a été relâchée
|
||||
for action_name in ["up", "down", "left", "right", "confirm", "cancel"]:
|
||||
for action_name in ["up", "down", "left", "right", "page_up", "page_down", "confirm", "cancel"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "key" and \
|
||||
config.controls_config.get(action_name, {}).get("key") == event.key:
|
||||
update_key_state(action_name, False)
|
||||
@@ -2094,7 +2119,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
|
||||
elif event.type == pygame.JOYBUTTONUP:
|
||||
# Vérifier quel bouton a été relâché
|
||||
for action_name in ["up", "down", "left", "right", "confirm", "cancel"]:
|
||||
for action_name in ["up", "down", "left", "right", "page_up", "page_down", "confirm", "cancel"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "button" and \
|
||||
config.controls_config.get(action_name, {}).get("button") == event.button:
|
||||
update_key_state(action_name, False)
|
||||
@@ -2188,14 +2213,14 @@ def handle_controls(event, sources, joystick, screen):
|
||||
|
||||
elif event.type == pygame.JOYAXISMOTION and abs(event.value) < 0.5:
|
||||
# Vérifier quel axe a été relâché
|
||||
for action_name in ["up", "down", "left", "right"]:
|
||||
for action_name in ["up", "down", "left", "right", "page_up", "page_down"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "axis" and \
|
||||
config.controls_config.get(action_name, {}).get("axis") == event.axis:
|
||||
update_key_state(action_name, False)
|
||||
|
||||
elif event.type == pygame.JOYHATMOTION and event.value == (0, 0):
|
||||
# Vérifier quel hat a été relâché
|
||||
for action_name in ["up", "down", "left", "right"]:
|
||||
for action_name in ["up", "down", "left", "right", "page_up", "page_down"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "hat":
|
||||
update_key_state(action_name, False)
|
||||
|
||||
|
||||
@@ -2119,7 +2119,7 @@ def draw_pause_games_menu(screen, selected_index):
|
||||
|
||||
def draw_pause_settings_menu(screen, selected_index):
|
||||
from rgsx_settings import get_symlink_option
|
||||
from utils import check_web_service_status
|
||||
from utils import check_web_service_status, check_custom_dns_status
|
||||
# Music
|
||||
if config.music_enabled:
|
||||
music_name = config.current_music_name or ""
|
||||
@@ -2140,10 +2140,16 @@ def draw_pause_settings_menu(screen, selected_index):
|
||||
|
||||
# Web Service at boot (only on Linux/Batocera)
|
||||
web_service_txt = ""
|
||||
custom_dns_txt = ""
|
||||
if config.OPERATING_SYSTEM == "Linux":
|
||||
web_service_enabled = check_web_service_status()
|
||||
web_service_status = _("settings_web_service_enabled") if web_service_enabled else _("settings_web_service_disabled")
|
||||
web_service_txt = f"{_('settings_web_service')} : < {web_service_status} >"
|
||||
|
||||
# Custom DNS at boot
|
||||
custom_dns_enabled = check_custom_dns_status()
|
||||
custom_dns_status = _("settings_custom_dns_enabled") if custom_dns_enabled else _("settings_custom_dns_disabled")
|
||||
custom_dns_txt = f"{_('settings_custom_dns')} : < {custom_dns_status} >"
|
||||
|
||||
api_keys_txt = _("menu_api_keys_status") if _ else "API Keys"
|
||||
back_txt = _("menu_back") if _ else "Back"
|
||||
@@ -2152,6 +2158,8 @@ def draw_pause_settings_menu(screen, selected_index):
|
||||
options = [music_option, symlink_option]
|
||||
if web_service_txt: # Ajouter seulement si Linux/Batocera
|
||||
options.append(web_service_txt)
|
||||
if custom_dns_txt: # Ajouter seulement si Linux/Batocera
|
||||
options.append(custom_dns_txt)
|
||||
options.extend([api_keys_txt, back_txt])
|
||||
|
||||
_draw_submenu_generic(screen, _("menu_settings_category") if _ else "Settings", options, selected_index)
|
||||
@@ -2161,6 +2169,8 @@ def draw_pause_settings_menu(screen, selected_index):
|
||||
]
|
||||
if web_service_txt:
|
||||
instruction_keys.append("instruction_settings_web_service")
|
||||
if custom_dns_txt:
|
||||
instruction_keys.append("instruction_settings_custom_dns")
|
||||
instruction_keys.extend([
|
||||
"instruction_settings_api_keys",
|
||||
"instruction_generic_back",
|
||||
|
||||
@@ -203,6 +203,7 @@
|
||||
"instruction_settings_symlink": "Verwendung von Symlinks für Installationen umschalten",
|
||||
"instruction_settings_api_keys": "Gefundene Premium-API-Schlüssel ansehen",
|
||||
"instruction_settings_web_service": "Web-Dienst Autostart beim Booten aktivieren/deaktivieren",
|
||||
"instruction_settings_custom_dns": "Custom DNS (Cloudflare 1.1.1.1) beim Booten aktivieren/deaktivieren",
|
||||
"settings_web_service": "Web-Dienst beim Booten",
|
||||
"settings_web_service_enabled": "Aktiviert",
|
||||
"settings_web_service_disabled": "Deaktiviert",
|
||||
@@ -211,6 +212,13 @@
|
||||
"settings_web_service_success_enabled": "Web-Dienst beim Booten aktiviert",
|
||||
"settings_web_service_success_disabled": "Web-Dienst beim Booten deaktiviert",
|
||||
"settings_web_service_error": "Fehler: {0}",
|
||||
"settings_custom_dns": "Custom DNS beim Booten",
|
||||
"settings_custom_dns_enabled": "Aktiviert",
|
||||
"settings_custom_dns_disabled": "Deaktiviert",
|
||||
"settings_custom_dns_enabling": "Custom DNS wird aktiviert...",
|
||||
"settings_custom_dns_disabling": "Custom DNS wird deaktiviert...",
|
||||
"settings_custom_dns_success_enabled": "Custom DNS beim Booten aktiviert (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "Custom DNS beim Booten deaktiviert",
|
||||
"controls_desc_confirm": "Bestätigen (z.B. A/Kreuz)",
|
||||
"controls_desc_cancel": "Abbrechen/Zurück (z.B. B/Kreis)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
"instruction_settings_symlink": "Toggle using filesystem symlinks for installs",
|
||||
"instruction_settings_api_keys": "See detected premium provider API keys",
|
||||
"instruction_settings_web_service": "Enable/disable web service auto-start at boot",
|
||||
"instruction_settings_custom_dns": "Enable/disable custom DNS (Cloudflare 1.1.1.1) at boot",
|
||||
"settings_web_service": "Web Service at Boot",
|
||||
"settings_web_service_enabled": "Enabled",
|
||||
"settings_web_service_disabled": "Disabled",
|
||||
@@ -213,6 +214,13 @@
|
||||
"settings_web_service_success_enabled": "Web service enabled at boot",
|
||||
"settings_web_service_success_disabled": "Web service disabled at boot",
|
||||
"settings_web_service_error": "Error: {0}",
|
||||
"settings_custom_dns": "Custom DNS at Boot",
|
||||
"settings_custom_dns_enabled": "Enabled",
|
||||
"settings_custom_dns_disabled": "Disabled",
|
||||
"settings_custom_dns_enabling": "Enabling custom DNS...",
|
||||
"settings_custom_dns_disabling": "Disabling custom DNS...",
|
||||
"settings_custom_dns_success_enabled": "Custom DNS enabled at boot (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "Custom DNS disabled at boot",
|
||||
"controls_desc_confirm": "Confirm (e.g. A/Cross)",
|
||||
"controls_desc_cancel": "Cancel/Back (e.g. B/Circle)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
"instruction_settings_symlink": "Alternar uso de symlinks en instalaciones",
|
||||
"instruction_settings_api_keys": "Ver claves API premium detectadas",
|
||||
"instruction_settings_web_service": "Activar/desactivar inicio automático del servicio web",
|
||||
"instruction_settings_custom_dns": "Activar/desactivar DNS personalizado (Cloudflare 1.1.1.1) al inicio",
|
||||
"settings_web_service": "Servicio Web al Inicio",
|
||||
"settings_web_service_enabled": "Activado",
|
||||
"settings_web_service_disabled": "Desactivado",
|
||||
@@ -213,6 +214,13 @@
|
||||
"settings_web_service_success_enabled": "Servicio web activado al inicio",
|
||||
"settings_web_service_success_disabled": "Servicio web desactivado al inicio",
|
||||
"settings_web_service_error": "Error: {0}",
|
||||
"settings_custom_dns": "DNS Personalizado al Inicio",
|
||||
"settings_custom_dns_enabled": "Activado",
|
||||
"settings_custom_dns_disabled": "Desactivado",
|
||||
"settings_custom_dns_enabling": "Activando DNS personalizado...",
|
||||
"settings_custom_dns_disabling": "Desactivando DNS personalizado...",
|
||||
"settings_custom_dns_success_enabled": "DNS personalizado activado al inicio (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "DNS personalizado desactivado al inicio",
|
||||
"controls_desc_confirm": "Confirmar (ej. A/Cruz)",
|
||||
"controls_desc_cancel": "Cancelar/Volver (ej. B/Círculo)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
"instruction_settings_symlink": "Basculer l'utilisation de symlinks pour l'installation",
|
||||
"instruction_settings_api_keys": "Voir les clés API détectées des services premium",
|
||||
"instruction_settings_web_service": "Activer/désactiver le démarrage automatique du service web",
|
||||
"instruction_settings_custom_dns": "Activer/désactiver les DNS personnalisés (Cloudflare 1.1.1.1) au démarrage",
|
||||
"settings_web_service": "Service Web au démarrage",
|
||||
"settings_web_service_enabled": "Activé",
|
||||
"settings_web_service_disabled": "Désactivé",
|
||||
@@ -213,6 +214,13 @@
|
||||
"settings_web_service_success_enabled": "Service web activé au démarrage",
|
||||
"settings_web_service_success_disabled": "Service web désactivé au démarrage",
|
||||
"settings_web_service_error": "Erreur : {0}",
|
||||
"settings_custom_dns": "DNS Personnalisé au démarrage",
|
||||
"settings_custom_dns_enabled": "Activé",
|
||||
"settings_custom_dns_disabled": "Désactivé",
|
||||
"settings_custom_dns_enabling": "Activation du DNS personnalisé...",
|
||||
"settings_custom_dns_disabling": "Désactivation du DNS personnalisé...",
|
||||
"settings_custom_dns_success_enabled": "DNS personnalisé activé au démarrage (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "DNS personnalisé désactivé au démarrage",
|
||||
"controls_desc_confirm": "Valider (ex: A/Croix)",
|
||||
"controls_desc_cancel": "Annuler/Retour (ex: B/Rond)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
"instruction_settings_symlink": "Abilitare/disabilitare uso symlink per installazioni",
|
||||
"instruction_settings_api_keys": "Mostrare chiavi API premium rilevate",
|
||||
"instruction_settings_web_service": "Attivare/disattivare avvio automatico servizio web all'avvio",
|
||||
"instruction_settings_custom_dns": "Attivare/disattivare DNS personalizzato (Cloudflare 1.1.1.1) all'avvio",
|
||||
"settings_web_service": "Servizio Web all'Avvio",
|
||||
"settings_web_service_enabled": "Abilitato",
|
||||
"settings_web_service_disabled": "Disabilitato",
|
||||
@@ -210,6 +211,13 @@
|
||||
"settings_web_service_success_enabled": "Servizio web abilitato all'avvio",
|
||||
"settings_web_service_success_disabled": "Servizio web disabilitato all'avvio",
|
||||
"settings_web_service_error": "Errore: {0}",
|
||||
"settings_custom_dns": "DNS Personalizzato all'Avvio",
|
||||
"settings_custom_dns_enabled": "Abilitato",
|
||||
"settings_custom_dns_disabled": "Disabilitato",
|
||||
"settings_custom_dns_enabling": "Abilitazione DNS personalizzato...",
|
||||
"settings_custom_dns_disabling": "Disabilitazione DNS personalizzato...",
|
||||
"settings_custom_dns_success_enabled": "DNS personalizzato abilitato all'avvio (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "DNS personalizzato disabilitato all'avvio",
|
||||
"controls_desc_confirm": "Confermare (es. A/Croce)",
|
||||
"controls_desc_cancel": "Annullare/Indietro (es. B/Cerchio)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
"instruction_settings_symlink": "Ativar/desativar uso de symlinks para instalações",
|
||||
"instruction_settings_api_keys": "Ver chaves API premium detectadas",
|
||||
"instruction_settings_web_service": "Ativar/desativar início automático do serviço web na inicialização",
|
||||
"instruction_settings_custom_dns": "Ativar/desativar DNS personalizado (Cloudflare 1.1.1.1) na inicialização",
|
||||
"settings_web_service": "Serviço Web na Inicialização",
|
||||
"settings_web_service_enabled": "Ativado",
|
||||
"settings_web_service_disabled": "Desativado",
|
||||
@@ -212,6 +213,13 @@
|
||||
"settings_web_service_success_enabled": "Serviço web ativado na inicialização",
|
||||
"settings_web_service_success_disabled": "Serviço web desativado na inicialização",
|
||||
"settings_web_service_error": "Erro: {0}",
|
||||
"settings_custom_dns": "DNS Personalizado na Inicialização",
|
||||
"settings_custom_dns_enabled": "Ativado",
|
||||
"settings_custom_dns_disabled": "Desativado",
|
||||
"settings_custom_dns_enabling": "Ativando DNS personalizado...",
|
||||
"settings_custom_dns_disabling": "Desativando DNS personalizado...",
|
||||
"settings_custom_dns_success_enabled": "DNS personalizado ativado na inicialização (1.1.1.1)",
|
||||
"settings_custom_dns_success_disabled": "DNS personalizado desativado na inicialização",
|
||||
"controls_desc_confirm": "Confirmar (ex. A/Cruz)",
|
||||
"controls_desc_cancel": "Cancelar/Voltar (ex. B/Círculo)",
|
||||
"controls_desc_up": "UP ↑",
|
||||
|
||||
@@ -34,6 +34,14 @@ logger = logging.getLogger(__name__)
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
logging.getLogger("requests").setLevel(logging.WARNING)
|
||||
|
||||
# Helper pour vérifier si pygame.mixer est disponible
|
||||
def is_mixer_available():
|
||||
"""Vérifie si pygame.mixer est disponible et initialisé."""
|
||||
try:
|
||||
return pygame is not None and hasattr(pygame, 'mixer') and pygame.mixer.get_init() is not None
|
||||
except (AttributeError, NotImplementedError):
|
||||
return False
|
||||
|
||||
# Liste globale pour stocker les systèmes avec une erreur 404
|
||||
unavailable_systems = []
|
||||
|
||||
@@ -65,7 +73,8 @@ def restart_application(delay_ms: int = 2000):
|
||||
if int(delay_ms) <= 0:
|
||||
try:
|
||||
try:
|
||||
pygame.mixer.music.stop()
|
||||
if is_mixer_available():
|
||||
pygame.mixer.music.stop()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
@@ -300,6 +309,176 @@ def toggle_web_service_at_boot(enable: bool):
|
||||
return (False, error_msg)
|
||||
|
||||
|
||||
def toggle_custom_dns_at_boot(enable: bool):
|
||||
"""Active ou désactive le service custom DNS au démarrage de Batocera.
|
||||
|
||||
Args:
|
||||
enable: True pour activer, False pour désactiver
|
||||
|
||||
Returns:
|
||||
tuple: (success: bool, message: str)
|
||||
"""
|
||||
try:
|
||||
# Vérifier si on est sur un système compatible (Linux avec batocera-services)
|
||||
if config.OPERATING_SYSTEM != "Linux":
|
||||
return (False, "Custom DNS service is only available on Batocera/Linux systems")
|
||||
|
||||
services_dir = "/userdata/system/services"
|
||||
service_file = os.path.join(services_dir, "custom_dns")
|
||||
source_file = os.path.join(config.APP_FOLDER, "assets", "progs", "custom_dns")
|
||||
|
||||
if enable:
|
||||
# Mode ENABLE
|
||||
logger.debug("Activation du service custom DNS au démarrage...")
|
||||
|
||||
# 1. Créer le dossier services s'il n'existe pas
|
||||
try:
|
||||
os.makedirs(services_dir, exist_ok=True)
|
||||
logger.debug(f"Dossier services vérifié/créé: {services_dir}")
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to create services directory: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
# 2. Copier le fichier custom_dns
|
||||
try:
|
||||
if not os.path.exists(source_file):
|
||||
error_msg = f"Source service file not found: {source_file}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
shutil.copy2(source_file, service_file)
|
||||
os.chmod(service_file, 0o755) # Rendre exécutable
|
||||
logger.debug(f"Fichier service copié et rendu exécutable: {service_file}")
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to copy service file: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
# 3. Activer le service avec batocera-services
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['batocera-services', 'enable', 'custom_dns'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode != 0:
|
||||
error_msg = f"batocera-services enable failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
logger.debug(f"Service activé: {result.stdout}")
|
||||
except FileNotFoundError:
|
||||
error_msg = "batocera-services command not found"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to enable service: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
# 4. Démarrer le service immédiatement
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['batocera-services', 'start', 'custom_dns'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode != 0:
|
||||
# Le service peut ne pas démarrer si déjà en cours, ce n'est pas grave
|
||||
logger.warning(f"batocera-services start warning: {result.stderr}")
|
||||
else:
|
||||
logger.debug(f"Service démarré: {result.stdout}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to start service (non-critical): {str(e)}")
|
||||
|
||||
success_msg = _("settings_custom_dns_success_enabled") if _ else "Custom DNS enabled at boot"
|
||||
logger.info(success_msg)
|
||||
|
||||
# Sauvegarder l'état dans rgsx_settings.json
|
||||
settings = load_rgsx_settings()
|
||||
settings["custom_dns_at_boot"] = True
|
||||
save_rgsx_settings(settings)
|
||||
|
||||
return (True, success_msg)
|
||||
|
||||
else:
|
||||
# Mode DISABLE
|
||||
logger.debug("Désactivation du service custom DNS au démarrage...")
|
||||
|
||||
# 1. Désactiver le service avec batocera-services
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['batocera-services', 'disable', 'custom_dns'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode != 0:
|
||||
error_msg = f"batocera-services disable failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
logger.debug(f"Service désactivé: {result.stdout}")
|
||||
except FileNotFoundError:
|
||||
error_msg = "batocera-services command not found"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to disable service: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
# 2. Arrêter le service immédiatement
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['batocera-services', 'stop', 'custom_dns'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode != 0:
|
||||
logger.warning(f"batocera-services stop warning: {result.stderr}")
|
||||
else:
|
||||
logger.debug(f"Service arrêté: {result.stdout}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to stop service (non-critical): {str(e)}")
|
||||
|
||||
success_msg = _("settings_custom_dns_success_disabled") if _ else "✓ Custom DNS disabled at boot"
|
||||
logger.info(success_msg)
|
||||
|
||||
# Sauvegarder l'état dans rgsx_settings.json
|
||||
settings = load_rgsx_settings()
|
||||
settings["custom_dns_at_boot"] = False
|
||||
save_rgsx_settings(settings)
|
||||
|
||||
return (True, success_msg)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Unexpected error: {str(e)}"
|
||||
logger.exception(error_msg)
|
||||
return (False, error_msg)
|
||||
|
||||
|
||||
def check_custom_dns_status():
|
||||
"""Vérifie si le service custom DNS est activé au démarrage.
|
||||
|
||||
Returns:
|
||||
bool: True si activé, False sinon
|
||||
"""
|
||||
try:
|
||||
if config.OPERATING_SYSTEM != "Linux":
|
||||
return False
|
||||
|
||||
# Lire l'état depuis rgsx_settings.json
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("custom_dns_at_boot", False)
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to check custom DNS status: {e}")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
_extensions_cache = None # type: ignore
|
||||
_extensions_json_regenerated = False
|
||||
@@ -1983,8 +2162,9 @@ def handle_xbox(dest_dir, iso_files, url=None):
|
||||
|
||||
|
||||
def play_random_music(music_files, music_folder, current_music=None):
|
||||
if not getattr(config, "music_enabled", True):
|
||||
pygame.mixer.music.stop()
|
||||
if not getattr(config, "music_enabled", True) or not is_mixer_available():
|
||||
if is_mixer_available():
|
||||
pygame.mixer.music.stop()
|
||||
return current_music
|
||||
if music_files:
|
||||
# Éviter de rejouer la même musique consécutivement
|
||||
@@ -1997,11 +2177,12 @@ def play_random_music(music_files, music_folder, current_music=None):
|
||||
|
||||
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
|
||||
if is_mixer_available():
|
||||
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)}")
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2.3.2.0"
|
||||
"version": "2.3.2.1"
|
||||
}
|
||||
Reference in New Issue
Block a user