mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-16 05:42:31 -05:00
feat: recalbox 346/346 via md5_composite, add mame variants
Add md5_composite() to verify.py replicating Recalbox Zip::Md5Composite (sorted filenames, sequential content hash). Independent of ZIP compression level, resolves all 9 MAME arcade untested entries. Add Recalbox-specific MAME ZIP variants from Recalbox 10 pack. Batocera 671/680 (9 untested MAME-specific), all others 100%.
This commit is contained in:
@@ -54,6 +54,21 @@ def md5sum(filepath: str | Path) -> str:
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def md5_composite(filepath: str | Path) -> str:
|
||||
"""Compute composite MD5 of a ZIP - matches Recalbox's Zip::Md5Composite().
|
||||
|
||||
Sorts filenames alphabetically, reads each file's contents in order,
|
||||
feeds everything into a single MD5 hasher. The result is independent
|
||||
of ZIP compression level or metadata.
|
||||
"""
|
||||
with zipfile.ZipFile(filepath) as zf:
|
||||
names = sorted(n for n in zf.namelist() if not n.endswith("/"))
|
||||
h = hashlib.md5()
|
||||
for name in names:
|
||||
h.update(zf.read(name))
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -> dict:
|
||||
"""Load a platform config with inheritance and shared group resolution.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ except ImportError:
|
||||
sys.exit(1)
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from common import load_platform_config, md5sum
|
||||
from common import load_platform_config, md5sum, md5_composite
|
||||
|
||||
DEFAULT_DB = "database.json"
|
||||
DEFAULT_PLATFORMS_DIR = "platforms"
|
||||
@@ -192,6 +192,18 @@ def verify_entry_md5(file_entry: dict, local_path: str | None) -> dict:
|
||||
if len(expected) < 32 and actual_lower.startswith(expected.lower()):
|
||||
return {"name": name, "status": Status.OK, "path": local_path}
|
||||
|
||||
# Recalbox uses Zip::Md5Composite() for ZIP files: sorts filenames,
|
||||
# hashes all contents sequentially. Independent of compression level.
|
||||
if local_path.endswith(".zip"):
|
||||
try:
|
||||
composite = md5_composite(local_path)
|
||||
composite_lower = composite.lower()
|
||||
for expected in md5_list:
|
||||
if composite_lower == expected.lower():
|
||||
return {"name": name, "status": Status.OK, "path": local_path}
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
pass
|
||||
|
||||
return {
|
||||
"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||
"expected_md5": md5_list[0] if md5_list else "", "actual_md5": actual_md5,
|
||||
|
||||
Reference in New Issue
Block a user