chore(release): v0.3.26

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-03 20:08:42 +08:00
1 parent 7793c7b3bc
commit 6b19cede62
15 files changed
+26 -73

No files matched your search

+11
View File
@@ -4,6 +4,17 @@
## [Unreleased]
## [0.3.26] - 2026-10-03
### 新增
- 集数映射:资源识别到作品后,按作品季表校验解析出的季集号,不再按错号建出假的集(例如第 2 季只有 12 集却建出 S02E13)。元数据滞后(季总集数未知、在播最新季超出不多)先按原号放行。
- 确定性换算:季内绝对集号(`S02 13` → S02E01)、跨季连续编号(ANi `- 25` → 第 2 季对应集)、综艺按播出日期对集;与元数据滞后分不清时看发布时间是否贴近目标集播出日期。
- 映射规则(作品 + 季 + 发布组):偏移表达式(`EP-12`)、对照表、特别篇 / 花絮 / 忽略;规则算出越界自动停用并转待处理。
- 对不上的资源照常绑定作品,但不建集、订阅评估跳过,进待处理「集数待确认」(同作品同季同组合并,附建议规则),可确认 / 修改 / 忽略。
- 整理、季包选文件、刮削、文件管理识别与推荐名统一套用映射,下载与整理认同一集;待确认的文件不按原号入库。
- 作品页「集数映射」:季表摘要、规则管理、草稿规则模拟预览、应用后按作品重算;订阅详情显示映射摘要。
- 智能体兜底:集数待确认事项可由后台调查查看上下文、模拟、写规则(需持续授权,写入前服务端强制模拟全部样本通过);没有授权时把模拟通过的规则留作建议,一键确认。迁移 `0066_episode_mapping`。
## [0.3.25] - 2026-10-03
### 新增
+3 -1
View File
@@ -2,7 +2,7 @@
内部使用、Agent 自动化优先的媒体整理入库平台。需求基线见 [media_automation_requirements_architecture_v0.7.md](media_automation_requirements_architecture_v0.7.md)。
当前版本 v0.3.25,本机测试环境已部署;各版变化见 [CHANGELOG.md](CHANGELOG.md)。业务逻辑以 MoviePilot v3 为参考,逐项对照见 [MoviePilot v3 对照](docs/porting/moviepilot-v3-comparison.md)。正在推进的计划与待办见 [docs/plan](docs/plan/README.md),开发与发布约定见 [CLAUDE.md](CLAUDE.md)。
当前版本 v0.3.26,本机测试环境已部署;各版变化见 [CHANGELOG.md](CHANGELOG.md)。业务逻辑以 MoviePilot v3 为参考,逐项对照见 [MoviePilot v3 对照](docs/porting/moviepilot-v3-comparison.md)。正在推进的计划与待办见 [docs/plan](docs/plan/README.md),开发与发布约定见 [CLAUDE.md](CLAUDE.md)。
## 功能
@@ -19,6 +19,8 @@
- 浏览器:camofox BrowserProvider、原站视图(截图 + 坐标输入)、接管租约、下载捕获走统一提交。
- 运维:管理员登录(TOTP / Passkey)、API Key 分级、主密钥轮换、定时任务看板、统一任务页、运行状态页、审计、备份与只读对账恢复。
- 集数映射:识别后按作品季表校验季集号(元数据滞后放行),绝对集号 / 播出日期确定性换算,作用域为作品 + 季 + 发布组的映射规则,模拟预览,待确认进待处理,智能体兜底写规则(写入前强制模拟)。
未做:综艺正片覆盖、双版本组合校验、旧库分范围接管、Agent 偏好选片、规则学习与回放、Emby 库存参与决策。
## 快速启动
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/server",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/main.ts" },
"tasks": {
"dev": "deno run -A --watch --env-file=../../.env src/main.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/web",
"version": "0.3.25",
"version": "0.3.26",
"private": true,
"type": "module",
"scripts": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"version": "0.3.25",
"version": "0.3.26",
"workspace": [
"./packages/adapters",
"./packages/agent",
+1 -2
View File
@@ -17,7 +17,7 @@
## 当前状态
- 版本 v0.3.25,本机测试环境已部署。
- 版本 v0.3.26,本机测试环境已部署。
- 开发与发布约定见仓库根 [CLAUDE.md](../../CLAUDE.md)。
## 待办
@@ -31,7 +31,6 @@
### 进行中
- 集数解析与映射:[episode-resolution.md](episode-resolution.md),5 批,Agent 兜底在最后。
- 补字幕:[subtitles.md](subtitles.md),第 1、2 步已完成;待办:以后接进整理 / 订阅工作流。
- 沙箱第二批:站点网页、RSS、网页抓取的 HTML / XML 解析迁入常驻子进程池(ADR-005)。
-59
View File
@@ -1,59 +0,0 @@
# 集数解析与映射(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.inspect`(只读上下文包)、`episode_mapping.simulate`(试草稿规则)与 `episode_mapping.apply_rule`(经授权写规则,服务端强制先模拟全部样本通过、不误伤已对上的资源);Skill「集数映射」与能力地图;`episode_mapping` 待处理接后台自动调查,没有授权时留「智能体建议」一键确认 | agent 测试;模拟不通过的建议不能写入 |
以后再做:TMDB Episode Group、Bangumi `sort / ep` 对照、综艺会员加更等变体细分。
## 状态
- [x] 批次 1
- [x] 批次 2
- [x] 批次 3
- [x] 批次 4
- [x] 批次 5
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/adapters",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts", "./fsworker": "./src/fs/fsworker.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/agent",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/contracts",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/db",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/domain",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/mapping",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/tasks",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umt/testkit",
"version": "0.3.25",
"version": "0.3.26",
"exports": { ".": "./src/index.ts" },
"tasks": {
"test": "deno run -A npm:vitest run",