MAW / DOCS

MAW documentation

多重字幕

主副字幕导入、绑定、联动与导出的完整规则。

本文同步自 MAW 原始仓库的 docs/user/MULTI_SUBTITLE.md。

本文为当前主副字幕的详细行为与实现规范。快速操作见 编辑器指南,数据字段以 JSON_SCHEMA 为准。

1. 目标

在不干扰单字幕工作流的前提下,为编辑器增加主字幕 + 一条副字幕的双语编辑能力:

主字幕 + 副字幕
       ↓
按段级时间码自动一对一匹配
       ↓
共享时间编辑、双轨波形显示、双列字幕列表

多重字幕是可选模式,默认关闭。开启后即显示可编辑的空副轨与齿轮设置;快速导入询问选「否」仍启用空轨。可在副轨空白处右键、按 N 或 Ctrl/Cmd 拖动创建字幕,也可从齿轮设置导入字幕。关闭模式保留副轨,重新开启、撤销与工程保存重开均保留数据。

2. 产品边界

2.1 MVP 支持

  • 主轨 + 一条副轨。
  • 副字幕可以手动创建,或从 .srt / .mosp/.json 导入。
  • 副字幕文件至少使用段级 start、end、text;SRT 没有 items,mosp/json 中已有的可选 items 会作为可恢复的字词时间码保留。
  • 按 300ms 容差自动一对一匹配。
  • 匹配预览、未匹配保留、手动绑定和解绑。
  • 主轨/副轨/双列字幕列表。
  • 一份共享波形背景上的主字幕 lane 和副字幕 lane。
  • 正常联动移动、边界调整、成对删除、成对合并;绑定后默认自动同步副字幕时长,可在齿轮设置中关闭。
  • 「自动吸附调整相邻字幕」控制同一轨道相邻字幕的默认移动/边界联动,默认开启;按住 Alt 始终临时反转这个同轨模式。操作主字幕时绑定的副字幕仍按本规范跟随,操作副字幕时的绑定限制与同步规则不变,不删除绑定关系。
  • 副字幕支持与主字幕一致的选中、Alt+点击 禁用/启用、隐藏禁用项、←/→ 与 Ctrl/Cmd+方向键 时间调整、F 跳转播放、Ctrl/Cmd+A 全选、Ctrl/Cmd+D / Esc 清除选择,以及拖动中的 A/D 微调;多重字幕下按 ↑/↓ 可在主轨与副轨之间切换当前焦点,主副字幕的其它快捷键以最后点击的轨道为当前目标。
  • 绑定状态下从主轨发起 B、Ctrl/Cmd+Enter 或剃刀拆分,并用弹窗人工选择副字幕文本断点;副轨波形右键也可单独按鼠标位置拆分。
  • 多重字幕设置收纳在工具栏齿轮中,支持显示方式、主/副字幕语言、跨轨吸附、成对选中和交换主副字幕。“成对选中”默认开启;普通点击以最后点击的轨道为准,点击未绑定副字幕会清除旧主字幕选区,点击已绑定字幕时只补选它实际绑定的另一条字幕;显式 Ctrl/Shift 多选仍可保留主副字幕作为有意的绑定/替换选择,当前字幕编辑区仍以最后点击的字幕为准。单词型适合英语等按空格分词的语言;字符型适合中文、日文等按字符拆分的语言。仅在主字幕或副字幕单独显示时,列表字数和超长筛选按对应轨道的语言类型计数;双列模式不显示列内字数,当前字幕面板仍按最后点击字幕的语言类型计数。
  • 选中单条副字幕后按 B,直接进入副字幕拆分流程;在字幕列表悬停已选副字幕时,拆分点取鼠标对应的文字位置,并遵循副字幕的“单词型 / 字符型”设置。
  • 字幕列表和波形的 Shift 框选都会命中主轨与副轨;副字幕禁用项沿用主字幕的斜纹背景。波形轨道编号徽标可在齿轮中开启,默认关闭。
  • 多重字幕波形空白处按 Ctrl/Cmd 拖动或按 N 会根据鼠标所在 lane 创建主字幕或副字幕;创建虚影显示在对应 lane。指针位置没有主字幕但命中副字幕时,B 拆分副字幕。空白波形右键会按当前时间点存在的主/副字幕显示对应的音频位置拆分入口,没有对应字幕时入口置灰。
  • 开启多重字幕时使用齿轮中的“副字幕时波形高度”(默认 168px);关闭后恢复“配置”中的波形行高。
  • 基础波形开启多重字幕时,主/副两个 lane 会自动使用适中的增高高度;普通多行波形仍使用齿轮中的“副字幕时波形高度”。
  • 主轨和副轨分别导出 SRT,也可导出双语整合 SRT。

