Files
UHD_Media_Tool/docs/runbook/identity.md
T
rootandClaude Opus 5.5 e7de7e2e69 feat(organize): identify takeover downloads by file name and close organize decisions
Takeover identify (item 2):
- Adopted tasks without source release / plan: on completion planImport
  parses main video path (file + parent + grandparent dirs, like MP
  MetaInfoPath) merged with the torrent name, then runs ID-2 matching via
  identifyParsed (local recall + TMDB; trigger "takeover" may query TMDB).
  auto -> bind/create entity, backfill download_task.media_entity_id and
  organize right away; no pool entry, no identity decision.
- Failure / ambiguity: organize_identity decision with evidence and
  options: candidates, select entity (local / TMDB), provisional entity,
  dismiss.

Decision closure (item 3):
- decision-hooks registry: the decisions resolve route runs the owning
  module's executor before closing; errors keep the decision open.
- organize_identity: backfill entity, freeze manual plan, enqueue run.
- organize_blocked with target_exists: replace (verify + trash old) /
  keep both (rename "<name> (n)" with sidecars) / skip.
- Successful organize closes both organize_identity and organize_blocked
  of the same download task (resolution manual_organize), also for manual
  path organizes matched to download tasks via path mappings.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 20:54:19 +08:00

246 lines
22 KiB
Markdown

