- deno task test:all(scripts/test-all.sh):逐包跑完再汇总,连不上测试库直接失败, web 用 Node 跑 vitest;deno task ci 改用它 - deno task release(scripts/release.sh):工作区不干净、CHANGELOG 无本版条目即拒绝; 打 tag、构建、只替换 app、核对健康接口版本 - deno task dev:up:起开发库并迁移到最新;开发 API 端口改 4390(4380 留给本机部署版) - CLAUDE.md:命令、提交与发布约定、文档放哪 Co-Authored-By: Claude Opus 5.5 <[email protected]>
49 KiB
MoviePilot v3 逐项业务对照
继续开发前,先逐项核对现有业务与 MoviePilot v3 的处理逻辑。每项同时说明业务结果、失败边界、本项目差异和需要补的证据;完成对照后再讨论实现调整。本文是当前对照记录,尚未完成的项目明确列为待核对。
日期:2026-10-01。本项目业务代码基线:8013196e3f5e6a8c4ea0cd26cf77294a82a13ddd,v0.3.7。前置材料:开发情况基线、工程检查。初始对照阶段只读源码并更新文档;后续用户授权的实现状态见第 4、5 节。
1 参考基线和判定方法
| 项目 | 本轮固定基线 |
|---|---|
| MoviePilot 仓库 | jxxghp/MoviePilot |
| 参考发布版本 | v3.0.10-1,提交 0aa857173f77de31c7c8d9d2e12052d99f37bcc1,2026-09-28;version.py 已核对 |
| 分支查询 | 本轮只读查询时 v3 分支为 5741d3c56d761d87868d4f2d0515ac5c498f94d6;本报告采用上面的发布标签,后续逐项核对不随分支移动 |
| 本地参考位置 | /tmp/umt-moviepilot-v3-review-20261001,独立浅克隆,未改上游源码 |
| 旧资料 | 既有移植文档使用 e6820a8/早期 v3.0.0;原参考仓库保持不变,旧样本结论不直接升级为本轮结论 |
| 证据范围 | 阅读当前源码、迁移和测试断言;没有启动 MP 服务或运行上游测试,也没有对本项目新增故障注入 |
MP 是优先采用的业务参考;用户已确认尽量复用其成熟业务逻辑和实现,存在明确需求差异时再讨论调整。最终行为仍由本项目需求和用户确认决定。两边使用不同任务和数据机制,只比较同一场景的业务结果,不因模块名字相近就认定能力相同。已有 MP 差分样本、运行记录和有意偏离登记继续保留,按各自提交解释。
每项记录五件事:触发场景;MP 的明确处理分支;本项目正式调用路径;差异属于实现缺口、验收缺口、有意调整还是暂不适用;拟采用的规则及最小验证场景。源码结论、未复现影响和讨论建议分开。参考行为与来源登记沿用 移植规范。
2 顺序和进度
按下面顺序逐项讨论。状态「源码对照完成」只表示这一项的控制流核对已完成,不表示故障验收或实现调整已经完成。
| 顺序 | 业务主题 | 核对重点/需求 | 本轮状态 |
|---|---|---|---|
| 01 | 任务持久化、恢复和升级兼容 | 接受请求、入队、回填、中断恢复、旧任务处置;工程检查 §2 | 源码对照完成,恢复原则已认可;局部恢复修正和 9 个故障测试已完成,见第 4 节 |
| 02 | 下载纳管与实例隔离 | 管理标签、接管、去标签、同 hash 多实例、暂停/删除范围;R14、R28 | 正在逐项讨论;下载入口与浏览器详情页交接已确认,见第 5 节;其余待核对 |
| 03 | 部分入库、缓存清理与磁盘水位 | 未完成文件、H&R、保留期、未纳管占用、同卷汇总;R15、R21 | 待核对 |
| 04 | 整理计划、替换、路径与记录 | 冻结目标、跨卷、字幕随行、替换旧版本、记录删除;R07、R15、R23 | 待核对;01 仅覆盖恢复机制 |
| 05 | 刮削与媒体文件布局 | NFO/图片、缺失与覆盖、部分失败、任意目录、自动触发;R10、R11 | 待核对;01 仅覆盖刮削任务入队 |
| 06 | 识别、身份与映射治理 | 本地身份、人工锁、详情 ID、跨季、元数据滞后、错误关联;R03、R08、R09、R22 | 待核对 |
| 07 | 订阅完成条件与多版本 | 追更、综艺正片/上下段、整季包、独立双版本;R02、R04、R05 | 待核对 |
| 08 | 规则、选片、升级与换源 | 硬条件、优先级、偏好学习、替换计划、授权边界;R16、R20、R27 | 待核对 |
| 09 | RSS、站点快照、搜索与详情 | 去重补漏、缓存新鲜度、限流、文件清单、四站证据;R01、R25、R30 | 待核对 |
| 10 | 浏览器辅助与人工接管 | HTTP/浏览器切换、挑战升级、同会话、交还与重启;R06、R31、R32 | 待核对 |
| 11 | 旧库接管、库存与媒体服务器 | 初次扫描、影响预览、分范围纳管、查询 unknown、资产对账;R09、R18、R24 | 待核对 |
| 12 | 智能体执行与授权 | 能力调用、审批、后台等待、预算、恢复与模型证据;R12、R17、R19、R26、R29 | 待核对 |
| 13 | API、公开记录与管理员入口 | 双入口行为、增量、鉴权、多实例配置;R13、R23、R28 | 待核对 |
| 14 | 验收、备份恢复与发布 | 必执行测试、页面样本、版本迁移、恢复演练、镜像来源;工程检查 §3 | 待核对;MP 中无等价要求的部分独立验收 |
3 第一项:任务持久化、恢复和升级兼容
3.1 业务场景与对照结论
| 场景 | MP v3.0.10-1 | 本项目 v0.3.7 | 差异判定与建议 |
|---|---|---|---|
| 请求已接受,执行队列暂时失败 | 整理入口先持久化 admission 并取得租约,再入进程内队列;入队失败保留持久记录和错误,交给恢复路径 | enqueueTracked 依次写业务任务、引擎入队、回填 run;queueScrape 也有三步,回填失败共用入队失败 catch |
恢复边界需要补强。 已接受但未关联成功应保留可恢复事实;不能仅因回填失败就宣称外部入队失败。具体双写方案待故障验证后选择 |
| 查询恢复记录失败 | __replay_pending 的 claim 查询异常记录日志并返回,本轮不恢复;明确空结果另行返回 |
enqueueSweep 的 engine.get(...).catch(() => null) 把查询异常与不存在合并,随后可按新时间槽补投 |
状态判定需要调整。 查询失败应记录并跳过本轮;补投必须依据明确的不存在/可重投终态,并保留现有幂等与租约边界 |
| 升级后遇到旧任务/检查点 | 有版本化输入和检查点;当前和指定 legacy 检查点显式解码,未知版本拒绝;一次执行账本迁移将有旧执行迹象的任务隔离到 manual_review |
当前只注册 scrapeMedia v2,旧 v1 输入不同;0058 删除旧 media_scrape 表,worker 对旧版本没有对应认领处理器 |
升级处置缺口。 不能无限承诺自动兼容,也不能让旧任务无声悬空。升级前列出在途版本,再决定兼容执行、迁移或带理由终止;无法确定副作用时保留证据并人工处理 |
| 已完成的外部步骤遇到进程中断 | 成功步骤直接返回持久结果;遗留 started 先观察,已发生则补成功,未发生才重做,未知/冲突进入人工复核 |
OpenWorkflow 持久步骤、tasks_op_ledger fencing、asset_operation、冻结计划和文件恢复已经存在;E4 和 tasks 崩溃恢复测试覆盖同版本 worker 中断 |
保留现有机制,补指定故障证据。 不能把入队关联缺口扩展成「没有崩溃恢复」。完整文件冲突和替换场景留在 04 逐项核对 |
| 业务结果提交与后续事件通知 | 整理历史、终态结算、receipt 和 outbox 由同一短事务提交,提交后再派发 | 整理核验中资产/路径、业务记录和 organization.changed 在业务事务内提交;outbox 中继再向引擎派发 |
方向一致。 本项目已有 outbox,但刮削与通用任务入口尚未因此获得原子关联;还需核对中继的重投窗口和业务唯一约束 |
| 正式 handler 意外漏注册 | MP 的 runtime/tasks.py 管理进程内异步任务生命周期,与本项目的任务名+版本 handler 注册不是同一机制 |
buildTaskRegistry 缺核心任务时注册 stub;现有测试主要断言名称。当前正式装配已覆盖最初 9 个核心任务 |
本项目独立维护风险。 建议正式装配验证 handler 来源,缺失时明确失败;MP 的生命周期 TaskRegistry 不能证明这个问题已有等价解决 |
这里的 MP 行为限定在已读的整理任务链,不能推广成 MP 的全部刮削、下载或任意任务都遵守同一协议。尤其 MP 的「持久准入+内存队列」与本项目的「业务库+持久引擎库」不等价:可以借鉴恢复规则,不能照搬队列实现。MP claim 的未命中也可能表示没有取得租约,并非严格等价于本项目查询 run 得到「不存在」。
升级兼容也有明确范围:MP 的分类检查点 v1→v2 迁移遇到已有执行状态、执行载荷或步骤证据时不重写旧计划,继续使用已知旧版本解码路径。这支持「保留已经产生的执行证据」的规则,不能据此承诺任意旧 handler 都能继续执行。见 检查点迁移。
本项目刮削双写控制流已确认,但本轮没有故障注入证明实际受影响。上一轮线上只读检查未发现未结束的旧版刮削 run,也没有 scrape_record 记录;该时点结论不代替升级策略。见 工程检查 §2。
3.2 精确来源
以下 MP 链接全部固定在 0aa8571,行号仅适用于该提交。上游测试名称说明已存在对应断言,本轮没有运行这些测试。
| 结论 | MP 源码与测试 | 本项目源码/已有验证 |
|---|---|---|
| 先持久接受,再安排执行 | workflow.py TransferQueueService.put;queue.py __record_enqueue_failure;test_transfer_queue_service.py test_transfer_queue_service_commits_admission_before_failed_enqueue 使用 SQLite 仓储注入队列失败 |
common.ts enqueueTracked 第 134 行;scrape.ts queueScrape 第 152 行 |
| 查询异常不当作不存在 | queue.py __replay_pending 第 754 行;admission.py claim_recoverable;test_transfer_pending_replay.py test_replay_survives_db_failure 断言不执行恢复 |
common.ts enqueueSweep 第 159 行起 |
| 旧执行迹象保守隔离 | models.py TransferPlanCheckpoint.from_payload;迁移 _backfill_pending;test_transfer_execution_migration.py test_upgrade_is_conservative_and_repairs_interrupted_indexes |
handlers.ts 第 193 行;0058;引擎 startWorker 第 221 行 |
| 步骤恢复先看已有结果和实际副作用 | execution.py _DurableTransferStepRunner.run;test_transfer_execution_runner.py 成功步骤不重做、未知孤立步骤进入人工复核断言 |
op-ledger.ts;organize.ts;E4、tasks 崩溃恢复 |
| 结果和事件共同提交 | chain.py TransactionalChainDurableEventWriter.transfer_result |
organize.ts 核验事务第 1386 行、emitRecord 第 1710 行;outbox-relay.ts 第 46 行起 |
| handler 装配风险不可强行类比 | runtime/tasks.py | context.ts 第 96 行;modules.test.ts 第 86 行 |
另有结算回滚/重放专项断言:test_chain_durable_events.py 检查 outbox 冲突回滚历史与 pending、陈旧租约不写业务、并发结算只提交一次。这些场景值得纳入后续验收,不能把本项目已有的业务事务直接等同于全部专项均已通过。
MP 还在 test_transfer_planning_checkpoint.py 检查非预览整理缺少 durable writer/execution repository 时,在副作用前拒绝执行。这可支持本项目「关键装配缺失应明确失败」的原则,仍不是相同的 handler 注册方案。
3.3 已确认的恢复原则和验收场景
用户认可这一项的恢复方向,并明确避免过度设计和过度防御。以下原则按团队内部产品的规模执行,讨论阶段的原则已落实局部修正,见第 4 节。
- 请求接受后必须可追踪、可恢复。 已创建的业务记录、稳定身份和原输入要能关联到已有 run;关联回填失败与真正入队失败要能区分。查不清入队结果时记录不确定性,不能直接假定没有副作用。
- 不存在、已结束和查不到是三种不同事实。 临时查询失败跳过本轮并保留诊断;明确查无 run 才进入补投判断;已有运行不能只因到达新时间槽就替换。
- 升级检查实际在途任务。 优先等待旧任务结束,或明确说明后终止并通过现有入口重新发起;确有未完成任务必须继续且不能重做时,再评估兼容或迁移。没有在途旧任务时,不新增旧处理器和通用兼容层。涉及已经执行的文件操作时保留原输入和执行证据。
- 恢复复用已有结果。 沿用现有冻结计划和已完成步骤;普通查询故障等待下轮重查,可重试失败使用已有重试。删除、覆盖或替换文件的实际状态不明或冲突时,停止自动重放并在现有记录中说明,不为所有异常新增人工审核流程。
最小验收样本:
| 样本 | 注入点 | 应核对的结果 |
|---|---|---|
| T01 | 业务记录插入后、引擎入队前退出 | 能补投或显式结束,不能永远只显示 queued;保留同一业务身份 |
| T02 | 引擎已接受,但 run 关联回填失败 | 找到原 run 并修复关联;不能错误标成入队失败而让 worker 跳过;不能创建第二次外部动作 |
| T03 | 引擎提交后响应丢失,调用方不知道是否接受 | 通过稳定身份与原输入确认已有 run;确认不了时有诊断及等待/人工路径 |
| T04 | 已有 active run,巡检查询一次失败 | 本轮无新增 run;原关联不被覆盖;下一轮查询正常时恢复判断 |
| T05 | 上一版本存在未完成 scrapeMedia v1,再启动当前版本与迁移 |
兼容、转换、终止或人工处置有明确结果和证据;无旧 run 永久悬空;迁移前后输入可解释 |
| T06 | 正式装配遗漏一个核心 handler | 装配检查失败或启动时给出明确错误;不能以 stub 的成功回显通过验收 |
已有同版本 kill-worker 测试继续作为回归。T01 至 T06 是针对不同改动的验收场景清单,按实际修复选择,不要求每个功能开发前全部执行。T02、T03 涉及两边不同的队列机制,因此样本按本项目的引擎接口设计,不机械复用 MP 测试。
当前取舍:保留 OpenWorkflow、冻结计划和现有账本;优先局部修正查询异常判定与入队/关联回填的异常分类,再核实是否可以用已有幂等和巡检完成恢复。 只有故障样本证明现有机制无法处理时,才评估复用 outbox 等进一步调整;专门恢复器、新状态机和补偿服务不作为默认方案。旧任务处置先落实发布检查清单。第一项实现细节确定后,第二项核对下载纳管与多实例隔离,再进入部分入库后的清理保护。
4 用户确认后的当前实现
4.1 局部任务恢复
已按第 3 节原则修正入队后关联回填、查询失败补投判定、run 关联恢复与刮削去重。9 个真实 PG 故障样本通过;未新增另一套恢复基础设施。旧版本实际在途任务的发布处置写入部署手册。T05 的跨版本专项和 T06 的 handler 装配强化仍不能因这 9 个测试而宣称完成。
4.2 分类、来源与存量
参考插件 categoryeditor v1.3:插件保存 YAML 并刷新分类 helper,匹配由 MP core 实现。参考 v3 的 app/domain/classification/projection.py 的 legacy TMDB 匹配分支:顺序首次匹配、字段 AND、值 OR、排除、年份和空规则兜底。我们内置同类规则编辑能力,保留用户提供的全部名称和兜底习惯;不复制 v3 的完整分类策略版本发布体系。
目录接管参考 MP app/application/transfer/monitor/snapshot.py、poller.py:先快照现状,再比对新增/变化;完整存量作为单独手动操作。我们采用数据库持久快照、已有识别与整理计划,一条配置一个来源路径。同分类可配置多条不同来源,综艺归 tv;只有复制与移动。qB 标签继续使用现有任务管理和实例范围。
当前源码已接入分类编辑和测试、来源选择、自动/固定分类、qB 配置标签、快照与存量向导。已有路径绑定保留,不按新规则迁移旧库;源离线保留基线,已知 qB 任务不被目录扫描重复接管。具体入口和分批限制见 整理手册。测试使用本项目临时目录与隔离 PG,不是运行 MP 服务;未完成浏览器截图审查;后续 v0.3.9 已发布,见 发布记录。
其他主题仍按第 2 节逐项讨论。这轮只补齐与已讨论整理功能有关的分类、标签与目录接管行为,不宣称整个下载隔离、清理、订阅和智能体业务对照已完成。
4.3 本次验证记录
- 分类匹配 domain 12 个定向测试;domain 全量 22 文件 / 654 测试通过。contracts 全量 7 文件 / 1048 测试、db 全量 4 文件 / 21 测试通过。
- source monitor 13 个真实 PG/临时文件/HTTP mock qB 测试:基线不处理存量、稳定观察、旧基线保留、分类和失败文件处理、存量只读与分批、文件事实变化、无标签未登记下载等待并在完成后接管。
- 最终合并复验分类 API、来源规划和 source monitor:3 文件 / 23 个真实 PG 测试全部通过。分类 API 与来源规划其中 10 个,包括并发配置保存、固定目录不重复、自动目录层级、已有绑定保留、qB 标签与来源/实例范围,以及媒体类型限制。
- 文件执行、移动、恢复、刮削、接管和向导覆盖最终回归 7 文件 / 38 测试通过;worker lane 注册与文档归属 8 测试通过。
- server 完整回归初次运行 127 文件,783 测试通过、2 失败、1 跳过;失败涉及新任务文档归属及开发过程中分类并发合并,最终相关 3 文件 / 23 测试和 worker lane 8 测试单独复验通过。完整回归不是最终同一时间源码的全绿报告,环境条件跳过也不计为完成验收。
- web 全量 25 文件 / 228 测试、web typecheck 与 production build 通过。workspace TypeScript / Deno 检查、Biome 检查和
git diff --check通过。
没有使用浏览器截图替代或冒充前端验收;本次未替换线上镜像、未执行线上迁移,也未修改宿主机程序。
4.4 v0.3.9 发布与文件管理入口
用户要求部署后,核对发现文件管理入口原来只复用向导,没有携带来源配置。本次补齐同根/目录边界/最长来源匹配、唯一匹配自动应用、多配置明确选择及首击等待加载;H&R 与根目录保护保留。新增匹配测试后 web 全量 26 文件 / 232 项通过,typecheck、Biome 和 production build 通过。
v0.3.9 Docker 镜像完成 web build、server compile 和空环境二进制自检后部署;执行 0059 迁移,注册 scanOrganizeSource@1 和 organize.sources。发布前没有在途业务或引擎任务,备份校验通过;部署后 HTTP / HTTPS、版本一致、登录后的分类/来源/文件根读取以及 3 个分类预览通过。详细镜像与证据见发布记录。
5 下载入口与浏览器详情页交接(讨论记录)
2026-10-01 用户继续逐项讨论后确认以下业务决策,并随后授权实施。实现与验证见第 5.6 节;这批变更已部署为 v0.3.10。
5.1 已确认
- 常规入口包括订阅自动下载、手动搜索选择下载、外部 qB 任务接管,前两种使用较多。三种入口进入共同的后续下载管理和整理流程,保留来源。
- 手动下载独立于订阅,不要求先建订阅,不自动创建持续订阅。
- 优先沿用 MP 普通订阅的完成口径:下载器成功接收资源后记录下载事实,按目标覆盖判断完成,不以整理入库成功作为普通订阅完成的前置条件。下载与整理状态分别展示;洗版和多版本口径后续单独核对。
- 浏览器手动下载入口位于串流窗口外的工具操作栏,桌面串流与截图模式共用。用户进入原站资源详情页后点击「下载当前资源」,复用现有详情解析和下载提交能力,不要求用户点击原站下载按钮或等待文件捕获。
- 下载按钮绑定当前浏览器标签页的资源详情;按站点定义解析资源身份和详情,使用对应站点的种子获取方式。默认下载器与保存目录可直接提交,也提供修改选项;提交结果及下载任务入口在工具操作栏显示。
- 浏览器详情页入口不以资源预先存在于本地搜索/快照索引或已有订阅为条件。需要新增当前页面与详情解析、手动下载的衔接;本地缺少记录不能阻止用户选择的资源进入手动流程。
5.2 已核对的代码依据与现有差异
MP 固定基线中的 app/api/endpoints/download.py 手动入口使用 source="Manual",不创建订阅;app/chain/subscribe/search.py 提交订阅下载后调用完成判断,app/chain/subscribe/completion.py 普通电影可在取得下载结果后完成,普通剧集按剩余目标和下载事实判断。外部 qB 任务在配置管理标签时按标签筛选,并由 app/chain/transfer/queue.py 检查下载完成、来源监控目录及已有整理状态;无下载历史的任务由文件重新识别。
本项目已有 packages/adapters/src/browser/camofox/client.ts 的 pageContent 当前页面读取、packages/adapters/src/sites/spider/detail.ts 的可配置详情解析,以及 M-Team 等站点的 detail/downloadTarget 能力。现有 apps/server/src/modules/browser/routes.ts 文件捕获入口要求匹配本地资源,不能替代本次确认的详情页直接下载入口。现有搜索/工作台手动提交与收录版本的关联限制也需在后续实现中梳理。
5.3 已确认:未识别资源与 TMDB/Local 元数据
MP 手动添加入口识别失败时返回 requires_confirmation;前端 AddDownloadDialog.vue 允许用户确认继续下载,通过 allow_unrecognized 提交最小媒体上下文。该分支不强制用户先指定 TMDB 身份。
用户确认未识别资源可以下载。整理阶段采用以下识别与元数据补全流程:
- 常规识别先匹配 TMDB;成功后按 TMDB 元数据整理。
- 自动匹配失败时由 Agent 接棒,读取 PT 详情页并结合网络搜索核对原名、译名、别名、年份及季集信息,再尝试匹配 TMDB。因翻译/别名导致的失败应在查明正确条目后回到 TMDB 模式。
- 找不到合适 TMDB 条目时进入 Local 模式,由 Agent 基于 PT 详情页及搜寻资料补全标题、简介、年份、类型、演职人员等信息,选取封面,生成本地 NFO 和图片。有依据的字段补全,缺少资料的字段留空。
- TMDB 与 Local 模式共用分类、命名、复制/移动、整理记录和入库流程。Local 保存独立身份及资料来源,后续可以重新匹配 TMDB;不为 Local 新建一套整理系统。
- Local 使用补全后的语种、国家、类型等字段匹配现有分类配置;字段不足时使用对应电影/剧集的兜底分类,允许手动调整。
实现复用现有身份候选、元数据补全、字段投影与 NFO 刮削链路;资料不足或候选冲突仍保留待处理。具体实现和验收范围见第 5.6 节。
5.4 已确认:已有任务与已有作品
用户认可同种子复用已有下载任务,同一作品的不同资源仍允许手动下载。媒体详情需要展示库内已有版本及规格,用户据此决定下载何种资源;已有作品不作为手动下载的阻断条件。
5.5 已确认:正常入库与一次性洗版入库
用户确认在本次下载中选择「正常入库」或「洗版入库」:正常模式允许多版本并存;洗版模式在下载完成后整理时用新版本替换旧版本,是本次任务的一次性规划,不自动变成持续洗版订阅。
- 洗版允许用户选择替换哪些已有版本。只有一个旧版本时默认选中,有多个时由用户勾选,未选择的版本保留。
- 新文件成功落库后再清理对应旧文件;部分整理失败时保留相应旧文件。
- 剧集按实际成功入库的季集范围替换。例如旧版有第 1–10 集、新资源只包含第 1–6 集,只替换前六集。特殊编号、上下段及合并集由 Agent 辅助核对,不能明确对应时供用户调整。
固定 MP 基线 app/modules/filemanager/transhandler.py 提供 always/size/never/latest 覆盖模式;latest 其它版本清理按同目录、季集与 Part 匹配视频文件。它的清理步骤在新文件转移前执行,不能把本项目拟采用的「新文件成功落库后清理旧文件」描述为 MP 原样行为。
多版本是否产生不同路径取决于命名模板。MP 的 app/runtime/config.py 默认电影文件名包含 videoFormat,默认剧集文件名没有分辨率/编码等版本字段;本项目 packages/domain/src/naming/defaults.ts 当前沿用这两条模板。因此需要明确多版本命名方案,不能假定不同资源会自动产生不同文件名。已有 path_binding 仍按前述约定保留,模板调整不自动迁移旧库。
用户要求模板可配置,并提供目前使用的两条模板作为参考配置,原样记录如下。本轮未修改线上命名设置。
电影:
{{title}}{% if year %} ({{year}}){% endif %}/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{% if edition %} - {{edition}}{% endif %}{{fileExt}}
电视剧:
{{title}}{% if year %} ({{year}}){% endif %}/Season {{season}}/{{title}} - {{season_episode}}{% if part %}-{{part}}{% endif %}{% if episode %} - 第 {{episode}} 集{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{% if edition %} - {{edition}}{% endif %}{{fileExt}}
已核对本项目支持模板编辑、videoFormat 和 edition。edition 按 MP 语义为来源与特效组合(如 WEB-DL DV),剪辑版本另有 cut 变量,不改变用户提供的模板。模板不能区分的同名文件冲突需沿用整理冲突处理;不据此宣称模板可以区分所有同规格版本。
使用现有命名引擎直接编译并渲染上述两条模板,完整字段及年份/分辨率/edition 缺失的样本均通过;文档差异空白检查通过。此验证未修改任何媒体文件或线上配置。
一次性洗版已接入手动计划和冻结整理计划;同路径与不同路径替换复用现有整理记录、文件执行和操作账本。用户选择的旧版本及季集范围随本次计划保存,验证记录见第 5.6 节。
后续仍需讨论手动选择与自动筛选规则、同 hash 多实例及删除范围。
5.6 本轮实现与验收(已部署 v0.3.10)
手动搜索、站点工作台与原站详情共用独立手动下载入口,支持下载器、映射保存目录和正常/一次性洗版选择。未识别先尝试现有身份解析,仍未识别时返回确认结果;确认后建立无 Slot 的手动计划,不创建订阅。迁移 0060_manual_acquisition 允许计划无 Slot,并添加 download_task.import_plan_id 保存本次入库选择,原下载任务的订阅计划关联继续保留。
原站详情入口在桌面串流/截图之外显示「下载当前资源」与「下载选项」。POST /browser/sessions/{id}/resource 从当前可见标签按站点定义读取详情,登记此前没有索引的资源并缓存 PT 内容;不点击原站下载按钮。桌面新增 popup 会被发现,无法唯一确定当前标签时给出明确提示,不提交旧页面。普通 Agent 浏览器动作沿用原标签选择。原生桌面新页未被上游登记时,仍需回到已登记详情页;本轮没有改浏览器插件登记协议。
整理增加 metadata.resolve_organize:常规匹配 → 详情页/网络补全与模型抽取 → 别名重查 TMDB → 有资料的 Local 身份。复用现有预算、补全记录、字段来源、分类和刮削;不能将 TMDB 查询故障视为没有条目,候选冲突或资料不足保留待处理。Local 身份不锁定,后续可重新识别。公网封面通过现有图片抓取能力写入;成功的 Local 入库安排 NFO/图片任务,普通 TMDB 自动刮削继续遵循原设置。
一次性洗版冻结用户所选旧文件及事实;新文件核验和资产登记成功后,按实际季集/Part 覆盖清理所选旧版及私有附属文件。同路径替换先暂存旧文件,核验失败恢复旧文件;未选文件、未成功替换的季集、未完整覆盖的合并集、共享图片/NFO及下载缓存保留。清理复用现有回收站与 asset_operation;不增加持续洗版订阅。命名模板仍通过设置编辑,本轮没有修改用户线上模板或已有路径绑定。
普通订阅现在按下载器确认接收及实际目标覆盖结束;多目标必须全部满足,TV 未知总集数不伪造完整覆盖。Slot 与下载任务继续表示真实下载/核验进度,洗版目标沿用入库后的判定。
本轮验证:
- 手动下载/订阅/面板 15 项与搜索入口 11 项隔离 PG 测试通过;覆盖未知资源确认、无假订阅、映射目录、同 hash 原路径及新入库计划、多目标订阅完成。
- 浏览器详情入口及既有浏览器 API 共 13 项通过;适配器全量 58 文件/461 项通过、1 文件/3 项环境跳过,其中可见标签交接 12 项定向通过。没有用 fixture 结果替代用户真实浏览器验收。
- 整理、分类与来源 4 文件/18 项通过,包含同路径失败恢复、旧文件变化保护、剧集部分失败/合并集保留,以及 Local 在自动刮削关闭时仍排 NFO/图片任务。领域整理专项 22 项通过。
- Local 与既有元数据补全 21 项通过;NFO/Local/刮削差分 25 项通过,Local 内部人物编号不会写成负 TMDB ID。模型和外部服务使用受控 fixture,没有声称真实模型或全部 PT 站已验收。
- server 完整回归 132 文件:804 项通过、9 项失败、1 项环境跳过。9 个失败集中在 4 个旧测试文件,仍把手动提交视作订阅评估、使用旧订阅完成原因或固定 41 能力。修正测试准备入口和新口径后,这 4 文件合并复验 19 项全部通过;保留实际入库、季集覆盖、资产/文件保留和不重复下载断言,并增加独立手动不创建订阅/Slot 的验证。没有将这次分批复验描述为最终同一时点的单次全量全绿报告。
- contracts 全量 1052 项、db 21 项、domain 656 项、web 232 项通过。workspace TypeScript/Deno、Biome、设计 token、文案标点和
git diff --check通过。 - 用本机 Chromium 与真实 React 组件验证单旧版默认选择、无选择禁用洗版、勾选洗版、切回正常、未知资源二次确认、串流外按钮交接;API 为 fixture,未产生真实下载,页面无未捕获异常。
- web production build、server compile 与空环境二进制模块自检通过。局部证据存于本机
.local/manual-download-ui/。
以上业务回归主要为源码与隔离环境验证。随后于 2026-10-01 发布 v0.3.10,线上 0060 迁移、HTTP/HTTPS、管理员接口及 6 个生产页面冒烟通过,未触发真实下载或媒体整理;镜像、备份与验证证据见 发布记录。
5.7 v0.3.11 体验修复
搜索资源标题接入与站点工作台同一详情抽屉与读取接口,复用按需详情抓取和缓存,不增加第二套解析器。详情抽屉仍提供下载选项、库存和 Agent 入口。桌面浏览器的最大化规则修复后,上下黑边消失。已部署并经过组件交互、生产真实缓存详情接口与 HTTPS 页面验证,范围和证据见 发布记录。
6 整理使用方式与文件管理器专项研究(2026-10-02)
本节只记录研究与最少改动建议,未修改业务代码。MP 后端仍使用 §1 固定提交;补充前端固定源码 /tmp/umt-moviepilot-frontend-v3-review-20261001,提交 63515db2e873d6adaf6aa385a89c5901e3bc1ea6。MP 仅源码对照,没有 MP 实际页面截图。 本项目截图来自本轮 https://localhost:4380 已登录页面,使用 Chromium / Playwright,只打开页面、选择项与整理对话框;未点击执行整理、下载、接管或清理,未新增测试数据和来源配置。
6.1 实际页面步骤与证据
截图均在 .local/organize-flow-review-20261002/,已打开检查;这是本机研究证据,不作为发布包。
| 步骤 | 实际操作与健康情况 | 截图 |
|---|---|---|
| 1 | 整理记录页正常显示作品、源→目标、复制、失败原因和来源;手动整理入口可见 | 01-organize-history.png |
| 2 | 点击手动整理,当前环境没有整理来源配置,仅显示「手动选择其他来源目录」;可以继续,但空状态没有去新增来源的入口 | 02-manual-source-picker.png |
| 3 | 打开手动来源目录对话框,下载根与媒体库根可浏览;尚未选择时确认禁用,正常 | 08-manual-directory.png |
| 4 | 文件管理器打开下载目录,选择一个电影目录后出现底部整理/移动/复制工具栏;移动因做种义务禁用,正常 | 03-file-manager.png、05-file-selection.png |
| 5 | 点击整理,目录展开为一个视频,自动识别作品、显示已有记录和 H&R;页面显示「已选 0 项」但下一步可点,执行范围表达容易混淆 | 06-file-organize-wizard.png |
| 6 | 下一步显示复制/移动、冲突/跳过/替换、自动/媒体库/指定目录、命名和元数据刷新;H&R 禁用移动,正常;没有提交预览或执行 | 07-file-organize-options.png |
| 7 | 失败记录菜单点击重新整理,源文件与原作品进入相同向导,正常;未执行 | 10-record-reorganize.png |
| 8 | 设置页实际显示媒体库、整理方式、刮削、分类、来源与命名;本环境没有来源配置 | 04-settings.png |
| 9 | 下载面板切换已完成正常,显示已入库与入库失败及原因;下载盘独立展示。未操作下载或接管,下载详情整理仅做源码核对 | 09-download-board.png、11-download-completed.png |
6.2 业务边界与 MP 差异
| 场景 | MP 固定源码行为 | 本项目当前路径、差异与最少建议 |
|---|---|---|
| 文件管理器单项/多选整理 | components/filebrowser/FileList.vue:562、:568 将当前项或去重后的 selected 传给同一个 ReorganizeDialog,不是另建整理系统。对话框 ReorganizeDialog.vue:667 使用文件项或历史 ID 查询 transfer/manual/target-path,展示匹配目的目录;用户明确选择目标后不再覆盖 |
routes/console/files.tsx:392 过滤视频/目录,进入 FileSourceSelection 再共用三步向导,方向一致。来源匹配按根、目录边界和最长路径,唯一匹配自动应用,多匹配需用户选择(components/organize/source-match.ts:4、file-source-selection.tsx:23)。保留已有保护和预览,不需要再做第二个简化整理弹窗 |
| 手动整理、文件整理、历史重整的来源默认 | MP 相同对话框对 fileitems 与 logids 都查询自动目标,匹配结果包含整理方式和刮削/分类目录选项;后端 app/api/endpoints/transfer.py:549 针对各来源匹配目录,不同目标时不宣称共同匹配 |
本项目来源存量带 sourceConfigId/defaultAction,文件管理器先匹配来源;但「其他来源目录」直接创建不含配置的 files 来源(source-selection.tsx:37),历史和下载详情也直接进向导(routes/console/organize.tsx:319、downloads/download-detail.tsx:233)。默认方式因此回到全局(organize-wizard.tsx:233),请求只在 files 分支透传配置(:327、:341)。服务器 services/organize-config.ts:17 对手动文件不会按目录自动匹配,只有显式配置或带实例/标签的 qB 自动来源。这是入口默认不一致,建议解析完 FileRef 后共用已有来源选择,不另建配置体系;历史重新整理应优先保留原次策略或明确展示当前匹配策略 |
| 成功移动后的重新整理 | MP app/api/endpoints/transfer.py:737 对成功且方式含 move 的历史,用历史目标文件作为本次输入;失败/复制使用原源文件 |
本项目 file-manager/tree.ts:75 的 recordSources 只解析原 source_path/主文件 source_path;源不存在则进入 unresolved。record-parts.ts:30 仍让已结束移动记录显示重新整理入口。这会让成功移动后的正常重整无可用文件。最少修正是按成功移动历史选择现存目标,源缺失其他场景说明不可重整;不承诺任意丢失文件恢复。此项为源码确定差异,本轮没有制造真实移动样本 |
| 已有成功整理记录的手动扫描 | MP ReorganizeDialog.vue:1388 查询历史,显示成功记录处理选项,:1314 对预览与提交一致传 reorganize/skip_success |
本项目文件行显示「有 N 条整理记录」,但勾选框是批量修改作品/季集的选择,不是纳入整理范围;所有未排除行仍进入预览(organize-wizard.tsx:274、:588)。已有文件靠冲突/跳过/替换处理,而「跳过目标已有」与「跳过成功记录」不是相同概念。先把「已选」改为「批量修改已选」,明确「本次整理 N 个未排除视频」;历史成功跳过有实际需求再复用已有记录判断,不默认新增整套状态 |
| 下载接管和手动整理 | MP 管理标签决定外部下载纳管,完成后进入整理;文件管理器整理是明确选中文件的单次操作 | 本项目 qB 标签来源用于自动纳管/整理(organize-config.ts:55、:64),文件管理器单次整理和来源存量不等于下载任务接管,也不改变目录监控基线。下载详情可以在完成/importing/imported 时打开向导(download-detail.tsx:98),内容路径先转换为登记根 FileRef(organize-wizard.tsx:126);向导请求没有传下载 taskId/instance/tags(model.ts:248)。建议文案明确「整理所选文件」与「接管下载」;不在文件整理时隐式增加标签或接管任务 |
| 整理、刷新元数据和刮削 | MP 对话框支持 scrape;匹配目录可给出 scraping 默认(ReorganizeDialog.vue:711),设置用于长期默认,本次选项用于本次操作 |
本项目第 2 步的「刷新元数据」是字段级 refreshMetadata(file-manager/organize.ts:523),不是 NFO/海报刮削;页面底部已经说明现有 NFO/图片不搬,可整理后刮削。Local 成功/部分成功后另有 NFO/图片任务(acquisition-organize/services/organize.ts:1225),应保留 §5 已确认的 Agent→TMDB/Local,不因对标 MP 强迫仅 TMDB。最少先区分刷新资料与写入 NFO/图片;如需本次刮削开关,复用现有 queue,不创建第二套刮削 |
6.3 保留与最小验证
保留仅复制/移动、同分类多个来源、固定/自动分类、已绑定作品沿用原路径、执行前预览、跨卷核验后删源、H&R、来源监控不回填存量,以及 Agent/TMDB/Local 共用整理。不要照抄 MP 的软/硬链接、rclone、音乐或额外分类发布系统。
建议优先处理:① 文件/手动/下载/历史入口统一来源策略展示;② 成功移动历史改用目标重整;③ 向导明确批量修改选择与实际整理范围;④ 无来源空状态加现有设置入口。完成这些后再讨论成功记录跳过和本次刮削,不把它们提前扩成新业务系统。
最小验证使用同一来源下同一目录,从文件管理、手动其他目录、下载详情、历史入口进入,核对所选来源、方式、目标、分类一致;增加成功移动后源已删除、多个来源同路径、跨不同来源多选及部分失败样本。H&R 在本轮文件入口可见且禁用移动;其他入口及服务器执行保护还需定向验证。预览冻结、实际文件执行、Agent 实际补全、来源多配置和源离线没有在本轮页面运行,不把源码能力等同浏览器验收。截图也不能证明完整可访问性;批量单选的方向键导航、焦点与读屏说明仍需交互验证。
6.4 用户反馈与后续讨论(2026-10-02)
用户要求以下样式问题先记下,等整理模块讨论完成后一并修改;当前不改样式:
- 右上角通知数字角标目前为金色,与用户期望的整体样式不一致;具体替代颜色尚未确定。
- 分页的每页条数选择控件仍呈现原生样式,应复用项目现有选择控件与统一样式。
整理讨论按实际场景逐项进行,每项对照「MP 行为 → 当前行为 → 希望的行为 → 验收示例」,讨论确认后再实施。建议顺序:入口和来源默认;文件范围与已有记录;作品识别、目标命名与刮削;执行结果、失败重试与历史重新整理。前面已确认的复制/移动、分类 YAML、存量单次触发、qB 标签/快照、TMDB/Local 和多版本/洗版约定继续沿用,不重新扩展需求。
用户进一步倾向于 MP 的独立、共用整理弹窗方案,整理流程也优先参考 MP。据此讨论统一弹窗:手动整理、文件管理器、下载详情和历史重整传入各自上下文,共用来源/目标配置、识别修正、整理选项、预览和提交逻辑。「全局生效」指规则与交互在各入口一致;单次调整只作用于本次整理,长期默认在设置中保存。自动整理共用业务规则,后台执行不要求弹出窗口。弹窗具体操作结构与细节继续讨论,尚未授权据此实施业务改动。
后续讨论中用户认可「本次设置作用于整个所选范围」:单文件只处理该文件,目录递归处理其中视频,多选合并去重;自动识别按文件进行,手动指定作品作用于本批范围,混合批次中需要单独纠正的作品另行选择整理。用户要求参考 MP 的弹窗能力:手动指定电影/剧集,直接输入 TMDB ID 或调用 TMDB 搜索并选择作品,选择转移模式与目标路径、是否刮削,并通过队列执行。既有范围仍仅复制/移动,TMDB/Local 与 Agent 兜底继续沿用。
用户另提出学习 MP 的「整理队列/整理记录」划分。当前本项目整理页将记录和进行中状态集中展示;底层已有 task、引擎调度与整理记录关联(file-manager/organize.ts),可优先复用。拟将等待/执行中的任务展示于整理队列,将处理结果展示于整理记录;整理成功的文件在开启刮削时再触发 NFO/图片任务,界面区分整理与刮削状态。MP 固定前端提供预览、加入队列和立即整理按钮,是否完整沿用按钮组合尚未确定;本项目不因拆分视图另造调度机制。以上仍为需求讨论记录,未实施业务改动。
用户随后确认提交按钮只保留「加入整理队列」,不提供「立即整理」。任务受理成功后即可关闭弹窗或继续其他操作,不要求用户停留等待文件处理完成;进度和结果通过整理队列/整理记录查看。仍沿用既有执行前预览约定。本项已定,下一项继续讨论已有成功整理记录的跳过与重新整理语义。
已有成功记录的处理,用户要求采用 MP 做法。重新核对固定前端源码:ReorganizeDialog.vue 的 skipSuccessfulRecords 初始为 false;手动文件/目录入口查询成功历史,有记录时显示数量和「跳过成功记录」开关,默认关闭,用户本次开启后才跳过;改变开关会清除旧预览,预览与提交共用该参数。历史 ID 入口直接采用重新整理语义,不走上述手动历史提示查询。本项目采用这些默认与交互,先前讨论提出的「普通整理默认跳过」不采用。成功记录跳过和目标文件冲突仍是两个独立判断;保留本项目只提供「加入整理队列」的已确认差异。
6.5 本轮落实(v0.3.13)
用户授权「一鼓作气做完」。共用整理弹窗已改为单个配置表单与可展开预览,手动、文件管理、下载详情、历史重整统一来源匹配和选项;支持自动/电影/剧集、TMDB 搜索与 ID 定位、本批作品与季号、复制/移动、目标路径、命名/冲突、刮削开关,只提交现有整理队列。成功受理即可关闭;部分受理后已入队文件从本批移除,避免重新预览时重复提交。异步定位取消后不会覆盖用户新选择,选项或识别变化使旧预览失效。
整理页分队列与记录:队列直接查询现有 verifyAndImport 与 scrapeMedia 的 pending/running/sleeping 任务,覆盖未生成记录的下载核验任务;记录默认终态且聚焦整理行为,旧记录/筛选深链接仍可打开。成功移动重整用结果的媒体库目标路径;复制和失败仍用源。成功历史判断同时要求完整成功记录与成功主文件,识别提示与执行共用查询;手动跳过默认关闭,目标冲突另行判断。本次刮削值冻结到计划,TMDB/Local 及恢复执行都复用原刮削任务机制。
通知数字角标改为主题 primary/primary-foreground;每页条数控件改为项目现有 Select,保留分页行为。使用手册同步更新。验证与发布证据集中于 .local/organize-final-20261002/,浏览器交互的写请求使用拦截响应,不对用户媒体进行实际下载、移动、替换或刮削;真正文件执行由隔离数据库与临时目录回归验证。
6.6 原地入库补充(2026-10-02,v0.3.14 待部署)
用户指出文件管理整理不应一律复制/移动,并要求修复和记录。核对已有固定 MP 前后端源码:api/constants.ts 的整理方式是 copy/move/link/softlink,没有独立的原地登记枚举;文件管理的 ScrapeDialog.vue/app/chain/scraping.py 提供独立就地刮削。storages/local.py 的同路径 move 快速返回只是底层保护,不能据此认定上层整理流程已支持原地入库。
本项目既有「刮削」可就地写 NFO/图片,addToLibrary 仅创建作品条目,不登记视频位置、资产及季集覆盖;保留原文件名选项仍会搬运到模板目录。新增共用弹窗「原地入库」,保留路径和名称,复用识别、预览、队列、逐文件结果与资产登记事务;记录方式为 in_place,迁移 0061 扩展两个枚举约束。媒体库内选择默认原地入库,下载缓存继续原复制/移动。原地模式不使用分类搬运目标和命名模板、不建立路径绑定,配对字幕一并登记;可选刮削只针对本次成功文件。
这是为本项目资产管理补齐的行为,参考 MP 就地刮削语义,并非声称 MP 有同名模式。未改动自动接管配置或加入链接方式。实现与验证边界见发布记录和整理手册。