2.2 暂不支持

  • 多条副轨的当前界面管理。
  • 一对多/多对一的实际编辑行为。
  • jieba 或其他 Python 分词器在浏览器中的调用。

工程数据使用可扩展的轨道与绑定结构,为后续能力预留空间,但 MVP 强制每个绑定组各包含一个主字幕和一个副字幕。

3. 多重字幕开关

  • multi_subtitle.enabled 随工程保存,默认值为 false。
  • 旧工程没有 multi_subtitle 时视为关闭。
  • 已有主字幕时拖入新的 SRT,弹出:
    • 替换当前字幕;
    • 作为多重字幕。
  • 已有工程时拖入 mosp/json,弹出“打开工程”或“使用工程字幕作为副字幕”;后者只导入源工程的顶层字幕段和可选 items,不带入源工程媒体、波形和工作区。
  • 没有副轨时点击“多重字幕”开关,立即启用空副轨并询问是否导入。选择“否”或取消文件选择保留空副轨;确认并导入后沿用“作为多重字幕”流程。
  • “多重字幕”开关的提示说明当前工程可在存在多条字幕时开启模式,用于双语字幕编辑等场景;未启用时不显示齿轮设置按钮。
  • 导入弹窗先居中选择行为,再在右下角使用“导入”或“取消”确认;已有主字幕时默认选中“作为多重字幕”,仍可切换为替换主轨;替换主轨、导入多重字幕和替换副轨都作为一次可撤销操作。
  • 选择“作为多重字幕”后创建副轨、执行匹配预览并自动开启开关。
  • 已有副轨时再次拖入 SRT 只允许“替换副轨”或“取消”;拖入 mosp/json 仍可选择“打开工程”或“使用工程字幕作为副字幕”,后者会替换当前副轨,禁止静默覆盖。
  • 显式“导入字幕”入口继续保持替换主轨的原有语义。
  • 关闭开关只隐藏副轨和相关 UI,不删除副字幕数据、绑定和导出信息。
  • 选中存在绑定关系的主字幕或副字幕时,共享波形中该字幕及其绑定字幕块右侧显示 🔗 标记。
  • 多重字幕相关选项收纳在工具栏齿轮中;“跨轨道吸附”默认开启,关闭后恢复仅在当前轨道内寻找吸附目标;“显示轨道徽标”默认关闭,开启后在共享波形显示 1 主轨和 2 副轨。
  • “绑定时自动对齐”默认开启,执行 G 绑定后等价于随后执行一次 H;关闭后保留绑定关系但不自动改写副字幕时间范围。
  • 多重字幕开关开启时,波形“每行高度”临时切换到“副字幕时波形高度”预设(默认 168px);关闭开关后恢复切换前的“配置”值。
  • “交换主副字幕”会交换主/副轨的文本、时间、可选 items 和绑定端点,作为一次可撤销操作。表情包等主轨专属字段不会随降级到副轨的字幕段保存;items、color 和 color_ref 会保留,原主轨颜色按绑定关系映射到新主轨。颜色引用的 headIdx 始终指向所在数组的 0-based head。
  • 多重字幕启用时,视频预览工具栏显示“预览副字幕”;预览设置中可分别调整主/副字幕字号、字体和颜色,副字幕设置与主字幕设置之间有分隔线。主字幕默认白色,副字幕默认黄色且小 2px,二者共用可拖动预览框。

4. 工程数据契约

顶层 segments 继续是主轨真源。新增的 multi_subtitle 为可选字段:

{
  "segments": [
    {
      "id": "main-001",
      "start": 1000,
      "end": 3000,
      "text": "主字幕"
    }
  ],
  "multi_subtitle": {
    "schema": "moy.asr.multi_subtitle.v1",
    "enabled": true,
    "display_mode": "both",
    "main_split_mode": "word",
    "tracks": [
      {
        "id": "extension-1",
        "role": "extension",
        "name": "副字幕",
        "language": "English",
        "split_mode": "word",
        "source_name": "translation.srt",
        "segments": [
          {
            "id": "extension-001",
            "start": 1100,
            "end": 2900,
            "text": "Extended subtitle"
          }
        ]
      }
    ],
    "bindings": [
      {
        "id": "binding-001",
        "track_id": "extension-1",
        "main_segment_ids": ["main-001"],
        "extension_segment_ids": ["extension-001"],
        "start_offset_ms": 100,
        "end_offset_ms": -100
      }
    ]
  }
}

