feat(scrape): TMDB 标志写 clearlogo.png

- 富详情请求加 images(include_image_language=zh,en,null),作品原语言不是中英文时另取 /images;
  选一张 PNG 标志(原语言 → 中文 → 英文 → 无文字,同语言按评分)存作品字段 logoPath,变化时触发重刮
- 刮削布局新角色 clearlogo:电影写影片目录 clearlogo.png、剧集写剧集根目录,库根 / 平铺电影 <视频名>-clearlogo.png;
  覆盖方式与 hash 规则同其它图片
- 布局金样差分登记偏离 tmdb_clearlogo;mock TMDB 支持 logos 与 /images

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-06 19:37:34 +08:00
1 parent 1dca95f883
commit 680419bb64
16 files changed
+379 -12

No files matched your search

+54
View File
@@ -199,6 +199,60 @@ describe("刮削目标布局", () => {
expect(atRoot.map((x) => x.path)).toEqual(["x.nfo", "x-poster.jpg", "x-fanart.png"]);
});
it("标志 clearlogo.png:电影写影片目录、剧集写剧集根目录;库根 / 平铺的电影用 <视频名>-clearlogo.png;选中季 / 集不写", () => {
const withLogo = { ...images, logoPath: "/logo.png" };
const movie = planScrapeTargets({
kind: "movie",
workDir: "星际穿越 (2014)",
videos: [{ path: "星际穿越 (2014)/星际穿越 (2014) - 1080p.mkv" }],
images: withLogo,
options: { images: true, episodeThumbs: true },
});
expect(movie.filter((x) => x.role === "clearlogo").map((x) => [x.path, x.imagePath])).toEqual([
["星际穿越 (2014)/clearlogo.png", "/logo.png"],
]);
const atRoot = planScrapeTargets({
kind: "movie",
workDir: null,
videos: [{ path: "x.mkv" }],
images: withLogo,
options: { images: true, episodeThumbs: true },
});
expect(atRoot.map((x) => x.path)).toEqual(["x.nfo", "x-poster.jpg", "x-fanart.png", "x-clearlogo.png"]);
const tv = planScrapeTargets({
kind: "tv",
workDir: "S",
videos: [{ path: "S/Season 1/a.mkv", season: 1, episode: 1 }],
images: withLogo,
options: { images: true, episodeThumbs: true },
});
expect(tv.slice(0, 4).map((x) => x.path)).toEqual([
"S/tvshow.nfo",
"S/poster.jpg",
"S/fanart.png",
"S/clearlogo.png",
]);
const seasonOnly = planScrapeTargets({
kind: "tv",
workDir: "S",
videos: [{ path: "S/Season 1/a.mkv", season: 1, episode: 1 }],
images: withLogo,
options: { images: true, episodeThumbs: true },
parts: { work: false },
});
expect(seasonOnly.some((x) => x.role === "clearlogo")).toBe(false);
// 关图片不写;没有标志不写
const noImages = planScrapeTargets({
kind: "tv",
workDir: "S",
videos: [{ path: "S/Season 1/a.mkv", season: 1, episode: 1 }],
images: withLogo,
options: { images: false, episodeThumbs: false },
});
expect(noImages.some((x) => x.role === "clearlogo")).toBe(false);
expect(movie.length).toBe(4);
});
it("剧集视频在库根:不写 tvshow / 季文件,只写集 NFO", () => {
const t = planScrapeTargets({
kind: "tv",