# 资源识别与待识别池运行手册(DEC-1)
新观察到的资源(RSS、站点列表快照、搜索结果)先进待识别池,只在有理由时才查 TMDB。只有和订阅或本地作品相关、
又需要你决定的资源才进待处理。对照 MoviePilot:RSS / 站点资源只在匹配订阅或用户搜索时才识别,识别失败只写日志、不告警
(`app/chain/subscribe/match.py` `_prepare_match_torrents`:未识别的种子最多重试 3 次,之后跳过)。
需求依据:REQ §4.2–4.3(观察不等于事实)、§6.3(新作品收录 / 追更补缺 / 升级都由规则触发)、§7.5(待识别池可检索、
不污染正式库、有界复查、不留死数据)、§13(待处理按作品与问题类型合并)。
## 识别流程(resolveObservation)
1. 解析标题(release-parser),本地召回:显式外部 ID、`title_alias` 精确 / pg_trgm ≥ 0.45(本地作品 = 订阅、追踪、已登记的作品)。
2. 判断是否查 TMDB(`lookup`,记在 `source_release.resolution_evidence.lookup` 和池条目 `query.lookup`):
| lookup | 条件 |
|---|---|
| `manual` | 任务输入 `trigger: "manual"`:池里点「重新识别」、Agent / 能力 `identity.resolve` |
| `search` | 任务输入 `trigger: "search"`:搜索结果 |
| `takeover` | 接管的下载任务按文件名识别(`identifyParsed(…, { trigger: "takeover" })`,见下文「接管任务按文件名识别」) |
| `tracked_alias` | 本地召回有候选(标题命中订阅 / 本地作品的别名) |
| `previously_looked_up` | 周期复查,且这条池条目以前查过 TMDB(旧数据、手动、规则触发) |
| `eager` | 设置 `identity.eagerTmdbLookup = true` |
| `new_title_rule` | 有已发布、开启 `newTitle` 且有有效持续授权的获取策略,资源类型在规则的 `mediaKinds` 内,标题年份(若有)不早于窗口能覆盖的年份 |
都不满足:只进池,`reason = unmatched`,不查 TMDB,不开待处理。
3. 查了 TMDB 的,召回 TMDB 候选(`recallTmdbCandidates`:中文名 → 英文名,按类型单语言搜索,标题对不上的按年份相近度拉前几个详情比对别名 / 译名),
交给 `domain.resolveIdentity` 打分:auto 建档 / 关联并发 `release.resolved`;否则进池。打分规则与 MP 的对照见
`docs/porting/moviepilot-identity-match.md`(ID-2)。
4. 自动绑定时把站点标题登记为作品别名,只在标题精确命中(或别名命中且另一种文字的名称也命中)时登记,分类词 / 单字 / 停用词不登记。
FIX-5 守卫(`service/alias-guard.ts`):逐个名称再查一遍,以下任一成立就不登记,原因记在 `resolution_attempt.best.aliases.skipped`
(`added` 是登记了的):证据等级不是 `rule_confirmed`(`low_evidence`);资源年份与作品年份差超过 1 年且不是季年份(`year_conflict`);
作品有已接受的外部身份,且同一种文字(中文 / 拉丁)下已有确认的外部标题(主标题 / 原标题 / TMDB 译名与别名),这个名称对不上
(`conflicts_external_title`);这个名称已经挂在别的作品上(`owned_by_other`)。
标题更新(RSS 标题与列表标题不同、站点改标题):按新标题重新解析,发 `release.observed(isNew=false)`,以 `force` 重新识别
(已识别的也不短路,触发来源仍是 observed);重新识别不能确认时撤销原自动绑定、进池。人工锁定的不动。
任务输入 `trigger` 缺省:`force` 为 true 视为 `review`(池复查),否则 `observed`。
搜索模块想让搜索结果直接识别,入队 `resolveObservation` 时传 `trigger: "search"`(目前搜索结果经 `release.observed` 进来,
按 observed 处理;命中订阅别名的照样会查)。
## 接管任务按文件名识别(QB-1)
用户手动加进 qB、贴了管理标签的任务(`download_task.origin = adopted`,没有 `source_release` / 计划)下载完成后,`verifyAndImport`
的 `planImport` 先按 MP transfer 的做法识别作品(`acquisition-organize/services/takeover.ts`):
1. 主视频 = 要下载(priority≠0)的视频文件里最大的一个(跳过 sample);`parseReleasePath(主视频路径)` 合并 文件 → 上级 → 上上级
目录名(qB 文件名含种子根目录,相当于 MP `MetaInfoPath`),再用种子名补缺(`mergeParsed`);文件名解析不出标题时直接用种子名。
2. `identifyParsed`(`service/resolve.ts`):同一套 ID-2 打分(本地召回 + TMDB 候选 → `resolveIdentity`),`trigger: "takeover"` 视为
允许查 TMDB;不写待识别池、不开身份事项。auto 且自动化开启 → 关联 / 新建作品(新建的入队一次 full 刷新),回填
`download_task.media_entity_id`,直接整理。
3. 失败 / 歧义 / 自动化关闭:整理记录 `identity_unknown`,事项 `organize_identity:<下载任务 id>`(`identity_ambiguous`),
证据带种子名、主视频、解析出的标题 / 年份 / 季集、识别结果与候选。选项:候选(最多 3 个,本地作品或 TMDB)、
「选择作品(本地)」(`requires: mediaEntityId`)、「选择作品(TMDB)」(`requires: tmdb`,本地没有时建档)、
「作为临时作品入库」(建 `provisional` 作品 + 别名)、「忽略」。
4. 处理(`POST /decisions/{id}/resolve`):整理模块注册的执行钩子(`modules/decision-hooks.ts`)在关闭前同步执行 —— 回填
`download_task.media_entity_id` → 冻结手动整理计划 → 入队执行;执行结果记在 `resolution.execution`。缺输入 / 作品不存在
→ 400 / 404,事项保持打开。
## 待处理只收相关的
| 结果 | 开事项? |
|---|---|
| `unmatched` | 否 |
| `ambiguous` / `proposed`(查过 TMDB,有候选) | 是,`identity_ambiguous`,级别 warning |
| `no_match` / 复查已停的 `lookup_failed` | 只有本地召回有候选(与本地作品相关)时开 `identity_unresolved`,级别 warning |
合并:dedupeKey `identity-group:<siteId>:<归一化标题>`,同来源同标题的资源并成一条。成员 = `identity_candidate.decision_id`
指向该事项且仍 `pending` 的条目。标题 1 条时写资源原标题,多条时写「来源「X」的 N 条资源待识别 / 待确认身份:<标题>」,
`evidence.releases` 列前 50 条,`evidence.count` 为总数。
- 处理(选候选 / 手动 TMDB ID / 选本地作品):先处理代表资源(subject),再把确定的作品套到组内其它资源(都加人工锁)。
- 忽略:组内每条池条目都 `dismissed`。
- 组内某条被单独识别 / 指定 / 忽略:从组里摘除,代表资源和候选选项换成剩下的最近一条;组空了才关事项。
- 旧式单条事项(`identity:<releaseId>`)在该资源下次复查时并入合并事项并关闭。
收件箱:顶栏角标和待处理页缺省只算 warning 及以上(`minSeverity=warning`),"仅信息"类在待处理页「级别 → 含仅信息」里看。
待处理页按问题类型 + 作品 / 来源分组,前 3 组展开,其余折叠;合并事项卡片可展开组内资源。
## 池的治理
- 复查有上限:`unmatched` 每天一次本地召回,最多 3 次;查过 TMDB 的按原退避(无结果 1h 起、查询失败 15min 起,翻倍到 7 天,最多 8 次)。
- 新证据即重试:`title_alias` 插入触发器 `title_alias_wake_identity_pool`,把归一化标题相同或相似度 ≥ 0.45 的
`unmatched` / `no_match` 池条目的 `next_review_at` 设为现在。建档、手动加别名、合并作品都会触发。
- 过期归档:`identity.poolArchiveDays`(缺省 30)天没有新尝试的 `unmatched` 条目改为 `archived`,在池复查定时任务里做,
每进程每小时最多一次。归档不删资源,仍可按状态筛出、手动指定。
- 检索:媒体概览 → 待识别,按原始标题 / 解析标题检索,原因筛「未命中订阅」即 unmatched。条目详情里可「重新识别」
(手动触发,会查 TMDB)、手动指定 TMDB ID / 本地作品(复用 `/identity-pool/{id}/assign`,加人工锁)或忽略。
## 设置
设置 → 元数据 → 资源识别:
- `identity.eagerTmdbLookup`(缺省关):打开即旧行为,每条新资源都查 TMDB。每条约 1–2 次搜索 + 命中时 1 次详情
(识别缓存命中为 0);每小时 100 条的 RSS 约每天 2400–7200 次请求,站点独有的短剧 / 综艺多半查不到。
打开后无结果的资源仍只进池,不开事项。
- `identity.poolArchiveDays`(缺省 30)。
## 存量清理(迁移 0047_identity_pool)
未关闭的 `identity_unresolved` 事项中,资源未关联作品、池里没有候选、归一化标题也不命中任何本地别名的:
事项改 `dismissed`,`resolution = {"resolution":"moved_to_pool","by":"migration:0047_identity_pool"}`;
池条目改 `reason = unmatched`、清 `decision_id`、停自动复查。相关的保留原样,下次复查时并入合并事项。
需要重建镜像 / 重启 api + worker 才生效(迁移随启动执行)。
## 规则更新后的存量重评(ID-2,`scripts/identity-reevaluate.ts`)
匹配规则更新(新镜像已部署、api + worker 已重启)后,用这个脚本处理存量。缺省只读,加 `--apply` 才改库;DATABASE_URL 必须显式给出。
```sh
# 用户栈的 PG 不对宿主暴露端口:取容器 IP,密码取栈的 .env
PGIP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' umt-postgres-1)
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/identity-reevaluate.ts --rollback-wrong # 先看清单
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/identity-reevaluate.ts --rollback-wrong --apply # 确认后执行
```
- 待识别事项:列出 open 的 `identity_ambiguous` 成员,按新解析规则给出预估(只用池里存的候选,不查 TMDB);`--apply` 把这些池条目排入立即复查,
由运行中的服务按新规则重新识别——能自动确认的绑定作品、建映射,并从合并事项摘除(组空即关闭)。
- `--rollback-wrong`:找站点来源的分类词 / 通用词别名(例如「电视剧」),对挂着它的作品用新解析 + 作品自身名称(主标题 / 原标题 / 非站点来源别名)
核对已绑定资源;对不上的解除绑定、退回池(`reason = no_match`,立即复查),删除该别名和由误并入资源登记的站点别名,各记一条
`resolution_attempt(outcome = manual, reason = rollback_wrong_alias)`。内容单元不删,只报告无资源引用的数量;引用了这些资源的其他表只报告。
- 2026-09-29 用户库副本演练:《东北有个周东北》29 条绑定里 23 条误并入,删除 7 个站点别名(「电视剧」「动漫」「综艺」与 4 个链式英文名)。
## 冲突别名与临时内容单元清理(FIX-5,`scripts/identity-cleanup.ts`)
守卫上线前登记的错误别名、重复 / 孤立的临时内容单元用这个脚本清理。缺省只读,`--apply` 在一个事务里执行并写审计
`identity.cleanup`;`--dry-run` 显式只读;`--keep-orphans` 不删孤立单元;`--entity <id>` 只处理一部作品。连接方式同上。
```sh
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/identity-cleanup.ts # 看清单
DATABASE_URL=postgres://umt:<密码>@$PGIP:5432/umt deno run -A scripts/identity-cleanup.ts --apply # 确认后执行
```
- 冲突别名:只动 `source = site` 的作品级别名,且不是作品自己的名字(主标题 / 原标题 / TMDB 别名)。同一归一化别名还挂在别的作品上
(或是别的作品的标题)→ 删;作品有已接受外部身份、同一种文字下已有确认外部标题而它对不上 → 删(中文标题的拼音写法保留);
本作品下带这个名字的资源都解析出年份且都与作品年份差超过 1 年 → 删。
- 重复的临时内容单元:同作品同类型同季同集号(未退役)有多条且有临时的,保留被引用最多的(同数时 confirmed 优先、再取最早的),
其余的引用改指向保留的那条(撞唯一约束的元数据行直接删),子单元改挂,然后删除。
- 孤立的临时内容单元(FIX-6 收紧):只删**资源解析建出、外部元数据不认识**的临时单元。同时满足才删:`provisional`;没有资源 / 资产 /
订阅 / 下载 / 整理等任何引用;没有任何元数据痕迹(字段来源 / 字段覆盖 / 标题 / 播出日期 / 总集数来源 / metadata 非空);
作品**没有**已接受的外部身份,或这个季 / 集**超出**作品的外部季集结构(季号 > TMDB 季数,或集号 > 该季已知总集数;
季数未知时整部作品都不删,特别篇季 0 总在结构内);没有保留的子单元。字段来源 / 覆盖 / 单元别名随之删除。
**TMDB / 元数据来源的季集账本单元永不删除**,即使没有资源、状态还是 provisional。
- 清单按类别输出:删除(作品没有外部映射 / 超出外部季集结构)与保留(仍被引用 / TMDB·元数据·人工来源 / 在外部季集结构内 /
有保留的子单元),`--dry-run` 显式只读(与 `--apply` 互斥)。先看「删除」两类里有没有正常作品,再 `--apply`;
审计 `identity.cleanup` 的 `orphanUnits` 记每条删除的单元与原因。
- 事故(FIX-6,2026-09-29):FIX-5 版本只看"无引用 + 没有 TMDB 字段来源",把旧版本建的、还没回写字段来源的 TMDB 季集账本单元
(《人生切割术》S00–S03 与 20 集、《沙丘:预言》S00 与 17 集等)当孤立删除。恢复:对受影响作品跑 full 元数据刷新——
计划页执行「元数据语言回刷」(`POST /schedules/metadata.backfill_languages/run-now`,停用状态也可手动执行)或逐个
`POST /media-entities/{id}/refresh?full=1`,正片季的季 / 集单元会按 TMDB 重建为 confirmed。**季 0(特别篇)不在 full 刷新范围内**,
删掉的特别篇单元只能等资源 / 文件再次命中时懒建。
## 排查
```sql
-- 池分布
select reason, status, count(*) from identity_candidate group by 1, 2 order by 3 desc;
-- 某条资源为什么没查 TMDB
select resolution_status, resolution_evidence->>'lookup' as lookup, resolution_evidence->>'detail' as detail
from source_release where id = '<id>';
-- 某个合并事项的成员
select p.source_release_id, r.title, p.reason from identity_candidate p join source_release r on r.id = p.source_release_id
where p.decision_id = '<decisionId>' and p.status = 'pending';
-- 站点来源的可疑别名(分类词等)
select e.title, a.alias, a.created_at from title_alias a join media_entity e on e.id = a.media_entity_id
where a.source = 'site' and a.normalized in ('电视剧', '动漫', '综艺', '电影', '纪录片', '音乐', '短剧');
-- 迁移搬走的事项
select count(*) from decision where resolution->>'resolution' = 'moved_to_pool';
```
## 元数据补全(META-1)
TMDB 查不到的作品(短剧、平台独播剧)按标题查网页,出一份带出处的字段建议;确认后才建本地临时作品(REQ R03 / R10、§7.3、§7.5)。
字段来源记 `web`(值在出处网页原文里)或 `agent`(Agent 归纳 / 改写,如简介),不记 `tmdb`。
代码:`apps/server/src/modules/sources-identity/service/enrich.ts`(建议 / 应用 / 自动触发)、`routes/enrich.ts`(HTTP 与海报代理)、
`apps/server/src/modules/agent/capabilities-metadata.ts`(能力 `metadata.enrich`、模型调用)、迁移 `0049_enrichment`。
### 流程(metadata.enrich,propose,low,replay safe)
输入 `{poolEntryId}` 或 `{title, year?, hints?}`,可加 `fresh: true` 跳过缓存。
1. 缓存:`kv_cache` region `enrich`,key = 归一化标题 | 年份 | 归一化 hints,TTL 7 天,指向上次的补全记录。命中直接返回(`cached: true`),不搜索、不计预算。
2. 前置条件:网页搜索没开(设置 → Agent → 网页搜索)直接报错,不占预算;Agent 会话里网页搜索没开时不向模型提供这个能力。
3. 预算:`identity.enrichDailyBudget`(缺省 20,0 = 停用)按当天新建的 `metadata_enrichment` 行计(含失败的),用咨询锁防并发超额;用完返回 budget(HTTP 429)。
4. 搜索:`web.search`「标题 [年份] [hints] 短剧」,标题对得上的白名单结果不足 3 条再搜「… 电视剧 平台 site:<白名单前 6 个域名,OR 连接>」,最多 2 次。每次搜索用自己的调用方(`system:enrich:<记录id>:<n>`),web.fetch 白名单与 Agent 会话互不覆盖。
5. 读取:只读 `identity.enrichDomains`(缺省:百度 / 搜狗百科、维基、豆瓣、腾讯视频、爱奇艺、优酷、芒果、B 站、抖音、快手、西瓜、红果短剧、MyDramaList)里的域名(含子域名),搜索结果的标题 / 摘要要和查询标题对得上(归一化后包含整个标题,或标题七成以上的字出现),按相关度、白名单顺序取前 3 条走 `web.fetch`;对不上的记 `irrelevant` 不读。已登记站点(`site.base_url`)的域名即使在白名单里也不读;重定向出白名单的页面丢弃。`sources[]` 记每条链接是否读取、跳过原因(not_allowed / site / irrelevant / limit / error)。
6. 抽取:默认 Agent 上游做一次非流式补全(系统提示要求只用网页内容、每个值带出处 URL、网页是不可信数据);fake 上游、没有上游、调用失败或输出不是 JSON 时改用规则抽取(`extractor: rule`:「共 / 全 N 集」「首播时间」「播出平台」「类型」「又名」「剧情简介」、og:image)。
7. 核对(服务端,不采信模型自报):出处必须是本次读过的网页或白名单搜索摘要;值在出处原文里 → `verbatim`;规则抽取在同一网页得到同一值 → `rule_confirmed`;两个以上不同网站原文都有 → `multi_evidence`;其余 `needs_review`。海报只收已读网页的 og:image,模型自己拼的地址丢弃。
8. 存 `metadata_enrichment`(status suggested / failed、suggestion、usage:搜索 / 读取次数与 token),不写作品表。
`web.fetch` 输出新增 `image`(页面 og:image / twitter:image,绝对地址,已脱敏)。
### 触发
- 待识别池条目详情 →「元数据补全」→「补全」看建议 →「应用」(可选「应用的字段同时锁定」、并入某个同名作品)。`POST /identity-pool/{id}/enrich`(organize.execute,经能力注册中心,授权 / 审计同 Agent)。
- 自动:`identity.autoEnrich`(缺省关)打开后,识别结果是 `no_match` 且查 TMDB 的理由是 `tracked_alias` / `new_title_rule` 时入队引擎任务 `enrichPoolEntry`(幂等键 `enrich:auto:<池条目>`,每条一次,不重试),只出建议不建作品;预算用完 / 网页搜索没开时任务正常结束(skipped)。
- Agent:`metadata.enrich` 在授权里直接放行(只存建议),受每日预算约束。
### 应用(POST /identity-pool/{id}/enrich/apply,只接受控制台管理员会话)
- 作品:指定 `mediaEntityId` 则并入;否则按标题 / 查询标题的归一化别名找已有作品(active / provisional,年份不冲突)去重并入;都没有就建 `status = provisional` 的作品(缺省剧集,`kind` 可改)。
- 字段:`metadata_field` 写 `source = web | agent`、`source_revision = enrich:<记录id>`、`evidence = {sourceUrl, evidenceLevel, enrichmentId, extractor}`;映射 title→title、year→year、synopsis→overview、platform→platform、episodeCount→episodeCount、genre→genres、posterUrl→posterUrl,然后按原规则投影(TMDB 值存在时仍优先 TMDB,锁定的字段不变)。`lock: true` 把应用的字段加进 `field_locks`。
- 别名:标题、查询标题、建议里的别名写 `title_alias`(source agent,kind other),会唤醒相近的池条目复查。
- 单元:剧集建第 1 季 + 1..集数(最多 200)临时单元。
- 待识别资源经 `assignReleaseIdentity` 关联到该作品(人工锁);记录改 applied,审计 `metadata.enrichment_applied`。不写外部身份。
- 后续 TMDB 收录:`provisionalEntitiesForTmdbReview()` 列出补全建的、还没有 TMDB 身份的临时作品,留给身份巡检按标题 / 年份查 TMDB 后用 `setEntityIdentity` 补映射。
作品详情「元数据」里来源显示「网页」/「Agent」,下面一行是证据等级和出处链接;网页海报经 `GET /api/v1/img/enrich/{记录id}` 代理(只取该记录里白名单网页给出的图片,出处仍须在白名单;不接受任意 URL;地址守卫同 web.fetch,最多 3 跳、5 MB、只收图片)。
### 设置(设置 → 元数据 → 资源识别)
| 字段 | 缺省 | 说明 |
|---|---|---|
| `identity.autoEnrich` | 关 | 订阅 / 规则命中而 TMDB 无结果时自动出建议 |
| `identity.enrichDailyBudget` | 20 | 每日次数(手动 + 自动 + Agent);0 = 停用 |
| `identity.enrichDomains` | 见上 | 可读取的域名,不放 PT 站 |
单次成本:1–2 次 Brave 搜索(10 分钟搜索缓存命中不计)、最多 3 次网页读取、1 次模型调用(约 3–6 千输入 token)。
迁移 `0049_enrichment`:`metadata_field` / `field_override` 来源加 `web`、`metadata_field.evidence`、`metadata_enrichment` 表。需要重建镜像 / 重启 api + worker 才生效。
```sql
-- 今天的补全
select status, trigger, count(*), sum((usage->>'searchCalls')::int) searches from metadata_enrichment
where created_at >= date_trunc('day', now()) group by 1, 2;
-- 某作品的补全字段与出处
select field, source, value, evidence->>'evidenceLevel' lvl, evidence->>'sourceUrl' url from metadata_field
where media_entity_id = '<id>' and source in ('web', 'agent');
```
### 真机记录(2026-09-29,开发库写记录,用户栈只读设置 / 凭证,未应用)
默认上游 OpenCode Go / deepseek-v4.1-flash + Brave,对池里 4 条 HHClub 短剧标题各跑一次(共 8 次 Brave 调用):
| 标题 | 结果 | 耗时 | 读取 / token |
|---|---|---|---|
| 我被亲戚误会破产了 | failed:搜索结果全是聚合站,不在白名单(当时还没有 site: 限定) | 1.8 s | 0 |
| 重生60 我有情报系统 | failed:加 site: 后有白名单结果,读了 3 个爱奇艺页(当时未做相关度过滤),模型判定没有这部作品的信息 | 6.2 s | 3 次 / 1601 入 533 出 |
| 京夜喜你 | failed:白名单结果标题都对不上,不读网页、不调模型 | 1.9 s | 0 |
| 春城恋曲 | 同上 | 1.8 s | 0 |
结论:平台自制短剧在百科 / 豆瓣 / 平台站基本没有可被搜索到的条目,补全多数会以"白名单网站里没有标题对得上的结果"结束,不消耗读取和模型;
要提高命中率可以在 `identity.enrichDomains` 里加入短剧平台的公开页面域名。聚合站、盗播站不要加。