约束:

  • 当前 MVP 中 main_segment_ids 和 extension_segment_ids 必须各只有一个 ID。
  • 主轨和副轨的字幕段都使用稳定字符串 ID;拆分、合并、删除不得依赖数组下标。
  • start、end 和所有现有 items 时间仍为整数毫秒。
  • start_offset_ms = extension.start - main.start。
  • end_offset_ms = extension.end - main.end。
  • 副轨的 items 是可选数据;当前作为副字幕显示或拆分时不使用,但必须保留,以便交换回主字幕后继续使用。
  • 不保存外部文件的绝对路径;只保存来源文件名或用户可见名称。

5. 自动匹配与手动绑定

5.1 自动匹配

副字幕段与主字幕段满足以下条件时才成为候选:

  • 两个时间区间有交集;
  • abs(extension.start - main.start) <= 300;
  • abs(extension.end - main.end) <= 300。

候选冲突时采用开始时间差与结束时间差之和最小的候选,并保证一对一使用。无法匹配的副字幕保留为未绑定项。

导入预览至少显示:

  • 副字幕总数;
  • 自动绑定数量;
  • 未绑定数量;
  • 冲突数量;
  • 当前容差 300ms。

用户可以保留已匹配结果继续导入,之后分别选中一条主字幕和一条副字幕执行“绑定”。从副字幕右键选择“绑定到主字幕”时,会在所有时间重叠且尚未绑定的主字幕中自动选择开始时间最早的一条;只有重叠候选全部已有绑定时,才进入等待选择流程。自动选择会给出提示,说明已选择时间最早的未绑定主字幕。选择已有绑定的主字幕会替换原绑定。解绑只移除关系,不修改文本和时间。

选中单条副字幕后按 G 可执行“绑定到主字幕”;若同时选中一条主字幕则直接建立关系,否则复用上述自动选择或等待手动选择流程。按 Shift+G 可解绑当前副字幕,按 H 可将已绑定副字幕对齐到主字幕时间轴。副字幕右键菜单中的绑定、解绑、对齐项分别显示 G、Shift+G、H 快捷键。

5.2 副字幕类型

导入时根据文本自动判断,并允许用户修改:

  • continuous:CJK 等连续书写文本,允许在字符边界断开;
  • word:英语等空格分词文本,优先在空格或连接两个词的安全标点附近断开,禁止切碎单词。

纯浏览器规则同时用于便携 HTML 和 localhost 编辑器,不依赖 jieba。

6. 联动时间编辑

  • 正常拖动主轨或副轨的整条字幕时,绑定字幕跟随当前直接操作的轨道。
  • 主轨是源轨时,副字幕冲突优先限制副字幕;部分重叠时裁剪被挤压字幕,完全被目标范围覆盖或剩余时长不足最小值时删除并解除绑定,绝不反向缩短主字幕,也不保存副轨重叠区间。若一条旧字幕跨过目标范围左右两侧,则保留未被覆盖的较长一侧。
  • 拖动副字幕时,主轨相邻字幕、媒体起止范围和最小时长会参与限制;主轨没有可用空间时,副字幕也无法继续拖动。
  • 拖动起点时,只同步双方起点;拖动终点时,只同步双方终点。
  • H 将副字幕直接对齐到绑定主字幕的完整时间范围;与其它副字幕冲突时保持主字幕时间不变,并按副轨冲突规则挤压或删除被覆盖的字幕。
  • “跨轨道吸附”开启时,拖动任一轨道的字幕或边界也会把另一轨道字幕的起点和终点加入吸附目标;该选项默认开启,可在多重字幕齿轮设置中关闭。
  • 主轨的 C 合并、拼合字幕工具的自动起点/终点吸附也会连带处理绑定的副字幕;自动吸附按同一边界 delta 更新,保留双方 offset。
  • 主轨的 B、Ctrl/Cmd+Enter 和剃刀拆分仍使用同一个绝对切点联动拆分;只有 Alt 临时独立操作会暂不修改绑定的副字幕。
  • 同轨普通移动、键盘微调及传统边界模式的联动由「自动吸附调整相邻字幕」决定,Alt 临时反转;默认中缝模式按独立手柄与共享中缝区分,见 按键调整。绑定主字幕/副字幕的跟随、限制和 offset 规则不受该开关改变。按绑定关系产生的临时挤压在同一次拖动中拉回时仍会恢复,绑定继续存在,并重新计算受影响的 offset。边界拖动仍沿用当前轨道的边界规则。
  • 无移动的 Alt+点击 仍保持单字幕模式中的“切换禁用”行为,主轨和副轨均适用;隐藏禁用项时两条轨道的列表、波形和选择状态同步过滤。
  • 删除绑定对的任一字幕时,默认成对删除,使用现有撤销恢复。
  • 副字幕 lane 在共享波形中位于底部,主字幕 lane 紧贴在其上方;行高较小时会自动缩小 lane,避免上下顺序反转或溢出。

