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.
102 lines
3.8 KiB
Python
102 lines
3.8 KiB
Python
#!/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()
|