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

@@ -152,11 +152,12 @@ export function episodeMetadataMissing(u: UnitForNfo | undefined): boolean {
return !u || (!filled(u.metadata) && !str(u.title) && !u.air_date);
}
/** 图片路径:作品海报 / 背景图,季海报,集剧照 */
/** 图片路径:作品海报 / 背景图 / 标志,季海报,集剧照 */
export function imagePathsOf(entityMeta: unknown) {
return {
posterPath: str(val(entityMeta, "posterPath")) ?? str(val(entityMeta, "posterUrl")),
backdropPath: str(val(entityMeta, "backdropPath")),
logoPath: str(val(entityMeta, "logoPath")),
};
}
export const unitPosterPath = (m: unknown) => str(val(m, "posterPath"));
@@ -72,6 +72,7 @@ export function richEntityFields(r: TmdbRichDetail): Partial<Record<EntityMetada
originCountry: v(r.originCountry),
...(r.posterPath ? { posterPath: v(r.posterPath) } : {}),
...(r.backdropPath ? { backdropPath: v(r.backdropPath) } : {}),
...(r.logoPath ? { logoPath: v(r.logoPath) } : {}),
...(r.genres.length ? { genres: v(r.genres) } : {}),
...(r.networks.length ? { platform: v(r.networks.join(" / ")) } : {}),
...(r.entityType === "tv" && r.episodeCount !== null ? { episodeCount: v(r.episodeCount) } : {}),
@@ -140,6 +140,7 @@ const ENTITY_NFO_FIELDS: ReadonlySet<string> = new Set([
"externalIds",
"posterPath",
"backdropPath",
"logoPath",
]);
/**