Files
pokemon/scripts/list-import-vault-notes.py
T
ginnoir 52ee1b98a1 Complete curated-list import automation and vault sync.
Adds list-import tooling, expands romhack-import for PC variants and patch batches, and syncs catalog with 2026-06-23 valhalla placements (Vanguard, Xenoverse, GBA patches, Infinity 3.3.1).
2026-06-23 03:57:50 -05:00

125 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Create vault notes for list-import hacks missing from catalog."""
import json, re, textwrap, unicodedata
from datetime import date
from pathlib import Path
VAULT = Path(r"C:\Users\MattC\Documents\Obsidian Vault\Pokémon ROM Hacks\Hacks")
CATALOG = Path(__file__).resolve().parents[1] / "wiki" / "catalog.json"
NEW = [
("Alchemist", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/"),
("Concealed", "PC", None, "Complete", "https://www.pokecommunity.com/threads/concealed.527325/"),
("Consonancia", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/"),
("Crown", "PC", None, "Ongoing", "https://www.pokecommunity.com/threads/pokémon-crown.463821/"),
("Eon Guardians", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/"),
("Fire Ash", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/"),
("Floral Tempus", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/"),
("Hero Legacy", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/"),
("HGSS Sevii", "NDS", "HeartGold", "Complete", "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/"),
("Itinerant", "GBA", "FireRed", "Ongoing", "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/"),
("Jam Festival", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/"),
("Legends of the Arena", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/"),
("Mega Adventures", "GBA", "Ruby", "Complete", "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/"),
("Nightmare", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/"),
("Poketale", "PC", None, "Complete", "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file"),
("Relict", "PC", None, "Complete", "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html"),
("Shattered Light", "PC", None, "Ongoing", "https://eeveeexpo.com/shattered-light/"),
("Sienna", "GBA", "Ruby", "Complete", "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/"),
("Spades and Clubs", "GBA", "FireRed", "Beta", "https://senta-storage-system.neocities.org/patchrelease"),
("Tectonic", "PC", None, "Ongoing", "https://www.tectonic-game.com"),
("Vega Fairy EX", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/"),
]
UPDATES = {
"Coral": "roms/gbc/Hacks/Pokemon - Coral (Hack).gbc",
"Giratina Strikes Back": "roms/gba/Hacks/Pokemon - Giratina Strikes Back Full (Hack).gba",
}
def norm(s):
s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode().lower()
s = re.sub(r"^pokemon\s+", "", s)
return re.sub(r"[^a-z0-9]+", " ", s).strip()
def yaml_quote(s):
if s is None:
return '"—"'
if any(c in s for c in ':"\\#[]{}'):
return json.dumps(s)
return s
def note_body(title, source):
return textwrap.dedent(f"""\
# {title}
> [!info] From curated YouTube/pastebin list import (2026-06-23)
> Added to catalog from community recommendation lists. Download may be gated — see [[Wanted]].
## Summary
Surfaced from external recommendation lists (pastebin / Google Doc). Not yet in the RomM library unless noted in frontmatter.
## Links
- Info / thread: {source}
## In the library
> [!note] See `library_path` in frontmatter.
[[Index|← back to directory]]
""")
def patch_library_path(path: Path, lp: str):
text = path.read_text(encoding="utf-8")
text = re.sub(r"^library_path:.*$", f'library_path: "{lp}"', text, count=1, flags=re.M)
path.write_text(text, encoding="utf-8")
def main():
existing = {norm(p.stem) for p in VAULT.glob("*.md")}
today = date.today().isoformat()
created = []
for name, platform, base, status, source in NEW:
if norm(name) in existing:
continue
title = f"Pokémon {name}"
tags = ["hack", f"platform/{platform.lower()}", f"status/{status.lower().replace(' ', '-')}"]
if base:
tags.append(f"base/{base.lower().replace(' ', '-')}")
fm = [
"---",
f"title: {title}",
f'platform: {platform}',
f'base: {base or "—"}',
'version: "—"',
f"status: {status}",
"type: [New Experience]",
'generation: "—"',
'library_path: "—"',
f"source: {json.dumps(source)}",
f"added: {today}",
"play_status: Unplayed",
"tags:",
]
fm += [f" - {t}" for t in tags]
fm.append("---")
body = note_body(title, source)
out = VAULT / f"{name}.md"
out.write_text("\n".join(fm) + "\n" + body, encoding="utf-8")
created.append(name)
for stem, lp in UPDATES.items():
p = VAULT / f"{stem}.md"
if p.exists():
patch_library_path(p, lp)
print(f"Created {len(created)} notes: {', '.join(created)}")
print(f"Updated library_path: {', '.join(UPDATES)}")
if __name__ == "__main__":
main()