# 元数据运行手册(MD-1:语言回退链 + 每集元数据 + 媒体详情) ## 语言回退链 - 设置 → 元数据 → TMDB →「语言回退链」,即 `settings.metadata.languages`,缺省 `zh-CN, zh-SG, zh-TW, zh-HK, en-US`。 - 作品标题:按链逐个语言查 TMDB `translations`(语言 + 地区精确匹配);该语言译名为空时查同地区、文字相符的 `alternative_titles`(类型为空的优先);原始语言等于链中语言时原名也算。全部落空用请求语言下的 name / 原名。对照 MP `__update_tmdbinfo_cn_title`(中文名 → CN 别名 → SG 译名)。 - 中文名 `titleZh`:只在链里的中文语言中按顺序取(zh-CN 优先),值必须含汉字。链首改成 en-US 时标题变英文,`titleZh` 不变。 - 简介 / 标语:按链取 `translations` 的第一个非空值。 - 季 / 集:先按链首请求 `/tv/{id}/season/{n}`;已播出的集缺标题(TMDB 占位名"第 N 集""Episode N")或缺简介时,按链逐个语言补拉同一端点,补齐即停;链走完仍没有标题的集保留占位名(语言记为空)。未播出的集不触发补拉。 - 每个字段的来源值写 `metadata_field`,`language` 记实际取到的语言;同字段语言变了,旧语言的 tmdb 行删掉。 - `translations` 与 `alternative_titles` 写 `title_alias`(来源 tmdb,标语言;别名只在地区与文字相符时标,如 CN + 汉字 → zh-CN)。已有同文本别名(繁简归一化后同键)不重复登记,只给语言为空的 tmdb 行补语言。 ## 刷新 | 触发 | 拉哪些季的每集信息 | 新建集单元 | |---|---|---| | `POST /media-entities/{id}/refresh`(定时追踪刷新同) | 追踪中订阅的季 ∪ 库里已有集单元的季(最近 8 季) | 只在追踪中的季 | | `POST /media-entities/{id}/refresh?full=1`(详情页「刷新元数据」「更新每集信息」) | 全部正片季(最多 60) | 是 | - 刷新是后台任务 `refreshMetadata`(输入 `{mediaEntityId, full?}`),结果里 `titles` 是本次取到的标题 / 语言 / 中文名,`episodes[]` 是各季写入统计(`created` 新建单元数、`changedUnits` 有变化的单元数)。 - 增量:来源值和语言都没变的字段不写;只投影有变化的单元。不改编号、状态、路径绑定和资产覆盖。 - 现有作品补齐中文名 / 每集信息:对作品跑一次 `full=1`。批量: ```sh # 所有有 TMDB 身份的作品各跑一次(TMDB 请求走缓存;数量多时分批) curl -s -H "Authorization: Bearer $KEY" "$BASE/api/v1/media-entities?limit=200" | jq -r '.data.items[].id' | while read -r id; do curl -s -X POST -H "Authorization: Bearer $KEY" "$BASE/api/v1/media-entities/$id/refresh?full=1"; done ``` ## 集字段(字段级,可锁) - 集单元字段:`name`(投影到 `content_unit.title`)、`overview`、`airDate`(投影到 `air_date`)、`runtime`、`stillPath`、`voteAverage`、`voteCount`;季单元另有 `posterPath`。最终值在 `content_unit.metadata`,每个字段带来源 / 语言 / 时间 / 锁。 - 覆盖并锁定:`PUT /content-units/{id}/fields/{field}` `{value, lock?, reason?}`;取消:`DELETE` 同路径。锁定的字段刷新不改。界面:媒体库详情 → 季与集 → 每集行右侧铅笔。 ## TMDB 请求与缓存 - 富详情一次请求:`/{type}/{id}?language=链首&append_to_response=alternative_titles,credits,external_ids,translations`;季详情每语言一次。都走 `tmdb.request` PG 缓存(TTL / 空结果短 TTL / 条数上限见设置 → 元数据 → TMDB 缓存;对照 MP `@cached`:成功才缓存、业务失败不缓存)。 - 想立刻拿到 TMDB 刚改的数据:设置 → 元数据 → TMDB 缓存「清空」,再刷新。 - 仅 TMDB 作品详情页(`/console/media/tmdb/{type}/{id}`)的季在展开时拉 `GET /api/v1/media/tmdb/tv/{id}/season/{n}`,不落库。 ## 媒体详情页 - 媒体库详情与仅 TMDB 作品详情共用 `apps/web/app/components/media/media-detail.tsx`:背景图(图片代理 w1280,scrim 遮罩)、海报、标题 / 原名 / 年份 / 类型 / 评分 / 状态 / 季集数、简介、外部链接,主创(导演 / 主创 + 演员前 10,头像 w185),季折叠 + 每集行(剧照 w300、集号与标题、播出日期、时长、评分、简介折叠、库内状态)。 - 库内状态:作品有订阅时取覆盖矩阵(可切换版本目标);没有订阅时只看是否已入库。默认展开订阅的季,否则库里有文件的最新季,否则最新季。 ## 排查 | 现象 | 看哪里 | |---|---| | 标题仍是英文原名 | 作品详情「字段来源与锁」里 `标题` 的来源与语言;是否被锁;设置里的语言链;对作品跑 `full=1` | | 某集没有中文标题 | 该集在 TMDB 各语言都没有译名时保留占位名 / 英文名,属正常;可在每集行手动改并锁定 | | 季里没有集 | 默认刷新不为未追踪的季建集单元,点「更新每集信息」(full) |