本文主要说明自托管媒体库(以 Octans 联网字幕搜索 / 下载 / 同步方案为例)在接入第三方字幕站时,如何把 Provider 检索、候选评分、下载后校验与自动时间轴修正分层,并划清 hash 匹配、速率配额与隐私安全的职责边界。讨论的是可落地的架构取舍,不是某一版已发布 API 清单。

媒体库用户要的往往是「搜到对的字幕、下得下来、播的时候对得上」。实际工程却会撞上三类硬约束:第三方 API 字段与额度各不相同;hash 命中率在本地重封装 / 重命名片源上普遍偏低;下载到的字幕还可能整体偏移、fps 漂移甚至分段错位。若把「搜、下、判、修、播」揉成一条黑盒链路,后续排障和配额治理都会很难。下面按边界整理。

问题从哪来

现有播放主链通常已经具备:本地媒体文件、探针事实、播放 options、HLS / DirectPlay 交付,以及基础字幕输出(内嵌轨或外置 sidecar)。「联网搜字幕」不是把搜索结果列表贴到详情页就结束,至少还要同时回答:

  1. 找得准:同作品多版本(剧场 / 加长 / WEB-DL / Remux / 不同片头切点)下,如何排序候选。
  2. 下得起:各 Provider 搜索与下载额度不同,不能默认全库扫盲。
  3. 对得上:下载后整体偏几秒、23.976 / 25 fps 漂移、中间广告导致的分段错位,是否允许自动修、修到什么程度。
  4. 信得过:字幕压缩包与文本按不可信输入处理,API Key 与用户偏好不出站。

一句话分层建议:

Provider 适配层:检索、下载、配额与原始字段映射
评分与编排层:多阶段匹配分、合并去重、下载策略
后处理层:安全解压、编码探测、cue 解析、sanity check
同步层:高置信 constant offset → 可选 fps scale → split 仅提示
资产层:原始字幕 + 派生 synced 字幕;播放页保留手动 offset

Provider 负责最终匹配策略、资产入库、自动同步和播放选轨;这些应落在媒体库自己的编排与资产域。

Provider 选型与接入边界

第一版建议主源

Provider阶段建议主要价值主要风险 / 约束
OpenSubtitles.com RESTphase-01 主源国际多语言;支持 ID、hash、文件名等组合搜索下载有配额;字段需用真实 Key 抓样本确认;旧 .org XML-RPC 不作为新主线
SubDLphase-01 补充IMDb / TMDB / 季集 / 整季包 / unpack 结构清晰beta API;按 key 限额
ASSRT(射手网伪)phase-01 中文核心中文 / 双语覆盖;搜索 + 详情 + 包内文件列表无 IMDb/TMDB;下载 URL 有时效;默认约 20 次/分钟;需 attribution

第二阶段再评估:SubSource(实验 Provider)、SubDB / TheSubDB(hash 精确 fallback)、BetaSeries(剧集生态补充)。不建议把 HTML scraper 路线(如部分中文站公开接入方式)或已停运源写进核心 Provider 抽象。

统一请求 / 候选,再 adapter 转换

前端与业务层只应看到媒体库自己的搜索模型,而不是各站字段名。入参侧至少覆盖:媒体类型、标题 / 年份、IMDb / TMDB(及剧集 parent id)、季集号、本地文件名、文件大小、OpenSubtitles moviehash、媒体时长与帧率、语言与格式偏好、是否包含 HI / forced / 机翻。

候选结果侧归一为:Provider + ProviderSubtitleId、语言 / 格式、release / file name、季集、HI / forced / 机翻 / trusted、hash 是否命中、质量信号,以及内部 Score 与原始 payload。Provider 接口形态可收敛为:

SearchAsync(request) → candidates[]
DownloadAsync(request) → raw bytes / zip + meta
GetQuotaAsync() → 剩余额度(若可观测)

各站能力不对齐是常态:例如 ASSRT 主要靠文件名 / 文本搜索;OpenSubtitles 支持 moviehash;SubDL 适合 unpack=1 后按集挑选。适配器负责「能填则填」,评分层负责「缺信号时如何降级」,而不是强求每个 Provider 暴露同一组入参。

下载策略边界

默认:用户手动搜索 → 选候选 → 下载 top 选择(或「自动最佳」仅下 1~3)
禁止默认:全库批量打满下载配额
批量补字幕:单独开关 + 每 Provider 日上限 + 失败可见(quota / 无结果 / 解析失败 / 同步低置信)
ASSRT:detail 后再下;下载 URL 只短期缓存;资产侧保留来源标注
OpenSubtitles:记录每次下载后的剩余额度信号

