mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-19 16:26:00 +01:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06c06d0223 | ||
|
|
18e5f6d637 | ||
|
|
d2a52c5a2e | ||
|
|
9df7a35e85 | ||
|
|
26f1f58d7a | ||
|
|
a9cdba3aa6 | ||
|
|
1a118247d9 | ||
|
|
5497727e2e | ||
|
|
56a6d6f17b |
62
.github/workflows/release.yml
vendored
62
.github/workflows/release.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
echo "Building RGSX package from ports/RGSX/ directory…"
|
||||
cd ports/RGSX
|
||||
|
||||
zip -r "../../dist/RGSX_${VERSION}.zip" . \
|
||||
zip -r "../../dist/RGSX_update_latest.zip" . \
|
||||
-x "logs/*" \
|
||||
"logs/**" \
|
||||
"images/*" \
|
||||
@@ -43,15 +43,13 @@ jobs:
|
||||
"*.log"
|
||||
|
||||
cd ../..
|
||||
|
||||
echo "Creating stable-named copy for latest download link…"
|
||||
cp -f "dist/RGSX_${VERSION}.zip" "dist/RGSX_latest.zip"
|
||||
cp -f "dist/RGSX_update_latest.zip" "dist/RGSX_latest.zip"
|
||||
|
||||
echo "✓ RGSX package created successfully"
|
||||
|
||||
echo ""
|
||||
echo "Building RGSX Retrobat package (includes ports/ and windows/ directories)…"
|
||||
zip -r "dist/RGSX_Retrobat_${VERSION}.zip" ports windows \
|
||||
echo "Building RGSX Full package (includes ports/ and windows/ directories)…"
|
||||
zip -r "dist/RGSX_full_latest.zip" ports windows \
|
||||
-x "ports/RGSX/logs/*" \
|
||||
"ports/RGSX/logs/**" \
|
||||
"ports/RGSX/images/*" \
|
||||
@@ -73,8 +71,6 @@ jobs:
|
||||
"*.xml" \
|
||||
"*.log"
|
||||
|
||||
echo "Creating stable-named copy for Retrobat package…"
|
||||
cp -f "dist/RGSX_Retrobat_${VERSION}.zip" "dist/RGSX_Retrobat_latest.zip"
|
||||
|
||||
echo "✓ All packages created successfully"
|
||||
ls -lh dist/
|
||||
@@ -88,28 +84,50 @@ jobs:
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: |
|
||||
## 📦 RGSX Release ${{ github.ref_name }}
|
||||
# 📦 RGSX Release ${{ github.ref_name }}
|
||||
|
||||
### 📥 Installation
|
||||
## 📥 Automatic Installation (Only for batocera Knulli)
|
||||
|
||||
### ON PC :
|
||||
1. Open File Manager (F1) then "Applications" and launch xterm
|
||||
2. Use the command line `curl -L bit.ly/rgsx-install | sh`
|
||||
3. Launch RGSX from "Ports" menu
|
||||
|
||||
### ON RASPBERRY/ARM SBC / HANDHELD :
|
||||
1. Connect your device with SSH on a computer/smartphone connected to same network (ssh root@IPADDRESS , pass:linux)
|
||||
2. Use the command line `curl -L bit.ly/rgsx-install | sh`
|
||||
3. Launch RGSX from "Ports" menu
|
||||
|
||||
## 📥 Manual Installation
|
||||
|
||||
#### Batocera/Knulli
|
||||
1. Download `RGSX_${{ github.ref_name }}.zip`
|
||||
2. Extract in `/userdata/roms/ports/RGSX/`
|
||||
### Batocera/Knulli
|
||||
1. Download latest release : https://github.com/RetroGameSets/RGSX/releases/latest/download/RGSX_full_latest.zip
|
||||
2. Extract only PORTS folder in `/userdata/roms/`
|
||||
3. Launch RGSX from the Ports menu
|
||||
|
||||
#### Retrobat/Windows
|
||||
1. `RGSX_Retrobat_${{ github.ref_name }}.zip`
|
||||
2. Extract in retrobat/roms (les dossiers `ports/` et `windows/` seront créés automatiquement)
|
||||
### Retrobat/Full Installation on Windows
|
||||
1. Download latest release : https://github.com/RetroGameSets/RGSX/releases/latest/download/RGSX_full_latest.zip
|
||||
2. Extract all folders in your Retrobat\roms folder
|
||||
3. Launch RGSX from system "Windows"
|
||||
|
||||
|
||||
## 📥 Manual Update (you shouldn't need to do this as RGSX updates automatically on each start)
|
||||
|
||||
#### Batocera/Knulli
|
||||
1. Download latest update : https://github.com/RetroGameSets/RGSX/releases/latest/download/RGSX_update_latest.zip
|
||||
2. Extract only PORTS folder in `/userdata/roms/`
|
||||
3. Launch RGSX from the Ports menu
|
||||
|
||||
#### Retrobat
|
||||
1. Download latest update : https://github.com/RetroGameSets/RGSX/releases/latest/download/RGSX_update_latest.zip
|
||||
2. Extract all folders in your Retrobat\roms folder
|
||||
3. Launch RGSX from system "Windows"
|
||||
|
||||
|
||||
### 📖 Documentation
|
||||
[]README.md](https://github.com/${{ github.repository }}/blob/main/README.md)
|
||||
[README.md](https://github.com/${{ github.repository }}/blob/main/README.md)
|
||||
files: |
|
||||
dist/RGSX_${{ github.ref_name }}.zip
|
||||
dist/RGSX_latest.zip
|
||||
dist/RGSX_Retrobat_${{ github.ref_name }}.zip
|
||||
dist/RGSX_Retrobat_latest.zip
|
||||
dist/RGSX_latest.zip
|
||||
dist/RGSX_update_latest.zip
|
||||
dist/RGSX_full_latest.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,4 +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
|
||||
#!/usr/bin/env python3
|
||||
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||
python3 "$SCRIPT_DIR/__main__.py"
|
||||
103
ports/RGSX/assets/progs/rgsx_web
Normal file
103
ports/RGSX/assets/progs/rgsx_web
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# BATOCERA SERVICE
|
||||
# name: RGSX Web Service for Batocera
|
||||
# description: Automatic launch Web interface service for RGSX
|
||||
# author: RetroGameSets / ninao.xyz
|
||||
# depends: python3
|
||||
# version: 1.3
|
||||
|
||||
SCRIPT="/userdata/roms/ports/RGSX/rgsx_web.py"
|
||||
PYTHON="/usr/bin/python3"
|
||||
PIDFILE="/var/run/rgsx_web.pid"
|
||||
LOGFILE="/userdata/roms/ports/RGSX/LOGS/rgsx_web_service.log"
|
||||
SERVICE_NAME="rgsx_web"
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ ! -f "$SCRIPT" ]; then
|
||||
echo "[${SERVICE_NAME}] Error: script not found at $SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") 2>/dev/null; then
|
||||
echo "[${SERVICE_NAME}] Already running (PID $(cat "$PIDFILE"))"
|
||||
exit 0
|
||||
fi
|
||||
echo "[${SERVICE_NAME}] Starting..."
|
||||
mkdir -p "$(dirname "$LOGFILE")"
|
||||
$PYTHON "$SCRIPT" >> "$LOGFILE" 2>&1 &
|
||||
echo $! > "$PIDFILE"
|
||||
echo "[${SERVICE_NAME}] Started (PID $(cat "$PIDFILE"))"
|
||||
;;
|
||||
|
||||
stop)
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
echo "[${SERVICE_NAME}] Stopping..."
|
||||
kill $(cat "$PIDFILE") 2>/dev/null && rm -f "$PIDFILE"
|
||||
echo "[${SERVICE_NAME}] Stopped"
|
||||
else
|
||||
pkill -f "$PYTHON $SCRIPT" && echo "[${SERVICE_NAME}] Stopped (no PID file)"
|
||||
fi
|
||||
;;
|
||||
|
||||
restart)
|
||||
echo "[${SERVICE_NAME}] Restarting..."
|
||||
"$0" stop
|
||||
sleep 1
|
||||
"$0" start
|
||||
;;
|
||||
|
||||
status)
|
||||
ENABLE_STATE=$(is_enabled)
|
||||
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") 2>/dev/null; then
|
||||
echo "[${SERVICE_NAME}] Running (PID $(cat "$PIDFILE")) - ${ENABLE_STATE} on boot"
|
||||
exit 0
|
||||
elif pgrep -f "$PYTHON $SCRIPT" > /dev/null; then
|
||||
echo "[${SERVICE_NAME}] Running (detected without PID file) - ${ENABLE_STATE} on boot"
|
||||
exit 0
|
||||
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}"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -13,7 +13,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "2.3.0.4.1"
|
||||
app_version = "2.3.0.8"
|
||||
|
||||
|
||||
def get_application_root():
|
||||
@@ -97,7 +97,7 @@ GITHUB_RELEASES_URL = f"https://github.com/{GITHUB_REPO}/releases"
|
||||
|
||||
# URLs pour les mises à jour OTA (Over-The-Air)
|
||||
# Utilise le fichier RGSX_latest.zip qui pointe toujours vers la dernière version
|
||||
OTA_UPDATE_ZIP = f"{GITHUB_RELEASES_URL}/latest/download/RGSX_latest.zip"
|
||||
OTA_UPDATE_ZIP = f"{GITHUB_RELEASES_URL}/latest/download/RGSX_update_latest.zip"
|
||||
OTA_VERSION_ENDPOINT = "https://retrogamesets.fr/softs/version.json" # Endpoint pour vérifier la version disponible
|
||||
|
||||
# URLs legacy (conservées pour compatibilité)
|
||||
|
||||
@@ -1609,7 +1609,13 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Sous-menu Settings
|
||||
elif config.menu_state == "pause_settings_menu":
|
||||
sel = getattr(config, 'pause_settings_selection', 0)
|
||||
# Calculer le nombre total d'options selon le système
|
||||
total = 4 # music, symlink, api keys, back
|
||||
web_service_index = -1
|
||||
if config.OPERATING_SYSTEM == "Linux":
|
||||
total = 5 # music, symlink, web_service, api keys, back
|
||||
web_service_index = 2
|
||||
|
||||
if is_input_matched(event, "up"):
|
||||
config.pause_settings_selection = (sel - 1) % total
|
||||
config.needs_redraw = True
|
||||
@@ -1618,6 +1624,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right"):
|
||||
sel = getattr(config, 'pause_settings_selection', 0)
|
||||
# Option 0: Music toggle
|
||||
if sel == 0 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
config.music_enabled = not config.music_enabled
|
||||
save_music_config()
|
||||
@@ -1630,6 +1637,7 @@ def handle_controls(event, sources, joystick, screen):
|
||||
pygame.mixer.music.stop()
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Musique {'activée' if config.music_enabled else 'désactivée'} via settings")
|
||||
# Option 1: Symlink toggle
|
||||
elif sel == 1 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
from rgsx_settings import set_symlink_option, get_symlink_option
|
||||
current_status = get_symlink_option()
|
||||
@@ -1638,10 +1646,32 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.popup_timer = 3000 if success else 5000
|
||||
config.needs_redraw = True
|
||||
logger.info(f"Symlink option {'activée' if not current_status else 'désactivée'} via settings")
|
||||
elif sel == 2 and is_input_matched(event, "confirm"):
|
||||
# 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")):
|
||||
from utils import toggle_web_service_at_boot, check_web_service_status
|
||||
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")
|
||||
config.popup_timer = 1000
|
||||
config.needs_redraw = True
|
||||
# Exécuter en thread pour ne pas bloquer l'UI
|
||||
import threading
|
||||
def toggle_service():
|
||||
success, message = toggle_web_service_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 web {'activé' if not current_status else 'désactivé'} au démarrage")
|
||||
else:
|
||||
logger.error(f"Erreur toggle service web: {message}")
|
||||
threading.Thread(target=toggle_service, 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"):
|
||||
config.menu_state = "pause_api_keys_status"
|
||||
config.needs_redraw = True
|
||||
elif sel == 3 and is_input_matched(event, "confirm"):
|
||||
# Option Back (dernière option)
|
||||
elif sel == (total - 1) and is_input_matched(event, "confirm"):
|
||||
config.menu_state = "pause_menu"
|
||||
config.last_state_change_time = pygame.time.get_ticks()
|
||||
config.needs_redraw = True
|
||||
|
||||
@@ -2040,6 +2040,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
|
||||
# Music
|
||||
if config.music_enabled:
|
||||
music_name = config.current_music_name or ""
|
||||
@@ -2057,16 +2058,34 @@ def draw_pause_settings_menu(screen, selected_index):
|
||||
if ' : ' in symlink_option:
|
||||
base, val = symlink_option.split(' : ',1)
|
||||
symlink_option = f"{base} : < {val.strip()} >"
|
||||
|
||||
# Web Service at boot (only on Linux/Batocera)
|
||||
web_service_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} >"
|
||||
|
||||
api_keys_txt = _("menu_api_keys_status") if _ else "API Keys"
|
||||
back_txt = _("menu_back") if _ else "Back"
|
||||
options = [music_option, symlink_option, api_keys_txt, back_txt]
|
||||
|
||||
# Construction de la liste des options
|
||||
options = [music_option, symlink_option]
|
||||
if web_service_txt: # Ajouter seulement si Linux/Batocera
|
||||
options.append(web_service_txt)
|
||||
options.extend([api_keys_txt, back_txt])
|
||||
|
||||
_draw_submenu_generic(screen, _("menu_settings_category") if _ else "Settings", options, selected_index)
|
||||
instruction_keys = [
|
||||
"instruction_settings_music",
|
||||
"instruction_settings_symlink",
|
||||
]
|
||||
if web_service_txt:
|
||||
instruction_keys.append("instruction_settings_web_service")
|
||||
instruction_keys.extend([
|
||||
"instruction_settings_api_keys",
|
||||
"instruction_generic_back",
|
||||
]
|
||||
])
|
||||
key = instruction_keys[selected_index] if 0 <= selected_index < len(instruction_keys) else None
|
||||
if key:
|
||||
button_height = int(config.screen_height * 0.045)
|
||||
@@ -2182,6 +2201,7 @@ def draw_pause_api_keys_status(screen):
|
||||
hint_rect = hint_surf.get_rect(center=(config.screen_width//2, menu_y + menu_height - 30))
|
||||
screen.blit(hint_surf, hint_rect)
|
||||
|
||||
|
||||
def draw_filter_platforms_menu(screen):
|
||||
"""Affiche le menu de filtrage des plateformes (afficher/masquer)."""
|
||||
from rgsx_settings import load_rgsx_settings
|
||||
|
||||
@@ -202,6 +202,15 @@
|
||||
,"instruction_settings_music": "Hintergrundmusik aktivieren oder deaktivieren"
|
||||
,"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"
|
||||
,"settings_web_service": "Web-Dienst beim Booten"
|
||||
,"settings_web_service_enabled": "Aktiviert"
|
||||
,"settings_web_service_disabled": "Deaktiviert"
|
||||
,"settings_web_service_enabling": "Web-Dienst wird aktiviert..."
|
||||
,"settings_web_service_disabling": "Web-Dienst wird deaktiviert..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Bestätigen (z.B. A/Kreuz)"
|
||||
,"controls_desc_cancel": "Abbrechen/Zurück (z.B. B/Kreis)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -203,6 +203,15 @@
|
||||
,"instruction_settings_music": "Enable or disable background music playback"
|
||||
,"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"
|
||||
,"settings_web_service": "Web Service at Boot"
|
||||
,"settings_web_service_enabled": "Enabled"
|
||||
,"settings_web_service_disabled": "Disabled"
|
||||
,"settings_web_service_enabling": "Enabling web service..."
|
||||
,"settings_web_service_disabling": "Disabling web service..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Confirm (e.g. A/Cross)"
|
||||
,"controls_desc_cancel": "Cancel/Back (e.g. B/Circle)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -202,6 +202,15 @@
|
||||
,"instruction_settings_music": "Activar o desactivar música de fondo"
|
||||
,"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"
|
||||
,"settings_web_service": "Servicio Web al Inicio"
|
||||
,"settings_web_service_enabled": "Activado"
|
||||
,"settings_web_service_disabled": "Desactivado"
|
||||
,"settings_web_service_enabling": "Activando servicio web..."
|
||||
,"settings_web_service_disabling": "Desactivando servicio web..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Confirmar (ej. A/Cruz)"
|
||||
,"controls_desc_cancel": "Cancelar/Volver (ej. B/Círculo)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -203,6 +203,15 @@
|
||||
,"instruction_settings_music": "Activer ou désactiver la lecture musicale"
|
||||
,"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"
|
||||
,"settings_web_service": "Service Web au démarrage"
|
||||
,"settings_web_service_enabled": "Activé"
|
||||
,"settings_web_service_disabled": "Désactivé"
|
||||
,"settings_web_service_enabling": "Activation du service web..."
|
||||
,"settings_web_service_disabling": "Désactivation du service web..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Valider (ex: A/Croix)"
|
||||
,"controls_desc_cancel": "Annuler/Retour (ex: B/Rond)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -196,6 +196,15 @@
|
||||
,"instruction_settings_music": "Abilitare o disabilitare musica di sottofondo"
|
||||
,"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"
|
||||
,"settings_web_service": "Servizio Web all'Avvio"
|
||||
,"settings_web_service_enabled": "Abilitato"
|
||||
,"settings_web_service_disabled": "Disabilitato"
|
||||
,"settings_web_service_enabling": "Abilitazione servizio web..."
|
||||
,"settings_web_service_disabling": "Disabilitazione servizio web..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Confermare (es. A/Croce)"
|
||||
,"controls_desc_cancel": "Annullare/Indietro (es. B/Cerchio)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -196,6 +196,15 @@
|
||||
,"instruction_settings_music": "Ativar ou desativar música de fundo"
|
||||
,"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"
|
||||
,"settings_web_service": "Serviço Web na Inicialização"
|
||||
,"settings_web_service_enabled": "Ativado"
|
||||
,"settings_web_service_disabled": "Desativado"
|
||||
,"settings_web_service_enabling": "Ativando serviço web..."
|
||||
,"settings_web_service_disabling": "Desativando serviço web..."
|
||||
,"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}"
|
||||
,"controls_desc_confirm": "Confirmar (ex. A/Cruz)"
|
||||
,"controls_desc_cancel": "Cancelar/Voltar (ex. B/Círculo)"
|
||||
,"controls_desc_up": "UP ↑"
|
||||
|
||||
@@ -495,7 +495,7 @@ async def check_for_updates():
|
||||
|
||||
# Créer le dossier UPDATE_FOLDER s'il n'existe pas
|
||||
os.makedirs(UPDATE_FOLDER, exist_ok=True)
|
||||
update_zip_path = os.path.join(UPDATE_FOLDER, f"RGSX_v{latest_version}.zip")
|
||||
update_zip_path = os.path.join(UPDATE_FOLDER, f"RGSX_update_v{latest_version}.zip")
|
||||
logger.debug(f"Téléchargement de {UPDATE_ZIP} vers {update_zip_path}")
|
||||
|
||||
# Télécharger le ZIP
|
||||
|
||||
@@ -69,7 +69,8 @@ def load_rgsx_settings():
|
||||
},
|
||||
"show_unsupported_platforms": False,
|
||||
"allow_unknown_extensions": False,
|
||||
"roms_folder": ""
|
||||
"roms_folder": "",
|
||||
"web_service_at_boot": False
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
@@ -16,7 +16,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
import glob
|
||||
import threading
|
||||
from rgsx_settings import load_rgsx_settings, save_rgsx_settings
|
||||
from rgsx_settings import load_rgsx_settings, save_rgsx_settings, get_allow_unknown_extensions
|
||||
import zipfile
|
||||
import time
|
||||
import random
|
||||
@@ -25,6 +25,7 @@ from history import save_history
|
||||
from language import _
|
||||
from datetime import datetime
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -85,9 +86,7 @@ def generate_support_zip():
|
||||
Returns:
|
||||
tuple: (success: bool, message: str, zip_path: str ou None)
|
||||
"""
|
||||
import zipfile
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
try:
|
||||
# Créer un fichier ZIP temporaire
|
||||
@@ -162,6 +161,146 @@ DO NOT share this file publicly as it may contain sensitive information.
|
||||
logger.error(f"Erreur lors de la génération du fichier de support: {e}")
|
||||
return (False, str(e), None)
|
||||
|
||||
|
||||
def toggle_web_service_at_boot(enable: bool):
|
||||
"""Active ou désactive le service web 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, "Web service auto-start is only available on Batocera/Linux systems")
|
||||
|
||||
services_dir = "/userdata/system/services"
|
||||
service_file = os.path.join(services_dir, "rgsx_web")
|
||||
source_file = os.path.join(config.APP_FOLDER, "assets", "progs", "rgsx_web")
|
||||
|
||||
if enable:
|
||||
# Mode ENABLE
|
||||
logger.debug("Activation du service web 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 rgsx_web
|
||||
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', 'rgsx_web'],
|
||||
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', 'rgsx_web'],
|
||||
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_web_service_success_enabled") if _ else "Web service enabled at boot"
|
||||
logger.info(success_msg)
|
||||
|
||||
# Sauvegarder l'état dans rgsx_settings.json
|
||||
settings = load_rgsx_settings()
|
||||
settings["web_service_at_boot"] = True
|
||||
save_rgsx_settings(settings)
|
||||
|
||||
return (True, success_msg)
|
||||
|
||||
else:
|
||||
# Mode DISABLE
|
||||
logger.debug("Désactivation du service web au démarrage...")
|
||||
|
||||
# 1. Désactiver le service avec batocera-services
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['batocera-services', 'disable', 'rgsx_web'],
|
||||
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)
|
||||
|
||||
success_msg = _("settings_web_service_success_disabled") if _ else "✓ Web service disabled at boot"
|
||||
logger.info(success_msg)
|
||||
|
||||
# Sauvegarder l'état dans rgsx_settings.json
|
||||
settings = load_rgsx_settings()
|
||||
settings["web_service_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)
|
||||
|
||||
|
||||
|
||||
_extensions_cache = None # type: ignore
|
||||
_extensions_json_regenerated = False
|
||||
|
||||
@@ -385,7 +524,6 @@ def check_extension_before_download(url, platform, game_name):
|
||||
# Autoriser si l'utilisateur a choisi d'autoriser les extensions inconnues
|
||||
allow_unknown = False
|
||||
try:
|
||||
from rgsx_settings import get_allow_unknown_extensions
|
||||
allow_unknown = get_allow_unknown_extensions()
|
||||
except Exception:
|
||||
allow_unknown = False
|
||||
@@ -1052,7 +1190,6 @@ def extract_zip(zip_path, dest_dir, url):
|
||||
if os.path.isdir(file_path):
|
||||
logger.warning(f"Conflit: dossier existant avec le même nom que le fichier {file_path}, suppression du dossier")
|
||||
try:
|
||||
import shutil
|
||||
shutil.rmtree(file_path)
|
||||
except Exception as rm_err:
|
||||
logger.error(f"Impossible de supprimer le dossier {file_path}: {rm_err}")
|
||||
@@ -1890,6 +2027,26 @@ def save_music_config():
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors de la sauvegarde de la configuration musique: {str(e)}")
|
||||
|
||||
def check_web_service_status():
|
||||
"""Vérifie si le service web 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("web_service_at_boot", False)
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to check web service status: {e}")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def normalize_platform_name(platform):
|
||||
"""Normalise un nom de plateforme en supprimant espaces et convertissant en minuscules."""
|
||||
|
||||
Reference in New Issue
Block a user