本文主要说明自托管媒体库(以 Octans 联网字幕搜索 / 下载 / 同步方案为例)在接入第三方字幕站时,如何把 Provider 检索、候选评分、下载后校验与自动时间轴修正分层,并划清 hash 匹配、速率配额与隐私安全的职责边界。讨论的是可落地的架构取舍,不是某一版已发布 API 清单。
媒体库用户要的往往是「搜到对的字幕、下得下来、播的时候对得上」。实际工程却会撞上三类硬约束:第三方 API 字段与额度各不相同;hash 命中率在本地重封装 / 重命名片源上普遍偏低;下载到的字幕还可能整体偏移、fps 漂移甚至分段错位。若把「搜、下、判、修、播」揉成一条黑盒链路,后续排障和配额治理都会很难。下面按边界整理。
问题从哪来
现有播放主链通常已经具备:本地媒体文件、探针事实、播放 options、HLS / DirectPlay 交付,以及基础字幕输出(内嵌轨或外置 sidecar)。「联网搜字幕」不是把搜索结果列表贴到详情页就结束,至少还要同时回答:
- 找得准:同作品多版本(剧场 / 加长 / WEB-DL / Remux / 不同片头切点)下,如何排序候选。
- 下得起:各 Provider 搜索与下载额度不同,不能默认全库扫盲。
- 对得上:下载后整体偏几秒、23.976 / 25 fps 漂移、中间广告导致的分段错位,是否允许自动修、修到什么程度。
- 信得过:字幕压缩包与文本按不可信输入处理,API Key 与用户偏好不出站。
一句话分层建议:
Provider 适配层:检索、下载、配额与原始字段映射
评分与编排层:多阶段匹配分、合并去重、下载策略
后处理层:安全解压、编码探测、cue 解析、sanity check
同步层:高置信 constant offset → 可选 fps scale → split 仅提示
资产层:原始字幕 + 派生 synced 字幕;播放页保留手动 offset
Provider 不负责最终匹配策略、资产入库、自动同步和播放选轨;这些应落在媒体库自己的编排与资产域。
Provider 选型与接入边界
第一版建议主源
| Provider | 阶段建议 | 主要价值 | 主要风险 / 约束 |
|---|---|---|---|
| OpenSubtitles.com REST | phase-01 主源 | 国际多语言;支持 ID、hash、文件名等组合搜索 | 下载有配额;字段需用真实 Key 抓样本确认;旧 .org XML-RPC 不作为新主线 |
| SubDL | phase-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 API | fallback | 低成本精确匹配;不能按 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、AppliedOffsetMs、AppliedScale、SyncConfidence、SyncAlgorithm、SyncStatus。播放页仍需支持 runtime 手动提前 / 延后、保存默认偏移、恢复原始轨——自动同步不能吞掉用户校准权。
同步能力分层
| 问题类型 | 典型原因 | 第一版建议 |
|---|---|---|
| ConstantOffset | 片头差异导致整体偏几秒 | 高置信可自动生成派生字幕 |
| LinearDrift | 23.976 / 24 / 25 等 fps 不一致 | 第二阶段:固定候选 scale |
| SegmentSplit | 广告 / recap / 删减导致阶跃错位 | 只标记提示,默认不自动重写 |
| WrongRelease | 同作品版本差过大 | 不自动硬修,回退人工选候选 |
| Forced / partial | cue 过少 | 跳过按完整字幕的同步策略 |
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 队列)
决策上可压成几条硬边界:
- 默认 Provider:OpenSubtitles.com + SubDL + ASSRT;hash 只强加分。
- Provider 只做检索 / 下载 / 限额 / 字段映射;评分与同步在库内。
lastCueEnd ≠ mediaDuration;覆盖率只做下载后弱校验。- 原始字幕不可覆盖;自动修正只产派生资产。
- 第一版自动同步仅高置信整体偏移;分段错位默认只提示。
- 配额与出站最小化是产品能力,不是可选优化。
注意事项
- 本文是架构与边界说明,不是已实现接口契约;各站字段、错误码与真实配额需用 API Key 抓样本复核。
- 自动同步置信阈值(偏移毫秒、覆盖率区间)应可配置,并用中英剧 / 电影 / forced 样本回归,避免 silent 误修。
- 引入 GPL 同步工具前单独评估分发与链接边界;轻量 constant offset 可先自研。
- 批量补字幕会直接撞击下载配额与站方 ToS,默认关闭更稳妥。
到这里可以把联网字幕能力压成三句:用 Provider 适配隔离各站差异与配额;用多阶段评分把 hash 降为强信号而非唯一入口;用下载后校验与派生同步资产把「能播且可校准」收在媒体库自己的资产与播放控制面里,同时守住出站最小化与不可信输入处理。
相关阅读
同系列还可对照:
- 客户端字幕渲染:不做烧录时的 WebVTT / ASS / PGS 边界:下载后的外置字幕如何进入客户端渲染与 full-cache / delay 控制面。
- 媒体库轨识别与动态范围:stream index、语言标题与 HDR/DV 分层探针:外置 sidecar 归属、展示轨投影与播放映射分层。
来源
本文综合改写自 Octans 项目研究文档中的联网字幕搜索、匹配与自动同步方案探索。表述面向公开工程讨论,已去掉内部 DTO 清单与未发布实现细节;具体 Provider 字段、额度与同步置信阈值以目标环境实测为准。