65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageOps
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
CACHE = ROOT / ".tmp" / "gzhh-images"
|
|
RAW = CACHE / "raw"
|
|
MANIFEST = CACHE / "manifest.json"
|
|
ARTICLES = ROOT / "src" / "data" / "articles.generated.json"
|
|
OUTPUT = ROOT / "public" / "assets" / "article-covers"
|
|
|
|
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
|
|
by_url = {
|
|
item["url"]: item
|
|
for item in manifest
|
|
if item.get("status") == "ok" and item.get("file")
|
|
}
|
|
articles = json.loads(ARTICLES.read_text(encoding="utf-8"))
|
|
OUTPUT.mkdir(parents=True, exist_ok=True)
|
|
|
|
exported = 0
|
|
missing = []
|
|
used_files = set()
|
|
|
|
for article in articles:
|
|
source_url = article.get("coverSourceUrl") or article.get("cover", "")
|
|
if not source_url.startswith("http"):
|
|
continue
|
|
cache_entry = by_url.get(source_url)
|
|
if not cache_entry:
|
|
missing.append({"title": article.get("title", ""), "url": source_url})
|
|
continue
|
|
|
|
key = hashlib.sha256(source_url.encode("utf-8")).hexdigest()[:12]
|
|
output_name = f"cover-{key}.webp"
|
|
output_path = OUTPUT / output_name
|
|
with Image.open(RAW / cache_entry["file"]) as image:
|
|
frame = ImageOps.exif_transpose(image).convert("RGB")
|
|
frame.thumbnail((960, 960), Image.Resampling.LANCZOS)
|
|
frame.save(output_path, "WEBP", quality=82, method=6)
|
|
|
|
article["coverSourceUrl"] = source_url
|
|
article["cover"] = f"/assets/article-covers/{output_name}"
|
|
used_files.add(output_name)
|
|
exported += 1
|
|
|
|
ARTICLES.write_text(
|
|
json.dumps(articles, ensure_ascii=False, indent=2) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
summary = {
|
|
"articles": len(articles),
|
|
"exported": exported,
|
|
"uniqueFiles": len(used_files),
|
|
"missing": len(missing),
|
|
"bytes": sum((OUTPUT / name).stat().st_size for name in used_files),
|
|
}
|
|
print(json.dumps(summary, ensure_ascii=False))
|
|
if missing:
|
|
raise RuntimeError(f"Missing {len(missing)} cached cover images")
|