forked from Mirrors/RGSX
v2.2.2.4
- correct ps3 extracting/folder_rename bug - added support for Anbernic RG35XX - added support for local custom source of games (games.zip) in /saves/ports/rgsx folder when choose "custom source" on rgsx games settings.
This commit is contained in:
@@ -13,7 +13,7 @@ except Exception:
|
|||||||
pygame = None # type: ignore
|
pygame = None # type: ignore
|
||||||
|
|
||||||
# Version actuelle de l'application
|
# Version actuelle de l'application
|
||||||
app_version = "2.2.2.3"
|
app_version = "2.2.2.4"
|
||||||
|
|
||||||
|
|
||||||
def get_application_root():
|
def get_application_root():
|
||||||
|
|||||||
@@ -720,6 +720,11 @@ def extract_zip_data(zip_path, dest_dir, url):
|
|||||||
"""Extrait le contenu du fichier ZIP dans le dossier config.APP_FOLDER sans progression a l'ecran"""
|
"""Extrait le contenu du fichier ZIP dans le dossier config.APP_FOLDER sans progression a l'ecran"""
|
||||||
logger.debug(f"Extraction de {zip_path} dans {dest_dir}")
|
logger.debug(f"Extraction de {zip_path} dans {dest_dir}")
|
||||||
try:
|
try:
|
||||||
|
# Capture existing directories before extraction to identify the newly created one(s)
|
||||||
|
try:
|
||||||
|
before_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
before_dirs = set()
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
zip_ref.testzip() # Vérifier l'intégrité de l'archive
|
zip_ref.testzip() # Vérifier l'intégrité de l'archive
|
||||||
for info in zip_ref.infolist():
|
for info in zip_ref.infolist():
|
||||||
@@ -730,6 +735,19 @@ def extract_zip_data(zip_path, dest_dir, url):
|
|||||||
with zip_ref.open(info) as source, open(file_path, 'wb') as dest:
|
with zip_ref.open(info) as source, open(file_path, 'wb') as dest:
|
||||||
shutil.copyfileobj(source, dest)
|
shutil.copyfileobj(source, dest)
|
||||||
logger.info(f"Extraction terminée de {zip_path}")
|
logger.info(f"Extraction terminée de {zip_path}")
|
||||||
|
# PS3: renommer uniquement le dossier nouvellement extrait (parité avec RAR)
|
||||||
|
ps3_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), "ps3")
|
||||||
|
if dest_dir == ps3_dir:
|
||||||
|
try:
|
||||||
|
after_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
after_dirs = set()
|
||||||
|
ignore_names = {"ps3", "images", "videos", "manuals", "media"}
|
||||||
|
new_dirs = [d for d in (after_dirs - before_dirs) if d not in ignore_names and not d.endswith('.ps3')]
|
||||||
|
expected_base = os.path.splitext(os.path.basename(zip_path))[0]
|
||||||
|
success, error_msg = handle_ps3(dest_dir, new_dirs=new_dirs, extracted_basename=expected_base)
|
||||||
|
if not success:
|
||||||
|
return False, error_msg
|
||||||
return True, "Extraction terminée avec succès"
|
return True, "Extraction terminée avec succès"
|
||||||
except zipfile.BadZipFile as e:
|
except zipfile.BadZipFile as e:
|
||||||
logger.error(f"Erreur: Archive ZIP corrompue: {str(e)}")
|
logger.error(f"Erreur: Archive ZIP corrompue: {str(e)}")
|
||||||
@@ -754,6 +772,12 @@ def extract_zip(zip_path, dest_dir, url):
|
|||||||
if file.lower().endswith('.iso'):
|
if file.lower().endswith('.iso'):
|
||||||
iso_before.add(os.path.abspath(os.path.join(root, file)))
|
iso_before.add(os.path.abspath(os.path.join(root, file)))
|
||||||
|
|
||||||
|
# Capturer les dossiers avant extraction (pour détection PS3)
|
||||||
|
try:
|
||||||
|
before_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
before_dirs = set()
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
zip_ref.testzip() # Vérifier l'intégrité de l'archive
|
zip_ref.testzip() # Vérifier l'intégrité de l'archive
|
||||||
total_size = sum(info.file_size for info in zip_ref.infolist() if not info.is_dir())
|
total_size = sum(info.file_size for info in zip_ref.infolist() if not info.is_dir())
|
||||||
@@ -817,6 +841,20 @@ def extract_zip(zip_path, dest_dir, url):
|
|||||||
logger.warning("Aucun nouvel ISO détecté après extraction pour conversion Xbox.")
|
logger.warning("Aucun nouvel ISO détecté après extraction pour conversion Xbox.")
|
||||||
# On ne retourne pas d'erreur fatale ici, on continue
|
# On ne retourne pas d'erreur fatale ici, on continue
|
||||||
|
|
||||||
|
# PS3: renommer uniquement le dossier nouvellement extrait (parité avec RAR)
|
||||||
|
ps3_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), "ps3")
|
||||||
|
if dest_dir == ps3_dir:
|
||||||
|
try:
|
||||||
|
after_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
after_dirs = set()
|
||||||
|
ignore_names = {"ps3", "images", "videos", "manuals", "media"}
|
||||||
|
new_dirs = [d for d in (after_dirs - before_dirs) if d not in ignore_names and not d.endswith('.ps3')]
|
||||||
|
expected_base = os.path.splitext(os.path.basename(zip_path))[0]
|
||||||
|
success, error_msg = handle_ps3(dest_dir, new_dirs=new_dirs, extracted_basename=expected_base)
|
||||||
|
if not success:
|
||||||
|
return False, error_msg
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.remove(zip_path)
|
os.remove(zip_path)
|
||||||
logger.info(f"Fichier ZIP {zip_path} extrait dans {dest_dir} et supprimé")
|
logger.info(f"Fichier ZIP {zip_path} extrait dans {dest_dir} et supprimé")
|
||||||
@@ -910,7 +948,7 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
root_dir = file_name.split('/')[0] if '/' in file_name else ''
|
root_dir = file_name.split('/')[0] if '/' in file_name else ''
|
||||||
if root_dir:
|
if root_dir:
|
||||||
root_dirs.add(root_dir)
|
root_dirs.add(root_dir)
|
||||||
logger.debug(f"Ligne parsée: {file_name}, taille: {file_size}, date: {file_date}")
|
#logger.debug(f"Ligne parsée: {file_name}, taille: {file_size}, date: {file_date}")
|
||||||
else:
|
else:
|
||||||
logger.debug(f"Dossier ignoré: {file_name}")
|
logger.debug(f"Dossier ignoré: {file_name}")
|
||||||
else:
|
else:
|
||||||
@@ -933,10 +971,28 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
config.download_progress[url]["status"] = "Extracting"
|
config.download_progress[url]["status"] = "Extracting"
|
||||||
config.download_progress[url]["progress_percent"] = 0
|
config.download_progress[url]["progress_percent"] = 0
|
||||||
config.needs_redraw = True
|
config.needs_redraw = True
|
||||||
|
# Mettre à jour l'historique pour indiquer le début d'extraction
|
||||||
|
try:
|
||||||
|
if isinstance(config.history, list):
|
||||||
|
for entry in config.history:
|
||||||
|
if entry.get("url") == url and entry.get("status") in ["Téléchargement", "downloading", "Extracting"]:
|
||||||
|
entry["status"] = "Extracting"
|
||||||
|
entry["progress"] = 0
|
||||||
|
entry["message"] = "Extraction en cours"
|
||||||
|
save_history(config.history)
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Erreur lors de la mise à jour de la progression: {str(e)}")
|
logger.error(f"Erreur lors de la mise à jour de la progression: {str(e)}")
|
||||||
# Continuer l'extraction même en cas d'erreur de mise à jour de la progression
|
# Continuer l'extraction même en cas d'erreur de mise à jour de la progression
|
||||||
|
|
||||||
|
# Capture existing directories before extraction to identify the newly created one(s)
|
||||||
|
try:
|
||||||
|
before_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
before_dirs = set()
|
||||||
|
|
||||||
escaped_rar_path = rar_path.replace(" ", "\\ ")
|
escaped_rar_path = rar_path.replace(" ", "\\ ")
|
||||||
escaped_dest_dir = dest_dir.replace(" ", "\\ ")
|
escaped_dest_dir = dest_dir.replace(" ", "\\ ")
|
||||||
process = subprocess.Popen(unrar_cmd + ['x', '-y', escaped_rar_path, escaped_dest_dir],
|
process = subprocess.Popen(unrar_cmd + ['x', '-y', escaped_rar_path, escaped_dest_dir],
|
||||||
@@ -948,6 +1004,9 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
return False, f"Erreur lors de l'extraction: {stderr}"
|
return False, f"Erreur lors de l'extraction: {stderr}"
|
||||||
|
|
||||||
extracted_size = 0
|
extracted_size = 0
|
||||||
|
# Sauvegarde périodique de l'historique (comme ZIP)
|
||||||
|
last_save_time = time.time()
|
||||||
|
save_interval = 0.5
|
||||||
extracted_files = []
|
extracted_files = []
|
||||||
total_files = len(files_to_extract)
|
total_files = len(files_to_extract)
|
||||||
for i, (expected_file, file_size) in enumerate(files_to_extract):
|
for i, (expected_file, file_size) in enumerate(files_to_extract):
|
||||||
@@ -956,14 +1015,31 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
extracted_size += file_size
|
extracted_size += file_size
|
||||||
extracted_files.append(expected_file)
|
extracted_files.append(expected_file)
|
||||||
os.chmod(file_path, 0o644)
|
os.chmod(file_path, 0o644)
|
||||||
logger.debug(f"Fichier extrait: {expected_file}, taille: {file_size}, chemin: {file_path}")
|
#logger.debug(f"Fichier extrait: {expected_file}, taille: {file_size}, chemin: {file_path}")
|
||||||
try:
|
try:
|
||||||
with lock:
|
with lock:
|
||||||
if url in config.download_progress:
|
if url in config.download_progress:
|
||||||
|
percent = int(((i + 1) / total_files * 100)) if total_files > 0 else 0
|
||||||
|
percent = max(0, min(100, percent))
|
||||||
config.download_progress[url]["downloaded_size"] = extracted_size
|
config.download_progress[url]["downloaded_size"] = extracted_size
|
||||||
config.download_progress[url]["status"] = "Extracting"
|
config.download_progress[url]["status"] = "Extracting"
|
||||||
config.download_progress[url]["progress_percent"] = ((i + 1) / total_files * 100) if total_files > 0 else 0
|
config.download_progress[url]["progress_percent"] = percent
|
||||||
config.needs_redraw = True
|
config.needs_redraw = True
|
||||||
|
# MAJ historique (progression extraction)
|
||||||
|
try:
|
||||||
|
if isinstance(config.history, list):
|
||||||
|
for entry in config.history:
|
||||||
|
if entry.get("url") == url and entry.get("status") in ["Téléchargement", "Extracting", "downloading"]:
|
||||||
|
entry["status"] = "Extracting"
|
||||||
|
entry["progress"] = percent
|
||||||
|
entry["message"] = "Extraction en cours"
|
||||||
|
now = time.time()
|
||||||
|
if now - last_save_time >= save_interval:
|
||||||
|
save_history(config.history)
|
||||||
|
last_save_time = now
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Erreur lors de la mise à jour de la progression d'extraction: {str(e)}")
|
logger.error(f"Erreur lors de la mise à jour de la progression d'extraction: {str(e)}")
|
||||||
# Continuer l'extraction même en cas d'erreur de mise à jour de la progression
|
# Continuer l'extraction même en cas d'erreur de mise à jour de la progression
|
||||||
@@ -971,9 +1047,18 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
logger.warning(f"Fichier non trouvé après extraction: {expected_file}")
|
logger.warning(f"Fichier non trouvé après extraction: {expected_file}")
|
||||||
|
|
||||||
# Vérifier si c'est un dossier PS3 et le traiter si nécessaire
|
# Vérifier si c'est un dossier PS3 et le traiter si nécessaire
|
||||||
ps3_dir = os.path.join(os.path.dirname(os.path.dirname(config.APP_FOLDER)), "ps3")
|
ps3_dir = os.path.join(config.ROMS_FOLDER, "ps3")
|
||||||
if dest_dir == ps3_dir:
|
if dest_dir == ps3_dir:
|
||||||
success, error_msg = handle_ps3(dest_dir)
|
# Déterminer les nouveaux dossiers créés par cette extraction
|
||||||
|
try:
|
||||||
|
after_dirs = set([d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))])
|
||||||
|
except Exception:
|
||||||
|
after_dirs = set()
|
||||||
|
ignore_names = {"ps3", "images", "videos", "manuals", "media"}
|
||||||
|
new_dirs = [d for d in (after_dirs - before_dirs) if d not in ignore_names and not d.endswith('.ps3')]
|
||||||
|
# Nom attendu à partir du nom de l'archive
|
||||||
|
expected_base = os.path.splitext(os.path.basename(rar_path))[0]
|
||||||
|
success, error_msg = handle_ps3(dest_dir, new_dirs=new_dirs, extracted_basename=expected_base)
|
||||||
if not success:
|
if not success:
|
||||||
return False, error_msg
|
return False, error_msg
|
||||||
|
|
||||||
@@ -981,6 +1066,29 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
for dir_name in dirs:
|
for dir_name in dirs:
|
||||||
os.chmod(os.path.join(root, dir_name), 0o755)
|
os.chmod(os.path.join(root, dir_name), 0o755)
|
||||||
|
|
||||||
|
# Finaliser: marquer comme terminé dans l'historique et la progression
|
||||||
|
try:
|
||||||
|
# Mettre à jour l'historique final
|
||||||
|
if isinstance(config.history, list):
|
||||||
|
for entry in config.history:
|
||||||
|
if entry.get("url") == url and entry.get("status") in ("Extracting", "Téléchargement", "downloading"):
|
||||||
|
entry["status"] = "Download_OK"
|
||||||
|
entry["progress"] = 100
|
||||||
|
message_text = _("utils_extracted").format(os.path.basename(rar_path))
|
||||||
|
entry["message"] = message_text
|
||||||
|
save_history(config.history)
|
||||||
|
config.needs_redraw = True
|
||||||
|
break
|
||||||
|
# Mettre à jour la progression
|
||||||
|
if url in getattr(config, 'download_progress', {}):
|
||||||
|
try:
|
||||||
|
config.download_progress[url]["status"] = "Download_OK"
|
||||||
|
config.download_progress[url]["progress_percent"] = 100
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"MAJ statut final après extraction RAR: ignorée ({e})")
|
||||||
|
|
||||||
os.remove(rar_path)
|
os.remove(rar_path)
|
||||||
logger.info(f"Fichier RAR {rar_path} extrait dans {dest_dir} et supprimé")
|
logger.info(f"Fichier RAR {rar_path} extrait dans {dest_dir} et supprimé")
|
||||||
return True, "RAR extrait avec succès"
|
return True, "RAR extrait avec succès"
|
||||||
@@ -996,29 +1104,59 @@ def extract_rar(rar_path, dest_dir, url):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Erreur lors de la suppression de {rar_path}: {str(e)}")
|
logger.error(f"Erreur lors de la suppression de {rar_path}: {str(e)}")
|
||||||
|
|
||||||
def handle_ps3(dest_dir):
|
def handle_ps3(dest_dir, new_dirs=None, extracted_basename=None):
|
||||||
"""Gère le renommage spécifique des dossiers PS3 extraits."""
|
"""Gère le renommage spécifique des dossiers PS3 extraits.
|
||||||
|
|
||||||
|
- Si new_dirs est fourni, ne considère que ces dossiers.
|
||||||
|
- Ignore les dossiers système connus: images, videos, manuals, ps3, media.
|
||||||
|
- Essaie de faire correspondre le dossier attendu au nom du RAR (underscores -> espaces).
|
||||||
|
"""
|
||||||
logger.debug(f"Traitement spécifique PS3 dans: {dest_dir}")
|
logger.debug(f"Traitement spécifique PS3 dans: {dest_dir}")
|
||||||
|
time.sleep(2) # petite latence post-extraction
|
||||||
|
|
||||||
# Attendre un peu que tous les processus d'extraction se terminent
|
ignore_names = {"ps3", "images", "videos", "manuals", "media"}
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# Rechercher le dossier extrait directement dans dest_dir
|
if new_dirs is None:
|
||||||
extracted_dirs = [d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))]
|
try:
|
||||||
logger.debug(f"Dossiers trouvés dans {dest_dir}: {extracted_dirs}")
|
candidates = [d for d in os.listdir(dest_dir) if os.path.isdir(os.path.join(dest_dir, d))]
|
||||||
|
except Exception:
|
||||||
|
candidates = []
|
||||||
|
else:
|
||||||
|
candidates = list(new_dirs)
|
||||||
|
|
||||||
# Filtrer pour ne garder que les dossiers nouvellement extraits
|
# Filtrer: ignorer .ps3 déjà traité et dossiers système
|
||||||
ps3_dirs = [d for d in extracted_dirs if not d.endswith('.ps3')]
|
ps3_dirs = [d for d in candidates if not d.endswith('.ps3') and d not in ignore_names]
|
||||||
logger.debug(f"Dossiers PS3 à renommer: {ps3_dirs}")
|
logger.debug(f"Dossiers PS3 candidats: {ps3_dirs}")
|
||||||
|
|
||||||
if len(ps3_dirs) == 1:
|
# Tenter une correspondance au nom de l'archive (remplacer '_' -> ' ' et normaliser)
|
||||||
old_path = os.path.join(dest_dir, ps3_dirs[0])
|
target = None
|
||||||
new_path = os.path.join(dest_dir, f"{ps3_dirs[0]}.ps3")
|
if extracted_basename:
|
||||||
|
def norm(s: str) -> str:
|
||||||
|
s = s.replace('_', ' ')
|
||||||
|
s = ' '.join(s.split()).strip().lower()
|
||||||
|
return s
|
||||||
|
expected = norm(extracted_basename)
|
||||||
|
for d in ps3_dirs:
|
||||||
|
if norm(d) == expected:
|
||||||
|
target = d
|
||||||
|
break
|
||||||
|
# Si pas de match exact: si un seul candidat, prendre celui-ci
|
||||||
|
if target is None and len(ps3_dirs) == 1:
|
||||||
|
target = ps3_dirs[0]
|
||||||
|
|
||||||
|
if not target:
|
||||||
|
if ps3_dirs:
|
||||||
|
logger.warning(f"Plusieurs dossiers PS3 détectés (aucune correspondance unique): {ps3_dirs}")
|
||||||
|
else:
|
||||||
|
logger.warning("Aucun dossier PS3 à renommer trouvé")
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
old_path = os.path.join(dest_dir, target)
|
||||||
|
new_path = os.path.join(dest_dir, f"{target}.ps3")
|
||||||
logger.debug(f"Tentative de renommage PS3: {old_path} -> {new_path}")
|
logger.debug(f"Tentative de renommage PS3: {old_path} -> {new_path}")
|
||||||
|
|
||||||
max_retries = 3
|
max_retries = 3
|
||||||
retry_delay = 2
|
retry_delay = 2
|
||||||
|
|
||||||
for attempt in range(max_retries):
|
for attempt in range(max_retries):
|
||||||
try:
|
try:
|
||||||
# Fermer les handles potentiellement ouverts
|
# Fermer les handles potentiellement ouverts
|
||||||
@@ -1051,13 +1189,6 @@ def handle_ps3(dest_dir):
|
|||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
return False, error_msg
|
return False, error_msg
|
||||||
|
|
||||||
elif len(ps3_dirs) > 1:
|
|
||||||
logger.warning(f"Plusieurs dossiers PS3 détectés: {ps3_dirs}")
|
|
||||||
return True, None
|
|
||||||
else:
|
|
||||||
logger.warning("Aucun dossier PS3 à renommer trouvé")
|
|
||||||
return True, None
|
|
||||||
|
|
||||||
|
|
||||||
def handle_xbox(dest_dir, iso_files, url=None):
|
def handle_xbox(dest_dir, iso_files, url=None):
|
||||||
"""Gère la conversion des fichiers Xbox extraits et met à jour l'UI (Converting)."""
|
"""Gère la conversion des fichiers Xbox extraits et met à jour l'UI (Converting)."""
|
||||||
|
|||||||
Reference in New Issue
Block a user