升级
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
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")
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { readdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
@@ -14,6 +15,12 @@ const cleanMarkdown = (value) =>
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
const getLocalCoverPath = (url) => {
|
||||
if (!url) return "";
|
||||
const key = createHash("sha256").update(url).digest("hex").slice(0, 12);
|
||||
return `/assets/article-covers/cover-${key}.webp`;
|
||||
};
|
||||
|
||||
const getExcerpt = (body, title) => {
|
||||
const ignored = /(?:data:image|%3Csvg|transform=|阅读|点赞|分享|推荐|留言|2024届612|font-family|__bottom-bar__|sns_opr_btn|picture_content|page_content)/i;
|
||||
const lines = body
|
||||
@@ -60,16 +67,18 @@ const parseArticle = (fileName, raw) => {
|
||||
const contentStart = raw.search(/>\s*原文地址:/);
|
||||
const body = contentStart >= 0 ? raw.slice(contentStart).split(/\r?\n/).slice(2).join("\n") : raw;
|
||||
const images = [...body.matchAll(/!\[[^\]]*\]\((https?:\/\/[^\s\)]+)\)/g)]
|
||||
.map((match) => match[1])
|
||||
.map((match) => match[1].replaceAll("&", "&"))
|
||||
.filter((url) => /mmbiz\.qpic\.cn/.test(url));
|
||||
const excerptText = getExcerpt(body, title);
|
||||
const coverSourceUrl = images[0] ?? "";
|
||||
|
||||
return {
|
||||
title,
|
||||
date,
|
||||
displayDate: date ? date.replaceAll("-", ".") : "日期待补",
|
||||
sourceUrl,
|
||||
cover: images[0] ?? "",
|
||||
cover: getLocalCoverPath(coverSourceUrl),
|
||||
coverSourceUrl,
|
||||
excerpt: excerptText.length > 88 ? `${excerptText.slice(0, 88)}…` : excerptText || "一页从公众号找回的班级记录。",
|
||||
category: getCategory(title),
|
||||
fileName
|
||||
|
||||
Reference in New Issue
Block a user