diff --git a/CHANGELOG.md b/CHANGELOG.md index 799f656a..74017362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ## [Unreleased] +### 修复 +- OurBits 详情页:简介是页面里未渲染的 BBCode(站点靠前端脚本渲染),之前原样显示 `[quote]`、`[img]` 且换行全丢;改为按 BBCode 解析,保留换行、去掉标记,图片进截图,引用块里的 MediaInfo 单独取;文件列表按需取 `viewfilelist.php`。已缓存的详情在过期或手动刷新后生效。 + ### 新增 - 下载器可以单独设水位(硬阈值 / 恢复水位 / 清理目标)和保种天数,不填用全局;多个下载器共用一块缓存盘时取最严格的。公网 BT 专用的 qB 可设保种 0 天(站点 H&R 仍遵守)。 diff --git a/packages/adapters/src/sites/definitions/definitions.test.ts b/packages/adapters/src/sites/definitions/definitions.test.ts index 16fc0149..4ae53713 100644 --- a/packages/adapters/src/sites/definitions/definitions.test.ts +++ b/packages/adapters/src/sites/definitions/definitions.test.ts @@ -6,6 +6,7 @@ import { HHANCLUB_LIST_PAGE, HHANCLUB_LIST_PAGE_2026, HHANCLUB_LIST_PAGE_TAGS, + OURBITS_DETAIL_PAGE, OURBITS_LIST_PAGE, } from "@umt/testkit"; import { describe, expect, it } from "vitest"; @@ -234,6 +235,19 @@ describe("2026-10 真实列表页结构(脱敏样例)", () => { expect(a!.tags).toEqual(["官方", "中字"]); }); + it("OurBits 详情:ubbcode 里的 BBCode 简介保留换行、去掉标记,图片进截图,引用块里的 MediaInfo 单独取", () => { + const def = BUILTIN_SITE_DEFINITIONS.ourbits as IndexerDefinition; + const page = parseDetailPage(OURBITS_DETAIL_PAGE, def, "900001", OBSERVED).detail!.page!; + expect(page.descriptionText).toContain("官组作品,感谢原制作者发布。\n"); + expect(page.descriptionText).toContain("◎片 名 示例剧\n◎年 代 2025"); + expect(page.descriptionText).not.toMatch(/\[(img|url|quote|b|color)/); + expect(page.descriptionText).not.toContain("Complete name"); + expect(page.mediaInfo).toMatch(/^General\nComplete name/); + expect(page.screenshots).toEqual(["https://img.example.test/poster.jpg", "https://img.example.test/shot1.jpg"]); + expect(page.doubanId).toBe("36000001"); + expect(def.umt.detail?.page?.fileListPath).toBe("viewfilelist.php?id={id}"); + }); + it("IMDb ID 规范化:纯数字补 tt + 7 位,0 与非法值丢弃", () => { expect(imdbIdOf("299977")).toBe("tt0299977"); expect(imdbIdOf("35522483")).toBe("tt35522483"); diff --git a/packages/adapters/src/sites/definitions/ourbits.json b/packages/adapters/src/sites/definitions/ourbits.json index ad9d2c5e..445f113b 100644 --- a/packages/adapters/src/sites/definitions/ourbits.json +++ b/packages/adapters/src/sites/definitions/ourbits.json @@ -269,6 +269,9 @@ "imdb": "a[href*='imdb.com']::attr(href)", "douban": "a[href*='douban.com']::attr(href)", "fileList": "td.rowfollow > ul > li::text" + }, + "page": { + "fileListPath": "viewfilelist.php?id={id}" } }, "customClass": "movieclaw_tracker.sites.custom.ourbits.OurBitsSite" diff --git a/packages/adapters/src/sites/spider/detail-page.ts b/packages/adapters/src/sites/spider/detail-page.ts index 821c20ca..78aeaa73 100644 --- a/packages/adapters/src/sites/spider/detail-page.ts +++ b/packages/adapters/src/sites/spider/detail-page.ts @@ -11,6 +11,7 @@ import { looksLikeMediaInfo, MAX_FILES, MAX_SCREENSHOTS, + pageFromBbcode, screenshotUrl, tidyText, } from "../detail-text.ts"; @@ -284,5 +285,22 @@ export function extractDetailPage($: CheerioAPI, conf: DetailConf, base: string) } } } + + // 简介是未渲染的 BBCode 原文(OurBits:div.ubbcode,站点靠前端脚本渲染):按 BBCode 取简介 / 截图 / MediaInfo, + // 换行保留;发布者、文件、标签与 HTML 上的外部 ID 照旧 + const ubb = desc?.length ? (desc.is(".ubbcode") ? desc : desc.find(".ubbcode").first()) : null; + const raw = ubb?.length ? ubb.text() : ""; + if (/\[(?:img|url|quote|b|color|size|code)\b[^\]]*\]/i.test(raw)) { + const b = pageFromBbcode(raw, base, { mediaInfo: page.mediaInfo }); + page.descriptionText = b.descriptionText; + page.mediaInfo = b.mediaInfo; + if (b.screenshots.length) { + page.screenshots = b.screenshots; + page.probe.imageCount = b.probe.imageCount; + } + page.imdbId ??= b.imdbId; + page.doubanId ??= b.doubanId; + page.tmdb ??= b.tmdb; + } return page; } diff --git a/packages/testkit/src/sites/fixtures/definitions/sites-2026.ts b/packages/testkit/src/sites/fixtures/definitions/sites-2026.ts index 70a29369..e6cb3f5a 100644 --- a/packages/testkit/src/sites/fixtures/definitions/sites-2026.ts +++ b/packages/testkit/src/sites/fixtures/definitions/sites-2026.ts @@ -68,3 +68,29 @@ export const HHANCLUB_LIST_PAGE_TAGS = `
| 副标题 | 示例剧 | 全40集 |
| 基本信息 | 大小:185.04 GB |
| 简介 | [quote][b][color=blue]官组作品,感谢原制作者发布。[/color][/b][/quote]
+
+[img]https://img.example.test/poster.jpg[/img]
+◎片 名 示例剧
+◎年 代 2025
+◎豆瓣链接 [url=https://movie.douban.com/subject/36000001/]https://movie.douban.com/subject/36000001/[/url]
+
+[quote]General
+Complete name : Sample.Show.S01E01.2160p.WEB-DL.mp4
+Format : MPEG-4
+Video
+Format : HEVC
+Width : 3 840 pixels
+Audio
+Format : AAC[/quote]
+[img]https://img.example.test/shot1.jpg[/img] |
| 种子文件 | 文件数:40个文件 |