Hash 匹配:强加分,不是唯一入口

字幕站与具体视频文件 hash 建立关联的比例有限。对用户本地下载、重封装、重命名、二次压制的片源,只走 hash 经常空结果。因此:

信号角色说明
moviehash + 文件大小(OpenSubtitles 系)强加分命中几乎可确认「同一文件版本」;未命中不代表无字幕
SubDB 类纯 hash APIfallback低成本精确匹配;不能按 TMDB / 季集 / release 通用搜
tmdb_id / imdb_id + 季集主检索入口电影 / 剧集身份层
文件名 / release token版本层source / platform / edition / group 等
lastCueEnd / mediaDuration下载后弱校验排除明显错片;不是搜前主分

推荐多阶段评分,而不是单字段判决:

IdentityScore      作品 ID / 年 / 季集
  → ReleaseScore   source / platform / edition / group / 分辨率 / codec
  → SubtitleAttributeScore  语言 / forced / HI / 格式 / 是否机翻
  → TimingSanityScore       下载后 cue 解析与覆盖率
  → ProviderQualityScore    trusted / votes / downloads / hash_match

Release 冲突要敢扣分。例如本地是 Extended.BluRay,候选是 Theatrical.WEB-DL,edition 与 source 同时冲突时应显著降权,而不是只靠标题字符串相似。

字幕时间语义:没有「字幕总时长」

SRT / ASS 等侧车文件只有 cue 时间轴,没有等价于 mediaDuration 的总时长字段。应对字段拆开理解:

firstCueStart / lastCueEnd / subtitleSpan
cueCount / activeCueDuration
mediaDuration(来自 ffprobe / MediaInfo)
subtitleCoverageRatio = lastCueEnd / mediaDuration   # 弱信号

片尾曲、演职员表、forced 轨都会让 lastCueEnd 明显早于片长。经验规则可粗分为:普通完整字幕覆盖率约在 0.75~1.02 为正常;过低扣分;lastCueEnd 显著超过片长则强扣或拒绝;forced / signs-only 不做覆盖率强判断。剧集优先季集与 release token,时长只排除明显错集。

下载前排序 vs 下载后管线

下载前 API 通常看不到 cue 时间轴,因此无法可靠预判「整条慢 3 秒」或「后半段整体错位」。下载前只做 ID / 季集 / release / 语言属性 / 质量信号排序。

下载完成后必须进后处理:

ZIP / raw
  → 安全解压(防路径穿越、限文件数与体积、禁符号链接)
  → 选目标字幕文件
  → 编码探测 → 格式白名单(.srt / .ass / .ssa / .vtt)
  → cue 解析 → language / cueCount / lastCueEnd 校验
  → 可选自动同步分析
  → 原始资产入库;高置信时生成 synced 派生资产

不要覆盖原始字幕。 建议同时保留:

subtitle.zh-cn.ass
subtitle.zh-cn.synced.ass

并记录原始 / 派生资产 ID、AppliedOffsetMsAppliedScaleSyncConfidenceSyncAlgorithmSyncStatus。播放页仍需支持 runtime 手动提前 / 延后、保存默认偏移、恢复原始轨——自动同步不能吞掉用户校准权。

同步能力分层

问题类型典型原因第一版建议
ConstantOffset片头差异导致整体偏几秒高置信可自动生成派生字幕
LinearDrift23.976 / 24 / 25 等 fps 不一致第二阶段:固定候选 scale
SegmentSplit广告 / recap / 删减导致阶跃错位只标记提示,默认不自动重写
WrongRelease同作品版本差过大不自动硬修,回退人工选候选
Forced / partialcue 过少跳过按完整字幕的同步策略

Constant offset 可用「语音活动序列 vs 字幕活动序列」在候选偏移窗内做重叠评分(语言无关思路与常见开源同步工具同类)。阈值可粗定为:小于 250ms 忽略;中等偏移且高置信自动派生;超大偏移默认不自动改。Linear drift 可先试固定 scale 表;segment split 留给高级工具(如可选外部 alass),并注意 GPL 等许可证边界。

速率限制、配额与可观测性

配额是产品能力,不是运维事后补丁:

维度实践建议
搜索 vs 下载许多源搜索相对宽松、下载严格;策略应分开计数
每 Provider 配置API Key、RPM / 日下载上限、冷却与重试
批量任务独立开关;失败原因落到任务结果(quota / empty / parse / low-confidence sync)
可观测暴露剩余额度(若 API 提供)、429 / 限流次数、按 Provider 成功率
用户可见候选页与任务页能看懂「为什么没下」或「为什么没自动同步」

