Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ASSShift

按样式平移 ASS 字幕时间轴,并可选按时间 / 样式重组字幕的命令行小工具

Platform PowerShell License

中文 · English


ASSShift 把 ASS 字幕中指定样式(或不指定样式 = 全部行)的 DialogueStart / End 时间整体向前或向后平移 N 秒,并可同时完成两件整理工作:

  • -sort:按时间轴重排事件行(Subresync 逻辑),或先按样式分块、块内再按时间排序
  • -mininfo:把 [Script Info] 精简为最小标准形式

典型用途:

  • 双语字幕里各语言独立微调(如 JP / CN 各调各的),或整个字幕整体延迟 / 提前
  • 片头 / 片尾单独校正
  • 跳过带 \pos 等特效标签的排版行不动
  • 把字幕组藏在零时长行Start = End)里的注释聚到最前,统一删除
  • 免去 Subresync 的 UTF-16 LE 转码步骤,直接完成「排序 + 精简」重组

原始文件永不覆盖,处理结果写入同目录下的 fixed_<原名>.ass


目录


特性

  • 样式可选 —— 指定一个或多个样式(空格或逗号分隔)只平移它们;省略样式 = 整个字幕平移
  • 🧹 两种排序模式 —— -sort time 纯时间轴重排(Subresync 逻辑);-sort style 先按样式分块(块序 = 首次出现顺序),块内按时间排序;两种模式中零时长注释行都排最前,方便一把删除
  • 🧼 -mininfo 精简头部 —— [Script Info] 重写为 6 键最小标准形式,丢弃注释与字幕组元数据
  • 🎯 -Skip 关键字排除 —— 正文含关键字的行保持不变(如 \pos 特效行),不区分大小写,可重复指定
  • 📁 单文件 / 目录批量 —— 给文件名只处理该文件(支持通配符);不给则处理当前目录所有 *.ass
  • 🔒 原文件零修改 —— 输出 fixed_*.ass,且目录扫描自动跳过已有 fixed_*
  • 🧷 编码与 BOM 完整保留 —— UTF-8 / UTF-8 BOM / UTF-16 LE/BE / ANSI 均按原样回写,无需像 Subresync 那样先转 UTF-16 LE
  • 时间钳制 —— 提前到 0:00:00.00 之前的部分自动钳到 0:00:00.00
  • 🧠 命令行友好 —— 负数偏移、引号、逗号分隔的样式列表、offset 0 纯重组模式全部正确解析
  • 📖 自文档化 —— ASSShift -h 即可查看完整用法

环境要求

  • Windows 7 / 10 / 11(任意带 Windows PowerShell 5.1 的版本)
  • 无需额外依赖,PowerShell 与 .NET 均为系统自带

安装

仓库只含两个文件,放到同一目录即可:

ASSShift.cmd     ← 命令行入口(推荐通过它调用)
ASSShift.ps1     ← 实际处理脚本

建议把这个目录加入 PATH,之后可在任意位置直接调用 ASSShift

保存提示:ASSShift.cmd 请以 ANSI 或 UTF-8(无 BOM)+ CRLF 保存(BOM 会让 @echo off 报错)。ASSShift.ps1 内容为纯 ASCII,任何编码均可。

快速上手

:: 整个字幕提前 0.2 秒(当前目录所有 *.ass)
ASSShift -0.2

:: 只平移 CN、JP 两种样式
ASSShift CN JP -0.2 abc.ass

:: 等价写法
ASSShift CN,JP -0.2 abc.ass

:: 平移 + 跳过 \pos 特效行
ASSShift CN JP -0.16 -Skip "\pos" abc.ass

:: 纯重组:不平移时间,按样式分块排序 + 精简 Script Info
ASSShift 0 -sort style -mininfo abc.ass

用法

ASSShift [styles...] <offset> [-Skip <keyword>] [-sort [time|style]] [-mininfo] [<files>...]
ASSShift [styles...] -offset <seconds> [-Skip <keyword>] [-sort [time|style]] [-mininfo] [<files>...]
ASSShift -h

一句话规则offset 是分界线 —— 它之前的是样式名,它之后的是文件名。另外,.ass 结尾的 token 无论出现在哪里都视为文件(样式名不可能叫 xxx.ass),所以 ASSShift abc.ass -0.2 也合法。

参数

