Sync catalog with vault: engine facet, Jaizu Emerald set, and PC placements.
Add engine annotation + MOC/wiki export support, a PC import staging helper, and refresh catalog.json after placing gated fan-games and new hack notes.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Repack staged PC downloads from /tmp/pc-import into roms/windows/."""
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import zipfile
|
||||
import shutil
|
||||
|
||||
DEST = "/storage1/Emulation/roms/windows"
|
||||
STAGE = "/tmp/pc-import"
|
||||
|
||||
|
||||
def repack_rar_to_zip(rar_path, dest_zip):
|
||||
tmp = tempfile.mkdtemp(prefix="pcrepack_")
|
||||
try:
|
||||
r = subprocess.run(["bsdtar", "-xf", rar_path, "-C", tmp], capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
return False, "bsdtar: " + (r.stderr or r.stdout)[:200]
|
||||
tmp_zip = dest_zip + ".part"
|
||||
with zipfile.ZipFile(tmp_zip, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for root, _, files in os.walk(tmp):
|
||||
for fn in files:
|
||||
fp = os.path.join(root, fn)
|
||||
z.write(fp, os.path.relpath(fp, tmp))
|
||||
os.replace(tmp_zip, dest_zip)
|
||||
has_exe = any(fn.lower() == "game.exe" for fn in os.listdir(tmp))
|
||||
return True, f"{os.path.getsize(dest_zip):,} bytes, Game.exe={has_exe}"
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
def merge_zip_overlay(base_zip, overlay_zip, dest_zip):
|
||||
tmp = tempfile.mkdtemp(prefix="pcmerge_")
|
||||
try:
|
||||
with zipfile.ZipFile(base_zip) as z:
|
||||
z.extractall(tmp)
|
||||
with zipfile.ZipFile(overlay_zip) as z:
|
||||
z.extractall(tmp)
|
||||
tmp_zip = dest_zip + ".part"
|
||||
with zipfile.ZipFile(tmp_zip, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for root, _, files in os.walk(tmp):
|
||||
for fn in files:
|
||||
fp = os.path.join(root, fn)
|
||||
z.write(fp, os.path.relpath(fp, tmp))
|
||||
os.replace(tmp_zip, dest_zip)
|
||||
has_exe = os.path.exists(os.path.join(tmp, "Game.exe"))
|
||||
return True, f"{os.path.getsize(dest_zip):,} bytes, Game.exe={has_exe}"
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
def apply_deserted():
|
||||
base_rar = update_rar = None
|
||||
for fn in os.listdir(STAGE):
|
||||
if "Deserted" not in fn:
|
||||
continue
|
||||
if "1.4" in fn:
|
||||
update_rar = os.path.join(STAGE, fn)
|
||||
else:
|
||||
base_rar = os.path.join(STAGE, fn)
|
||||
if not base_rar:
|
||||
return False, "base rar missing"
|
||||
tmp = tempfile.mkdtemp(prefix="pcdeserted_")
|
||||
try:
|
||||
r = subprocess.run(["bsdtar", "-xf", base_rar, "-C", tmp], capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
return False, "base extract: " + (r.stderr or "")[:120]
|
||||
if update_rar:
|
||||
r = subprocess.run(["bsdtar", "-xf", update_rar, "-C", tmp], capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
return False, "update extract: " + (r.stderr or "")[:120]
|
||||
dest_zip = os.path.join(DEST, "Pokemon - Deserted (Hack).zip")
|
||||
tmp_zip = dest_zip + ".part"
|
||||
with zipfile.ZipFile(tmp_zip, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for root, _, files in os.walk(tmp):
|
||||
for fn in files:
|
||||
fp = os.path.join(root, fn)
|
||||
z.write(fp, os.path.relpath(fp, tmp))
|
||||
os.replace(tmp_zip, dest_zip)
|
||||
has_exe = os.path.exists(os.path.join(tmp, "Game.exe"))
|
||||
return True, f"{os.path.getsize(dest_zip):,} bytes, Game.exe={has_exe}, update={bool(update_rar)}"
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(DEST, exist_ok=True)
|
||||
for label, fn in [
|
||||
("bushido", lambda: repack_rar_to_zip(
|
||||
f"{STAGE}/bushido.rar", f"{DEST}/Pokemon - bushido (Hack).zip")),
|
||||
("rejuvenation", lambda: merge_zip_overlay(
|
||||
f"{STAGE}/rejuvenation.zip", f"{STAGE}/rejuvenation-patch.zip",
|
||||
f"{DEST}/Pokemon - Rejuvenation (Hack).zip")),
|
||||
("deserted", apply_deserted),
|
||||
]:
|
||||
ok, msg = fn()
|
||||
print(f"{label}: {ok} {msg}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user