M1: fetch-static — cdragon download, parse, icon URLs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
90
backend/tft/staticdata/parse.py
Normal file
90
backend/tft/staticdata/parse.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Normalize the raw Community Dragon TFT JSON into flat unit/trait/item tables.
|
||||
|
||||
Fails loudly on missing keys — never guess through structure drift.
|
||||
"""
|
||||
|
||||
CDRAGON_GAME = "https://raw.communitydragon.org/latest/game"
|
||||
|
||||
|
||||
def icon_url(asset_path: str) -> str:
|
||||
p = asset_path.lower()
|
||||
for ext in (".tex", ".dds"):
|
||||
if p.endswith(ext):
|
||||
p = p[: -len(ext)] + ".png"
|
||||
return f"{CDRAGON_GAME}/{p}"
|
||||
|
||||
|
||||
def detect_set(raw: dict) -> int:
|
||||
candidates = [
|
||||
int(k) for k, v in raw["sets"].items() if v.get("champions")
|
||||
]
|
||||
if not candidates:
|
||||
raise ValueError("no set with champions found in cdragon data")
|
||||
return max(candidates)
|
||||
|
||||
|
||||
def parse(raw: dict, set_override: int | None = None) -> dict:
|
||||
set_number = set_override if set_override is not None else detect_set(raw)
|
||||
set_data = raw["sets"][str(set_number)]
|
||||
|
||||
units = {}
|
||||
for c in set_data["champions"]:
|
||||
if not c["traits"]:
|
||||
continue # PvE monsters, summons
|
||||
units[c["apiName"]] = {
|
||||
"api_name": c["apiName"],
|
||||
"name": c["name"],
|
||||
"cost": c["cost"],
|
||||
"traits": c["traits"],
|
||||
"role": c.get("role"),
|
||||
"stats": c["stats"],
|
||||
"ability_name": c["ability"]["name"],
|
||||
"ability_variables": {
|
||||
v["name"]: v["value"] for v in c["ability"]["variables"]
|
||||
},
|
||||
"icon": icon_url(c["squareIcon"]),
|
||||
}
|
||||
|
||||
traits = {}
|
||||
trait_name_to_api = {}
|
||||
for t in set_data["traits"]:
|
||||
traits[t["apiName"]] = {
|
||||
"api_name": t["apiName"],
|
||||
"name": t["name"],
|
||||
"breakpoints": [
|
||||
{"min_units": e["minUnits"], "style": e["style"]}
|
||||
for e in t["effects"]
|
||||
],
|
||||
"icon": icon_url(t["icon"]),
|
||||
}
|
||||
trait_name_to_api[t["name"]] = t["apiName"]
|
||||
|
||||
# Champion traits are display names; map them to api names.
|
||||
for u in units.values():
|
||||
u["traits"] = [trait_name_to_api[name] for name in u["traits"]]
|
||||
|
||||
set_prefix = f"TFT{set_number}_"
|
||||
items = {}
|
||||
augments = {}
|
||||
for i in raw["items"]:
|
||||
api = i["apiName"]
|
||||
if not (api.startswith(set_prefix) or api.startswith("TFT_Item_")):
|
||||
continue
|
||||
entry = {
|
||||
"api_name": api,
|
||||
"name": i["name"],
|
||||
"composition": i["composition"],
|
||||
"icon": icon_url(i["icon"]) if i["icon"] else None,
|
||||
}
|
||||
if "Augment" in api:
|
||||
augments[api] = entry
|
||||
else:
|
||||
items[api] = entry
|
||||
|
||||
return {
|
||||
"meta": {"set": set_number, "set_name": set_data["name"]},
|
||||
"units": units,
|
||||
"traits": traits,
|
||||
"items": items,
|
||||
"augments": augments,
|
||||
}
|
||||
Reference in New Issue
Block a user