参数 是否必需 说明
<styles...>(位置式) 可选 一个或多个样式名,空格逗号分隔均可:CN JP 等价于 CN,JP省略样式 = 对所有样式的 Dialogue 行平移
<offset>(位置式) -offset 二选一 秒数。正数 = 延迟负数 = 提前;offset 前第一个纯数字 token 即被识别为偏移;0 = 不平移(纯重组模式,需搭配 -sort / -mininfo
-style <list> / -styles <list> 可选 显式指定样式列表;可在任意位置出现;可重复;用于纯数字样式名等边界情况
-offset <seconds> 可选 显式指定偏移;比位置式更自文档化,推荐用于脚本 / 留档
-Skip <keyword> 可选 正文 Text 含关键字的行保持不变不区分大小写;可重复 -Skip a -Skip b,命中任一即跳过
-sort [time|style] 可选 重排 [Events] 段事件行(默认不排序)。time = 纯时间轴排序,零时长行(Start = End)排最前;style = 先按样式分块(块序 = 首次出现顺序),块内按时间排序,块内零时长行置顶;-sort 等价 timeFormat: 行与空行位置不动,Comment: 行同样参与排序
-mininfo 可选 [Script Info] 重写为最小标准形式(ScriptType / Collisions / ScaledBorderAndShadow / PlayResX / PlayResY / Timer),丢弃注释与字幕组元数据;PlayResX / PlayResY 缺失时省略
<files>...(位置式) 可选 要处理的 .ass 文件,多个空格分隔;支持通配符 ep*.ass;省略则处理当前目录所有 *.assfixed_* 除外)
-file <name> / -filename <name> 可选 显式指定文件;可重复;带空格的路径需加引号
-h / -help / -? / /? 可选 打印用法帮助并退出

兼容写法:/offset--offset-skip=keyword-sort=style 等均可。位置式与显式式可混用,但有三条防呆约束:偏移只能给一次(重复报错);-sort 显式给出两个不同模式会报错offset 0 且未给 -sort / -mininfo 时直接报错(无事可做,不会产出与原文件相同的 fixed_*)。

示例

:: 1) 整个字幕提前 0.2 秒(不指定样式 = 所有样式)
ASSShift -0.2
ASSShift -0.2 abc.ass

:: 2) 文件名写在 offset 前也可以(.ass 结尾的 token 一律视为文件)
ASSShift abc.ass -0.2

:: 3) 单样式
ASSShift CN -0.2 abc.ass

:: 4) 多样式(空格 / 逗号 / 引号,三种写法等价)
ASSShift CN JP -0.2 abc.ass
ASSShift CN,JP -0.2 abc.ass
ASSShift "CN,JP" -0.2 abc.ass

:: 5) 显式 -offset,适合写进脚本 / 文档
ASSShift CN JP -offset -0.16 abc.ass

:: 6) 延迟 3 秒(位置式与显式式等价)
ASSShift CN JP 3 abc.ass
ASSShift CN JP -offset 3 abc.ass

:: 7) 跳过含关键字的行(含 \pos 需加引号;多关键字命中任一即跳过)
ASSShift CN -0.2 -Skip pos abc.ass
ASSShift CN JP -0.16 -Skip "\pos" abc.ass
ASSShift CN -0.2 -Skip pos -Skip end abc.ass

:: 8) 多文件与通配符
ASSShift CN JP -0.2 ep01.ass ep02.ass ep03.ass
ASSShift CN -0.2 ep*.ass

:: 9) 目录批量:当前目录所有 *.ass(fixed_* 除外)
ASSShift -0.16 -Skip "\pos"

:: 10) 纯时间轴排序(Subresync 逻辑),零时长注释行置顶
ASSShift 0 -sort time abc.ass

:: 裸 -sort 等价于 -sort time
ASSShift 0 -sort abc.ass

:: 11) 按样式分块排序(块序 = 样式首次出现顺序),块内按时间
ASSShift 0 -sort style abc.ass

:: 12) 精简 [Script Info]
ASSShift 0 -mininfo abc.ass

:: 13) 平移 + 分块排序 + 精简,一步到位
ASSShift CN JP -0.16 -sort style -mininfo abc.ass

:: 14) 纯重组:不平移任何时间,只排序 + 精简
ASSShift 0 -sort style -mininfo abc.ass

