fix(sites): 憨憨详情页按真实结构解析豆瓣块与 MediaInfo

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 23:29:19 +08:00
1 parent df22200bfd
commit 653bdcb976
6 files changed
+71 -6

No files matched your search

@@ -264,7 +264,9 @@
},
"page": {
"labelSelectors": ["div.font-bold.leading-6", "span.font-bold"],
"fileListPath": "viewfilelist.php?id={id}"
"fileListPath": "viewfilelist.php?id={id}",
"mediaInfo": "#mediainfo-raw",
"descriptionStrip": "div.mt-5, div.flex.flex-row.items-center"
}
},
"vipLevels": ["贵宾", "VIP"],
@@ -1,4 +1,9 @@
import { HHANCLUB_DETAIL_PAGE_2026, HHANCLUB_DETAIL_PAGE_FULL, HHANCLUB_FILELIST_FRAGMENT } from "@umt/testkit";
import {
HHANCLUB_DETAIL_PAGE_2026,
HHANCLUB_DETAIL_PAGE_FULL,
HHANCLUB_DETAIL_PAGE_REAL_2026,
HHANCLUB_FILELIST_FRAGMENT,
} from "@umt/testkit";
import { describe, expect, it } from "vitest";
import { hhanclubDefinition } from "../definitions/index.ts";
import { looksLikeMediaInfo, pageFromBbcode } from "../detail-text.ts";
@@ -109,6 +114,30 @@ Format : AVC[/quote]
});
});
describe("憨憨真实详情页(2026-10-02 摘录)", () => {
const { detail } = parseDetailPage(HHANCLUB_DETAIL_PAGE_REAL_2026, hhanclubDefinition, "219860", OBSERVED);
const page = detail!.page!;
it("MediaInfo 只取 #mediainfo-raw 原文,不带摘要表", () => {
expect(page.mediaInfo!.startsWith("General\nComplete name")).toBe(true);
expect(page.mediaInfo).not.toContain("体 积");
});
it("豆瓣块一项一行;去掉分隔线、空值项、标题行与更新提示;链接之间已有逗号不再补分隔", () => {
const t = page.descriptionText!;
expect(t.split("\n").slice(0, 3)).toEqual([
"片名: 斗罗大陆Ⅱ绝世唐门 年番1",
"别名: 斗罗大陆2,斗罗大陆2:绝世唐门\u200e,斗罗大陆2绝世唐门,绝世唐门动画版",
"年代: 2023",
]);
expect(t).toContain("\n导演: 沈乐平 Leping Shen\n");
expect(t).toContain("编剧: 沈乐平 Leping Shen,唐家三少 Wei Zhang");
expect(t).toContain("主演:\n梁达伟 Dawei Liang / 蒋丽 Li Jiang");
expect(t).not.toMatch(/-{5,}|标语|该信息最后更新|\(23691\)/);
expect(page.doubanId).toBe("35567787");
});
});
describe("详情页扩展内容(憨憨 2026 真实结构:分节 div,无 #kdescr)", () => {
const { kind, detail } = parseDetailPage(HHANCLUB_DETAIL_PAGE_2026, hhanclubDefinition, "91003", OBSERVED);
const page = detail!.page!;
@@ -220,16 +220,38 @@ export function extractDetailPage($: CheerioAPI, conf: DetailConf, base: string)
} else if (infoBlock) {
const c = infoBlock.clone();
c.find("img").remove();
if (p.descriptionStrip) c.find(p.descriptionStrip).remove();
// 块里的「标签」span 与值之间补上冒号 / 换行,读起来是「片名:xxx」一行一项
// (换行要用 BR 占位:源码里的换行在 blockText 里按空白处理)
// 站点排版用的分隔线(憨憨是行内 font):换成换行
c.find("font, span, div")
.filter((_, x) => /^[-=_—]{5,}$/.test($(x).text().trim()))
.replaceWith(BR);
c.find(p.labelSelectors?.join(", ") || "span.font-bold").each((_, n) => {
const e = $(n);
const t = e.text().trim();
// 空值的项(憨憨「标语:」)整项去掉
const v = e.next();
if (v.length && !v.text().trim() && !v.find("img").length) {
(e.parent().children().length === 2 ? e.parent() : e).remove();
v.remove();
return;
}
if (t && t.length <= 16 && !/[::]$/.test(t)) e.text(`${t}:`);
e.before("\n");
e.before(BR);
});
// 并排的演职员链接之间补分隔(之间已有逗号等文字的不补)
c.find("a + a").each((_, n) => {
const prev = n.prev;
if (prev && prev.type === "text" && prev.data.trim()) return;
$(n).before(" / ");
});
const t = blockText($, c)
.replace(/[ \t]{2,}/g, " ")
.replace(/[ \t]*\n[ \t]*/g, "\n")
.replace(/:\s*\n(?=\S)/g, ":");
.replace(/\n{3,}/g, "\n\n")
.replace(/:\s*\n(?=\S)/g, ":")
.trim();
if (t) page.descriptionText = t.slice(0, 20_000);
}