OpenSubtitles 一类:匿名与登录等级下载额度不同,接入时应按账号档位规划批量策略。ASSRT:token 与 IP 共享分钟配额,详情 / 搜索都会计入时要避免列表页狂刷。SubDL:按 key 限流,整季 full_season 更要克制。

隐私与安全边界

联网字幕能力会把「本地媒体元数据」送出站,边界要写进产品与实现:

出站最小化:
- 优先作品 ID + 季集 + 语言,而不是整路径绝对路径
- 文件名 / release 可参与匹配,但日志与遥测脱敏
- moviehash 是文件指纹信号:仅在用户启用对应 Provider / 功能时发送
- 不上传完整媒体文件内容做「搜字幕」

密钥与配置:
- Provider API Key 仅存服务端密钥管理;不下发浏览器
- 多用户部署时按实例或按用户隔离 key 与配额账本(按产品模型定)

不可信字幕输入:
- 压缩包路径穿越防护与体积上限
- 格式白名单;解析失败即失败
- 不执行字幕内脚本 / 外部引用;ASS 未知语义不喂给不可信原生路径
- 播放优先走已解析、白名单格式的资产

合规与 attribution:
- ASSRT 等要求在合适位置标注来源
- 商业使用前核对各站 ToS / 商业条款

历史上恶意字幕文件曾被用于攻击部分播放器;自托管库仍应按「外站字节流不可信」处理,而不是假设「热门字幕站 = 安全」。

与播放 / 轨事实的交界

联网下载得到的是外置字幕资产,最终仍要进入既有轨展示与客户端渲染链路:

  • 资产图谱:归属媒体文件、语言、forced、原始 vs 派生、来源 Provider 与 attribution。
  • 展示轨:按「每媒体文件一行」投影;共享季包字幕时避免把选轨模型变成多对多主键。
  • 渲染:WebVTT / ASS / 位图边界仍由客户端渲染专题约束;联网链路不应默认把「搜到的字幕」推进服务端烧录。
  • 控制面:HLS sidecar delay、full-cache 状态与手动 offset 仍属播放会话职责,同步层生成的派生文件只是另一种资产输入。

推荐落地顺序(摘要)

phase-01  ISubtitleProvider + 三主源 + Key / quota 可观测
phase-02  release parser、多源合并评分、安全下载与原始资产
phase-03  timing sanity + 高置信 constant offset 派生 + 播放页手动 offset
phase-04  fps scale、split 提示、可选外部同步工具、实验 Provider / hash fallback
phase-05  媒体库级批量补字幕(日额度、冷却、不覆盖人工字幕、人工 review 队列)

决策上可压成几条硬边界:

  1. 默认 Provider:OpenSubtitles.com + SubDL + ASSRT;hash 只强加分。
  2. Provider 只做检索 / 下载 / 限额 / 字段映射;评分与同步在库内。
  3. lastCueEnd ≠ mediaDuration;覆盖率只做下载后弱校验。
  4. 原始字幕不可覆盖;自动修正只产派生资产。
  5. 第一版自动同步仅高置信整体偏移;分段错位默认只提示。
  6. 配额与出站最小化是产品能力,不是可选优化。

注意事项

  1. 本文是架构与边界说明,不是已实现接口契约;各站字段、错误码与真实配额需用 API Key 抓样本复核。
  2. 自动同步置信阈值(偏移毫秒、覆盖率区间)应可配置,并用中英剧 / 电影 / forced 样本回归,避免 silent 误修。
  3. 引入 GPL 同步工具前单独评估分发与链接边界;轻量 constant offset 可先自研。
  4. 批量补字幕会直接撞击下载配额与站方 ToS,默认关闭更稳妥。

到这里可以把联网字幕能力压成三句:用 Provider 适配隔离各站差异与配额;用多阶段评分把 hash 降为强信号而非唯一入口;用下载后校验与派生同步资产把「能播且可校准」收在媒体库自己的资产与播放控制面里,同时守住出站最小化与不可信输入处理。

相关阅读

同系列还可对照:

来源

本文综合改写自 Octans 项目研究文档中的联网字幕搜索、匹配与自动同步方案探索。表述面向公开工程讨论,已去掉内部 DTO 清单与未发布实现细节;具体 Provider 字段、额度与同步置信阈值以目标环境实测为准。