Files
UHD_Media_Tool/docs/plan/episode-resolution.md
T

60 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 集数解析与映射(2026-10-03 定)
解析器只回答「发布者声称这是第几季第几集」;本模块回答「媒体库应当把它当成哪一集」。参考 MP 的偏移表达式、ANI-RSS 的订阅预览,在其上加元数据校验、确定性换算、规则与待处理,Agent 兜底放最后。
ANI-RSS(GPL-2.0,只借思路不抄代码)摸排结论:一条订阅 = 一条 feed + 一个字幕组 + 一个 bgm 条目;集号靠一条正则;偏移只有整数,自动推断 = `-(feed 最小集号 - 1)`,不核对元数据;TMDB 只用于集标题(可选 Episode Group);体验来自「订阅预览」(按偏移算好的集号 + 已下载 + 缺集)与缺集 / 摸鱼提醒。
## 现状与缺口
- 本地 UUID 主身份、外部身份表、集单元的 `kind / content_type / segment / source_issue` 已有。
- `release-parser/offset.ts` 的偏移表达式求值器没有任何调用方。
- `ensureUnits` 拿解析结果直接找或建集单元:TMDB 第 2 季 12 集,解析出 S02E13 会建临时 S02E13,不报错。
- 整理(`organize-plan.ts`)、季包选文件(`downloads.ts`)、接管(`takeover.ts`)会对文件名重新解析,映射必须在这些地方同样生效。
## 判定流程
输入:解析结果 + 作品 + 季表(每季总集数、是否最新季、作品是否完结、已知每集播出日期)+ 资源发布时间 + 发布组 + 该作品的映射规则。只处理剧集类作品的正片(`content_type = main`、季号 ≥ 1);电影、特别篇、花絮原样通过。
1. **有适用规则**(作品 + 季 + 发布组,越具体越优先)→ 按规则换算 → 校验。校验失败:规则停用、开待处理,本条资源按「待确认」处理。
2. **无规则,原号校验**:
- 季存在且集号 ≤ 该季总集数 → 通过。
- 季总集数未知、或该季是最新季且作品未完结、且集号超出不多 → **放行**(元数据滞后),记 `unverified`。
- 否则 → 不通过,进第 3 步。
3. **确定性换算**(结果都要再校验,且只取唯一解):
- 季内绝对集号:`S02 13`、第 1 季 12 集 → `13 - 12 = S02E01`。
- 跨季绝对集号:季号是推定的(`seasonInferred`),集号超出第 1 季 → 按各季总集数累加换算。
- 与「元数据滞后」冲突时(最新在播季)用发布时间判:发布时间与换算后那集的播出日期相差 ≤ 7 天才认换算,否则按滞后放行。
- 综艺:有 `airDate` 时按播出日期对集。
4. **仍不行** → 资源已绑定作品但集数待确认:不建集单元,订阅评估跳过(原因 `episode_unresolved`),开待处理 `episode_mapping`(按作品 + 季 + 发布组去重),附建议规则。
结果写入 `source_release.episode_resolution`(原始季集、规范季集、方式 `raw / rule / absolute_in_season / absolute_cross_season / air_date / unverified / unresolved`、规则 id、证据),`parsed` 里的季集改为规范值,下游不用改口径。
## 映射规则
- 作用域:作品(必填)+ 来源季(可空)+ 发布组(可空)。不做全局 / 站点级(站点标题差异由别名表解决)。
- 类型:`expression`(复用 `offset.ts`,如 `EP-12`、`EP*2-1`,可带目标季)、`table`(`26 → S02E01`、`27-28 → S02E02`)、`special`(映射为特别篇 / 花絮 / 忽略)。
- 证据等级复用 `manual / rule_confirmed / multi_evidence / needs_review`,不用百分比。
- 失效:规则算出的结果校验不通过 → 停用并开待处理,不做置信度衰减。
- 规则建立或修改后,按作品重算已绑定资源的集数解析(不重做身份识别)。
- 建议规则:同作品 + 季 + 发布组下的待确认资源,用发布时间对播出日期配对,试 `EP±n` / `EP*2` / `EP*2-1`,全部样本成立才给建议。
## 分批
| 批次 | 内容 | 验收要点 |
| --- | --- | --- |
| 1 领域纯函数 | `packages/domain/src/episode-resolution/`:类型、校验、确定性换算、规则应用、建议规则推导、总入口 | domain 单测覆盖上面每个分支(含滞后放行、发布时间判定、多解拒绝、表格规则、双集) |
| 2 存储与识别接入 | 迁移(`episode_mapping_rule` 表、`source_release.episode_resolution`);季表加载;识别(`resolve.ts` 及其他 `ensureUnits` 调用方)接入;`parsedOf` 叠加;订阅评估跳过待确认;待处理 `episode_mapping`;规则失效;按作品重算 | server pg 测试:ANi 连续编号进库即为 S02E01 并能被订阅覆盖;规则失效开待处理;滞后放行不卡追更 |
| 3 文件侧接入 | 整理计划、季包选文件、接管、文件管理识别统一套用同一作品的映射 | 下载按 S02E01 计划、文件名 ` - 13` 整理后命名为 S02E01;季包按缺集选对文件 |
| 4 接口与界面 | contracts 端点:规则增删改、模拟预览(给定作品 / 季 / 发布组 / 草稿规则,列近期资源的原始 → 规范与校验结果);待处理 `episode_mapping` 的确认 / 修改 / 忽略;作品页与订阅详情「集数映射」面板 | 契约测试、web 单测、冒烟;文案过 `check:copy` |
| 5 Agent 兜底 | 能力 `episode_mapping.propose`(只读上下文包 → 结构化规则建议)与 `episode_mapping.apply`(经授权写规则,必须先模拟全部样本通过);登记到 Skill 与能力地图;`episode_mapping` 待处理接后台自动调查 | agent 测试;模拟不通过的建议不能写入 |
以后再做:TMDB Episode Group、Bangumi `sort / ep` 对照、综艺会员加更等变体细分。
## 状态
- [x] 批次 1
- [ ] 批次 2
- [ ] 批次 3
- [ ] 批次 4
- [ ] 批次 5