merge: fix/i-scrape
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
commit
ee503dd1ea
35 files changed
+1915
-200
No files matched your search
@@ -50,6 +50,21 @@
|
||||
|
||||
洗版在本次冻结计划中保存选中的旧文件。新文件核验登记成功后才清理所选旧版本,剧集只处理成功对应的季集与 Part;覆盖不完整的合并集保留。相同目标路径会先暂存旧文件,失败后恢复。旧版的私有字幕等随之清理,共享 NFO/图片、未选版本及下载缓存保留;按现有文件替换设置移入回收站或删除。
|
||||
|
||||
## 收尾核验与资产登记
|
||||
|
||||
- 目标路径已有位置时:本次是「替换」(向导 / 待处理选替换,或洗版选中的旧版本),或旧位置属于别的作品,退役旧位置(没有别的位置时旧资产退役)并新建资产,大小、校验、版本信息都是新文件的;否则沿用同一资产。沿用的位置之前被对账判为缺失 / 不可用时恢复可用,资产事实换成这次入库的文件。
|
||||
- 文件级标题粗核:同一批视频(合集、混合包)里,文件名解析出的标题和作品标题 / 原名 / 别名明显不是同一部的(没有足够共同词;
|
||||
剧集只看带 SxxEyy 的文件),排除为待确认 `title_mismatch`,不按本作品命名入库,记录部分完成并开待处理「有 N 个视频没有整理」,
|
||||
Move 时下载任务保留。只在同一批里至少有一个文件对得上作品时才判断别的文件(全都对不上多半是作品名的另一种写法,交给资源级识别);
|
||||
用户在向导里逐文件指定过的不核。
|
||||
- ffprobe 判定「不是视频」(没有视频流,伪装或损坏)的文件:核验失败,已拷 / 搬进库的新文件和它的字幕等附属文件移入回收站(Move 时源已删,回收站里是唯一一份),附属文件结果记跳过 `main_failed`,开待处理「N 个文件不是视频,没有入库」。原地入库不动原文件;洗版替换照旧回滚旧文件。
|
||||
|
||||
- 跨卷 Move(复制 → 校验 → 删源)删源前一律全量 sha256 校验,不用抽样;复制与同卷移动仍按 `verifyHash`。
|
||||
- 计划期判断「目标已存在且同尺寸是不是同一文件」的全量 sha256 按(路径、大小、修改时间、inode)缓存,向导预览 / 复核 / 执行不再各算一遍。
|
||||
- 整理时补全元数据(`metadata.resolve_organize`,模型 + 网页搜索)带 3 分钟超时,上游挂住不会一直占着文件道。
|
||||
- 季号:解析器对有集号没季号的文件推定第 1 季,服务端与域层用同一个值(`organize-season-inference.test.ts`)。
|
||||
- 回收站清除先删文件再删行;清过期项时顺带删各库根 `.umt-trash/replaced-*` 里过期、没有回收站登记的目录。
|
||||
|
||||
关联迁移 `0060_manual_acquisition`,已于 2026-10-01 随 v0.3.10 发布执行。业务依据与验收见 [MP 对照 §5.6](../porting/moviepilot-v3-comparison.md#56-本轮实现与验收已部署-v0310)。
|
||||
|
||||
## 与 MP 的对照
|
||||
|
||||
+30
-5
@@ -28,7 +28,7 @@ SCR-2(用户 2026-09-30:"已经有的也可以重新刮削……如果是直接
|
||||
| --- | --- |
|
||||
| 文件管理「刮削…」(右键 / ⋯ 菜单、多选批量栏、详情按钮) | `POST /files/scrape {items[{root,path,mediaEntityId?,external?}], mode?, addToLibrary?}`;任意视频文件或目录,每项一条记录,请求内最多等 `FILES_TRANSFER_WAIT_SEC`(缺省 20 s),没刮完的 `pending=true`,前端按 `GET /files/scrape-records?ids=` 轮询 |
|
||||
| 作品详情「重新刮削」「覆盖重写」 | `POST /library/{id}/scrape {mode?}`(202):对作品目录刮削,每个目录一条记录;没有已入库文件 412(到文件管理里对目录刮削) |
|
||||
| 整理入库成功(`finalizeRecord` 结果为已入库 / 部分入库) | 设置 `organize.scrapeAfterImport` 打开时对作品目录排刮削,幂等键 `scrapeMedia:record:<整理记录 id>:<序号>` |
|
||||
| 整理入库成功(`finalizeRecord` 结果为已入库 / 部分入库) | 设置 `organize.scrapeAfterImport`(缺省开)打开时对作品目录排刮削,幂等键 `scrapeMedia:record:<整理记录 id>:<目录>`;只对有 TMDB id 或本地元数据的作品排,没排上见下「入库后没排上」 |
|
||||
| 元数据刷新后 NFO 字段有变化 | 只对刮削过的作品(有成功 / 部分成功的记录):对作品目录排「更新」模式刮削(`trigger=auto`),任务延后 2 分钟开始;见下「刷新后自动重刮」 |
|
||||
| 改作品的 TMDB 映射 | 清掉旧作品的 tmdb 来源字段 → 排 full 刷新(幂等键 `refreshMetadata:identity:<新身份 id>`)→ 刷新写回新字段后按上一行自动重刮 |
|
||||
|
||||
@@ -81,6 +81,19 @@ SCR-2(用户 2026-09-30:"已经有的也可以重新刮削……如果是直接
|
||||
|
||||
TMDB 有这一集但没有译名 / 简介(只有占位名和播出日期)不算缺,照常写(和 MP 一样)。未登记目录直接取 TMDB 时同一规则:季详情失败的季跳过。
|
||||
|
||||
### 入库后没排上
|
||||
|
||||
入库后该刮却没排上任务时,在整理记录上留一条 `status = skipped` 的刮削记录(迁移 0074),整理详情「整理后刮削」显示「未刮削」与原因;
|
||||
同一整理记录同一原因只记一次。设置关闭(或本次整理取消勾选)是预期,不记。
|
||||
|
||||
| 原因 | 情况 |
|
||||
| --- | --- |
|
||||
| `scrape_not_library` | 整理目标不在媒体库目录里 |
|
||||
| `scrape_root_read_only` | 库根是只登记模式 |
|
||||
| `scrape_no_metadata` | 作品没有 TMDB id,也没有本地元数据(Local 补全的字段) |
|
||||
| `task_enqueue_failed` | 排任务失败(记录状态 failed) |
|
||||
| `scrape_internal_error` | 查库等意外错误 |
|
||||
|
||||
### 识别(文件管理)
|
||||
|
||||
顺序:请求指定 > 目录里已登记文件所属的唯一作品(`source=library`)> 按路径识别(`source=auto`)。
|
||||
@@ -101,8 +114,17 @@ TMDB 有这一集但没有译名 / 简介(只有占位名和播出日期)不算
|
||||
| 电影目录 | 目录里每个视频 `<视频名>.nfo`(不进子目录)+ 目录 `poster.jpg` / `fanart.jpg`;蓝光原盘目录(含 `BDMV` / `VIDEO_TS`)写 `<目录名>.nfo` |
|
||||
| 电影文件 | `<视频名>.nfo` + 同目录 `poster.jpg` / `fanart.jpg`;文件直接在登记目录根时图片改为 `<视频名>-poster.jpg` / `-fanart.jpg` |
|
||||
|
||||
- 自定义平铺模板(多部电影放在同一目录):目录里有登记在别的作品下的视频,或只刮部分视频时目录里还有没登记到本作品的视频,
|
||||
图片改为 `<视频名>-poster.jpg` / `-fanart.jpg`,不写整个目录共用的 `poster.jpg`。作品详情「重新刮削」对电影只刮该作品已入库的视频,
|
||||
不给同目录别的电影写本作品的 NFO(同一作品的多个版本照旧共用一张 poster)。
|
||||
- 图片扩展名按下载到的实际类型(jpeg / png / webp),URL 认不出或与内容不符时以内容为准。
|
||||
|
||||
- 集号:已登记视频按覆盖的集单元;其余按路径解析(季号缺失时取季目录名,再缺按第 1 季;同 MP 对每集重新 `MetaInfoPath`)。
|
||||
认不出集号的视频记 `scrape_no_episode` 跳过。多集文件按首集。
|
||||
认不出集号的视频记 `scrape_no_episode` 跳过,记录算部分完成。
|
||||
- 多集文件(文件名 `E01-E02`,或已登记文件覆盖多个集单元):一个 `<视频名>.nfo` 里按 Kodi 约定每集写一个 `<episodedetails>` 块
|
||||
(MP 只写首集,偏离登记在 `nfo-deviations.json` 的 `multiEpisode`);剧照按首集。某一集缺元数据时只写有元数据的那几块,全缺才跳过。
|
||||
- 综艺按播出日期命名的期数(默认综艺模板没有集号时用日期):按集单元的播出日期对上集(本地季表,或按 TMDB id 现取的季详情),
|
||||
写该集的季号、集号与 `<aired>`;日期对不上(或同一天有多集)的跳过 `scrape_no_episode`。
|
||||
- 字段:本地作品有元数据时用最终字段(字段锁、人工覆盖优先,见 `metadata.md`);否则按 TMDB id 直接取 TMDB(与刷新元数据同一映射)。
|
||||
TMDB id 只认与刮削类型一致的映射(同一作品同时有 movie / tv 两个 accepted 映射时不串)。
|
||||
- 作品类型:剧集 / 综艺按剧集刮,电影 / 合集 / 其他按电影刮(`<视频名>.nfo`,根元素 `<movie>`),范围判定与 NFO 生成同一个函数 `scrapeKindOf`。
|
||||
@@ -163,7 +185,7 @@ TMDB 有这一集但没有译名 / 简介(只有占位名和播出日期)不算
|
||||
|
||||
| 字段 | 缺省 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `organize.scrapeAfterImport` | 关 | 入库后自动刮削(MP 目录「刮削」缺省同样关) |
|
||||
| `organize.scrapeAfterImport` | 开 | 入库后自动刮削(MP 目录「刮削」缺省关;我们缺省开,因为「更新」方式不动别人写的文件、缺元数据不写占位,且只对有 TMDB id 或本地元数据的作品排)。以前保存过设置的照旧按保存的值 |
|
||||
| `organize.scrapeMode` | `update` | `update` 更新 / `missing` 只补缺失(MP「仅缺失」)/ `overwrite` 全部覆盖,见上「覆盖方式」;手动刮削时对话框可临时改。以前保存过的 `missing` / `overwrite` 照旧生效,要用更新到设置里改 |
|
||||
| `organize.scrapeImages` | 开 | 海报、背景图、季海报 |
|
||||
| `organize.scrapeEpisodeThumbs` | 开 | 每集剧照;`scrapeImages` 关时不生效 |
|
||||
@@ -177,6 +199,7 @@ TMDB 有这一集但没有译名 / 简介(只有占位名和播出日期)不算
|
||||
`title`、`originaltitle`、`premiered`、`year`;剧集另有 `season=-1`、`episode=-1`。
|
||||
- 季:`plot`、`outline`、`title`(单元有简介 / 日期但没名称时「季 N」)、`premiered`、`releasedate`、`year`、`seasonnumber`。
|
||||
- 集:`title`(TMDB 占位名时「第 N 集」)、`plot`、`outline`、`aired`、`year`、`season`、`episode`、`rating`。
|
||||
多集文件每集一个 `<episodedetails>` 块。
|
||||
季 / 集单元整个缺元数据时不写(见「季 / 集缺元数据」)。
|
||||
- 取值:标题 / 简介 / 标语按元数据语言链(见 `metadata.md`);字段锁与人工覆盖优先(用的是投影后的最终值)。
|
||||
|
||||
@@ -189,6 +212,7 @@ TMDB 有这一集但没有译名 / 简介(只有占位名和播出日期)不算
|
||||
| 制片国取 TMDB `origin_country`(代码转中文名);剧集 `studio` 写播出平台 | 本地不存 `production_countries` / `production_companies` |
|
||||
| 电影不写 `studio` | 同上 |
|
||||
| 集 NFO 不写 `uniqueid` / `tmdbid` | 本地不存 TMDB 集 id;媒体服务器按季号集号匹配 |
|
||||
| 多集文件每集一个 `<episodedetails>` 块(MP 只写首集) | 只写首集时 Kodi 只显示第一集 |
|
||||
| 简介含 `]]>` 时拆成两段 CDATA | MP 的 minidom 直接抛错 |
|
||||
|
||||
重新生成 MP 输出(改了样例或跟进上游后):
|
||||
@@ -213,14 +237,15 @@ cd /opt/uhd_media_tool && deno run -A npm:@biomejs/biome check --write apps/serv
|
||||
- 原因码(`packages/contracts/src/reasons.ts`):`scrape_no_metadata`、`scrape_root_read_only`、`scrape_root_offline`、`scrape_not_video`、
|
||||
`scrape_no_videos`、`scrape_path_missing`、`scrape_tmdb_unavailable`、`scrape_no_episode`、`scrape_exists`、`scrape_unchanged`、
|
||||
`scrape_user_modified`、`scrape_metadata_missing`、`scrape_write_failed`、`scrape_image_failed`、`scrape_internal_error`(查库等非写文件错误,
|
||||
已写的文件结果保留)、`path_escape`、`task_enqueue_failed`。
|
||||
已写的文件结果保留)、`scrape_canceled`(任务被取消,记录收尾为失败,已写的文件结果保留)、`scrape_not_library`、`path_escape`、`task_enqueue_failed`。
|
||||
|
||||
| 现象 | 看哪里 |
|
||||
| --- | --- |
|
||||
| 入库后没有 NFO | 设置里「入库后自动刮削」是否打开;作品详情「刮削」是否有记录;引擎运行 `scrapeMedia` |
|
||||
| 入库后没有 NFO | 整理详情「整理后刮削」是否有「未刮削」及原因;设置里「入库后自动刮削」是否打开;引擎运行 `scrapeMedia` |
|
||||
| 刮削对话框一直让选作品 | 文件名解析不出标题,或 TMDB 有多个同名候选;选一次即可,打开「同时加入媒体库」后下次按已入库作品识别 |
|
||||
| 全部「跳过」 | 覆盖方式是只补缺失,或更新时文件不是本工具写的 / 被人改过(`scrape_exists` / `scrape_user_modified`);要替换选「全部覆盖」或作品详情「覆盖重写」 |
|
||||
| 改了映射 / 刷新了元数据,NFO 没变 | 作品以前没刮削过(不自动重刮);重刮任务要等 2 分钟;NFO 被人改过(`scrape_user_modified`) |
|
||||
| 记录「部分完成」、原因认不出集号 / 集数待确认 | 文件名没有集号(综艺日期对不上季表),或集数映射待确认;确认集数或刷新元数据后重新刮削 |
|
||||
| 记录「部分成功」、原因缺元数据 | 季 / 集还没取到元数据且 TMDB 季详情取不到;刷新元数据(作品详情「刷新」带 full)后会自动重刮 |
|
||||
| 图片失败、NFO 正常 | TMDB 图片访问(出口代理);稍后重新刮削,只补缺失的图片 |
|
||||
| 「没有可用的元数据」 | 作品没有 TMDB 字段也没有 TMDB id;在文件管理里刮削并指定 TMDB 条目 |
|
||||
|
||||
Reference in new issue
Block a user