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