feat(organize): 文件级标题粗核,混合包里明显不是本作品的视频降为待确认

- 同一批视频里文件名标题与作品标题 / 原名 / 别名明显不符(没有足够共同词)的排除为 title_mismatch,不按本作品命名入库;
- 只在同批至少一个文件对得上作品时才判断,剧集只看带 SxxEyy 的文件,用户逐文件指定过的不核;
- title_mismatch 算「本该入库却被排除」:记录部分完成、开待处理、Move 不移除下载任务。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-03 23:33:41 +08:00
1 parent b40716d74f
commit c532060c83
10 files changed
+283 -10

No files matched your search

+47
View File
@@ -5,6 +5,8 @@ import {
planOrganize,
sidecarLanguageSuffix,
sidecarStem,
titleMatchesNames,
titleMismatches,
} from "../src/index.ts";
const MiB = 1024 ** 2;
@@ -407,3 +409,48 @@ describe("原地入库计划", () => {
expect(p.requiresApproval).toBe(false);
});
});
describe("文件级标题粗核", () => {
const names = ["盗梦空间", "Inception"];
it("合集里别的电影判为不符;对得上的、解析不出标题的不拦", () => {
const r = titleMismatches(
[
{ path: "a", name: "Inception.2010.1080p.BluRay.x264-GRP.mkv" },
{ path: "b", name: "Interstellar.2014.1080p.BluRay.x264-GRP.mkv" },
{ path: "c", name: "盗梦空间.2010.2160p.mkv" },
],
names,
"movie",
);
expect([...r]).toEqual([["b", "Interstellar"]]);
});
it("全都对不上时不拦(多半是作品名的另一种写法)", () => {
expect(titleMismatches([{ path: "a", name: "Sousou.no.Frieren.S01E01.mkv" }], ["葬送的芙莉莲"], "tv").size).toBe(0);
expect(
titleMismatches(
[
{ path: "a", name: "Frieren.S01E01.1080p.WEB-DL.mkv" },
{ path: "b", name: "Sousou.no.Frieren.S01E02.1080p.WEB-DL.mkv" },
],
["葬送的芙莉莲", "Frieren: Beyond Journey's End"],
"tv",
).size,
).toBe(0);
});
it("剧集只看带 SxxEyy 的文件:只有集标题的文件名不拦", () => {
const r = titleMismatches(
[
{ path: "a", name: "Severance.S01E01.1080p.WEB-DL.H264-GRP.mkv" },
{ path: "b", name: "Other.Show.S01E01.1080p.WEB-DL.mkv" },
{ path: "c", name: "01 - The Beginning.mkv" },
],
["人生切割术", "Severance"],
"tv",
);
expect([...r.keys()]).toEqual(["b"]);
});
it("中文标题按相邻两字比较:同系列相近的标题不拦", () => {
expect(titleMatchesNames("哈利波特与密室", ["哈利波特与魔法石"])).toBe(true);
expect(titleMatchesNames("星际穿越", ["盗梦空间"])).toBe(false);
});
});