#!/usr/bin/env python3 """Halo 全量导出(Phase 2 T1):posts/photos/moments → .migration/*.json 对生产仅 GET;正文优先取列表 status.content,缺则回落 head-content 端点。 产物为迁移中间件,不入库(.gitignore .migration/)。 """ import json import sys import urllib.request from pathlib import Path BASE = "http://127.0.0.1:18090" OUT = Path(".migration") OUT.mkdir(exist_ok=True) def get(path: str) -> object: with urllib.request.urlopen(BASE + path, timeout=30) as r: return json.load(r) def export_list(api: str, size: int = 100) -> list[dict]: """翻页取全量 items。""" items, page = [], 1 while True: data = get(f"{api}?page={page}&size={size}") batch = data.get("items", []) items.extend(batch) if page * size >= data.get("total", 0) or not batch: return items page += 1 def main() -> int: posts = export_list("/apis/api.content.halo.run/v1alpha1/posts") # 正文兜底:head-content 拿完整 HTML(status.content 可能是截断摘要) for p in posts: name = p["metadata"]["name"] content = (p.get("status") or {}).get("content") if not content: try: head = get(f"/apis/api.content.halo.run/v1alpha1/posts/{name}/head-content") p["_fullContent"] = head.get("content", "") except Exception as e: # noqa: BLE001 - 单篇失败不阻断全量导出 p["_fullContent"] = "" print(f" warn: {name} head-content 失败: {e}", file=sys.stderr) photos = export_list("/apis/api.photo.halo.run/v1alpha1/photos") try: groups = get("/apis/api.photo.halo.run/v1alpha1/groups") except Exception: # noqa: BLE001 - 分组端点缺失时空兜底 groups = {"items": []} moments = export_list("/apis/api.moment.halo.run/v1alpha1/moments") (OUT / "posts.json").write_text(json.dumps(posts, ensure_ascii=False, indent=1)) (OUT / "photos.json").write_text(json.dumps(photos, ensure_ascii=False, indent=1)) (OUT / "photo_groups.json").write_text(json.dumps(groups, ensure_ascii=False, indent=1)) (OUT / "moments.json").write_text(json.dumps(moments, ensure_ascii=False, indent=1)) full = sum(1 for p in posts if p.get("_fullContent") or (p.get("status") or {}).get("content")) print(f"exported: posts={len(posts)}(含正文 {full})photos={len(photos)} groups={len(groups.get('items', []))} moments={len(moments)}") return 0 if __name__ == "__main__": sys.exit(main())