feat(scripts): TMDB 多语言别名清理脚本与保留规则文档

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 18:14:54 +08:00
1 parent 7efbe25c17
commit ce93ea3a93
5 files changed
+453

No files matched your search

@@ -336,6 +336,7 @@ export interface TmdbPort { searchMovie(q: string, year?: number): Promise<TmdbS
| --- | --- | --- |
| 查询名顺序、按类型分步计划、年份容差 ±1、标题精确匹配优先、别名回退、季年份匹配、无类型 id 的双查加消歧、连接失败和不存在分开 | ① 所有 direct 或 alias 结果**只作为候选**,按证据打分输出 `candidates[]`;分数够高并且只有一个候选时才自动绑定,否则进入待识别池(REQ §7.5);② 别名回退要**限制拉详情的次数**(例如前 5 个),避免上游那样对每个候选都请求一次;③ 已经存在本地实体时,先查 `title_alias`(pg_trgm)召回本地实体,再查 TMDB;④ TMDB 缺失或失败**不阻断**有本地证据的入库(REQ §14.1.3) | 本地 UUID 优先;控制成本;REQ 要求不因外部服务阻断 |
| 中文标题补全 | 放进元数据协调层(REQ §7.3 字段级来源),**不改变路径绑定** | REQ §7.1 |
| 别名与译名(`__get_names` 用全部 `alternative_titles` + 全部 `translations`;`__update_tmdbinfo_extra_title` 取 en / hk / tw / sg 译名,`__update_tmdbinfo_cn_title` 取 CN 地区别名) | **多语言保留规则**(2026-10-06 用户规则,`packages/adapters/src/tmdb/language-policy.ts`):译名、别名、简介、标语只留简中(zh-CN / zh-SG / zh-Hans)、繁中(zh-TW / zh-HK / zh-MO / zh-Hant)、英文(en-*)、作品原语言;`alternative_titles` 按地区推断语言(CN / SG 简中、TW / HK / MO 繁中、英语区英文、原产地区原语言)并校验文字,推断不出或文字不符的丢弃;原产地区的罗马字别名(type 含 roma)记 `<原语言>-Latn`。识别比较(`details().aliases`、`match.ts` 别名回退、`tmdbToCandidate`、按作品搜资源的 `work-match.ts`)同样只用这些 | 用户规则:俄 / 葡 / 越 / 西 / 泰等与作品无关的语言别名只会制造误匹配和噪声;MP 的 en / hk / tw / sg / CN 取值都在保留范围内 |
---
+47
View File
@@ -292,6 +292,53 @@ DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/identity
`POST /media-entities/{id}/refresh?full=1`,季 / 集单元会按 TMDB 重建为 confirmed。季 0(特别篇)自 DH-1 起也在 full 刷新
范围内(`metadata.includeSpecials` 缺省开),回刷即可重建。
## TMDB 多语言保留规则(2026-10-06)
用户规则:「除了简繁、英文,还有源语言之外,不需要获取其他更多的别名」,TMDB 的多语言数据整体按这个保留。
规则是一个纯函数模块 `packages/adapters/src/tmdb/language-policy.ts`(单测 `language-policy.test.ts`)。
- **保留的语言**:简中(zh-CN / zh-SG / zh-Hans,及不带地区的 zh)、繁中(zh-TW / zh-HK / zh-MO / zh-Hant)、英文(en-*)、
作品原语言(TMDB `original_language`,按主语言比较,如 ja → ja-JP / ja 都算;原语言是中文 / 英文时不额外增加,
原语言是中文时 zh 的其它地区也算原语言)。原名(`original_title / original_name`)总是保留。
- **alternative_titles**(只有地区没有语言):CN / SG → 简中,TW / HK / MO → 繁中,US / GB / AU / CA / NZ / IE → 英文,
作品 `origin_country` 里的地区 → 原语言;再校验文字:中文要汉字且不含假名 / 谚文,带地区时看简繁特有字(明显是另一种的不要),
日文要假名或汉字,韩文要谚文,泰 / 俄 / 阿 / 希伯来 / 印地等按各自文字,英文和其它拉丁语言要拉丁字母且不含非拉丁文字。
推断不出(没有地区、地区不在上面)或文字都不符的丢弃。例外:原产地区、type 含 roma(TMDB 的 "Romaji")的罗马字别名记
`<原语言>-Latn`(kind `romanized`),资源标题常写罗马字。
- **应用位置**:`TmdbClient.details()`(识别比较用的 `aliases` / `titles`,`match.ts` 别名回退、`tmdbToCandidate`、
`work-match.ts` 按作品搜资源都只看到保留语言)、`fetchRichDetail`(`translations` / `alternativeTitles` 只留保留语言,
别名带推断语言)、建档 `seedAliases` 与刷新 `tagTitleAliases` 写 `title_alias`(语言写规范化后的值,不再写空语言的 `other`;
本地化名文字与语言不符时——TMDB 缺该语言译名时回退成原名——不按该语言登记)。
- **语言链**(设置 `metadata.languages`):缺省 `zh-CN, zh-SG, zh-TW, zh-HK, en-US` 全在保留范围。设置仍允许填任意 `xx-YY`,
但按作品收敛:不在保留范围的语言(对这部作品既不是中英文也不是原语言)从链里去掉,标题 / 简介 / 标语 / 季集名都不取它;
请求语言(链首)被去掉时请求语言下的值不拿来兜底;链全被去掉时用缺省链。季集详情不知道原语言时(链里有中英文以外的语言)
先读一次作品详情(走请求缓存)。
- 作品与单元的 `metadata` 只存按语言链取到的单个值(带语言),不存 translations 列表,没有别的多语言数据。
### 存量清理(`scripts/tmdb-alias-language-cleanup.ts`)
缺省只读(`--dry-run` 显式只读,与 `--apply` 互斥);`--apply` 在一个事务里删除并写审计 `metadata.tmdb_alias_language_cleanup`
(payload 列出每条删除的作品 / 别名 / 语言 / kind / 原因);`--entity <id>` 只处理一部作品;`--samples N` 每类样例条数(缺省 5)。
连接方式同上(用户栈的 PG 取容器 IP):
```sh
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/tmdb-alias-language-cleanup.ts # 看统计与样例
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/tmdb-alias-language-cleanup.ts --apply # 逐类目过目后执行
```
- **判定口径**(`title_alias.source` 能区分来源):只动 `source = tmdb` 且未锁定的行;`user` / `site` / `agent` / `nfo` / `import`
来源与锁定的行一律不动(清单里只报数量)。tmdb 行中:`kind = original` 保留;与作品主标题 / 原标题归一化相同的保留;
`language` 非空 → 规范化后在保留范围(原语言取 `media_entity.metadata.originalLanguage`,没有时取 tmdb 字段来源)保留,否则删
(原因 `language`);`language` 为空(旧版建档写的 `other` 等)→ 汉字(不含假名 / 谚文)、拉丁字母、没有字母的保留,其它文字
只在与原语言相符时保留,否则删(原因 `script`)。拉丁字母分不出英 / 法 / 西 / 葡,空语言的拉丁别名一律按英文保留——
要彻底收敛这部分,对作品跑一次元数据刷新不会删它们(刷新只增不删),需要时人工处理。
- **字段来源**:`metadata_field`(来源 tmdb)里语言不在保留范围的值只报告不删(删了会让最终值暂时没有来源)。对清单里的作品
跑一次元数据刷新即收敛(同字段换语言时删旧行),批量用计划页「元数据语言回刷」(`metadata.backfill_languages`)。
- 输出:别名总数 / 删除 / 保留,保留按原因计数;删除按「语言 / kind」分组计数,每组列样例(作品、原语言、别名);
字段来源按「语言 / 作品或单元·字段」计数并列涉及的作品。
- **对部署库**(lessons 第 22 条):先 dry-run,协调者逐类目看清单(重点看删除组里有没有人工补录却被记成 tmdb 来源的、
原语言为空导致误删的日 / 韩 / 泰文别名)再 `--apply`。原语言为空的作品只保留中英文,先对这些作品刷新元数据补上原语言再清理更稳。
## 排查
```sql
+2
View File
@@ -9,6 +9,8 @@
- 季 / 集:先按链首请求 `/tv/{id}/season/{n}`;已播出的集缺标题(TMDB 占位名"第 N 集""Episode N")或缺简介时,按链逐个语言补拉同一端点,补齐即停(简介只从简介链里的语言取;只缺简介且剩下的语言都不在简介链里时不再补拉);链走完仍没有标题的集保留占位名(语言记为空)。未播出的集不触发补拉。
- 每个字段的来源值写 `metadata_field`,`language` 记实际取到的语言;同字段语言变了,旧语言的 tmdb 行删掉。
- `translations` 与 `alternative_titles` 写 `title_alias`(来源 tmdb,标语言;别名只在地区与文字相符时标,如 CN + 汉字 → zh-CN)。已有同文本别名(繁简归一化后同键)不重复登记,只给语言为空的 tmdb 行补语言。
- 多语言保留规则(2026-10-06):TMDB 的译名 / 别名 / 简介 / 标语只保留简中、繁中、英文和作品原语言,语言链按作品收敛
(链里的 ja-JP 只对日语原作生效,fr-FR 这类对原语言不是它的作品跳过)。规则、清理脚本见 `identity.md`「TMDB 多语言保留规则」。
## 刷新