:: 15) 不经 .cmd,直接调用 ps1(语法相同)
powershell -NoProfile -ExecutionPolicy Bypass -File ASSShift.ps1 CN,JP -offset -0.16 -Skip "\pos" -sort style -mininfo abc.ass

样例输出:

ASSShift
Style  : CN, JP
Offset : -0.16 seconds
Skip   : "\pos"
Sort   : style blocks (first-appearance order), timeline within, zero-duration first per block
Info   : rewrite [Script Info] to minimal form
Files  : abc.ass

abc.ass                                 changed: 116  skipped: 7  sorted: 340  info: cleaned

Done. Files: 1  changed: 116  skipped: 7  sorted: 340

行为说明

  • 输出:每个源文件旁生成 fixed_<原名>.ass;原文件永不修改

  • 目录扫描:不给文件名时,处理当前目录下所有 *.ass,并自动跳过 fixed_*(避免叠加处理)。显式给出的文件名按字面处理,不受 fixed_* 排除限制。

  • 样式匹配区分大小写(与渲染器一致)。样式名是 Dialogue 行第 4 个字段;省略样式 = 匹配所有 Dialogue

  • -Skip 匹配:作用于 Dialogue 行的 Text 字段(第 10 个字段,含 {\pos(...)} 等特效标签),不区分大小写,是“包含”关系。

  • 排序(-sort time[Events] 段内 Dialogue / Comment 行按**(零时长 → Start → End → 原始行号)**重排——零时长行(Start = End,字幕组用作注释)聚到最前;同时间的行保持原有相对顺序。

  • 排序(-sort style:按**(样式块序 → 零时长 → Start → End → 原始行号)重排——样式块按该样式在事件中首次出现的顺序**排列(尊重作者原布局,非字母序),块内按时间升序,块内零时长行置顶。

  • 排序通用规则:只重排事件行的原有槽位Format: 行、空行、其他段落一律不动;Comment: 行参与排序但永不平移;时间无法解析的行不参与排序(留在原槽位);排序发生在平移之后,使用最终时间,顺序永远与成品时间轴一致。

  • -mininfo:只重写第一个 [Script Info] 段;白名单 6 键按固定顺序输出,值取自原文件(缺失用默认值;PlayResX / PlayResY 缺失则整行省略;ScaledBorderAndShadow 规范化为 Yes/NoTimer 规范化为四位小数);重复键取首个。注意 WrapStyleYCbCr Matrix不在白名单内会被丢弃(与 Subresync 行为一致;若原文件 WrapStyle 非 0,丢弃后会回到默认换行方式)。

    处理前(Aegisub 导出的典型头部):

    [Script Info]
    ; Script generated by Aegisub 9820-cibuilds-8165f1ad5
    Title: xxxxxxxx-
    ScriptType: v4.00+
    WrapStyle: 0
    PlayResX: 1920
    PlayResY: 1080
    ScaledBorderAndShadow: yes
    Original Script: xxx字幕组
    YCbCr Matrix: TV.709
    

    处理后(-mininfo):

    [Script Info]
    ScriptType: v4.00+
    Collisions: Normal
    ScaledBorderAndShadow: Yes
    PlayResX: 1920
    PlayResY: 1080
    Timer: 100.0000
    
  • 时间钳制:负偏移把某行 Start / End 推到 0:00:00.00 之前的,自动钳到 0:00:00.00

  • 编码保留:根据 BOM / 内容自动识别 UTF-8、UTF-8 BOM、UTF-16 LE/BE、ANSI,并按原编码回写。

  • 只动 Dialogue 的时间Comment 行、Format 行、[V4+ Styles] 段的 Style: 定义行内容均保持不变

设计要点

为什么“offset 是分界线”?

样式名、偏移、文件名三种位置参数并存时,最容易混淆的是“这个纯数字是样式还是偏移”。ASSShift 用类型 + 位置双判据消歧:

  • 类型:纯数字 token → 偏移;非纯数字 → 样式或文件名
  • 位置:偏移之前的 token 全部当样式,之后的全部当文件名
  • 例外:以 .ass 结尾的 token 一律是文件——因此 ASSShift abc.ass -0.2ASSShift -0.2 abc.ass 都合法

因此 ASSShift CN JP 3 abc.ass 是完全确定的:CNJP 是样式,3 是偏移,abc.ass 是文件。唯一的死角是“样式名恰好是纯数字”,此时用 -style 3 绕开。

为什么裸 -sort 等价 -sort time

与 Subresync 的默认重排行为对齐:多数人要的就是“纯时间轴 + 零时长行置顶”。需要分块时显式写 -sort style 即可。-sort 的值只在下一个 token 恰为 time / style 时才被吞掉,所以 -sort abc.ass 不会误吞文件名。

为什么 style 分块序 = 首次出现顺序?

分块排序的本意是还原“字幕作者的块布局”(OP 块、正文块、ED 块……)。按首次出现顺序排列最忠实地保留作者意图;字母序反而会打乱。

确定性保证:两种排序键的末位都是原始行号,即使排序算法稳定性有差异,结果也唯一确定;同时间的行永远保持原有相对顺序。

建议:交互式手敲用位置式(CN JP -0.2 最顺手);写进脚本 / 文档用显式 -offset(一眼看懂)。两者完全等价。

技术细节.cmd原始命令行原文通过环境变量 ASSSHIFT_CMDLINE 整体交给 .ps1,由脚本自行分词。这样负数偏移、引号、逗号分隔、-sort 可选值等写法在 cmd.exepowershell -File、PowerShell 控制台三种调用方式下行为完全一致。.ps1 故意不写 param() 块,避免 -File 的参数绑定层把 -Skip-0.2 等以 - 开头的 token 当成参数名而报错。

常见问题

Q:不加样式会怎样? A:ASSShift -0.2 = 整个字幕所有 Dialogue整体平移;-Skip-sort-mininfo 照常生效。

Q:offset 0 是什么意思?为什么报 "nothing to do"? A:0 表示不平移时间,是纯重组模式,需搭配 -sort / -mininfo 使用。若 0 且两个开关都没给,程序会直接报错退出,避免产出一份与原文件相同的 fixed_*

Q:-sort 会不会把后面的文件名当成模式值吞掉? A:不会。只有下一个 token 恰好是 time / style(忽略大小写)时才作为 -sort 的值,其余情况都原样解析。

Q:-Skip 没生效,所有行都被改了? A:确认写的是 -Skip <关键字>-skip=keyword 也支持)。注意匹配的是 Text 字段,关键字出现在 Actor / Effect 等字段不会命中。控制台会打印 skipped: N 计数。

Q:多样式写法 CN JP 报错? A:请使用本仓库最新版 .cmd.ps1。旧版 .cmd 只把前两个参数映射到 -Style / -Offset,会误把第二个样式当偏移报 无法将值"JP"转换为 System.Decimal

Q:CN,JP(逗号)和 CN JP(空格)一样吗? A:完全一样。命令行原文整体交给脚本解析,逗号在样式 token 内会被自动拆分。

Q:偏移可以是 1:30 这种时分秒吗? A:不支持。偏移统一用(可带小数与正负号),如 -0.163+0.35

Q:处理完会覆盖原文件吗? A:永不。结果写到 fixed_*.ass。如需覆盖,自行把 fixed_* 改名即可。

Q:为什么我的样式没被匹配? A:样式名匹配区分大小写。若末尾提示 No Dialogue line matched the given styles,请核对 [V4+ Styles] 段里 Style: 定义的精确大小写。

Q:用 Subresync 必须先转 UTF-16 LE,这里需要吗? A:不需要。本工具自动检测 UTF-8 / UTF-8 BOM / UTF-16 LE/BE / ANSI 并按原编码回写,UTF-8 的中日文文件直接处理,不会乱码。

Q:-mininfo 会不会丢掉重要东西? A:会丢弃白名单之外的所有键(含 ; 注释、TitleOriginal *Video *WrapStyleYCbCr Matrix),这与 Subresync 的简化行为一致。渲染层面唯一可能有感知差异的是 WrapStyle 非 0 的文件(丢弃后回到默认换行方式);YCbCr Matrix 丢失时播放器会按自身规则猜测。

退出码

退出码 含义
0 全部成功
1 用法 / 参数错误(未给偏移、偏移非法、偏移重复、-sort 模式冲突、0 且无事可做等)
2 至少有一个文件处理失败(如文件被占用)

许可证

Apache 2.0 License

About

A small command-line tool to batch-shift ASS subtitle timings by style

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages