本文同步自 MAW 原始仓库的 docs/EDITOR_GUIDE.md。
MAWE — Moy’s ASR Workflow Editor
MAWE(Moy’s ASR Workflow Editor)是 MAW 自带的字幕编辑器,提供 Server 版和单文件 HTML 两种入口,并共享同一份工程格式与前端代码。当前以 Server 版为主;单文件 HTML 暂时只作为兼容备用入口,不作为新功能的主要更新对象。工程文件内容是 UTF-8 JSON,主扩展名为 .mosp;.json 作为旧工程和兼容扩展名继续支持。
- 推荐:
uv run python server-editor\serve.py "subtitle-project.mosp"。它通过http://127.0.0.1提供媒体 Range 请求,适合日常编辑和大型视频 Seek。 - 便携:双击转写生成的
.edit.html,或打开仓库根目录的blank-editor.html后单独选择.mosp/.json工程;浏览器无法自动读取关联媒体时会提示选择。它不需要启动服务,适合携带和离线检查。 - Windows 图形版:双击 Release 压缩包中的
MAW.exe生成工程;完成后默认使用 Server 版编辑器,便携编辑器 HTML 仅保留兼容入口。
无论用哪种方式,.mosp / .json 工程文件都是字幕真源;新工程优先使用 .mosp,旧 .json 工程无需迁移即可继续编辑。SRT 只能保留文本和时间,不能完整保留字/词级时间码、表情包、颜色、波形、工作区与静音空隙决定。
新建工程与空白导入
- 点击左上角「新建工程」会弹出浏览器保存对话框,选择位置后写入空白
.mosp并切换当前编辑器;取消对话框不会改动当前工程。 - 空白编辑器可拖入
.mosp/.json、媒体或 SRT。拖入媒体或 SRT 时会先创建并保存工程,再载入文件;SRT 解析失败或用户取消保存时不会开始编辑。 - 服务器版与便携版都使用浏览器保存对话框创建新工程:页面持有文件句柄,后续「保存工程」、Ctrl(Cmd)+S 和自动保存都写回该文件。浏览器新建的工程不会进入服务器「最近工程」,也不依赖本机 helper 进程。
- 在服务器版中新建工程后,服务器绑定旧工程的保存会被解除,避免把新工程写进旧文件;需要回到服务器工程时从「最近工程」重新打开。
- 不支持浏览器保存对话框的环境会退化为普通下载:只创建文件,不保留句柄,后续改动需通过「导出工程」或「另存为…」手动保存。
- 空白或只有 SRT 的工程可以正常编辑和保存;没有媒体时只是不显示播放器和波形,不影响保存。
基础字幕编辑
与播放器同步查看和定位
播放器播放时会高亮当前字幕。播放器下方的独立控制栏提供播放/暂停、前后 5 秒、进度、音量、倍速和全屏;它不会覆盖画面内的字幕预览。单击字幕列表或波形上的字幕块,会跳到该字幕的开始位置;双击波形可播放或暂停。拖动波形上的字幕块可整体移动字幕,拖动两端可调整开始和结束时间。
播放控制区的速度下拉框会同步显示当前 JKL 播放速度。打开「设置 → 通用操作」中的「JKL 播放模式」,默认的「倒放和正放」模式使用 1×、2×、4×、8×、16× 五档速度:按 J 向倒放方向切换,按 L 向正放方向切换;按 K 会停止并重置为 1×,停止后再次按 K 会以 1× 播放。倒放由编辑器驱动时间轴回退,不播放反向声音;速度控件会显示对应的 -1×、-2× 等负值。选择「慢速和倍速」后恢复旧行为:J 减半速度,K 重置为 1×,L 将速度加倍。
双击字幕文本可以编辑;也可以单选字幕后按 Enter——最后点击在字幕列表时直接原地编辑(等同双击该行),最后点击在波形等其它区域时聚焦字幕编辑区。波形空白处按 N 会根据鼠标所在的主/副字幕 lane 创建对应字幕,按住 Ctrl(macOS 为 Cmd)拖动则可按拖动范围创建指定时长字幕;拖动范围遇到已有字幕时会停在其边界,不能跨过;创建后会自动切换到新字幕并聚焦 current-cue-panel 文本框。波形区的创建、选中和定位操作优先绑定当前字幕编辑区;只有字幕列表自己的双击或 Enter 操作会进入列表内联编辑。内联编辑时,Enter 或 Ctrl+Enter(macOS 为 Cmd+Enter)按“字幕编辑拆分按键”设置保存或在文字光标处拆分,Shift+Enter 插入换行,空格播放或暂停。按 A/W / D/S 可跳到上一条 / 下一条字幕的开头并选中它;按 Shift+A/Shift+W / Shift+D/Shift+S 则保留当前选择,继续向前 / 后多选一条。播放中跳转会从新位置继续播放,暂停中跳转只移动播放指针。B 按指针所在区域拆分字幕:鼠标悬停在已选字幕列表行时按文字位置拆分,副字幕列表同样按鼠标对应的文字位置拆分,并遵循多重字幕齿轮中的“单词型 / 字符型”设置;位于波形上时按所指的音频位置拆分(与波形右键「按音频位置拆分」一致),多重字幕下若指针位置没有主字幕但命中副字幕则拆分副字幕;其它区域则在红色播放指针处拆分。开启“主字幕自动使用时间码拆分”且主字幕有可用字词时间码时,单主字幕波形入口会直接拆分;联动拆分弹窗会显示一个带 ⌚️ 标记、不可交互的主字幕时间码锚点。关闭该设置后主字幕也打开拆分弹窗,并默认定位到时间码对应位置,之后可自行调整;设置旁的提示会指向右上角「🔧 设置 → 拆分与合并」。波形工具可按 V 切回选择、按 R 切换分割。Ctrl/Cmd+Shift+A/D 可直接把当前字幕与前/后一条粘合;按住 Alt 拖动字幕块时允许挤压相邻字幕,副字幕只挤压副轨,主字幕按绑定关系带动副字幕。Alt + 点击 某条字幕可单独切换禁用状态;禁用项默认不会出现在导出的 SRT 中。新手引导打开时按 Esc 可直接跳过。
普通移动、边界微调和共享边界拖动是否默认联动,由「音频波形区 ⚙️ → 操作 → 自动吸附调整相邻字幕」控制,默认开启。开启时相邻字幕默认联动,按住 Alt 可临时独立调整;关闭时相邻字幕不会被自动带动,按住 Alt 可临时联动。拖动共享边界时,波形区状态栏会在「共享边界」文本旁按设置提示当前吸附模式及 Alt 的临时反转方式。多重字幕的主/副绑定跟随规则不受这个同轨相邻字幕设置改变。current-cue-panel 文本框按 Esc 默认保留文本改动并退出编辑;打开该面板齿轮中的「操作 → Esc 取消编辑」后,Esc 会恢复进入本次编辑前的文本。Enter 或 Ctrl+Enter 的保存/拆分语义不变。
多重字幕开启时,如果当前只选中一条副字幕,B 会直接打开该副字幕的拆分流程;在字幕列表中悬停已选副字幕时,B 会按鼠标所在的文字断点打开弹窗,并遵循副字幕的“单词型 / 字符型”设置。按 ↑ / ↓ 可在当前时间范围对应的主字幕和副字幕之间切换焦点;有绑定时优先切换到绑定项,没有绑定时选择时间重叠或距离最近的一条。按 Shift 在波形空白处拖动框选时,主轨和副轨都会参与命中。按 G 可把当前副字幕绑定到主字幕,按 Shift+G 解绑,按 H 将已绑定副字幕对齐到主字幕时间轴。G 在同时选中一条主字幕时直接绑定,否则会自动拾取时间重叠且尚未绑定的主字幕中时间最早的一条;如果所有重叠主字幕都已有绑定,才进入等待手动选择流程。绑定时默认自动执行一次 H,可在多重字幕齿轮中关闭“绑定时自动同步时长”。副字幕右键菜单中的「在鼠标位置拆分」「绑定到主字幕」「解绑」「对齐主字幕时间范围」分别标注 B / G / Shift+G / H。普通点击以最后点击的轨道为准:点击未绑定副字幕会清除旧主字幕选区;开启“同时选中主副字幕”时,点击已绑定字幕只补选它实际绑定的另一条字幕。显式 Ctrl/Shift 多选仍可保留主副字幕作为有意的绑定/替换选择。多重字幕工具栏的齿轮中可切换显示方式、主字幕语言类型、副字幕语言类型、跨轨道吸附、同时选中绑定的主副字幕、绑定时自动同步时长、显示轨道徽标和交换主副字幕;“同时选中主副字幕”与“绑定时自动同步时长”默认开启,“显示轨道徽标”默认关闭,编辑区仍以最后点击的字幕为准。单词型适合英语等按空格拆分的语言,字符型适合中文、日文等按字符拆分的语言。仅在主字幕或副字幕单独显示时,列表字数和超长筛选按对应轨道的语言类型计数;双列模式不显示列内字数,当前字幕面板仍按最后点击字幕的语言类型计数。跨轨道吸附默认开启,拖动字幕或边界时会把另一条轨道的起止位置加入吸附目标。开启多重字幕时使用齿轮中的「副字幕时波形高度」(默认 168px),关闭后恢复「配置」中的波形高度。共享波形双 lane 的轨道徽标默认关闭,开启后 1 / 2 分别表示主轨 / 副轨。
加载大文件或拖入视频、音频、工程和 SRT 时,编辑器会显示读取、解析、媒体元数据和波形生成阶段的进度;旧工程中由取整造成的 1ms 字/词时间码重叠,会在打开或保存边界自动修复,真正的字幕段重叠仍会由校验提示。 基础波形下,单主字幕块会自动增高;同时开启多重字幕时,主/副两个 lane 也会使用适中的增高高度(高于普通多行模式、低于单主字幕块)。 选中存在绑定关系的主字幕或副字幕时,共享波形中该字幕及其绑定字幕块右侧会显示 🔗 标记。
字幕时间的微调快捷键(包括选中字幕时的方向键、Shift 贴合,以及按住波形字幕块时的 A / D 调整)单独整理在 字幕按键调整文档 中。
拆分与合并字幕 ⭐
右键菜单和编辑区域都提供拆分、合并操作。拆分有两种语义:
- 从字幕文本处拆分:以当前文字光标为位置。
- 从波形处拆分:以当前音频播放位置为位置。
MAW 的工程文件会保存 segments[*].items 字/词级时间码。存在这些数据时,拆分后两段会按字/词边界重新分配时间,而不是粗略平分,因此时间仍然准确。没有 items 的外部 JSON 也能打开,但拆分时只能按字符比例估算,精度会下降。
拆分弹窗除鼠标操作外也支持键盘:弹窗打开时会自动聚焦当前操作的轨道(带虚线边框标识),主字幕与副字幕都可拆分时先聚焦主字幕;Tab 在主字幕 / 副字幕区之间切换焦点(主字幕被 ⌚️ 时间码锚定、不可交互时无法切入);WASD 或方向键移动 ✂️ 预切分位置——左右按当前语言类型(字符型 / 单词型)的合法边界逐个步进,上下在多行文本时按行移动,单行时无动作;空格 确认当前切分点,再次按下取消确认以便继续移动,效果与鼠标点击一致。已锁定的轨道上按移动键不会改动断点,而是闪烁边缘并提示先按空格解锁。弹窗打开期间,WASD 和方向键不会触发常规的字幕选择、轨道切换或播放头移动。
联动拆分时,主字幕的拆分不会被副字幕阻塞:如果副字幕在当前切点无法形成合法拆分(文本断点非法,或两侧无法各留至少 100ms 且强制钳制也救不回来),而主字幕自身仍可拆,确认后会==只拆分主字幕并自动解除与该副字幕的绑定==,同时给出警告提示;副字幕本身保持原样,可另行调整后再重新绑定。副字幕仅是时机不理想但可通过二次确认强制钳制时,仍走原有的「再次按 B / Enter 强制拆分」流程,两侧切点会被钳制到各留至少 100ms。
合并可用于把连续的短句重新组合成一条字幕。选中至少两条连续字幕后按 C 即可合并;不足两条时不会修改工程。若所选字幕全部属于同一个颜色或表情包 group,合并后的字幕会继承该 group;混合选区则不会错误继承。
单句检查、过滤与批量替换
当前字幕面板会显示单句时长、字数与阅读速度,便于发现字幕过长或过快。字幕列表可按文本筛选,并可隐藏禁用项。多重字幕关闭时按文本自动判断语言类型;开启时主字幕和副字幕分别使用齿轮中的语言类型:单词型按空白分隔的词计数,字符型按字母/数字字符计数,空白和标点不计入。只有主字幕或副字幕单独显示时,列表计数和超长过滤使用对应轨道的语言类型;双列模式不显示列内字数,当前字幕面板仍按最后点击字幕的语言类型计数。
“批量替换”支持预览逐行的替换前后内容;启用正则表达式时,非法规则不会修改工程。确认后才会写入 JSON,并可通过撤销恢复。
检测并移除静音空隙
编辑器可根据波形峰值检测媒体内部的静音区间。扫描时可调整最小空隙、音量阈值、滞回,以及前后保留量;前后保留量用来避免相邻两句贴得太紧。
“移除”是非破坏性的:不会剪掉原视频、不会改写原始字幕时间。它会在工程文件的 gap_remove 字段中保存可撤销决定,并建立一条压缩时间线:播放时可跳过已移除空隙,导出时可生成去空隙 SRT、OTIO、FFconcat 或保留区域 JSON。
波形中橙色斜纹代表已移除,灰蓝斜纹代表被保留的空隙。Alt + 点击 可切换单段状态;在波形空白处右键选择“添加空隙”会从鼠标位置插入一段默认时长的移除区段;在波形空白处按住 Alt 用左键拖动,可直接按范围增加新的空隙。选择“拖动边界”或“边界与中键”时可拖动左右边界;选择“中键拖动”或“边界与中键”时可用中键调整范围。空隙块现在可直接用左键拖动整体偏移,已恢复区也会作为一个整体移动而不会在原位置继续扩大;移动目标覆盖已有 Gap 时会吸收目标范围,不留下重复层。按住 Alt 拖动仍兼容整体偏移,Ctrl/Cmd + 拖动 可复制 Gap;更细的范围调整在“空隙操作”设置中启用。
“空隙检测与调整”中的“进一步收缩空隙”会在现有结果基础上,按当前前端/后端预留把所有已有空隙的左右边界额外向内调整;它不会改变扫描生成时的预留逻辑,适合对现有结果做微调,点击后仍可撤销。重复点击会继续执行一次额外收缩。
“禁用空隙内字幕”是“空隙检测与调整”下方的可展开操作。默认要求已移除空隙覆盖字幕时长至少 80%,并且字幕中未被覆盖的剩余时长不超过 300ms;两个条件同时满足时,点击“禁用字幕”会批量设置主字幕的 disabled 标记,完全位于空隙内的字幕自然会被处理。覆盖多个空隙时按合并后的空隙总覆盖时长计算;操作不改写字幕起止时间,并可通过撤销恢复。
拼接/合并字幕
识别结果里常见两种细碎问题:相邻字幕之间夹着很短的间隔,以及只有一两个字/词的过短字幕。波形工具栏的「拼接/合并字幕」工具窗可将间隔过短的前后字幕直接吸附在一起,去除中间的短暂空白,也可以直接吸收过短字幕;整个操作是一次可撤销的编辑:
- 间隔阈值(默认 200ms):相邻两条字幕的间隔小于此值时,直接吸附前后字幕,去除中间的短暂空白;改为 0 则不处理间隔。
- 吸附方向:向前吸附(默认)把后方字幕的起点吸附到前方字幕的终点;向后吸附则把前方字幕的终点吸附到后方字幕的起点。
- 吸收过短字幕(默认开启):中文少于 N 个字、英文少于 N 个词(短字幕阈值,默认 3)的字幕直接并入相邻字幕;关闭后只吸附间隔。
- 吸收方向:向前吸收(默认)并入上一条,向后吸收并入下一条。禁用项与说话人不同的字幕不会被合并。
- 多重字幕开启时,主字幕的自动延展和吸收合并会同步处理绑定的副字幕,并保留时间 offset;Alt 临时独立拖动仍是例外。正常调整时以直接操作的轨道为源:主字幕调整不会被副字幕冲突反向缩短,冲突时会挤压其它副字幕,完全覆盖或不足最短时长的副字幕会被删除并提示,副轨不会保存出重叠区间;直接拖动副字幕则受主字幕轨道边界限制,主轨没有空间时操作会停止。按
H会把副字幕直接对齐到主字幕完整时间范围,冲突时同样不修改主字幕,并按上述规则整理副轨。 - 按住
Alt拖动主字幕时,挤压相邻主/副字幕是本次拖动内的临时状态;把主字幕拉回去时,被挤压的副字幕也会恢复原来的时间范围。绑定主字幕右键菜单同样提供「解绑」。 - 波形空白处按鼠标所在 lane 操作:按
N或右键创建对应轨道的字幕;同时根据当前时间点是否存在对应字幕,显示主字幕和副字幕的音频位置拆分入口,没有对应字幕时入口置灰。右键已有字幕块时,以该字幕块所属轨道为准,拆分入口仍直接作用于该字幕块。
预览设置还可以单独调整副字幕背景色;副字幕背景沿用字幕预览的不透明度。所有参数都作为编辑器设置保存在本机浏览器,不写入工程 JSON。
波形设置中的“波形形状来源”默认使用媒体旁 .ReaPeaks 的最细 wave 层;没有可用 .ReaPeaks 时自动回退到自研 1000Hz 重采样缓存。
保存和导出
在 localhost 编辑器中,“保存工程”(Ctrl(Cmd)+S)会原子写回当前 .mosp / .json 工程,并在覆盖前创建同目录 .mosp.bak / .json.bak;“另存为”(Ctrl(Cmd)+Shift+S)可在当前工程目录内换用新的 .mosp 或 .json 文件名。文字编辑提交后会短暂防抖自动保存,避免刚失焦的修改要等到常规定时自动保存间隔才写入;常规定时自动保存仍按设置周期执行。若浏览器标签页仍开着但 localhost 服务已经退出,编辑器会提示改为导出工程文件,避免只报网络错误而丢失改动。便携 HTML 没有安全的原路径写入能力,因此使用“导出工程”下载工程文件。空白启动的 localhost 编辑器在打开或拖入工程时,会按工程记录的媒体绝对路径定位同目录同名工程文件;内容一致时由服务器接管:关联媒体自动加载,“保存工程”与自动保存随之可用,并记入最近工程;无法接管(媒体已移动、同目录无同名工程或内容不一致)时按便携流程提示选择关联媒体。
- 工程文件(
.mosp/.json):继续编辑时优先保存它;新工程建议使用.mosp,.json用于兼容旧工程和已有工作流。 - SRT / TXT:SRT 用于播放器、剪辑软件和普通字幕交付;可选择把首条字幕的起点拉到 0(只延长首条,不改变其结束时间或后续字幕时间码)。工程存在颜色标记时,可导出完整字幕,或按每种已使用颜色(含无颜色的
default)分别生成带颜色名后缀的 SRT。也可导出逐字幕行排列的纯文本 TXT。 - 去空隙导出:仅在有已移除空隙时出现,包括完整或按颜色拆分的 SRT、时间线 OTIO、FFconcat 和保留区域 JSON。
- 去空隙 OTIO marker:每个保留区间会生成一个媒体 clip,启用字幕会作为 clip marker 写入,marker 名称是字幕内容;有颜色时映射为 DaVinci Resolve 的
RED、YELLOW、GREEN、BLUE、PURPLE五种标记色,跨越被移除空隙的字幕会按保留区间拆分。视频素材只写入视频 clip,纯音频素材写入音频 clip;无颜色字幕使用白色默认标记。Resolve 还提供 Blue、Cyan、Green、Yellow、Red、Pink、Purple、Fuchsia、Rose、Lavender、Sky、Mint、Lemon、Sand、Cocoa、Cream 这 16 种可用颜色,当前 MAW 只使用其中五色。 - 表情包 OTIO:将已分配的表情包输出为独立图片轨道时间线。
- Resolve JSON:保存字幕、颜色、表情包与媒体的批量导入数据。它是导出用的交换文件,不是 MAW 工程文件;MAW 只负责导出这个数据文件,要实际操作达芬奇仍需在达芬奇环境中运行兼容的执行脚本。
界面语言与最近工程
工具栏右上角的 EN / ZH 按钮可在中文和 English 之间切换,选择会保存在当前浏览器中。界面翻译不会修改字幕文本或工程数据。
localhost 模式的「最近工程」菜单会列出最近打开的工程;菜单第一项「自动打开上次工程」控制以后不带工程路径启动服务器时是否恢复最近工程。命令行显式传入 .mosp / .json 工程或使用 --blank 时,仍以本次命令为准。
调整画面内字幕预览
播放到有字幕的时间后,画面内会显示字幕预览。直接拖动预览框可调整位置;悬停、聚焦或正在拖动时会显示八个缩放手柄。键盘聚焦预览框后:
- 方向键每次移动 1%;按住
Shift时每次移动 10%。 Alt + 方向键从右边或下边调整宽度/高度。Enter或空格切换持续显示编辑框,Esc退出焦点。
位置与大小以归一化比例保存在工程文件的 preview.subtitle,因此播放器或窗口改变大小后仍保持相对位置。设置中的“字幕预览”还可以选择主字幕和副字幕的字号、字体、颜色,并在多重字幕开启时用分隔线区分副字幕设置;面板会保持足够宽度以完整显示这些选项。波形设置中的“频谱颜色”默认关闭,关闭时使用纯色波形,打开后才使用频谱缓存着色。字号缺失时沿用响应式默认值。一次拖动或缩放只产生一条撤销记录;这些设置只改变预览呈现,绝不修改字幕或字词时间。
表情包与颜色
表情包根目录可通过命令行 -s 或 .env 的 STICKER_DIR 指定。编辑器会扫描支持的图片,右键字幕即可分配。跨多句使用同一个表情包时,第一句保存完整信息,后续句子保存对第一句的引用;拆分、合并和删除都会自动维护引用。
颜色的使用方式相同,适合给不同类别、角色或后续剪辑动作做标记。它们会保存在工程文件中,并可写入 Resolve JSON。
工程数据与兼容
JSON 的最小要求是顶层 segments 数组;每条字幕至少要有毫秒整数 start、end 和文本 text。完整字段、字/词时间码和波形缓存说明见 JSON_SCHEMA.md。
修改前端时,web/ 是唯一源码。修改后运行 uv run python edit.py --blank 来重新生成根目录的 blank-editor.html。