- scrape_record 状态加 skipped(迁移 0074);目标不在媒体库、库根只登记、作品没有 TMDB id 也没有本地元数据、排队失败时 留一条挂在整理记录上的「未刮削」记录(同原因只记一次),设置关闭不记; - 缺省开启 scrapeAfterImport,只对有 TMDB id 或本地元数据的作品排; - 已结束记录重放与收尾同一口径补排刮削(按整理记录幂等); - 整理详情「整理后刮削」显示未刮削原因,并列出失败与非预期跳过(缺元数据、认不出集号)的文件。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
248 lines
21 KiB
Markdown
248 lines
21 KiB
Markdown
# 刮削运行手册(SCR-1 写 NFO 与图片;SCR-2 照 MP 简化为就地刮削)
|
|
|
|
「刮削」= 在视频所在目录就地写 NFO,并下载海报、背景图、季海报、剧照,Emby / Jellyfin / Kodi 直接读取。
|
|
「刷新元数据」只更新本工具库里的字段,不写目录里的文件;两者分开。
|
|
|
|
SCR-2(用户 2026-09-30:"已经有的也可以重新刮削……如果是直接在对应目录刮削,那就直接在对应目录生成")起,
|
|
刮削对象从"作品"改成"目录 / 视频文件",照 MP 文件管理的刮削:**不要求先登记**,按路径识别作品后在该目录里写文件。
|
|
已登记作品的「重新刮削」、入库后自动刮削走同一实现(本质是对作品目录刮削)。
|
|
|
|
## 实现位置
|
|
|
|
| 位置 | 内容 |
|
|
| --- | --- |
|
|
| `packages/domain/src/scrape/nfo.ts` | NFO 生成(电影 / 剧集 / 季 / 集),纯函数 |
|
|
| `packages/domain/src/scrape/layout.ts` | 目标文件清单与命名 `planScrapeTargets`(`parts` 控制作品级 / 季级)、`inferWorkDir`、`isSeasonDirName` / `seasonOfDirName` |
|
|
| `apps/server/src/modules/acquisition-organize/services/scrape-input.ts` | 最终字段 → NFO 输入;TMDB 富详情 / 季详情 → NFO 输入(`tmdbEntity` / `tmdbSeasonUnits`,映射同刷新元数据) |
|
|
| `apps/server/src/modules/acquisition-organize/services/scrape.ts` | 刮削记录 `queueScrape`、执行 `runScrapeRecord`(目录布局 → 字段 → 写文件)、作品目录 `entityScrapeLocations` / `scrapeEntity`、入库后钩子 `scrapeAfterImport` |
|
|
| `apps/server/src/modules/file-manager/scrape.ts` | 文件管理「刮削」:按路径识别(复用 `identifyCore` + `resolveIdentity`)、候选、排任务、请求内等结果 |
|
|
| `handlers.ts` 任务 `scrapeMedia`(v2,输入 `{recordId}`) | 文件道;不重试(失败的重新刮削) |
|
|
| 迁移 `0058_scrape_record` | 每次刮削一条记录;替代 0057 的 `media_scrape`(一部作品一行) |
|
|
| 迁移 `0070_scrape_update_mode` | `scrape_record.mode` 增加 `update`;逐文件 hash 记在 `files` jsonb 里,不加列 |
|
|
| `sources-identity/service/metadata.ts` `refreshMetadata` / `clearTmdbMetadata` | 刷新后 NFO 字段有变化 → `scheduleEntityRescrape`;改 TMDB 映射时清旧字段(`identity-admin.ts` `setEntityIdentity` 调用) |
|
|
| 端口 `AoPorts.scrapeImage` / `scrapeTmdbDetail` / `scrapeTmdbSeason` | 图片字节(图片缓存 `DATA_DIR/cache/images` + 出口代理);未登记目录直接取 TMDB 富详情 / 季详情(元数据语言链,经 TMDB 缓存) |
|
|
|
|
## 触发
|
|
|
|
| 触发 | 做法 |
|
|
| --- | --- |
|
|
| 文件管理「刮削…」(右键 / ⋯ 菜单、多选批量栏、详情按钮) | `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>:<目录>`;只对有 TMDB id 或本地元数据的作品排,没排上见下「入库后没排上」 |
|
|
| 元数据刷新后 NFO 字段有变化 | 只对刮削过的作品(有成功 / 部分成功的记录):对作品目录排「更新」模式刮削(`trigger=auto`),任务延后 2 分钟开始;见下「刷新后自动重刮」 |
|
|
| 改作品的 TMDB 映射 | 清掉旧作品的 tmdb 来源字段 → 排 full 刷新(幂等键 `refreshMetadata:identity:<新身份 id>`)→ 刷新写回新字段后按上一行自动重刮 |
|
|
|
|
同一目录已有排队中(未开始,30 分钟内)、同覆盖方式、同作品的刮削时直接复用(`deduplicated`)。
|
|
|
|
### 覆盖方式
|
|
|
|
| 方式 | 目标不存在 | 目标存在 |
|
|
| --- | --- | --- |
|
|
| `update` 更新(缺省) | 写 | 本工具上次写入、之后没被改过 → 按新内容覆盖(内容没变就不重写,记 `scrape_unchanged`);被改过 → 跳过 `scrape_user_modified`;不是本工具写的 → 跳过 `scrape_exists` |
|
|
| `missing` 只补缺失 | 写 | 跳过 `scrape_exists` |
|
|
| `overwrite` 全部覆盖 | 写 | 覆盖(包括其他工具写的、人改过的) |
|
|
|
|
- 每次写入(任何方式)在该记录的逐文件结果里记内容的 sha256(`files[].hash`);「更新」时取同一登记目录里以前的记录,
|
|
每个路径按从新到旧第一条带 hash 的结果,与磁盘上现在的内容比对。跳过的结果不带 hash,人改过的文件以后每次都还是跳过,
|
|
要替换就用「全部覆盖」。
|
|
- 旧版本写的文件没有 hash:修改时间不晚于那次刮削结束(留 2 秒余量)就当没被改过。
|
|
- 已存在的目标是目录 / 符号链接时三种方式都跳过。
|
|
- 更新不删除文件:改身份后新作品没有背景图时,旧的 `fanart.jpg` 留在目录里(元数据里旧的背景图路径已清掉,不会再写旧图)。
|
|
|
|
### 刷新后自动重刮
|
|
|
|
- `refreshMetadata` 结束后,作品写进 NFO 的字段(标题、原名、年份、简介、标语、首映、类型、制片国、平台、时长、演职员、外部 ID、海报、背景图)
|
|
或季 / 集的名称、简介、日期、时长、剧照、季海报有变化时,调 `scheduleEntityRescrape`。评分、票数、播出状态的变化不触发(避免每天刷新都改写 NFO,
|
|
下次因为别的原因重刮时会带上新评分)。
|
|
- 没刮削过的作品不排(要先手动或入库后刮一次)。
|
|
- 防抖:任务带 `availableAt = 现在 + 2 分钟`;这段时间里再来的刷新命中同目录、同作品、`update` 方式的排队记录直接复用,不另排。
|
|
- 排上的记录在作品详情「刮削」卡片里显示为「入库后自动」那一类(`trigger=auto`)、方式 `update`。
|
|
|
|
### 改 TMDB 映射(纠错)后
|
|
|
|
`setEntityIdentity`(作品页改映射、`POST /media-entities/{id}/identities`)在同一事务里:
|
|
|
|
1. 旧映射退役、新映射接受(原有逻辑);
|
|
2. 旧 TMDB 带出来的 IMDb 映射(没人工锁的)一并退役——NFO 里 IMDb 是 default uniqueid,留着媒体服务器会认成旧作品;
|
|
3. 清掉该作品及其季 / 集单元的 tmdb 来源字段(`metadata_field` 与投影出的最终值;单元的 `title` / `air_date` 列跟着清),
|
|
人工覆盖、锁定字段和 web / agent 补全字段保留;海报 / 背景图一并清掉,不再按「TMDB 没有时保留旧值」留旧作品的图。
|
|
|
|
提交后排 full 刷新;刷新填回新作品字段后自动重刮(上一节),本工具写过且没被改过的 NFO 和图片换成新作品的。
|
|
刷新完成前若刚好有刮削在跑,季 / 集缺元数据的部分会按下一节跳过,不会写进旧作品的内容。
|
|
|
|
### 季 / 集缺元数据
|
|
|
|
本地作品有元数据时用最终字段;季单元或要刮的集单元**缺元数据**(没有单元,或从没被元数据来源填过、也没有标题 / 播出日期,
|
|
典型是整理懒建的集、改身份后被清空的单元)时,先按作品的 TMDB id 现取该季详情补齐(映射同刷新元数据,只补缺的单元,本地已有的字段不动,
|
|
不落库)。仍然缺(没有 TMDB id、季详情失败、TMDB 没有这一集)时:
|
|
|
|
- 该季 `season.nfo` / 该集 NFO 跳过,原因 `scrape_metadata_missing`,**不写「季 N」「第 N 集」占位**;没有 TMDB id 的作品(Local)无处可补,照旧写占位;
|
|
- 记录状态是 `partial`(原因 `scrape_metadata_missing`),不再报成功;刷新元数据后会自动重刮(上一节),或手动重新刮削。
|
|
|
|
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`)。
|
|
|
|
- 按路径识别复用 `/files/identify` 的核心(文件名 + 父 / 祖父目录解析 → 本地别名召回 + TMDB 远端候选,≤15 s),每个视频按
|
|
`resolveIdentity` 判断能否自动确认;**目录里所有视频都能自动确认且是同一作品**时直接用,否则该项进 `needsChoice`(合并各视频候选,前 5)。
|
|
- 选定后带 `mediaEntityId`(本地作品)或 `external {provider:"tmdb", externalId, kind}` 再提交一次(`source=chosen`)。
|
|
- 候选是 TMDB 条目:有已接受该 TMDB id 的本地作品就用它;没有也能刮削(直接取 TMDB 字段);`addToLibrary=true` 时顺手建作品
|
|
(同「整理」的按候选建作品,幂等)。**登记不是刮削的前提**。
|
|
|
|
### 写在哪里(对照 MP `ScrapingChain.scrape_metadata`)
|
|
|
|
| 选中的 | 写的文件 |
|
|
| --- | --- |
|
|
| 剧集目录 | `tvshow.nfo`、`poster.jpg`、`fanart.jpg`、`seasonNN-poster.jpg`;每个季目录(`Season 1` / `S01` / `Specials` / `SPs` / `第 1 季`)`season.nfo` + `poster.jpg`;每集 `<视频名>.nfo` + `<视频名>-thumb.jpg`。只进季目录一层,其他子目录不管 |
|
|
| 季目录 | `season.nfo` + 季目录 `poster.jpg` + 上级 `seasonNN-poster.jpg`;每集 NFO 与剧照。不写 `tvshow.nfo` |
|
|
| 单集文件 | 该集 `<视频名>.nfo` + 剧照 |
|
|
| 电影目录 | 目录里每个视频 `<视频名>.nfo`(不进子目录)+ 目录 `poster.jpg` / `fanart.jpg`;蓝光原盘目录(含 `BDMV` / `VIDEO_TS`)写 `<目录名>.nfo` |
|
|
| 电影文件 | `<视频名>.nfo` + 同目录 `poster.jpg` / `fanart.jpg`;文件直接在登记目录根时图片改为 `<视频名>-poster.jpg` / `-fanart.jpg` |
|
|
|
|
- 集号:已登记视频按覆盖的集单元;其余按路径解析(季号缺失时取季目录名,再缺按第 1 季;同 MP 对每集重新 `MetaInfoPath`)。
|
|
认不出集号的视频记 `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`。
|
|
- 登记目录:库根只写 `managed`(只登记模式跳过 `scrape_root_read_only`),库根离线 / 标记文件不对 `scrape_root_offline`;
|
|
下载根也能刮削(同 MP)。目标路径必须在登记目录内;已存在的目标是目录 / 符号链接时跳过。
|
|
|
|
```
|
|
人生切割术 (2022)/
|
|
├── tvshow.nfo
|
|
├── poster.jpg
|
|
├── fanart.jpg
|
|
├── season01-poster.jpg # 特别篇:season-specials-poster.jpg
|
|
└── Season 1/
|
|
├── season.nfo
|
|
├── poster.jpg # 季海报(与作品目录那张同一张)
|
|
├── 人生切割术 - S01E01 - 有关地狱的好消息.mkv
|
|
├── 人生切割术 - S01E01 - 有关地狱的好消息.nfo
|
|
├── 人生切割术 - S01E01 - 有关地狱的好消息-thumb.jpg
|
|
├── 人生切割术 - S01E02 - 半循环.mkv
|
|
├── 人生切割术 - S01E02 - 半循环.nfo
|
|
└── 人生切割术 - S01E02 - 半循环-thumb.jpg
|
|
星际穿越 (2014)/
|
|
├── 星际穿越 (2014) - 1080p.mkv
|
|
├── 星际穿越 (2014) - 1080p.nfo
|
|
├── poster.jpg
|
|
└── fanart.jpg
|
|
```
|
|
|
|
(上面是 `apps/server/test/file-manager/scrape.test.ts` 第一个用例对未登记目录刮削后的实际文件树。)
|
|
|
|
## 与 MP 的差分
|
|
|
|
文件布局用 MP 上游 `ScrapingChain.scrape_metadata` 的真实决策代码跑同一组目录(`apps/server/test/scrape/gen-scrape-layout-mp.py` →
|
|
`scrape-layout-mp.json`),`scrape-layout-mp.test.ts` 对照 7 个场景(剧集目录、季目录、单集文件、电影目录、电影文件、根下电影文件、蓝光原盘目录),
|
|
只允许下表登记的偏离:
|
|
|
|
| 同一目录结构 | MP 写 | 我们写 | 理由 |
|
|
| --- | --- | --- | --- |
|
|
| 作品 / 电影目录背景图 | `backdrop.jpg` + `fanart.jpg` | `fanart.jpg` | 三家都认 fanart.jpg,副本没用 |
|
|
| 每集剧照 | `<视频名>.jpg` | `<视频名>-thumb.jpg` | Kodi 约定,Jellyfin / Emby 同样识别;不和同名封面混 |
|
|
| 视频直接在登记目录根 | 根里写 `poster.jpg` / `backdrop.jpg` / `fanart.jpg` | `<视频名>-poster.jpg` / `<视频名>-fanart.jpg` | 根里放一张 poster.jpg 会被当成整个库的封面 |
|
|
| 其余(tvshow / season / 集 NFO、季海报两处、电影 NFO、蓝光 `<目录名>.nfo`、季目录只写季级、单集只写该集) | — | 同 MP | — |
|
|
|
|
行为上的差异:
|
|
|
|
| 项 | MP | 我们 | 理由 |
|
|
| --- | --- | --- | --- |
|
|
| 已有文件 | 手动刮削一律覆盖(`overwrite=True`),自动刮削按每类文件的策略 | 缺省「更新」(只覆盖本工具写过且没被改过的,按 hash 判断),也可选「只补缺失 / 全部覆盖」,刮削对话框里可临时改 | 元数据纠正后已有 NFO 要能跟着更新,又不能覆盖用户手改的、其他工具写的 |
|
|
| 季 / 集缺元数据 | 写占位(「第 N 集」) | 现取季详情补齐,仍缺跳过并记 partial;没有 TMDB id 的作品照旧写占位 | 占位 NFO 在「只补缺失」下永远不会被替换 |
|
|
| 识别 | 按路径识别,认不出直接失败;对话框可手填 TMDB / 豆瓣 id | 按路径识别,认不准时返回前 5 候选让用户选(也可搜索);已登记的目录直接用作品 | 选一次比手填 id 省事;已登记的不必再识别 |
|
|
| 执行 | 请求内同步 | 后台任务 `scrapeMedia`,请求内最多等 20 s | 大季包图片多;超时不丢 |
|
|
| 记录 | 只有日志 | 每次刮削一条记录(目录、识别结果、逐文件结果、原因),作品详情显示最近一条 | 可回看、可排查 |
|
|
| 图片种类 | poster / backdrop / logo / banner / disc / clearart / thumb(按图片源) | poster / fanart / 季海报 / 剧照 | 本地只有 TMDB 海报、背景图、剧照;其余要 fanart.tv 源 |
|
|
| 批量 | 多选共用一个识别条件 | 多选逐项各自识别,各自选候选 | 多选里常是不同作品 |
|
|
| 音乐 | 支持 | 不做 | 范围外 |
|
|
|
|
## 设置(设置 → 媒体库与目录 →「刮削」)
|
|
|
|
| 字段 | 缺省 | 说明 |
|
|
| --- | --- | --- |
|
|
| `organize.scrapeAfterImport` | 开 | 入库后自动刮削(MP 目录「刮削」缺省关;我们缺省开,因为「更新」方式不动别人写的文件、缺元数据不写占位,且只对有 TMDB id 或本地元数据的作品排)。以前保存过设置的照旧按保存的值 |
|
|
| `organize.scrapeMode` | `update` | `update` 更新 / `missing` 只补缺失(MP「仅缺失」)/ `overwrite` 全部覆盖,见上「覆盖方式」;手动刮削时对话框可临时改。以前保存过的 `missing` / `overwrite` 照旧生效,要用更新到设置里改 |
|
|
| `organize.scrapeImages` | 开 | 海报、背景图、季海报 |
|
|
| `organize.scrapeEpisodeThumbs` | 开 | 每集剧照;`scrapeImages` 关时不生效 |
|
|
|
|
## NFO 内容
|
|
|
|
对照 MP `app/modules/themoviedb/scraper.py`,元素名、顺序、属性一致,格式同 minidom `toprettyxml(indent=" ", encoding="utf-8")`:
|
|
|
|
- 公共(电影 / 剧集):`tmdbid` + `uniqueid type=tmdb`;有 TVDB / IMDb 时追加(有 IMDb 时 IMDb 为 `default`);`plot` / `outline`(CDATA);
|
|
`director`(带 `tmdbid`);`actor{name,type,role,tmdbid,thumb,profile}`;`genre`;`rating`(一位小数);`studio`;`country`;`runtime`;
|
|
`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`);字段锁与人工覆盖优先(用的是投影后的最终值)。
|
|
|
|
与 MP 的差异(差分登记 `apps/server/test/scrape/nfo-deviations.json`):
|
|
|
|
| 差异 | 理由 |
|
|
| --- | --- |
|
|
| 缺值不写元素(MP 写 `<premiered/>`、评分 0、空 CDATA) | 空元素不带信息;评分 0 会被当成真实评分 |
|
|
| 额外写豆瓣 id(`doubanid` + `uniqueid type=douban`)、`tagline`、集 `runtime` | 本地有这些字段 |
|
|
| 制片国取 TMDB `origin_country`(代码转中文名);剧集 `studio` 写播出平台 | 本地不存 `production_countries` / `production_companies` |
|
|
| 电影不写 `studio` | 同上 |
|
|
| 集 NFO 不写 `uniqueid` / `tmdbid` | 本地不存 TMDB 集 id;媒体服务器按季号集号匹配 |
|
|
| 多集文件每集一个 `<episodedetails>` 块(MP 只写首集) | 只写首集时 Kodi 只显示第一集 |
|
|
| 简介含 `]]>` 时拆成两段 CDATA | MP 的 minidom 直接抛错 |
|
|
|
|
重新生成 MP 输出(改了样例或跟进上游后):
|
|
|
|
```sh
|
|
cd /opt/moviepilot-plus/upstream/MoviePilot && PYTHONPATH=. \
|
|
.venv/bin/python /opt/uhd_media_tool/apps/server/test/scrape/gen-scrape-mp.py
|
|
cd /opt/moviepilot-plus/upstream/MoviePilot && PYTHONPATH=. \
|
|
.venv/bin/python /opt/uhd_media_tool/apps/server/test/scrape/gen-scrape-layout-mp.py
|
|
cd /opt/uhd_media_tool && deno run -A npm:@biomejs/biome check --write apps/server/test/scrape/scrape-layout-mp.json
|
|
```
|
|
|
|
## 结果与排查
|
|
|
|
- 文件管理刮削对话框:每项的状态、识别结果(作品、按路径识别 / 手动指定 / 已入库的作品、是否在媒体库)、写入 / 跳过 / 失败计数、逐文件结果;
|
|
认不准的项列候选,选定后「继续刮削」,可打开「同时加入媒体库」。
|
|
- 作品详情「刮削」卡片:该作品最近一条刮削记录;排队或进行中时每 3 秒刷新。
|
|
- `GET /files/scrape-records?ids=`、`GET /library/{id}` 的 `scrape`:`id`、`root`、`path`、`status`、`trigger`、`mode`、
|
|
`match{mediaEntityId, provider, externalId, kind, title, year, source}`、`written` / `skipped` / `failed`、`reason`、
|
|
`files[{path, kind, role, action, reason, hash}]`(path 为登记目录内相对路径;hash 为写入时内容的 sha256)、`organizationRecordId`、`taskId`。
|
|
- 审计 `organize.scrape`(目标 `scrape_record`;载荷含目录、识别结果、写入与失败的文件,最多 200 条);写入后发 `files.changed`,文件管理自动刷新。
|
|
- 原因码(`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`。
|
|
|
|
| 现象 | 看哪里 |
|
|
| --- | --- |
|
|
| 入库后没有 NFO | 整理详情「整理后刮削」是否有「未刮削」及原因;设置里「入库后自动刮削」是否打开;引擎运行 `scrapeMedia` |
|
|
| 刮削对话框一直让选作品 | 文件名解析不出标题,或 TMDB 有多个同名候选;选一次即可,打开「同时加入媒体库」后下次按已入库作品识别 |
|
|
| 全部「跳过」 | 覆盖方式是只补缺失,或更新时文件不是本工具写的 / 被人改过(`scrape_exists` / `scrape_user_modified`);要替换选「全部覆盖」或作品详情「覆盖重写」 |
|
|
| 改了映射 / 刷新了元数据,NFO 没变 | 作品以前没刮削过(不自动重刮);重刮任务要等 2 分钟;NFO 被人改过(`scrape_user_modified`) |
|
|
| 记录「部分完成」、原因认不出集号 / 集数待确认 | 文件名没有集号(综艺日期对不上季表),或集数映射待确认;确认集数或刷新元数据后重新刮削 |
|
|
| 记录「部分成功」、原因缺元数据 | 季 / 集还没取到元数据且 TMDB 季详情取不到;刷新元数据(作品详情「刷新」带 full)后会自动重刮 |
|
|
| 图片失败、NFO 正常 | TMDB 图片访问(出口代理);稍后重新刮削,只补缺失的图片 |
|
|
| 「没有可用的元数据」 | 作品没有 TMDB 字段也没有 TMDB id;在文件管理里刮削并指定 TMDB 条目 |
|
|
| 「TMDB 不可用」 | 设置里 TMDB API Key;未登记的目录要直接取 TMDB |
|