mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-16 05:42:31 -05:00
feat: batocera 679/680, fix variant indexing, add hikaru + segaboot
Fix variant name indexing: files in .variants/ now indexed under canonical name (naomi2.zip instead of naomi2.zip.da79eca4). Fix .zip detection for variant paths in verify.py. Add composite MD5 matching in resolver for ZIP variants. Add hikaru.zip (MAME 0.285, 6 ROMs) and segaboot.gcm (Triforce) from archive.org. Both match Batocera expected MD5s. Batocera 679/680 (1 untested: sc3000 private dump) Recalbox 346/346 (100%)
This commit is contained in:
@@ -38,6 +38,17 @@ def should_skip(path: Path) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _canonical_name(filepath: Path) -> str:
|
||||
"""Get canonical filename, stripping .variants/ hash suffix."""
|
||||
name = filepath.name
|
||||
if "/.variants/" in str(filepath) or "\\.variants\\" in str(filepath):
|
||||
# naomi2.zip.da79eca4 -> naomi2.zip
|
||||
parts = name.rsplit(".", 1)
|
||||
if len(parts) == 2 and len(parts[1]) == 8 and all(c in "0123456789abcdef" for c in parts[1]):
|
||||
return parts[0]
|
||||
return name
|
||||
|
||||
|
||||
def scan_bios_dir(bios_dir: Path, cache: dict, force: bool) -> dict:
|
||||
"""Scan bios directory and compute hashes, using cache when possible."""
|
||||
files = {}
|
||||
@@ -69,11 +80,11 @@ def scan_bios_dir(bios_dir: Path, cache: dict, force: bool) -> dict:
|
||||
if sha1 in files:
|
||||
if sha1 not in aliases:
|
||||
aliases[sha1] = []
|
||||
aliases[sha1].append({"name": filepath.name, "path": rel_path})
|
||||
aliases[sha1].append({"name": _canonical_name(filepath), "path": rel_path})
|
||||
else:
|
||||
entry = {
|
||||
"path": rel_path,
|
||||
"name": filepath.name,
|
||||
"name": _canonical_name(filepath),
|
||||
"size": size,
|
||||
**hashes,
|
||||
}
|
||||
@@ -86,11 +97,11 @@ def scan_bios_dir(bios_dir: Path, cache: dict, force: bool) -> dict:
|
||||
if sha1 in files:
|
||||
if sha1 not in aliases:
|
||||
aliases[sha1] = []
|
||||
aliases[sha1].append({"name": filepath.name, "path": rel_path})
|
||||
aliases[sha1].append({"name": _canonical_name(filepath), "path": rel_path})
|
||||
else:
|
||||
entry = {
|
||||
"path": rel_path,
|
||||
"name": filepath.name,
|
||||
"name": _canonical_name(filepath),
|
||||
"size": size,
|
||||
**hashes,
|
||||
}
|
||||
|
||||
@@ -127,6 +127,14 @@ def resolve_to_local_path(file_entry: dict, db: dict) -> str | None:
|
||||
for path, db_md5 in candidates:
|
||||
if db_md5.lower() == md5_lower:
|
||||
return path
|
||||
# Try composite MD5 for ZIP files (Recalbox uses Zip::Md5Composite)
|
||||
for path, _ in candidates:
|
||||
if ".zip" in os.path.basename(path):
|
||||
try:
|
||||
if md5_composite(path).lower() == md5_lower:
|
||||
return path
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
pass
|
||||
if candidates:
|
||||
primary = [p for p, _ in candidates if "/.variants/" not in p]
|
||||
return primary[0] if primary else candidates[0][0]
|
||||
@@ -194,7 +202,7 @@ def verify_entry_md5(file_entry: dict, local_path: str | None) -> dict:
|
||||
|
||||
# Recalbox uses Zip::Md5Composite() for ZIP files: sorts filenames,
|
||||
# hashes all contents sequentially. Independent of compression level.
|
||||
if local_path.endswith(".zip"):
|
||||
if ".zip" in os.path.basename(local_path):
|
||||
try:
|
||||
composite = md5_composite(local_path)
|
||||
composite_lower = composite.lower()
|
||||
|
||||
Reference in New Issue
Block a user