7. 列表与波形

7.1 字幕列表

多重字幕开启后支持三种视图:

  • 主轨;
  • 副轨;
  • 同时显示。

同时显示时按绑定关系对齐成行。未绑定项按时间插入,另一列留空。两列文本都可以独立编辑;时间操作仍按绑定联动规则执行。

7.2 波形

波形只有一份背景和一份派生缓存。现有按时间切分的多行波形窗口继续保留,每个窗口内部增加字幕 lane:

共享波形背景
主字幕 lane
副字幕 lane
共享播放指针

关闭多重字幕时只渲染主字幕 lane,恢复单字幕的高度和操作路径。B、Ctrl/Cmd+Enter、剃刀拆分仍只从主字幕 lane 发起;副字幕可以通过副字幕块右键菜单单独拆分。多重字幕开启且仅选中一条副字幕时,B 改为打开该副字幕的拆分弹窗,副字幕块右键菜单中的拆分项显示 B。共享波形右侧用 1 / 2 分别标记主字幕 lane 和副字幕 lane。波形空白处按鼠标所在 lane 操作:按轨道显示「创建字幕」或「创建副字幕」,并按当前时间点是否存在对应字幕显示主字幕和副字幕的音频位置拆分入口;没有对应字幕时入口置灰。右键已有字幕块始终按该字幕块所属轨道处理。

8. 联动拆分与弹窗

绑定状态下从主轨发起拆分时,不立即修改工程,而是打开小型拆分弹窗并同时显示主轨、副轨;副轨右键“在鼠标位置拆分”也使用同一弹窗,但只显示副轨:

  • 显示当前参与拆分的字幕完整文本;
  • 显示当前候选断点与左右文本预览;
  • 鼠标移动时实时改变候选断点,并吸附到合法边界;
  • 默认悬停自由移动候选断点;左键点击后锁定,标题提示“拆分点已锁定,再次点击后解锁”,再次点击解除锁定;锁定时 ✂️ 和下方左右文本预览使用强调样式;
  • 左键或“拆分”按钮确认,Enter 确认,Esc 取消;
  • 左下角“全部拆分后自动提交”默认开启:单字幕副字幕选完断点后直接提交,多字幕在主/副字幕的所有断点都确认后直接提交;关闭后需手动点击“拆分”或按 Enter;
  • 默认开启“主字幕自动使用时间码拆分”且存在可用字词时间码时,主轨切点由主字幕字词时间码锚定;弹窗中保留主字幕行,以 ⌚️ 标记显示不可交互的时间码锚点,用户只调整副轨切点。关闭该设置或没有可用字词时间码时,显示主轨交互区,并以可用时间码或文本估算位置作为初始位置;设置旁提示会指向右上角「🔧 设置 → 拆分与合并」;
  • 副轨右键“在鼠标位置拆分”只修改副轨。若该段已有绑定,会解除旧绑定,主字幕保持不变,拆出的两条副字幕可再分别绑定;
  • 移动鼠标并点击选择拆分断点;字符型语言(中文等)按字符拆分,单词型语言(英语等)在空格或安全标点附近切分,确保不会拆碎单词。主字幕和副字幕的语言类型可在多重字幕设置中分别切换;
  • 弹窗会在切点旁提示时间来源:波形入口固定使用指针绝对时间时显示“当前切分位置固定为波形指针位置”;自动时间码锚定时显示“当前切分位置由字词时间码推定”;关闭自动时间码但存在可用时间码时显示“默认位置参考主字幕字词时间码,可继续调整”;
  • 选择断点后自动移除相邻的 ,。,. 和空白;单词型拆分会自动 trim 两侧空格;
  • 任一侧为空、单词被拆碎或时间过短时禁止确认;
  • 联动确认后主轨和副轨各拆成两条,生成两组新的一对一绑定;
  • 整个过程必须是一次原子撤销操作。

