fix(sites): OurBits 详情页按 BBCode 解析简介
OurBits 的简介在 div.ubbcode 里是未渲染的 BBCode(站点前端脚本渲染),按 HTML 取文本后 [quote] / [img] / [url] 原样留下、换行全被合并。extractDetailPage 遇到 ubbcode 容器且内容带 BBCode 标记时, 改用 pageFromBbcode 取简介 / 截图 / MediaInfo(换行保留),发布者、文件、标签与页面上的外部 ID 照旧。 覆盖层补 fileListPath(viewfilelist.php),与憨憨一样按需取文件列表。脱敏样例 OURBITS_DETAIL_PAGE + 测试。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ee128e0b3f
commit
9cdf492291
6 files changed
+72
-1
No files matched your search
@@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- OurBits 详情页:简介是页面里未渲染的 BBCode(站点靠前端脚本渲染),之前原样显示 `[quote]`、`[img]` 且换行全丢;改为按 BBCode 解析,保留换行、去掉标记,图片进截图,引用块里的 MediaInfo 单独取;文件列表按需取 `viewfilelist.php`。已缓存的详情在过期或手动刷新后生效。
|
||||||
|
|
||||||
### 新增
|
### 新增
|
||||||
- 下载器可以单独设水位(硬阈值 / 恢复水位 / 清理目标)和保种天数,不填用全局;多个下载器共用一块缓存盘时取最严格的。公网 BT 专用的 qB 可设保种 0 天(站点 H&R 仍遵守)。
|
- 下载器可以单独设水位(硬阈值 / 恢复水位 / 清理目标)和保种天数,不填用全局;多个下载器共用一块缓存盘时取最严格的。公网 BT 专用的 qB 可设保种 0 天(站点 H&R 仍遵守)。
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
HHANCLUB_LIST_PAGE,
|
HHANCLUB_LIST_PAGE,
|
||||||
HHANCLUB_LIST_PAGE_2026,
|
HHANCLUB_LIST_PAGE_2026,
|
||||||
HHANCLUB_LIST_PAGE_TAGS,
|
HHANCLUB_LIST_PAGE_TAGS,
|
||||||
|
OURBITS_DETAIL_PAGE,
|
||||||
OURBITS_LIST_PAGE,
|
OURBITS_LIST_PAGE,
|
||||||
} from "@umt/testkit";
|
} from "@umt/testkit";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
@@ -234,6 +235,19 @@ describe("2026-10 真实列表页结构(脱敏样例)", () => {
|
|||||||
expect(a!.tags).toEqual(["官方", "中字"]);
|
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 与非法值丢弃", () => {
|
it("IMDb ID 规范化:纯数字补 tt + 7 位,0 与非法值丢弃", () => {
|
||||||
expect(imdbIdOf("299977")).toBe("tt0299977");
|
expect(imdbIdOf("299977")).toBe("tt0299977");
|
||||||
expect(imdbIdOf("35522483")).toBe("tt35522483");
|
expect(imdbIdOf("35522483")).toBe("tt35522483");
|
||||||
|
|||||||
@@ -269,6 +269,9 @@
|
|||||||
"imdb": "a[href*='imdb.com']::attr(href)",
|
"imdb": "a[href*='imdb.com']::attr(href)",
|
||||||
"douban": "a[href*='douban.com']::attr(href)",
|
"douban": "a[href*='douban.com']::attr(href)",
|
||||||
"fileList": "td.rowfollow > ul > li::text"
|
"fileList": "td.rowfollow > ul > li::text"
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"fileListPath": "viewfilelist.php?id={id}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"customClass": "movieclaw_tracker.sites.custom.ourbits.OurBitsSite"
|
"customClass": "movieclaw_tracker.sites.custom.ourbits.OurBitsSite"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
looksLikeMediaInfo,
|
looksLikeMediaInfo,
|
||||||
MAX_FILES,
|
MAX_FILES,
|
||||||
MAX_SCREENSHOTS,
|
MAX_SCREENSHOTS,
|
||||||
|
pageFromBbcode,
|
||||||
screenshotUrl,
|
screenshotUrl,
|
||||||
tidyText,
|
tidyText,
|
||||||
} from "../detail-text.ts";
|
} 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;
|
return page;
|
||||||
}
|
}
|
||||||
@@ -68,3 +68,29 @@ export const HHANCLUB_LIST_PAGE_TAGS = `<!DOCTYPE html><html><head><title>HHCLUB
|
|||||||
<div class="torrent-manage"><a href="download.php?id=900201">下载</a></div>
|
<div class="torrent-manage"><a href="download.php?id=900201">下载</a></div>
|
||||||
</div>
|
</div>
|
||||||
</body></html>`;
|
</body></html>`;
|
||||||
|
|
||||||
|
/** OurBits 详情页:简介是 div.ubbcode 里未渲染的 BBCode(站点靠前端脚本渲染),文件列表要另取 viewfilelist.php */
|
||||||
|
export const OURBITS_DETAIL_PAGE = `<!DOCTYPE html><html><head><title>OurBits :: 种子详情</title></head><body>
|
||||||
|
<a href="logout.php">退出</a>
|
||||||
|
<h1 id="top">Sample Show 2025 S01 2160p WEB-DL H265 AAC-UBWEB</h1>
|
||||||
|
<table width="100%">
|
||||||
|
<tr><td class="rowhead">副标题</td><td class="rowfollow">示例剧 | 全40集</td></tr>
|
||||||
|
<tr><td class="rowhead">基本信息</td><td class="rowfollow"><b>大小:</b>185.04 GB</td></tr>
|
||||||
|
<tr><td class="rowhead">简介</td><td class="rowfollow"><div id='kdescr'><div class='ubbcode'>[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]</div></div></td></tr>
|
||||||
|
<tr><td class="rowhead">种子文件</td><td class="rowfollow"><b>文件数:</b>40个文件<span id='filelist'></span></td></tr>
|
||||||
|
</table></body></html>`;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$comment": "2026-10-02 真实账号核对列表页 1 次(.local/site-samples/ourbits-torrents.html):标题列嵌套的 table.torrentname 有 5 个 td,MovieClaw 的 td:nth-child(n) 会先命中嵌套格子(大小 0、时间 N/A),改为只匹配行的直接子单元格;副标题在 td.embedded 里标签 div 之后,原定义取到的是标签;标签在 span.tag;列表页有 IMDb / 豆瓣 ID(label.imdb_rate / label.douban_rate 的 data 属性,IMDb 为纯数字,映射时补 tt + 7 位)。",
|
"$comment": "2026-10-02 真实账号核对列表页 1 次(.local/site-samples/ourbits-torrents.html):标题列嵌套的 table.torrentname 有 5 个 td,MovieClaw 的 td:nth-child(n) 会先命中嵌套格子(大小 0、时间 N/A),改为只匹配行的直接子单元格;副标题在 td.embedded 里标签 div 之后,原定义取到的是标签;标签在 span.tag;列表页有 IMDb / 豆瓣 ID(label.imdb_rate / label.douban_rate 的 data 属性,IMDb 为纯数字,映射时补 tt + 7 位)。 详情页(2026-10-02 核对 1 次):简介是 div.ubbcode 里未渲染的 BBCode,由详情解析按 BBCode 处理;文件列表按需取 viewfilelist.php。",
|
||||||
"torrents": {
|
"torrents": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"date_elapsed": {
|
"date_elapsed": {
|
||||||
@@ -49,5 +49,12 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"umt": {
|
||||||
|
"detail": {
|
||||||
|
"page": {
|
||||||
|
"fileListPath": "viewfilelist.php?id={id}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user