Files
wait4xandGLM-5.3 7a2880b65d fix(polish): 上线四缺陷修复——明暗委托/灯箱常开/评论站点名/书评宋体
- 明暗切换:document 级委托(软导航换 DOM 后元素级监听全丢);
  E2E 再抓一坑:SVGElement 非 HTMLElement 实例,守卫用 Element 基类
- 图库:#lb 无条件 display:flex 覆盖 UA 隐藏 → 灯箱"永远打开"盖全页;
  改 #lb:not([open]) 显式 none;时间戳标题清空;灯箱打磨(切换钮
  实底阴影/n/21 计数器/空标题隐藏/原图链接暗底亮蓝)
- 评论:site 'wait4x'→'wait4x.online' 对齐 Artalk 服务端(404 根因)
- 书评字体:文楷→思源宋(@fontsource 预分片);文楷降级金句 --font-kai
- 数据:21 张照片组修正 street→landscape(迁移器收到内部组 id 的坑)
- 新增 tests/e2e.mjs:Playwright 30 项全功能 E2E

验证: node tests/e2e.mjs 30/30 PASS(含软导航后明暗切换回归项)

Spec: 2026-10-25_fix-site-polish

Co-authored-by: GLM-5.3
2026-10-25 10:46:03 +08:00

88 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""图库迁移(Phase 2 T3):Halo photos → content/photos/{jpg,json sidecar}
EXIF 不在迁移时提——构建期 photos loader(src/lib/exif.ts)会补全;
sidecar 里 exif 留空对象。分组:Halo displayName 含山/雪/land/snow →
landscape,否则 street(当前仅一组 snow mountain → landscape)。
"""
import json
import re
import urllib.request
from pathlib import Path
from urllib.parse import unquote
BASE = "http://127.0.0.1:18090"
OUT = Path("content/photos")
def slugify(name: str) -> str:
stem = re.sub(r"\.(jpg|jpeg|png|webp)$", "", name, flags=re.I)
stem = re.sub(r"[^0-9A-Za-z\u4e00-\u9fff-]+", "-", stem).strip("-")
return stem or "photo"
def group_of(display: str) -> str:
low = display.lower()
return "landscape" if any(k in low for k in ("山", "雪", "snow", "land", "mountain")) else "street"
def compress(data: bytes) -> bytes:
from io import BytesIO
from PIL import Image
img = Image.open(BytesIO(data))
# EXIF 必须显式带上:PIL 重存默认剥离,而构建期 exifr 正是从文件提 EXIF
exif = img.info.get("exif")
if img.mode not in ("RGB", "L"):
img = img.convert("RGB")
img.thumbnail((2400, 2400))
buf = BytesIO()
# PIL 的 JPEG 保存不接受 exif=None(len(None) 崩),仅在确有 EXIF 时传参
kwargs = {"exif": exif} if exif else {}
img.save(buf, "JPEG", quality=86, optimize=True, **kwargs)
return buf.getvalue()
def main() -> int:
# 真实照片取代样例:先清样例(jpg/json 成对;仅清本脚本管辖的产物)
for f in OUT.glob("*"):
if f.suffix in (".jpg", ".json"):
f.unlink()
photos = json.load(open(".migration/photos.json", encoding="utf-8"))
n = 0
for p in photos:
spec = p["spec"]
url = spec.get("url") or spec.get("cover") or ""
if not url.startswith("/upload/"):
print(f" skip 非本站图: {url[:60]}")
continue
fname = unquote(url.rsplit("/", 1)[1])
slug = slugify(spec.get("displayName") or fname)
data = urllib.request.urlopen(BASE + url, timeout=60).read()
# 原图双留档:仓外 originals store(构建时独立 rsync,服务"查看原图/
# 下载")+ Phase 0 备份 tar;git 仓只进压缩版(196M 事故教训)
STORE = Path.home() / "docker_apps/blog/photos-originals"
STORE.mkdir(parents=True, exist_ok=True)
(STORE / f"{slug}.jpg").write_bytes(data)
(OUT / f"{slug}.jpg").write_bytes(compress(data))
(OUT / f"{slug}.json").write_text(json.dumps({
"title": spec.get("displayName", fname).rsplit(".", 1)[0],
"image": f"./{slug}.jpg",
// groupName 是内部 id(photo-group-xxx),组显示名需查组表;
// 本站唯一组 snow mountain → landscape(group_of 收到的曾是
// 内部 id 导致全判 street——已修数据,此处注释留档)
"group": group_of("snow mountain"),
"alt": spec.get("description", ""),
"exif": {},
}, ensure_ascii=False, indent=1))
n += 1
print(f"migrated {n} photos")
return 0 if n else 1
if __name__ == "__main__":
raise SystemExit(main())