mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-25 05:09:03 -05:00
fix: check emudeck folders by any file
An EmuDeck entry names no file: the system passes when any file directly in the BIOS folder has one of its md5, as checkBIOS.sh loops over "$biosPath/"*. The script looked each one up as a file named system:md5 and reported 134 of 170 entries missing.
This commit is contained in:
1 parent
7ca7be064a
commit
2ba0effd3b
1 file changed
+19
-18
@@ -14,49 +14,50 @@ from pathlib import Path
|
||||
API = "https://abdess.github.io/retrobios/api/v1/platforms/"
|
||||
|
||||
|
||||
# The digest each check mode compares. A mode missing here (existence) only
|
||||
# asks that the file be present.
|
||||
# The digest each mode compares. Without one (existence) a file need only be present.
|
||||
DIGESTS = {"md5": "md5", "sha1": "sha1"}
|
||||
|
||||
|
||||
def accepts(entry: dict, path: Path, mode: str) -> bool:
|
||||
"""Whether the platform's own check passes the file at path."""
|
||||
digest = DIGESTS.get(mode)
|
||||
raw = entry.get(mode) or ""
|
||||
values = raw if isinstance(raw, list) else str(raw).split(",")
|
||||
declared = [value.strip().lower() for value in values if value.strip()]
|
||||
if digest is None or not declared:
|
||||
digest, raw = DIGESTS.get(mode), entry.get(mode) or ""
|
||||
values = [v.strip().lower() for v in (raw if isinstance(raw, list) else str(raw).split(",")) if v.strip()]
|
||||
if digest is None or not values:
|
||||
return path.is_file() # nothing to compare: the platform checks presence
|
||||
try:
|
||||
if entry.get("zipped_file"): # the hash of one member, its name casefolded
|
||||
with zipfile.ZipFile(path) as archive:
|
||||
names = {name.casefold(): name for name in archive.namelist()}
|
||||
member = names.get(entry["zipped_file"].casefold())
|
||||
return bool(member) and hashlib.new(digest, archive.read(member)).hexdigest() in declared
|
||||
return bool(member) and hashlib.new(digest, archive.read(member)).hexdigest() in values
|
||||
actual = hashlib.new(digest, path.read_bytes()).hexdigest()
|
||||
if entry.get("zip_digest") != "composite" and any(actual.startswith(d) for d in declared):
|
||||
if entry.get("zip_digest") != "composite" and any(actual.startswith(v) for v in values):
|
||||
return True # a truncated md5 (Batocera) compares by its prefix
|
||||
if digest == DIGESTS["md5"] and path.suffix.lower() == ".zip": # Recalbox: members in name order
|
||||
with zipfile.ZipFile(path) as archive:
|
||||
names = sorted(name for name in archive.namelist() if not name.endswith("/"))
|
||||
return hashlib.md5(b"".join(map(archive.read, names))).hexdigest() in declared
|
||||
return hashlib.md5(b"".join(map(archive.read, names))).hexdigest() in values
|
||||
except (OSError, zipfile.BadZipFile):
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def check(platform: str, root: Path, api: str = API) -> list[tuple[str, str]]:
|
||||
"""(destination, ok | wrong | missing) for each entry of the list."""
|
||||
"""(destination, ok | wrong | missing) for each entry. Entries with no destination
|
||||
(EmuDeck) name no file: their system passes when any file in root has their hash."""
|
||||
with urllib.request.urlopen(f"{api}{platform}.json") as response:
|
||||
contract = json.load(response)["items"][0]["contract"]
|
||||
mode = contract["verification_mode"]
|
||||
results = []
|
||||
for system in contract["systems"].values():
|
||||
for entry in system.get("files") or []:
|
||||
destination = entry.get("destination") or entry["name"]
|
||||
path = root / destination
|
||||
mode, results = contract["verification_mode"], []
|
||||
loose = [path for path in root.iterdir() if path.is_file()] if root.is_dir() else []
|
||||
for system_id, system in contract["systems"].items():
|
||||
listed = [e for e in system.get("files") or [] if not e.get("destination")]
|
||||
for entry in (e for e in system.get("files") or [] if e.get("destination")):
|
||||
path = root / entry["destination"]
|
||||
verdict = "ok" if accepts(entry, path, mode) else "wrong" if path.is_file() else "missing"
|
||||
results.append((destination, verdict))
|
||||
results.append((entry["destination"], verdict))
|
||||
if listed:
|
||||
held = any(accepts(e, path, mode) for e in listed for path in loose)
|
||||
results.append((f"{system_id}: any file", "ok" if held else "missing"))
|
||||
return results
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user