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).
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parse curated URL lists, diff against wiki/catalog.json, report gaps."""
|
||||
import json, re, unicodedata
|
||||
from pathlib import Path
|
||||
|
||||
CATALOG = Path(__file__).resolve().parents[1] / "wiki" / "catalog.json"
|
||||
|
||||
# Games extracted from the 7 source lists (deduped, normalized keys).
|
||||
LIST_ENTRIES = [
|
||||
# UfzGCYzA
|
||||
("Abstract", "https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/"),
|
||||
("Alchemist", "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/"),
|
||||
("AfricanVs", "https://mega.nz/file/UgZj3BCQ#Xc6243i1iMfBTTJR7NfEsA7mFgfCFj37e7_u_B1EvMM"),
|
||||
("Awakening", "https://www.pokecommunity.com/threads/pokémon-awakening.535910/"),
|
||||
("Bizarre", "https://drive.google.com/file/d/1NXXr96vzeMD8sGplV1sWZFSph2vZijaK/view"),
|
||||
("Bushido", "https://eeveeexpo.com/bushido/"),
|
||||
("Empyrean", "https://www.pokecommunity.com/threads/pokémon-empyrean-v1-1-final-arc-released.411322/"),
|
||||
("Eon Guardians", "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/"),
|
||||
("Floral Tempus", "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/"),
|
||||
("HGSS Sevii", "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/"),
|
||||
("Infinity", "https://eeveeexpo.com/infinity/"),
|
||||
("Insurgence", "https://p-insurgence.com"),
|
||||
("Itinerant", "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/"),
|
||||
("Infinite Fusion", "https://www.pokecommunity.com/threads/v6-4-pokémon-infinite-fusion-new-pokémon-character-customization-and-more.347883/"),
|
||||
("Legends of the Arena", "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/"),
|
||||
("Mega Adventures", "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/"),
|
||||
("Nightmare", "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/"),
|
||||
("Pokerogue", "https://pokerogue.net"),
|
||||
("Poketale", "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file"),
|
||||
("Realidea System", "https://www.pokecommunity.com/threads/pokémon-realidea-system-now-playable-in-english.481090/"),
|
||||
("Reborn", "https://www.rebornevo.com/pr/index.html/"),
|
||||
("Reloaded", "https://pokemon-reloaded.blogspot.com"),
|
||||
("Reminiscencia", "https://www.pokecommunity.com/threads/pokémon-reminiscencia-full-release-spa-en-translation-complete.529202/"),
|
||||
("Shattered Light", "https://eeveeexpo.com/shattered-light/"),
|
||||
("Solar Light Lunar Dark", "https://pokemonsolarlightlunardark.fandom.com/wiki/Pokémon_Solar_Light_%26_Lunar_Dark_Wiki"),
|
||||
("Tectonic", "https://www.tectonic-game.com"),
|
||||
("Uranium", "https://pokemon-uranium.fandom.com/wiki/Main_Page"),
|
||||
("Xenoverse", "https://mega.nz/file/FbBgiTTK#qJpzZeUb5XqO5rLt6meW5_tOXeQ3K6y3_mslGNUf41M"),
|
||||
("Zeta", "https://zo.p-insurgence.com"),
|
||||
("Atlas", None), ("Unbreakable Ties", None), ("Bioterror", None), ("Fuso Meteor", None),
|
||||
("Comet", None), ("Ruckus", None), ("Island", None), ("Impetu", None),
|
||||
("Slowpoke Shack", None), ("Empire", None), ("Flux", None),
|
||||
# S1CSW465
|
||||
("Consonancia", "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/"),
|
||||
("Concealed", "https://www.pokecommunity.com/threads/concealed.527325/"),
|
||||
("Chaos in Vesita", "https://www.pokecommunity.com/threads/pokémon-chaos-in-vesita-new-version-out-now-eng-ger.491767/"),
|
||||
("Dark Horizon", "https://eeveeexpo.com/threads/9332/"),
|
||||
("Decay", "https://eeveeexpo.com/decay/"),
|
||||
("Fire Ash", "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/"),
|
||||
("Gaidr Deluxe", "https://www.pokecommunity.com/threads/pokémon-gadir-deluxe-complete-v-1-3.539451/"),
|
||||
("Hero Legacy", "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/"),
|
||||
("Hollow Woods", "https://www.pokecommunity.com/threads/pokémon-hollow-woods.525865/"),
|
||||
("Hydro Bliss", "https://eeveeexpo.com/threads/9100/"),
|
||||
("Jam Festival", "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/"),
|
||||
("Keishou", "https://www.pokecommunity.com/threads/pokémon-keishou-v2-06-1.504806/"),
|
||||
("Prisme", "https://pokemonprisme.com"),
|
||||
("Re:Union", "https://projetreunion.com"),
|
||||
("Relict", "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html"),
|
||||
# 6wPjUcrE
|
||||
("Spades and Clubs", "https://senta-storage-system.neocities.org/main"),
|
||||
("Giratina's Legend", "https://www.pokecommunity.com/threads/pokemon-giratinas-legend-07-01-24.289561"),
|
||||
("Crown", "https://www.pokecommunity.com/threads/pokémon-crown.463821"),
|
||||
("Odyssey II", None), # Discord only
|
||||
("Coral", "https://www.pokecommunity.com/threads/pokémon-coral-version-2022-demo-out-now.402361"),
|
||||
("DarkFire", "https://www.pokecommunity.com/threads/new-2024-beta-2-1-out-now-pokémon-darkfire.421395/"),
|
||||
("Sovereign of the Skies", "https://www.pokecommunity.com/threads/sovereign-of-the-skies-new-beta-2-0-0-version-released-06-10-2021.292651/"),
|
||||
("Legacy Edition", None), # Discord only
|
||||
("Iridium", None), # Discord only
|
||||
("Light Platinum DS", None), # Twitter only
|
||||
# ZwA8ng8E
|
||||
("Deserted", "https://eeveeexpo.com/threads/5344/"),
|
||||
# 1S4acLQA
|
||||
("Saiph", "https://www.pokecommunity.com/threads/pokémon-saiph-the-vytroverse-part-1-full-game-released.420990"),
|
||||
("Sors", "https://www.pokecommunity.com/threads/pokémon-sors-the-vytroverse-part-2-full-game-v1-3-available-now.433238"),
|
||||
("Saiph 2", "https://www.pokecommunity.com/threads/pokémon-saiph-2-the-vytroverse-part-3-full-game-v1-4-0-update-available.458509"),
|
||||
("Sors 2", "https://www.pokecommunity.com/threads/pokémon-sors-2-the-vytroverse-part-4-tech-demo-available.526108"),
|
||||
("Victory Fire", "https://www.pokecommunity.com/threads/pokemon-victory-fire-version-2-75-released.285031/"),
|
||||
("Resolute", "https://www.pokecommunity.com/threads/pokemon-resolute-version-version-2-97-released.294565/"),
|
||||
("Mega Power", "https://www.pokecommunity.com/threads/pokemon-mega-power-completed-beta-5-73-released.325422/"),
|
||||
("Nameless", "https://www.pokecommunity.com/threads/pokemon-nameless-version-complete-beta-5-35-released-with-darker-future-episode.419717/"),
|
||||
("Ruby Destiny", None),
|
||||
("ROWE", "https://www.pokecommunity.com/threads/pokemon-r-o-w-e-2-0-an-open-world-version-of-pokémon-emerald-gen-9-16-badges-sevii-islands-following-pokémon-costumes-and-much-more.442592/"),
|
||||
("Gaia", "https://www.pokecommunity.com/threads/pokémon-gaia-version.326118/"),
|
||||
("Vanguard", None),
|
||||
# tARt0w7x
|
||||
("Adventure Red", "https://www.pokecommunity.com/threads/pokémon-adventure-red-chapter-new-beta-expansion.298920/"),
|
||||
("AshGray", "https://www.pokecommunity.com/threads/pokémon-ashgray-version-beta-4-5-released.180722/"),
|
||||
("Azure Horizons", "https://hacksrepairman.blogspot.com/2020/03/pokemon-azure-horizons-fixed-beta2.html"),
|
||||
("Crystal Clear", "https://shockslayer.com/crystal-clear/"),
|
||||
("Dark Violet", "https://www.pokecommunity.com/threads/pokémon-darkviolet-full-version-released.291789/"),
|
||||
("Dreams", "https://www.pokecommunity.com/threads/dreams-completed-version-1-5-1-now-available.443298/"),
|
||||
("Elite Redux", "https://www.pokecommunity.com/threads/pokémon-elite-redux-v2-1-complete-—-unique-multi-ability-difficulty-hack.499227/"),
|
||||
("Emerald Rogue", "https://www.pokecommunity.com/threads/pokemon-emerald-rogue.479406/"),
|
||||
("Emerald Seaglass", "https://ko-fi.com/s/4a1535f351"),
|
||||
("Elysium", "https://www.pokecommunity.com/threads/pokémon-elysium-gba.502953/"),
|
||||
("Fire Red Extended", "https://www.pokecommunity.com/threads/pokémon-fire-red-extended-version.466535/"),
|
||||
("Flora Sky", "https://www.pokemoncoders.com/pokemon-flora-sky/"),
|
||||
("Glazed", "https://www.pokemoncoders.com/pokemon-glazed/"),
|
||||
("Light Platinum", "https://www.pokemoncoders.com/pokemon-light-platinum-rom-hack/"),
|
||||
("Liquid Crystal", "https://www.pokecommunity.com/threads/pokémon-liquid-crystal-3-3-xxxxx-live-beta.242023/"),
|
||||
("Mariomon", "https://www.pokecommunity.com/threads/super-mariomon.535764/"),
|
||||
("Odyssey", "https://www.pokecommunity.com/threads/pokémon-odyssey-complete-v4-0-1.488536/"),
|
||||
("Pisces", "https://pebblerplatoon.miraheze.org/wiki/Pisces_Download"),
|
||||
("Prism", "https://rainbowdevs.com/"),
|
||||
("Polished Crystal", "https://www.pokecommunity.com/threads/pokémon-polished-crystal-update-3-1-1.373172/"),
|
||||
("Radical Red", "https://www.pokecommunity.com/threads/pokémon-radical-red-version-4-1-released-gen-9-dlc-pokemon-character-customization-now-available.437688/"),
|
||||
("Recharged Series", "https://jaizu.moe"),
|
||||
("FireRed Rocket Edition", "https://www.pokecommunity.com/threads/pokémon-firered-rocket-edition-completed.360725/"),
|
||||
("Scorched Silver", "https://www.pokecommunity.com/threads/pokémon-scorched-silver-v1-3-complete.529230/"),
|
||||
("Sienna", "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/"),
|
||||
("Snakewood", "https://www.pokecommunity.com/threads/pokémon-snakewood-version.235371/"),
|
||||
("Team Rocket Edition", "https://www.pokecommunity.com/threads/pokémon-team-rocket-edition-dragonsden-version-kanto-sevii-johto-next-release-dlc-season-4.527368/"),
|
||||
("The Pit", "https://www.pokecommunity.com/threads/the-pit-v2-roguelite-style-hack.528423/"),
|
||||
("Unbound", "https://www.pokecommunity.com/threads/pokémon-unbound-completed.382178/"),
|
||||
("Vega", "https://www.pokecommunity.com/threads/pokémon-vega-and-altair-sirius-english-version.365959/"),
|
||||
("Vega Fairy EX", "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/"),
|
||||
# Google Doc
|
||||
("Lazarus", "https://ko-fi.com/nemo622"),
|
||||
("Renegade Platinum", "https://projectpokemon.org/home/forums/topic/52294-pokémon-renegade-platinum/"),
|
||||
("Heart n Soul", "https://www.hackdex.app/hack/pokemon-heart-and-soul"),
|
||||
("Dreamstone Mysteries", "https://github.com/dsmyst/dreamstone-mysteries"),
|
||||
("Rejuvenation", None),
|
||||
]
|
||||
|
||||
ALIASES = {
|
||||
"adventure red": "adventure red chapter",
|
||||
"ashgray": "ash gray",
|
||||
"ash gray": "ashgray",
|
||||
"firered rocket edition": "firered rocket edition",
|
||||
"fire red extended": "fire red extended",
|
||||
"darkfire": "dark fire",
|
||||
"gaidr deluxe": "gadir deluxe",
|
||||
"reunion": "re union",
|
||||
"re:union": "re union",
|
||||
"re union dx": "re union",
|
||||
"rowe": "r o w e",
|
||||
"r.o.w.e": "r o w e",
|
||||
"itinerant": "iternant",
|
||||
"keishou": "kieshou",
|
||||
"giratina's legend": "giratina",
|
||||
"vega fairy ex": "vega fairy",
|
||||
"team rocket edition": "team rocket edition",
|
||||
"mega adventures": "mega adventure",
|
||||
"reminiscencia": "reminiscensia",
|
||||
"spades and clubs": "spades",
|
||||
"odyssey ii": "odyssey 2",
|
||||
"heroes of lemuria": "odyssey 2",
|
||||
"light platinum ds": "light platinum ds",
|
||||
"heart n soul": "heart and soul",
|
||||
"recharged series": "recharged",
|
||||
}
|
||||
|
||||
|
||||
def norm(s: str) -> str:
|
||||
s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode().lower()
|
||||
s = re.sub(r"^pok[eé]mon\s+", "", s)
|
||||
s = re.sub(r"[^a-z0-9]+", " ", s).strip()
|
||||
return ALIASES.get(s, s)
|
||||
|
||||
|
||||
def load_catalog():
|
||||
data = json.loads(CATALOG.read_text(encoding="utf-8"))
|
||||
by_norm = {}
|
||||
for h in data["hacks"]:
|
||||
title = h.get("title") or h.get("stem", "")
|
||||
key = norm(title)
|
||||
by_norm.setdefault(key, []).append(h)
|
||||
if h.get("stem"):
|
||||
by_norm.setdefault(norm(h["stem"]), []).append(h)
|
||||
return by_norm
|
||||
|
||||
|
||||
def match_catalog(name, catalog):
|
||||
key = norm(name)
|
||||
hits = catalog.get(key, [])
|
||||
if hits:
|
||||
return hits[0]
|
||||
# fuzzy: substring
|
||||
for ck, hits in catalog.items():
|
||||
if key in ck or ck in key:
|
||||
return hits[0]
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
catalog = load_catalog()
|
||||
seen = set()
|
||||
rows = []
|
||||
for name, url in LIST_ENTRIES:
|
||||
nk = norm(name)
|
||||
if nk in seen:
|
||||
continue
|
||||
seen.add(nk)
|
||||
hit = match_catalog(name, catalog)
|
||||
rows.append({
|
||||
"name": name,
|
||||
"url": url,
|
||||
"in_catalog": hit is not None,
|
||||
"catalog_title": hit["title"] if hit else None,
|
||||
"platform": hit.get("platform") if hit else None,
|
||||
"library_path": hit.get("library_path") if hit else None,
|
||||
})
|
||||
|
||||
missing_cat = [r for r in rows if not r["in_catalog"]]
|
||||
in_cat = [r for r in rows if r["in_catalog"]]
|
||||
|
||||
print(f"Total unique list entries: {len(rows)}")
|
||||
print(f"In catalog: {len(in_cat)}")
|
||||
print(f"NOT in catalog: {len(missing_cat)}")
|
||||
print("\n=== NOT IN CATALOG ===")
|
||||
for r in sorted(missing_cat, key=lambda x: x["name"].lower()):
|
||||
print(f" {r['name']:30} {r['url'] or '(no URL)'}")
|
||||
|
||||
print("\n=== IN CATALOG (for library check) ===")
|
||||
for r in sorted(in_cat, key=lambda x: x["name"].lower()):
|
||||
lp = r["library_path"] or "—"
|
||||
print(f" {r['name']:30} | {r['platform'] or '?':5} | {lp}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user