diff --git a/CHANGELOG.md b/CHANGELOG.md index 75b2854d..cf16babd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ## [Unreleased] +### 修复 +- 憨憨详情页(按 2026-10-02 真实页面):豆瓣信息一项一行,去掉分隔线、空值项、重复的标题行和「该信息最后更新」提示;MediaInfo 只取原文,不再混进摘要表。已缓存的详情在过期或手动刷新后生效。 + ## [0.3.18] - 2026-10-02 ## [0.3.17] - 2026-10-02 diff --git a/packages/adapters/src/sites/definitions/hhanclub.json b/packages/adapters/src/sites/definitions/hhanclub.json index d9e6e326..61b17a5d 100644 --- a/packages/adapters/src/sites/definitions/hhanclub.json +++ b/packages/adapters/src/sites/definitions/hhanclub.json @@ -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"], diff --git a/packages/adapters/src/sites/spider/detail-page.test.ts b/packages/adapters/src/sites/spider/detail-page.test.ts index 26a78b52..05306475 100644 --- a/packages/adapters/src/sites/spider/detail-page.test.ts +++ b/packages/adapters/src/sites/spider/detail-page.test.ts @@ -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!; diff --git a/packages/adapters/src/sites/spider/detail-page.ts b/packages/adapters/src/sites/spider/detail-page.ts index 78aeaa73..17aaf50d 100644 --- a/packages/adapters/src/sites/spider/detail-page.ts +++ b/packages/adapters/src/sites/spider/detail-page.ts @@ -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); } diff --git a/packages/testkit/src/sites/fixtures/definitions/hhanclub.ts b/packages/testkit/src/sites/fixtures/definitions/hhanclub.ts index a4812cb7..d5237a57 100644 --- a/packages/testkit/src/sites/fixtures/definitions/hhanclub.ts +++ b/packages/testkit/src/sites/fixtures/definitions/hhanclub.ts @@ -154,3 +154,10 @@ export const HHANCLUB_FILELIST_FRAGMENT = `
| Example.Show.S01E18.2026.2160p.mkv | 5.04 GB |
| Example.Show.S01E19.2026.2160p.mkv | 4.98 GB |
文件名:斗罗大陆Ⅱ绝世唐门.Soul.Land.2.The.Peerless.Tang.Clan.S01E173.2023.2160p.WEB-DL.H.265.AAC2.0-HHWEB.mp4体 积: 1.20 GiB时 长: 21 min 52 s分辨率: 3 840 pixels x 2 160 pixels码 率: 7 701 kb/s帧 率: 30.000 FPS音 频: 01: AAC LC 2 channels 125 kb/sGeneral\nComplete name : 斗罗大陆Ⅱ绝世唐门.Soul.Land.2.The.Peerless.Tang.Clan.S01E173.2023.2160p.WEB-DL.H.265.AAC2.0-HHWEB.mp4\nFormat : MPEG-4\nFormat profile : Base Media\nCodec ID : isom (isom/iso2/mp41)\nFile size : 1.20 GiB\nDuration : 21 min 52 s\nOverall bit rate mode : Variable\nOverall bit rate : 7 837 kb/s\nWriting application : Lavf60.10.100\nVideo\nID : 1\nFormat : HEVC\nFormat/Info : High Efficiency Video Coding\nFormat profile : Main@L5@Main\nCodec ID : hev1\nCodec ID/Info : High Efficiency Video Coding\nDuration : 21 min 52 s\nSource duration : 21 min 52 s\nBit rate : 7 701 kb/s\nWidth : 3 840 pixels\nHeight : 2 160 pixels\nDisplay aspect ratio : 16:9\nFrame rate mode : Variable
\n