#!/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()