Files
MoviePilot/docs/refactor/media-search-design.md
2026-09-11 06:29:12 +08:00

10 KiB
Raw Blame History

音乐与影视搜索流程统一

目标与边界

电影、剧集和音乐共用识别、资源搜索、过滤、匹配与结果发布的编排。 媒体类型决定元数据解析器、关键词、身份和范围匹配规则,不拥有另一套 站点请求循环、提前停止条件、缓存、进度和上下文生命周期。

资源解析结果是资源自身的证据。目标媒体信息是用于比较和后续交付的目标, 不能先把目标名称、艺术家或 ID 写回资源元数据,再将其当作识别成功。

改造前调用链审计

基线为 v3@76174b11d6b26793f1471e77e9453f3c7fbb54aa。

环节 影视 音乐 判定
媒体身份识别 RecognitionChainMixin 的识别计划与步骤 同一计划,原生动作选择音乐来源链 已共用主流程;保留来源适配差异
原生与插件回退 MediaRecognitionOwner + MediaPluginOwner 同一选择状态机,事件和字段不同 已共用;不复制状态机
路径证据 文件名、父目录、已有身份 指纹、音频标签、文件名及专辑目录 必要差异;每级仍复用统一媒体识别入口
元数据目录搜索 MediaSearchOwner.search MediaCatalogOwner.search_music 统一上层入口与结果收口,来源模块 ABI 保持兼容
资源解析 MetaInfo(title, subtitle) 精确搜索未解析;标题搜索仅构造 MetaMusic;RSS 只解析标题 应统一至具备媒体类型意图的 MetaInfo 工厂
精确资源搜索 SearchMediaOwner 的准备、请求、解析步骤 三个独立音乐搜索循环 应移除音乐旁路,使用同一搜索状态机
停止换词 影视收到原始资源即停止,之后才过滤 音乐通过字符串匹配即停止,之后才过滤 均应基于最终可用的精确结果停止
资源匹配 解析作品名/年份/季集/身份,必要时消歧 标题和副标题字符串包含作品名及艺术家 应共用匹配阶段;具体规则由媒体类型提供
上下文生成 资源元数据与目标媒体分开 用目标信息重新构造资源 MetaMusic 应共用上下文生成,并保留原始证据
过滤与排序 搜索结果 owner 调用规则模块及种子工具 音乐重复实现同一规则调用与排序 应在同一结果处理 owner 收口
进度和缓存 原始候选及最终替换结果 仅统计已经匹配的候选 应统一原始召回、过滤结果、最终发布语义
主动订阅搜索 共用 SearchChain.process 并处理站点预算事实 自行循环 search_by_title,未经过同一预算结果处理 应复用同一订阅搜索编排
RSS 订阅匹配 使用资源元数据、身份和订阅约束 单独字符串匹配并回填目标元数据 复用相同音乐解析/匹配规则,保留 RSS 不再查询站点的语义
下载提交 共用批量选择、失败冷却和单次提交 已与电影共用直接候选下载 保留共用提交;禁止人工候选自动下载
范围完成 剧集按缺集/全集覆盖 专辑按独立音轨数量和文件清单覆盖 必要差异,不将专辑等同于单曲或电影

审计入口:app/chain/_recognition.py、app/chain/media/recognition.py、 app/chain/media/path.py、app/domain/metainfo.py、app/chain/search/media.py、 app/chain/search/result.py、app/chain/_music.py、app/chain/subscribe/search.py、 app/chain/torrents.py、app/chain/download/selection.py。

统一后的资源流程

  1. 校验来源身份并取得目标媒体快照;不改变显式来源和默认来源约定。
  2. 复制目标,完成适用的附加信息补全,按媒体类型生成有序关键词与范围约束。
  3. 通过现有 provider 层执行站点选择、分页、节流、预算和查询。
  4. 对原始候选计数;通过统一 MetaInfo 工厂解析主副标题。
  5. 在同一结果处理阶段应用规则和媒体匹配策略,记录被淘汰原因。
  6. 构造保留资源自身证据的 Context,排序、去重。人工候选不绑定目标身份。
  7. 应用调用方提供的候选约束(如订阅当前洗版优先级);有经过完整过滤的精确结果且没有要求多名称搜索时停止,否则继续换词。
  8. 统一发布流式替换/完成事件并缓存最终结果。

同步、异步和流式入口只负责不同的 I/O 驱动,不各自决定媒体业务分支。 音乐 owner 保留关键词和兼容门面,不再拥有完整搜索或结果处理循环。

实现由 app/chain/search/execution.py 驱动统一状态机,result.py 统一处理候选; MediaChain.search / async_search 统一元数据目录入口,来源服务只适配既有模块 ABI。 app/chain/subscribe/metadata.py 准备目标,subscribe/search.py 统一主动搜索和站点预算处理。

