字幕翻译 (Translating Subtitles)
概述
将字幕文件(SRT、带词级时间戳的 ASR JSON、或视频/音频)翻译为双语(简体中文 + 原语言) ASS 字幕。流程固定为 6 步, 必须按顺序全部执行, 不得跳过或改变顺序:
- 输入归一化 + ASR 转录(视频/音频; SRT 跳过; ASR 自动识别语种)
- 时间戳 → YAML(脚本 + 模型复核, 含分句合适性检查)
- 校对原文 + 时间戳二次核对(第二遍听写交叉验证; 错误/漂移直接修正到 YAML, 含分段重转修复)
- 分批翻译(术语表 + 注解字幕)
- 校对译文
- 合并为 ASS(脚本)
脚本位于本 skill 的 scripts/ 目录(与 SKILL.md 同级)。运行脚本时, <skill_dir> 指本 SKILL.md 所在目录。
环境与配置
- 需要
ffmpeg、python(含pyyaml)、以及本地 ASR 工具 q3asr(Qwen3-ASR GGUF 跨平台 CLI)。 - 运行时解析优先级:
run_transcribe.py --exe> 环境变量TRANSCRIBE_EXE> 自动下载。默认自动下载: 按os/arch/后端从ywwzwb/qwen3-asr-universal发布版取 q3asr 二进制缓存到~/.cache/opencode-translate/asr/(首次联网, 之后复用)。手动指定时设TRANSCRIBE_EXE(Linux/macOS 指向q3asr, Windows 指向q3asr.exe)即可, 不用改本文件。
工作目录(临时隔离)
每次翻译任务独立一个临时工作目录, 所有中间产物集中在一处, 完成后一键清理:
- 建目录:
mkdir -p "$TEMP/opencode/<输入文件基名>"($TEMP即系统临时目录, Windows 为%TEMP%, 如C:\Users\zwb\AppData\Local\Temp; 基名取输入文件名去扩展名)。 - 把输入文件(视频/音频/SRT)复制进该目录, 之后所有操作都在这个目录内完成。
- 所有中间产物(mp3、txt、srt、json、
main.yaml、seg*.yaml等)都生成在这里, 不污染输入文件所在目录。 - 完成后, 把最终
.ass复制到输入文件所在目录(或用户指定位置)。 - 用户要清理时, 直接删除整个工作目录即可。
术语表不受影响:
terminology.yaml在 skill 目录里全局共享(见第 4 步), 不放进工作目录。
第 1 步: 输入归一化 + ASR 转录
按输入类型准备音频:
- 视频(mkv/mp4/mov 等): 先转单声道 16kHz MP3:
ffmpeg -y -i <input>.mkv -vn -map 0:a:0 -ac 1 -ar 16000 -c:a libmp3lame <input>.mp3 - 音频(mp3/wav/m4a 等): 同样转成统一单声道 16kHz mp3, 输出命名为
<basename>.mono.mp3(如demo.mp3→demo.mono.mp3), 与视频路径的<input>.mp3区分, 避免与同名原文件冲突。 - SRT: 跳过本步(无需归一化与 ASR), 直接进入第 2 步(时间戳 → YAML)。
若输入是音频/视频, 运行 ASR 转录(一律作用于上面归一化后的 mp3: 视频为 <input>.mp3, 音频为 <basename>.mono.mp3):
python3 <skill_dir>/scripts/run_transcribe.py <audio>.mp3 -y
若 ASR 运行时缺失, 自动从
ywwzwb/qwen3-asr-universal最新 release 下载匹配os/arch/后端的 zip 到~/.cache/opencode-translate/asr/并缓存。后端自动探测: 首次运行时探测本机最优方案(cuda→vulkan→metal→cpu, 依据nvidia-smi/vulkaninfo是否存在), 结果保存到本 skill 目录的config.yaml(像 terminology.yaml 一样持久共享), 后续直接复用不再探测; 跨机器时做轻量复核, 失效则重新探测。模型默认 1.7B, 与后端一起存入config.yaml, 首次由 q3asr 自动下载到~/.cache/q3asr/models/(已有缓存则复用)。可用环境变量覆盖:TRANSCRIBE_BACKEND(cuda/vulkan/metal/cpu)、TRANSCRIBE_MODEL(如 1.7b/0.6b)、TRANSCRIBE_ASR_VER(默认 latest)。手动指定TRANSCRIBE_EXE仍为最高优先级。
- 产出同名
<audio>.txt、<audio>.srt、<audio>.json(词级时间戳[{text,start,end}], 秒)。 - 分段重转用
--out防止覆盖全片产物:run_transcribe.py会把.txt/.srt/.json以输入音频名命名。对同一 mp3 做窗口重转(--seek-start)时, 若不加--out会覆盖全片<audio>.json。加--out <名字>(如--out seg1)会把音频复制为<名字>.mp3再转录, 产物落到<名字>.json等, 全片 JSON 原样保留。 - ASR 自动识别语种(Qwen3-ASR 支持多语言); 如需强制指定语种再传
-l <Language>。 - 长音频: 先
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 <audio>.mp3得知时长, 给 bash 命令设置足够大的超时(本地 1.7B 模型约 0.05×时长 秒, 另加模型初始化)。
故障排查
- ASR 失败(退出码非 0):
run_transcribe.py失败时已自动打印logs/latest.log尾部, 按日志尾部定位; 若是本地 GPU/图形栈相关报错, 加--no-dml --no-vulkan重试。 - 自动下载的运行时无法启动(如冻结二进制缺
libllama.so报Failed to load dynlib/dll): 换用本机可用的 q3asr 源码安装/已解压运行时, 设TRANSCRIBE_EXE指向它即可, 不必改本文件。 - 乱码
!!!/ 花屏: 设置环境变量GGML_VK_DISABLE_F16=1后重新转录(Vulkan 禁用 fp16, 规避部分驱动不兼容)。 - ffmpeg 不存在: 立即停止, 先安装 ffmpeg 并确保在 PATH 中, 再继续第 1 步。
第 2 步: 时间戳 → YAML
按来源选择脚本:
- 音频/视频来源(
<audio>.json): 运行python3 <skill_dir>/scripts/timestamp_to_yaml.py <audio>.json main.yaml(可选--max-width每行宽度上限默认 30,--gap分句停顿阈值秒默认 1.5) - SRT 来源: 运行
python3 <skill_dir>/scripts/srt_to_yaml.py <input>.srt main.yaml
生成中间文件 main.yaml:
main:
- from: 00:00:02,003
to: 00:00:05,069
en: |
Narrator:
TODAY ON "HOW IT'S MADE"...
- from: 00:00:26,227
to: 00:00:28,026
en: |
ALUMINUM FOIL...
转换后立即跑塌缩检测(脚本, 必须先于人工复核): ASR 时间戳经常整块塌缩——多条 cue 挤在同一秒(甚至零时长)、文本乱码。机械复核前先用脚本扫一遍:
python3 <skill_dir>/scripts/check_collapse.py main.yaml
- 检测:
zero(零时长 from==to)、cluster(3+ 条共享同一开始时间 = 整块塌缩)、order(乱序)、overlap(时间重叠)。 - 退出码: 干净为 0, 有问题为 1。出现
zero/cluster即按第 3 步"分段重转修复"处理该区域。 - 窗口重转出的
seg*.yaml用--strict再扫一遍(2 条同秒即报警):python3 <skill_dir>/scripts/check_collapse.py seg.yaml --strict——大窗口重转自身也常在末尾塌缩, 转完先自查再拼回。
转换后必须复核(模型判断): 脚本按句号/叹号/问号/长停顿自动分句, 并按宽度自动拆分过长句子, 已自动合并过短片段(句内孤片并入相邻、无句末标点的单字孤儿并入下句)。转换脚本已内置"悬空分句自动合并": ASR/宽度切分常把句子拦腰截断在功能词处(以 the/a/to/any/each/boil/known 等结尾), 或幻觉句号后小写续写(plasters./is applied.), 或留下单字头(Plasters/are made of...)。timestamp_to_yaml.py 会自动把这些残片并入下句, 减少人工合并工作量。复核时:- 检查分句是否自然; 过长或切分不自然的句子重新确定拆分点(优先在顿号、逗号等软分隔处)。
- 极短片段必须合并: 若某条 cue 只有 1-2 个词或明显是从完整句中拆出的残片(如单独的
mercury,、The), 用 edit 并入上一句或下一句, 使每条字幕都是完整语块。标题性短句(Cheese.、Tights.)除外。 - 音频/视频来源: 重新拆分时必须读取原始 JSON, 按拆分后每个子片段的词 token 起止时间更新
from/to(SRT 无词级时间戳, 不适用此条)。
分句合适性检查(逐条 cue 判断, 必须执行): 脚本按宽度/停顿机械切分, 常把句子拦腰截断。对照以下标准逐条检查, 不合适就用 edit 合并或移动拆分点:
- 每条 cue 必须是完整语块: 不能以悬空介词/连词结尾。行尾出现
and、or、as、where、which、before、to、of、into等时, 说明切分点错了, 应把该词并入下一行或整体合并。 - 拆分点放在从句/并列连接词之前, 而不是之后。例:
assure quantity distribution/before they're carried...(而非...distribution before/they're carried...);come down 2,000 times per minute/to cut a total of 8,000...(而非...to cut a/total of 8,000...)。 - 同一语块的介词短语不要拆开:
5 hours of work保持完整, 不要拆成5 hours/of work;the brush and roller area不要拆成the brush and/roller area。 - 残片合并后若读起来才是一句完整的话, 就合并: 如
...cuts the billet strips into+small, equal-sized pieces.应合并为一条;...responsible for the+cloudiness of the beer.应合并。 - 中文分句镜像英文: 中文译文的行边界应与英文 cue 一致, 行尾同样不能悬空(如
按量分配,后接随后被送往..., 应把随后移到下一行;落下2000次,切割出应改为落下2000次/短短60秒内总计切割出8000根)。 - 合并/移动拆分点后, 必须读取原始 JSON 按新分片的词 token 起止时间更新
from/to。
第 3 步: 校对原文
逐句阅读 en 字段, 找出拼写错误、听译错误、漏字, 直接用 edit 工具修正 main.yaml 中的 en, 并在回复中列出修改点。禁止只在注解中提示而不改原文。
保持 main.yaml 的标准格式( - from: + en: | 块, 见第2步示例): 只做局部 edit, 禁止用脚本重排整个文件(如 yaml.safe_dump 重写), 以免破坏缩进与块标量格式。
分段重转修复(幻觉/错误时间戳)
发现坏区域(单条字幕时长异常长、文本乱码、cue 时间重叠)时:
- 选窗口: 坏区域起点往前 ~3s、终点往后 ~3s, 得
X与D = end - X。 - 重转该段(必须带
--out, 否则覆盖全片<audio>.json):python3 <skill_dir>/scripts/run_transcribe.py <audio>.mp3 --seek-start X --duration D --out seg1 -y(时间戳相对切片起点, 产物为seg1.json)。 - 重转段自检:
python3 <skill_dir>/scripts/check_collapse.py seg1.yaml --strict。大窗口重转常自身塌缩(多条 cue 挤在同一秒), 有zero/cluster就先缩小窗口重转, 不要继续拼。 - 还原绝对时间:
python3 <skill_dir>/scripts/timestamp_to_yaml.py seg1.json seg.yaml --offset X(脚本自动合并悬空分句, 见第 2 步)。 - 核对覆盖: 用
--offset后 seg.yaml 最后一条的to应 ≈X + D。若明显早于X + D(重转输出被截断), 扩大窗口重转, 不要继续拼。 - 拼回(必须传窗口参数):
python3 <skill_dir>/scripts/splice_yaml.py main.yaml seg.yaml main.new.yaml --seek-start X --duration D。脚本会用请求窗口而非段内容范围做删除, 并校验覆盖——若重转段被截断, 脚本会报错拒绝拼回(必要时可--force, 但先扩大窗口重转为宜)。 - 复核: 检查 splice 输出(删除清单 + 字数警告 + LOSS 行)。每次 splice 都会默认打印被删 cue 清单; 若出现
LOSS:行, 说明有条被删 cue 的文本没在重转内容里出现——若是完好句子, 扩大窗口重转。若出现BOUNDARY:行, 说明有条被删 cue 跨窗口边界(起点在窗口前或终点在窗口后), 其内容可能被拦腰截断——确认该窗口真覆盖了它, 否则扩大窗口重转。确认无漏词后, 用 edit 以main.new.yaml内容替换main.yaml; 若丢词, 扩大窗口重转或手工 edit 修正。
必须用 splice_yaml.py 拼回, 禁止手工拼接重转片段: 手动把新 cue 贴进 main.yaml 极易产生重复/重叠 cue(同一 from 出现两次), 用脚本按时间窗口替换可避免。替换后若发现重复 from, 说明拼接过当, 用 splice 重做。
时间戳二次核对(第二遍听写交叉验证)
同一音频连转两遍, 词级时间戳会明显漂移(实测: 两遍之间 max delta 可达数十秒, 部分 cue 相差 12-40s)。因此听写一遍出的时间戳不可全信。整理完 YAML 后, 必须再完整听写一遍, 与当前 cue 时间交叉核对:
- 复制音频再转第二遍(不要覆盖第一遍 JSON):
cp <audio>.mp3 <audio>.pass2.mp3, 然后python3 <skill_dir>/scripts/run_transcribe.py <audio>.pass2.mp3 -y, 产出<audio>.pass2.json(也可用--out pass2省去手动 cp, 效果相同)。 - 逐条核对:
python3 <skill_dir>/scripts/compare_timestamps.py main.yaml <audio>.pass2.json --threshold 1.0。脚本按规范化文本把每条 cue 的en定位到第二遍的词 token, 输出delta start/end(当前 cue 时间 − 第二遍词级时间)与<<<标记。阈值默认 1.0s(第二遍自身会漂移, 0.5s 假阳性太多)。 - 对
<<<或NOT FOUND的 cue 精确校对: 第二遍听写只是探测器, 不是权威——它自己也会漂移(整段整体偏移), 绝不能直接以第二遍时间戳为准改from/to。一律按上文"分段重转修复"流程对该窗口重转: 取该 cue 前后 ~3s 窗口重转 →--offset还原绝对时间 →splice_yaml.py拼回, 以窗口重转结果为准。若窗口重转与第二遍一致, 则主 yaml 时间确实错了, 修; 若一致确认主 yaml 对, 不改。 - 交叉复核译文侧:
compare_timestamps.py可对任意 yaml 用--full输出全部 cue 的 delta, 便于整体看漂移趋势。 - 反复执行直到无
<<<且无NOT FOUND(或已人工确认)。
说明: 第二遍听写也偶有自身漂移或文本不同(hence
NOT FOUND), 所以最终以分段窗口重转 + 人工听音为准,compare_timestamps.py只是快速发现可疑 cue 的探测器。
第 4 步: 分批翻译
开始翻译前, 先读取 <skill_dir>/terminology.yaml(不存在则创建空文件)。 术语表存放在本 skill 的目录里(全局安装时即机器级), 跨视频、跨项目、跨会话持久共享, 保证不同视频里同一人名/地名/专有名词译法一致。翻译中遇到新术语, 先把它加进 <skill_dir>/terminology.yaml 再使用; 匹配不区分大小写。
说明: 若
<skill_dir>与当前项目不同(全局安装), 术语表就是全局唯一的一份; 项目里不再单独维护terminology.yaml。
翻译采用结构化批量输出 + 脚本写入, 不用逐句 edit:
- 分批翻译(每批 ≤50 句): 在回复中输出结构化译文块——
start是该批第一句在main.yaml中的 cue 序号(0-based),translation列表逐句对应, 顺序与 main.yaml 的 cue 完全一致。禁止一次性输出全部字幕的翻译, 一批写完确认后(脚本写入 + 抽查)再处理下一批。
start: 0 # 本批第一句的 cue 序号(0-based)
translation:
- 第1句译文
- 第2句译文
- |
多行译文第一行
多行译文第二行
- 第4句译文
-
脚本写入: 把上面的结构化块保存为
batch.yaml(工作目录内), 运行python3 <skill_dir>/scripts/apply_translations.py main.yaml batch.yaml main.new.yaml脚本按 cue 序号把chs字段精确插入每条en块之后, 不重排文件(非 safe_dump), 注解与其他行原样保留。核对后cp main.new.yaml main.yaml。--overwrite: 替换已有 chs(默认遇已有 chs 报错, 防止错位批量静默覆盖)--dry-run: 只打印将写多少条, 不落盘- 脚本会校验
start + 条数不越界; 越界即报错, 停下核对start
-
翻译不落地前先自查: 每条译文遵守下方翻译规则(句尾无句号/逗号、数字阿拉伯化、术语表一致、行边界镜像英文 cue)。写完一批后人工抽查该批首尾几条, 确认 cue 序号与内容对齐(尤其检查翻译块里的
start是否等于上一批的start + 上一批条数)。
最终审阅仍用 edit 工具逐条修正——批量写入负责"灌入", 人工 edit 负责"精修"。
main:
- from: 00:00:02,003
to: 00:00:05,069
en: |
Narrator:
TODAY ON "HOW IT'S MADE"...
chs: |
旁白:
今天的《造物小百科》……
翻译规则
- 意译优先, 不逐字逐句。 按汉语语序和句式长度调整词序、位置, 可合并或拆分句子, 确保中文通顺自然。
- 专有名词统一走术语表。 人名、地名、作品名、品牌名等, 在
terminology.yaml中统一翻译, 并每次翻译前先读取。术语匹配不区分大小写。遇到新术语时先加入术语表再使用:
terminology:
Susan: 苏珊
Texas: 德州
HOW IT'S MADE: 造物小百科
- 句尾标点。 译文正文句末若最后一个字符是句号
。或逗号(全角,或半角,), 直接去掉。例: "欢迎收看本期节目。" → "欢迎收看本期节目"。句号/逗号只允许出现在句中, 不得作为译文句尾。 - 数字用阿拉伯数字。 译文中的数字尽量用阿拉伯数字书写: 三到八小时 → 3-8 小时、二十年前 → 20 年前、六千克面粉 → 6000 克面粉、百分之九十五 → 95%、四点四米 → 4.4 米、750 摄氏度 → 750 摄氏度。用于专有名词/标题里的数字(如 "How It's Made"、年份、型号)除外。
- 注解字幕。 字幕中出现中文语境少见的当地习俗、节日、专业名词、英制单位等, 添加 ≤20 字(约 4 字/秒)的简短注解, 写入
main.yaml的annotations列表。同一术语只在第一次出现时注解。
annotations:
- from: 00:00:02,003
text: 造物小百科:科普纪录片栏目
注解规则:
- 每个注解 ≤20 字, 尽量简洁。
from与对应字幕的开始时间对齐。to不必填写,yaml_to_ass.py按 4 字/秒 自动计算结束时间。- 同一句(开始时间相同)若出现多个注解, 脚本会合并为一条事件, 上下并列展示。
- 连续注解若前一条结束时间晚于后一条开始时间, 脚本会将前一条结束时间钳制到后一条开始之前, 避免时间重叠。
- 英制单位: 注解直接给出该句具体数值的标准国际单位换算, 如 "500磅≈227公斤"、"60英里≈96.6公里/时"、"62°F≈17°C", 不解释单位本身的含义(如"英制重量单位")。单位换算用 ≈ 表示近似; 数值不同时每次出现都需换算, 不受"首次出现"限制。
第 5 步: 校对译文
通读全部 chs, 检查错译、漏译、术语不一致、时间轴错位, 用 edit 工具修正。
校对完成后, 再通扫一遍 main.yaml, 把适合阿拉伯数字表示的数字直接用 edit 改成阿拉伯数字:
en(听写)里的英文词形数字:three to eight hours→3 to 8 hours、six thousand kilos→6,000 kilos、twenty years ago→20 years ago、half a centimeter→0.5 centimeter、seventy-five→75、first/second→1st/2nd。chs(译文)里的中文数字: 二十年前 → 20 年前、三到八小时 → 3-8 小时、六千公斤 → 6000 公斤、百分之九十五 → 95%、四点四米 → 4.4 米。- 用于专有名词/标题/年份/型号的数字保持不变(如 "How It's Made"、
Narrator:里的年份)。 - 只改明确无疑的; 拿不准的就保持原文。
第 6 步: 合并 ASS
运行: python3 <skill_dir>/scripts/yaml_to_ass.py main.yaml output.ass --check
--check 会校验 cue 完整性(重叠 / 零时长 / 乱序), 有错则报错并退出, 防止带病出片。合并完成后, 把成品 .ass 复制到输入文件所在目录(如视频旁边), 便于用户直接使用; 工作目录里的中间产物留给用户按需清理。
生成格式(模板内嵌于脚本, 要点如下):
[Script Info]
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080
WrapStyle: 2
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Translation,Noto Sans CJK SC,56,&H00FFFFFF,&H000000FF,&H00141414,&H80000000,-1,0,0,0,100,100,0,0,1,3,1,2,80,80,81,1
Style: Original,Noto Sans CJK SC,36,&H00FFFFFF,&H000000FF,&H00141414,&H80000000,-1,0,0,0,100,100,0,0,1,2,1,2,80,80,45,1
Style: Annotation,Noto Sans CJK SC,26,&H00FFE066,&H000000FF,&H00141414,&H80000000,-1,0,0,0,100,100,0,0,1,1,1,7,40,40,20,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
输出为三条独立轨道, 便于后期逐轨调整样式(各轨道用独立的 Layer 与 Style, 可在 Aegisub/剪辑软件中分开编辑):
| Layer | Style | 内容 | 字号/位置 |
|---|---|---|---|
| 0 | Translation | 简体中文译文 | fs56, 底栏主行 |
| 1 | Original | 原语言文本 | fs36, 紧贴译文下方 |
| 2 | Annotation | 注解 | fs26, 左上角 |
布局要求:
- 译文为主: 底栏大字号(Layer 0)。
- 原文为辅: 译文下方小字号(Layer 1)。
- 注解在左上角(Layer 2, Alignment 7)。
示例事件:
Dialogue: 0,0:00:02.00,0:00:05.06,Translation,,0,0,0,,今天的《造物小百科》……
Dialogue: 1,0:00:02.00,0:00:05.06,Original,,0,0,0,,Narrator: TODAY ON "HOW IT'S MADE"...
Dialogue: 2,0:00:02.00,0:00:03.62,Annotation,,0,0,0,,造物小百科:科普纪录片栏目
常见错误 (Common Mistakes)
| 错误 | 正确做法 |
|---|---|
| 跳过 YAML 直接输出 ASS | 必须先转 main.yaml, 翻译再合并 |
| 手写 ASS 代替脚本 | 用 yaml_to_ass.py 合并, 注解时间由脚本计算 |
| 出 ASS 前不校验完整性 | 用 yaml_to_ass.py --check 查重叠/零时长/乱序 |
| 一次性翻译全部字幕 | 每批 ≤50 句, 分批输出结构化译文, 脚本写入 |
| 逐句 edit 写 chs | 用 apply_translations.py 批量写入, edit 只用于最终审阅 |
批量 start 序号错位 | start 必须 = 上一批 start + 上一批条数; 脚本越界会报错 |
| 批量覆盖已有译文 | 默认遇已有 chs 报错; 确需替换才加 --overwrite |
| 人名地名前后译法不一致 | 写入 terminology.yaml, 每次先读取 |
| 注解超过 20 字 | 压缩, 只保留必要信息 |
| 注解结束时间随手填 | 交给脚本按 4 字/秒 计算 |
| 同一句多个注解未并列 | 脚本自动合并为上下两行 |
| 英制单位注解只解释单位含义 | 直接给出该数值的 SI 换算(如 "500磅≈227公斤") |
| 原文错误只加注解不改 | 直接修正 main.yaml 的 en |
| 同一术语反复注解 | 只在第一次出现时注解 |
| 译文句尾保留句号/逗号 | 去掉句末的 。、,、, |
| 跳过第 5 步校对 | 出 ASS 前必须通读 chs |
| 重转片段时间轴不对 | 用 --offset X 还原绝对时间 |
| 直接删旧字幕不重转 | 走分段重转: 重转 → --offset → splice 拼回 |
| 幻觉时间戳靠脚本钳制 | 用分段重转修复, 不用钳制 |
| 只信一遍听写的时间戳 | 听写会漂移, 必须第二遍听写交叉核对(compare_timestamps.py) |
| 塌缩区域不检测就人工复核 | 复核前先跑 check_collapse.py main.yaml |
分段重转不传 --out | 不带 --out 会覆盖全片 JSON, 必须传 |
拼回时不传 --seek-start / --duration | 不传窗口参数 splice 脚本无法正确替换, 必传 |
译完不跑 --check 就出片 | 禁用 --check 可能带重叠/零时长 cue 出片 |
| 第二遍时间戳直接覆盖主 yaml | 第二遍自身会漂移, 只用作探测器 |