8.2 主字幕波形拆分设置

  • 设置中提供“主字幕自动使用时间码拆分”,默认开启。
  • 开启时,只有主轨单独拆分且存在可用 items 字词时间码时才直接完成拆分;绑定状态下的联动弹窗会显示不可交互的主字幕时间码锚点,并由用户选择副轨断点。如果当前字幕没有可用字词时间码(例如只有 SRT 文本),会提示本次无法按时间码自动拆分并回退到拆分面板,主轨显示为可交互的拆分区。
  • 关闭时,主字幕相关波形拆分入口打开同一套字符间 ✂️ 拆分弹窗;如果存在主字幕字词时间码,弹窗初始断点会定位到对应位置,用户仍可继续调整。字幕列表中的普通文字光标拆分不受该设置影响。

8.1 联动合并

执行主轨 C 合并时:

  • 主轨先确定合并时间范围;
  • 副轨收集已绑定项,以及与该范围实际重叠至少 500ms 的未绑定项;仅有较短的边界误差不会触发副字幕合并;
  • 按现有合并分隔符合并副字幕文本和时间;
  • 主轨和副轨各生成一条新字幕,并自动重新建立一对一绑定;
  • 合并范围内没有副字幕项时,主轨合并结果保持未绑定。

8.3 副轨独立合并

仅选中连续的副字幕块时,右键菜单提供“合并副字幕块”,裸按 C 也执行同一操作:

  • 只合并副轨的文本和时间,不修改主轨;
  • 合并操作支持撤销;
  • 如果被合并的副字幕段存在绑定,旧的一对一绑定会被解除,合并结果等待用户重新绑定。

9. 导出

双语整合 SRT 只改变交付文件,不合并工程中的两轨;工具箱的翻译合并则可以生成单轨双行字幕工程,两者用途不同。

  • 现有主轨 SRT 导出保持不变。
  • 多重字幕开启时增加副轨独立 SRT 导出。
  • 「SRT(双语合并)」按两轨各自起止时间切分为不重叠条目:重叠期间主轨在上、副轨在下,未匹配字幕单独保留,禁用项排除。副轨无可导出文字时,副轨与整合导出灰显;关闭模式后隐藏。主轨导出仍包含启用的叠加字幕;首句延长至 0 只作用于主轨首句。
  • 工具箱或自动后处理开启「将双语字幕合并为单个字幕」时可输出单轨双行 SRT 和工程;行序默认翻译成中文时译文置顶、翻译成英文时原文置顶,可用「双语行序」强制译文在上或原文在上。合并产物文件名带 .bilingual 标记,翻译入口会同时拦截带标记的工程和 SRT,避免重复翻译。
  • 工程导出始终保留副轨、绑定、语言类型、稳定 ID、可选 items 和开关状态,即使 UI 当前关闭多重字幕。

10. 验收标准

  • 单字幕旧工程在开关关闭时的列表、波形、快捷键、拖动和主轨导出行为无回归。
  • 拖入副字幕能完成替换/添加选择、匹配预览和未匹配保留。
  • 主轨与副轨能在共享波形中清晰分 lane 显示,且不生成第二份波形缓存。
  • 「自动吸附调整相邻字幕」关闭时普通移动/边界拖动默认独立,Alt 临时联动;开启时默认联动,Alt 临时独立调整,同时保持主/副绑定。
  • 绑定、解绑、成对删除、撤销、联动合并均可用。
  • 弹窗拆分能用鼠标选择字符型/单词型断点,保护完整单词并清理指定标点;主字幕或副字幕单独列表显示时,字数统计按对应轨道的语言类型计数,双列模式不显示列内字数。
  • 主轨和副轨可以分别导出 SRT。
  • 便携 HTML 与 localhost 编辑器行为一致。
  • 自动化测试通过后,仍需在真实浏览器中手动验证拖动、播放、弹窗、双 lane 布局和导出。