修复若干问题

This commit is contained in:
zqlit committed 2026-05-21 13:35:18 +08:00
1 parent c8cdf9a7bc
commit bf083523c8
12 files changed
+581 -40

No files matched your search

+104
View File
@@ -0,0 +1,104 @@
import { NextResponse } from "next/server";
import { ARTALK_SERVER, ARTALK_SITE } from "@/lib/config";
async function getArtalkData(path: string, token: string) {
const url = `${ARTALK_SERVER}${path}`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error(`Artalk API error: ${res.status}`);
return res.json();
}
async function deleteArtalkPage(id: number, token: string) {
const url = `${ARTALK_SERVER}/api/v2/pages/${id}`;
const res = await fetch(url, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ site_name: ARTALK_SITE }),
});
return res.ok;
}
export async function POST(request: Request) {
try {
const body = await request.json().catch(() => ({}));
const token = (body as Record<string, string>).token;
if (!token) {
return NextResponse.json({ error: "token required" }, { status: 400 });
}
// 1. Login to get a valid token
const allPages: { id: number; key: string; title: string; comment_count?: number }[] = [];
let offset = 0;
const limit = 200;
// Fetch all pages
while (true) {
const data = await getArtalkData(
`/api/v2/pages?site_name=${encodeURIComponent(ARTALK_SITE)}&limit=${limit}&offset=${offset}`,
token
);
const pages = data.pages || data.data || [];
if (pages.length === 0) break;
allPages.push(...pages);
offset += limit;
if (pages.length < limit) break;
}
// 2. Group by title
const byTitle = new Map<string, typeof allPages>();
for (const p of allPages) {
const t = (p.title || "").trim();
if (!byTitle.has(t)) byTitle.set(t, []);
byTitle.get(t)!.push(p);
}
// 3. For each duplicate group, keep the one with most comments, delete the rest (especially 0-comment ones)
let deleted = 0;
const deletedIds: number[] = [];
for (const [title, pages] of byTitle) {
if (pages.length <= 1) continue;
// Sort: most comments first, then by id desc (newest first)
pages.sort((a, b) => {
const ca = a.comment_count ?? 0;
const cb = b.comment_count ?? 0;
if (ca !== cb) return cb - ca;
return b.id - a.id;
});
// Keep the first one, delete the rest
const [keep, ...toDelete] = pages;
for (const p of toDelete) {
try {
const ok = await deleteArtalkPage(p.id, token);
if (ok) {
deleted++;
deletedIds.push(p.id);
}
} catch { /* skip failed deletions */ }
}
}
// 4. Also clean up pages with 0 comments that are NOT part of duplicate groups
// (only if they look like test/404 pages — very short titles or empty keys)
// Skip this step to be safe — only deduplicate.
return NextResponse.json({
total: allPages.length,
duplicateGroups: [...byTitle.values()].filter((ps) => ps.length > 1).length,
deleted,
deletedIds,
});
} catch (error: unknown) {
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}