#!/usr/bin/env python3 """Export the Pokémon ROM-hack vault to a single JSON catalog for the website. Reads every /Pokémon ROM Hacks/Hacks/*.md note (frontmatter + the Summary / Features / Story / Why-it-stands-out / Links body sections) and emits wiki/catalog.json — the data source a static wiki site can render directly. This is READ-ONLY against the vault. Re-run after any enrichment pass. Run: python scripts/build-wiki-data.py """ from __future__ import annotations import json, os, re, glob, sys from collections import Counter from datetime import date sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import enrich_vault as E OUT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "wiki") OUT = os.path.join(OUT_DIR, "catalog.json") SCALARS = ["title", "platform", "base", "version", "status", "generation", "developer", "release_date", "banner", "homepage", "source", "library_path", "play_status", "scrape_dir", "engine"] def section(body, heading): m = re.search(rf"(?ms)^## {re.escape(heading)}\s*\n+(.+?)(?=^## |\n\[\[Index|\Z)", body) return m.group(1).strip() if m else "" def bullets(text): return [re.sub(r"^[-*]\s*", "", ln).strip() for ln in text.splitlines() if ln.strip().startswith(("-", "*"))] def links(text): out = [] for ln in text.splitlines(): m = re.search(r"\[?([\w /]+?)\]?:?\s*(https?://\S+)", ln) if m: out.append({"label": m.group(1).strip(" -:"), "url": m.group(2).rstrip(").")}) else: m2 = re.search(r"(https?://\S+)", ln) if m2: out.append({"label": "Link", "url": m2.group(1).rstrip(").")}) return out def main(): hacks = [] for f in sorted(glob.glob(os.path.join(E.HACKS, "*.md"))): fm_text, body, _ = E.read_note(f) fm = E.parse_fm(fm_text) stem = os.path.splitext(os.path.basename(f))[0] rec = {"stem": stem} for k in SCALARS: if fm.get(k) not in (None, ""): rec[k] = fm[k] rec["type"] = fm.get("type") or [] rec["tags"] = fm.get("tags") or [] if fm.get("rating") not in (None, ""): try: rec["rating"] = int(str(fm["rating"])) except ValueError: pass rec["summary"] = section(body, "Summary") rec["notability"] = section(body, "Why it stands out") rec["story"] = section(body, "Story") rec["features"] = bullets(section(body, "Features")) rec["links"] = links(section(body, "Links")) for k in ("base", "version", "status", "platform", "generation"): if rec.get(k) == "—": rec[k] = None hacks.append(rec) def facet(key): c = Counter(h.get(key) or "Unknown" for h in hacks) return dict(sorted(c.items(), key=lambda kv: (-kv[1], kv[0]))) type_counts = Counter(t for h in hacks for t in h["type"]) engine_counts = Counter(h["engine"] for h in hacks if h.get("engine")) out = { "generated": date.today().isoformat(), "count": len(hacks), "facets": { "platform": facet("platform"), "base": facet("base"), "status": facet("status"), "engine": dict(sorted(engine_counts.items(), key=lambda kv: (-kv[1], kv[0]))), "type": dict(sorted(type_counts.items(), key=lambda kv: (-kv[1], kv[0]))), "play_status": facet("play_status"), }, "image_base": "https://romhacks-files.ginnoir.com", "hacks": hacks, } os.makedirs(OUT_DIR, exist_ok=True) json.dump(out, open(OUT, "w", encoding="utf-8"), indent=2, ensure_ascii=False) enriched = sum(1 for h in hacks if len(h["summary"]) > 60) withimg = sum(1 for h in hacks if h.get("banner")) withfeat = sum(1 for h in hacks if h["features"]) print(f"wrote {OUT}") print(f" hacks={len(hacks)} with-image={withimg} with-features={withfeat} " f"rich-summary={enriched}") print(f" platforms: {out['facets']['platform']}") print(f" types: {out['facets']['type']}") if __name__ == "__main__": main()