Files
climperor/export_relations_site.py
T
voson 1d0428b4a3 Add hash routing and Dota 2 logo to relations preview.
- New web/relations/router.js (parseHash/serializeHash/installRouter):
  top tabs, hero + detail sub-tab, item, patch version, tag filters and
  search query all sync to URL (#/heroes/axe/core, ?tags=...&q=...);
  pushState for discrete picks, replaceState for debounced search.
- export_relations_site.py copies router.js so static export deep-links.
- Header shows dota2_logo.png + title, served via /ui-icon/ whitelist.
- fetch_dota2_logo.py fetches the transparent emblem asset.
- Docs: CHANGELOG / README / DESIGN / AGENTS updated.
2026-07-27 13:09:14 +08:00

125 lines
3.9 KiB
Python

"""Export the relations preview as a static site (no server needed).
Usage:
python export_relations_site.py [--out dist/relations] [--with-videos]
Copies web/relations/ + a snapshot of the /api/data payload (data.json) +
the referenced image assets into one directory, ready for any static host
(GitHub Pages, Cloudflare Pages, nginx, ...).
Notes:
- Only already-cached assets are exported. For full ability-icon coverage
run `python fetch_hero_abilities.py --icons-only` first.
- For patch-notes names/icons on the 版本 page, run `python fetch_patches.py`
first (downloads referenced item + ability icons into assets/).
- Ability videos (several GB locally) are skipped unless --with-videos is
given; the UI degrades quietly when a video is missing.
"""
from __future__ import annotations
import argparse
import json
import shutil
from pathlib import Path
from common import (
ABILITY_ICONS,
ABILITY_VIDEOS,
ATTR_ICONS,
HERO_PORTRAITS,
ITEM_CAT_ICONS,
ITEM_ICONS,
ROOT,
TEMPLATES_CDN,
UI_ICONS,
)
from serve_relations import WEB_DIR, build_payload
def copy_glob(src: Path, dst: Path, pattern: str = "*.png") -> int:
if not src.is_dir():
return 0
dst.mkdir(parents=True, exist_ok=True)
n = 0
for f in sorted(src.glob(pattern)):
if f.is_file():
shutil.copy2(f, dst / f.name)
n += 1
return n
def main() -> None:
ap = argparse.ArgumentParser(
description="Export relations preview as a static site"
)
ap.add_argument("--out", default=str(ROOT / "dist" / "relations"))
ap.add_argument(
"--with-videos",
action="store_true",
help="also copy assets/ability_videos (several GB)",
)
args = ap.parse_args()
out = Path(args.out).resolve()
if out == ROOT.resolve() or out.parent == out:
raise SystemExit(f"refusing unsafe --out: {out}")
if out.exists():
shutil.rmtree(out)
out.mkdir(parents=True)
# Frontend (uses relative paths — works from any sub-path).
for name in ("index.html", "router.js", "app.js", "style.css"):
shutil.copy2(WEB_DIR / name, out / name)
# Data snapshot (same payload as serve_relations /api/data).
payload = build_payload()
(out / "data.json").write_text(
json.dumps(payload, ensure_ascii=False, separators=(",", ":")),
encoding="utf-8",
)
# Assets.
counts = {
"attr": copy_glob(ATTR_ICONS, out / "attr"),
"item": copy_glob(ITEM_ICONS, out / "item"),
"item-cat": copy_glob(ITEM_CAT_ICONS, out / "item-cat", "itemcat_*.png"),
"ability": copy_glob(ABILITY_ICONS, out / "ability"),
"ui-icon": copy_glob(UI_ICONS, out / "ui-icon"),
}
# Portraits: official wide cards, fall back to CDN match templates.
portrait_dst = out / "portrait"
portrait_dst.mkdir(exist_ok=True)
n_portrait = 0
for hero in payload.get("heroes") or []:
key = hero.get("key")
if not key:
continue
src = HERO_PORTRAITS / f"{key}.png"
if not src.is_file():
src = TEMPLATES_CDN / f"{key}.png"
if src.is_file():
shutil.copy2(src, portrait_dst / f"{key}.png")
n_portrait += 1
counts["portrait"] = n_portrait
n_videos = 0
if args.with_videos and ABILITY_VIDEOS.is_dir():
shutil.copytree(ABILITY_VIDEOS, out / "ability-video")
n_videos = sum(1 for f in (out / "ability-video").rglob("*") if f.is_file())
total = sum(f.stat().st_size for f in out.rglob("*") if f.is_file())
print(f"exported static site -> {out}")
for name, n in counts.items():
print(f" {name}/: {n} files")
if args.with_videos:
print(f" ability-video/: {n_videos} files")
print(f" total: {total / 1e6:.1f} MB")
print(f"local check: python -m http.server -d {out} 8080")
print("deploy: upload the directory to any static host (Pages / nginx / ...)")
if __name__ == "__main__":
main()