音乐策略

  • MetaMusic.parse_resource 接受标题与副标题,复用现有 Python/Rust 标题解析, 补充明确艺术家/专辑字段、曲序结构和版本证据。缺少分隔且语义不明确时不猜测。
  • 音乐资源经 MetaInfo 工厂应用与影视相同的用户识别词,实际应用记录保存在 apply_words 中;RSS 重新匹配也使用订阅识别词,不修改共享资源缓存。 音频文件的真实后缀仍优先于标题中的格式声明。
  • 副标题的明确版本字段或独立版本标签补充主标题缺少的录音版本;已有标题版本 不被副标题覆盖。单曲的所属专辑字段只证明归属,即使没有曲序也不代表整专资源。
  • 展示繁转简前保留名称原文。作品、所属专辑与艺术家别名分开保存;单曲不使用 兼容 names 中混入的专辑名称。别名仅来自同一实体的来源数据。
  • 完整名称及署名优先;短名称不能仅凭子串命中另一首作品。署名冲突、未知分类、 不确定发行版本、不同录音版本或关联专辑只能成为显式请求的人工候选。
  • 单曲所属专辑可以作为人工搜索的后续查询,但不能自动认定包含目标单曲。
  • 元数据源各自排序和去重后公平合并,避免首个来源独占返回条数上限。
  • MusicBrainz 以完整名称的繁简短语组优先,完整查询无结果才启用逐字兜底, 并按完整名称重排有界候选窗口。2026-09-05 公网查询 recording:"晴天" AND artist:"周杰伦" 返回 10 个录音候选,前三项均为标题 “晴天”、艺术家“周杰倫”,证明中文完整短语不是零命中。 查询字段与短语语义参考 MusicBrainz 官方检索语法。
  • 不根据展示文本臆造 MusicBrainz ID,不更改默认 MusicBrainz 或显式单来源行为。
  • 署名清理保留原始分隔信息,不能从非中日韩文字的单词内部剥离艺名,避免把 Leeway 截为 way、把 Surprise 截为 Surp。中日韩连写署名及“的/之”形式保持兼容。 MusicBrainz 确认先采用完整名称,去署名结果只作回退;不符合艺术家、版本约束的 完整名称不能抢占有效回退。旧名称确认规则的派生缓存升级后重新建立。
  • MusicBrainz 的候选确认与资源匹配复用繁简、变音符、可信别名、完整署名和录音版本规则。 单曲不凭首词、包含关系或任意括号剥离认定同一作品;已返回的同一 ISRC 优先于名称打分。 专辑的 secondary_types 可提供整专版本证据,但不能反向覆盖其中单曲的录音版本。
  • TheAudioDB 与豆瓣音乐也复用名称、署名和版本规则;TheAudioDB 的 strTrackAlternate 投影为曲名别名,不能混入专辑名称。专辑查询及父专辑确认优先使用 album_artist, 单曲仍按自己的表演者确认,不因合辑署名不同而跳过其曲目。 备选来源保留既有发行版名称约束,不因录音版本后缀归一化而将豪华版合并成普通版。
  • 录音版本双方各自提供唯一有效年份或日期且冲突时,不确认成同一版本;支持全半角、 数字分隔日期及中文日期。普通数字曲名、缺失日期、无效日期与多时间值不被臆断为冲突。 已缓存的无显式 ID 名称识别结果也重新检查版本,已核验的相同 ISRC 保持身份优先级。
  • ISRC 优先级仅适用于符合 ISRC 官方结构 的代码,兼容大小写、展示前缀及分隔符,不能把占位文本相等当成身份相等。 代码内的年份是分配参考年,不用于推断录制日期。
  • 自动识别在某个检索式返回的候选全部不匹配时继续尝试后续检索式;手动元数据目录 浏览仍保留原始候选。Python/Rust 标题解析进入共同包装层时均保留 [Live] 等版本证据。
  • 音乐识别缓存按请求实体与来源身份或完整标题、署名、专辑、年份、版本、ISRC 编码, 不使用可碰撞的分隔符拼接;旧版派生缓存自动重建,负缓存同样不跨实体复用。 共享识别成功时,沿用现有模块回填 ABI,同时覆盖已确认实体的负缓存。

订阅与下载

订阅共用搜索入口、取消检查和站点预算事实处理。音乐实体合法性、总曲目数、 音质洗版优先级和整专完成判定作为领域步骤保留;不额外执行另一套关键词循环。 RSS 复用解析和匹配策略,但不重新发起站点搜索。

人工候选必须有清晰状态,默认自动 API/订阅仍只采用精确结果。候选进入手动下载 确认时仅提交资源本身;自动批量选择也拒绝待确认项,防止缓存或其他调用路径绕过。

验证要求

  • 电影、剧集、音乐参数化验证同一请求顺序、过滤后停止、空结果继续与最终缓存。
  • 同步、异步和 SSE 的结果、范围、来源、候选计数和停止条件一致。
  • 影视 IMDb/别名消歧、季集、用户过滤规则、分页与预算行为不回退。
  • 音乐主副标题、繁简原文、可信别名、名称边界、版本、曲序和专辑范围回归。
  • 音乐主动订阅与 RSS 使用一致的匹配依据,资源元数据不能被目标信息污染。
  • 人工候选、缺少 ID 的部分元数据及旧缓存不能流入自动下载。
  • 架构、复杂度、异步阻塞、类型、增量静态检查与后端全量测试通过。
  • 前端完整测试及桌面/窄屏操作检查通过后,完成最终提交 CI 和现版本发布验收。