Files
dusuniot/scripts/import-live-terms.ts

63 lines
3.0 KiB
TypeScript
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.
/**
* # 脚本 同步文章分类成员(dump 快照 → 原站当前状态)
*
* 背景:/blog/ 归档本地 302 篇(26 页)vs 原站当前 7 页——dump 之后原站调整了
* Blog/Gateway 等分类的成员。本脚本按原站 REST API 的 categories 重建本地
* content_terms 分类关联(仅调整 REST 返回的文章;本地有而原站已删除的不动)。
*
* 用法:bun scripts/import-live-terms.ts [--dry]
*/
import { SQL } from "bun";
const LIVE = "https://www.dusuniot.com";
const sql = new SQL(process.env.DATABASE_URL || "postgres://dusuniot:dusuniot@127.0.0.1:25432/dusuniot", { max: 1 });
const dry = process.argv.includes("--dry");
/** 本地分类 legacy_id → id(WP term id 与 legacy_id 一致) */
const catRows = await sql`select id, legacy_id, slug from categories where taxonomy = 'category' and legacy_id is not null`;
const catByLegacy = new Map<number, number>(catRows.map((r: any) => [Number(r.legacy_id), r.id as number]));
/** 本地已发布文章 legacy_id → content id */
const posts = await sql`select id, legacy_id from contents where type = 'post' and status = 'published' and legacy_id is not null`;
const contentByLegacy = new Map<number, number>(posts.map((r: any) => [Number(r.legacy_id), r.id as number]));
console.log("本地已发布文章:", posts.length);
/** 逐页拉原站文章的分类(_fields 精简返回) */
const liveCats = new Map<number, number[]>(); // wp post id → term ids
let page = 1;
while (true) {
const res = await fetch(`${LIVE}/wp-json/wp/v2/posts?per_page=100&page=${page}&_fields=id,categories`, { headers: { "User-Agent": "Mozilla/5.0" } });
if (!res.ok) {
if (res.status === 400) break; // 翻页越界
console.log("REST", res.status, "停止");
break;
}
const items = (await res.json()) as { id: number; categories: number[] }[];
for (const it of items) liveCats.set(it.id, it.categories || []);
if (items.length < 100) break;
page++;
await new Promise((r) => setTimeout(r, 400)); // 限速(429 防护)
}
console.log("原站文章:", liveCats.size);
let added = 0, removed = 0;
for (const [wpId, cats] of liveCats) {
const cid = contentByLegacy.get(wpId);
if (!cid) continue;
const localRows = await sql`select category_id from content_terms where content_id = ${Number(cid)}`;
const localSet = new Set<number>(localRows.map((r: any) => r.category_id as number));
const liveSet = new Set(cats.map((t) => catByLegacy.get(t)).filter((x): x is number => x != null));
for (const add of liveSet) {
if (localSet.has(add)) continue;
added++;
if (!dry) await sql`insert into content_terms (content_id, category_id) values (${cid}, ${Number(add)}) on conflict do nothing`;
}
for (const rm of localSet) {
if (liveSet.has(rm)) continue;
removed++;
if (!dry) await sql`delete from content_terms where content_id = ${cid} and category_id = ${Number(rm)}`;
}
}
console.log(`分类成员同步: 新增 ${added} 移除 ${removed}${dry ? "(dry 未写库)" : ""}`);
await sql.end();