Files
dusuniot/scripts/fix-nav-404.ts
T

77 lines
4.7 KiB
TypeScript
Raw 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.
/**
* # 脚本 导航 404 数据修复(一次性,幂等)
* 依据对原站 dusuniot.com 的逐 URL 探测结论:
* 1. 发布落地页草稿(原站已 404 但内容在库、且被站内内容/重定向规则引用):
* - contents.id=49 bluetooth-roaming-gateway(案例文章外链目标)
* - contents.id=40 iot-hardware-developer(页脚菜单组外链目标)
* - contents.id=53 ultra-convergence-solution(redirects 规则 491 的目标)
* - contents.id=64 single-board-computer(博客文章外链目标)
* 2. 修复导入内容里的畸形链接:href 中 URL 后又拼接了一次单斜杠版自身
* (…/product/x/https:/www.dusuniot.com/product/x/),还原为第一个 URL。
* 3. 补 redirects 表规则:目标多为「线上同样 404 的陈旧链接」,指向本地最近似存活页。
* 重复执行安全:草稿发布、内容修复与规则插入都先查再写。
*/
import { SQL } from "bun";
const sql = new SQL(process.env.DATABASE_URL || "postgres://dusuniot:dusuniot@127.0.0.1:25432/dusuniot");
// ── 1. 发布落地页草稿 ──
for (const id of [40, 49, 53, 64]) {
const [row] = await sql`SELECT id, slug, status FROM contents WHERE id = ${id}`;
if (!row) {
console.log(`contents.id=${id} 不存在,跳过`);
continue;
}
if (row.status === "published") {
console.log(`contents.id=${id} (${row.slug}) 已是 published`);
continue;
}
await sql`UPDATE contents SET status = 'published' WHERE id = ${id}`;
console.log(`已发布 contents.id=${id} (${row.slug})`);
}
// ── 2. 修复内容里畸形拼接的链接(URL 后跟单斜杠版自身) ──
const bad = await sql`SELECT id, slug, html FROM contents WHERE html LIKE '%/https:/www.dusuniot.com%'`;
const dupRe = /(https:\/\/www\.dusuniot\.com\/[^\s"'<>]+?)\/https:\/www\.dusuniot\.com\/[^\s"'<>]*/g;
for (const row of bad) {
const fixed = row.html.replace(dupRe, "$1");
if (fixed !== row.html) {
await sql`UPDATE contents SET html = ${fixed} WHERE id = ${row.id}`;
console.log(`已修复畸形链接: contents.id=${row.id} (${row.slug})`);
} else {
console.log(`contents.id=${row.id} (${row.slug}) 模式命中但无可替换(人工检查)`);
}
}
// ── 3. 补充 redirects 规则(source 唯一先查后插) ──
const RULES: { source: string; target: string; note: string }[] = [
// 原站已 404 的案例/新闻文:落对应归档(本站归档已可用)
{ source: "/case-study/tuya-smart-home-solution/", target: "/case-study/", note: "线上 404 的陈旧案例链接 → 案例归档" },
{ source: "/news/a-multi-protocol-smart-home-mini-pc-hub/", target: "/news/", note: "线上 404 的陈旧新闻链接 → 新闻归档" },
// 线上已 404 的落地页 → 本地最近的存活落地页(odm/zigbee-gateways 均 200 且主题相近)
{ source: "/landing-pages/oem-odm/", target: "/landing-pages/odm/", note: "线上 404 → 本地 ODM 落地页" },
{ source: "/landing-pages/tuya-router-gateway/", target: "/landing-pages/zigbee-gateways/", note: "线上 404 → 本地 Zigbee 网关落地页" },
{ source: "/landing-pages/tuya-series-products/", target: "/landing-pages/zigbee-gateways/", note: "线上 404 → 本地 Zigbee 网关落地页" },
{ source: "/landing-pages/tuya-smart-home-zigbee-gateway/", target: "/landing-pages/zigbee-gateways/", note: "线上 404 → 本地 Zigbee 网关落地页" },
// 原站 WooCommerce 属性归档(pa_type 筛选页),本站无该属性归档 → 商城列表
{ source: "/shop/type-iot-gateway/", target: "/shop/", note: "线上 200 的属性归档,本站无此筛选 → 商城" },
{ source: "/shop/type-som/", target: "/shop/", note: "线上 200 的属性归档,本站无此筛选 → 商城" },
{ source: "/shop/downlink-z-wave-or-zigbee/", target: "/shop/", note: "线上 404 的属性归档 → 商城" },
// 原站 301 后终态 404 的规格页短链 → 产品列表(本地无对应产品)
{ source: "/dsgw-075-tuya-specification/", target: "/collection/", note: "线上 301→404 → 产品列表" },
// 原站 200 但内容未导入(Elementor 页抓取导入成本高,先落 About Us;后续可导入真页替换)
{ source: "/partners/", target: "/about-us/", note: "原站合作伙伴页未导入 → 关于我们" },
];
for (const r of RULES) {
const [dup] = await sql`SELECT id FROM redirects WHERE source = ${r.source}`;
if (dup) {
console.log(`规则已存在(${dup.id}): ${r.source}`);
continue;
}
await sql`INSERT INTO redirects (source, target, code, is_regex, enabled) VALUES (${r.source}, ${r.target}, 301, false, true)`;
console.log(`+ 301 ${r.source} → ${r.target} (${r.note})`);
}
console.log("完成");
process.exit(0);