跳转至

Aegisub 自动化

2273 个字 33 行代码 预计阅读时间 8 分钟

Abstract

Aegisub 的自动化脚本,使用 Lua 编写,通过标题栏 自动化 > 自动化 菜单管理脚本(包括载入新的自定义脚本

可以实现通过脚本批量处理字幕内容的效果。

Lua 速成

Lua 语言语法很简单,写脚本也讲究能用就行,整理了一下基本的 Lua 语法来速成:

  • 行尾无分号,缩进不必须,甚至行间可以不用换行,-- 开头为注释
  • 动态类型,基本类型有:nil boolean number string function userdata thread table
    • 所有数字类型都是 number,不分整型和浮点型
    • string 可以用单双引号以及双中括号 [[]] 表示
      • 注:Lua 中的 string 其实相当于 bytes,针对 Unicode 字符的话需要另外处理
    • function 也是一个类型,可以作为一个变量来传参之类的
    • table 表也称关联数组,数组字典等都用 table 表示
  • 关于变量
    • 不必指定类型,直接赋值即可使用,未赋值的使用时为 nil 而不会报错
    • a = 1 全局变量;local a = 1 局部变量
    • 赋值语句用等号,左右可以是多个变量(逗号分隔)
      • 等号两侧元素个数不同不会报错,会补 nil 或忽略右侧多余值
  • 循环
    • while (condition) do ... end
    • for var=from,to,step do ... end
    • for i, v in ipairs(table) do ... end
    • repeat ... until (condition)
    • 可以嵌套,但只有 break 没有 continue
    • continue 可以用 goto label 来实现,label ::label:: 定义
  • 流程控制
    • if (cond1) then ... end
    • if (cond1) then ... else ... end
    • if (cond1) then ... elseif (cond2) then ... end
    • 可以嵌套,需要注意的是 else 后面不需要 then
  • 函数
    • function 定义,可以和变量一样指定全局(默认)或局部(加 local
      function add(a, b)
          return a + b
      end
      
    • 输入输出类型都不用指定,返回直接 return 即可,可以返回多个值
    • 调用时参数个数不同不会报错,多余的参数会被忽略,不足的参数会补 nil
    • 调用时可以省略括号
  • 运算符
    • 算数:+ - * / %,^ 乘方,// 整除
    • 逻辑:== ~= > < >= <= and or not
    • a .. b 字符串连接;#a 字符串或表的长度
    • 会进行类型转换,比如 1 + "2" 会得到 3
  • 字符串
    • string.len(str) 字节长度,utf8.len(str) 字符长度
    • string.gsub .find .gmatch .match 可以模式匹配(阉割版正则)
    • string.upper .lower .reverse .rep .char .byte .sub 一些看名字就知道用法的函数
    • string.format 格式化,类似 C printf
      • %c %d %s 等(o 八进制,u 无符号,x 十六进制,e 科学计数法,f 浮点数等)
    • 拼接用 ..,不能用 +(会一律尝试转 number
  • table
    • 数组也是 table,下标从 1 开始
    • table.concat(t, sep) 相当于 python sep.join(t)
    • table.insert .remove .sort
    • 未定义的键访问得到 nil,不会报错,值设为 nil 相当于删除
    • t[i] t.i gettable_event(t, i) 都可以访问元素
  • 模块
    • 文件内创建一个 table module = {},然后定义 module.func
    • 文件末尾 return module 即相当于一个模块
    • 引用时 require "module" 即可使用 module.func

自动化脚本框架

自动化 > 自动化 这个脚本管理器可以直接加载 lua 代码(全局 / 仅当前 assAegisub 有两种自动化脚本类型:

  • 宏,即通过自动化菜单中点击调用,通过 register_macro 注册
  • 导出滤镜,在 Export As 导出脚本时可选择启用滤镜,通过 register_filter 注册

所以简单来讲一个自动化脚本的结构可以是:

script_name = "..."
script_description = "..."
script_author = "..."
script_version = "..."
-- 上面这些是脚本元数据,aegisub 会读取并显示在菜单中

include("unicode.lua")

function macro_function(subtitles, selected_lines, active_line)
    -- do something
end

aegisub.register_macro(script_name, script_description, macro_function)
aegisub.register_macro(name, desc, func, validator, is_active_func)
  • name:脚本名称,显示在自动化菜单里,如果有 / 则分割为子菜单栏
  • desc:脚本描述,鼠标悬浮时显示
  • func:点击脚本名称时调用的函数,会传入以下三个参数
    • subtitles:全部字幕行,可以修改
    • selected_lines:选中的字幕行,一个 table,可以遍历,元素是 subtitles 中编号
    • active_line:当前行,一个 number
  • validator:脚本校验函数,返回 true/false,如果返回 false 则不可用,参数同 func
  • is_active_func:是否活跃,类似 validator,不常用
aegisub.register_filter(name, desc, priority, func, panel_provider)
  • name desc macro 一样
  • priority:选中多个滤镜时的应用优先级,越大越优先
  • func:施加滤镜时调用的函数,传入两个参数
    • subtitles:全部字幕行
    • settings:来自 panel 的设置,没有 panel 则空
  • panel_provider:一个函数,用来定义配置面板
aegisub.set_undo_point(name)
设置撤销点,name 为撤销点名称,可以在撤销历史中看到,Ctrl-Z 撤销函数效果。
aegisub.cancel()
取消当前操作,回滚所有更改。
Aegisub 自带示例

看自带的脚本示例更清晰,比如在每行前加 {\be1} 标签:

local tr = aegisub.gettext

script_name = tr"Add edgeblur"
script_description = tr"A demo macro showing how to do simple line modification in Automation 4"
script_author = "Niels Martin Hansen"
script_version = "1"

function add_edgeblur(subtitles, selected_lines, active_line)
    for z, i in ipairs(selected_lines) do
        local l = subtitles[i]
        l.text = "{\\be1}" .. l.text
        subtitles[i] = l
    end
    aegisub.set_undo_point(script_name)
end

aegisub.register_macro(script_name, tr"Adds \\be1 tags to all selected lines", add_edgeblur)

其中 tr aegisub.gettext 用来国际化,自己用可有可无。

API 及部分自带模块

subtitles API

传入的 subtitles 是所有行,不仅包括字幕行([Events],还有脚本信息行([Script Info])和样式行([V4+ Styles],所以索引既不是字幕行的行号,也不是 ass 文件中的物理行号。总行数可以用 #subtitles 读取。

subtitles 操作

macro function subtitles 是可修改的,而 validator 一类中是只读的。有以下操作:

  • 读取行:line = subtitles[i]line 为一个 table,内容下面介绍
  • 附加行:添加到文件末尾
    • subtitles[0] = line 索引 0 就表示附加
    • subtitles.append(line1, line2, ...) 可以添加多行
  • 插入行:在原第 i 行前插入新行
    • subtitles[-i] = line 索引负数表示插入
    • subtitles.insert(i, line1, line2, ...)
  • 替换行:subtitles[i] = line
  • 删除行:
    • subtitles[i] = nil
    • subtitles.delete(i1, i2, ...)
    • subtitles.delete({i1, i2, ...})
    • subtitles.deleterange(a, b) 闭区间行号

subtitles 行数据

读取到的 subtitles 每一行 line 是一个 table,包含以下键:

  • class:一个 string,表示类型,包括 info style dialogue unknown
  • raw:一个 string,表示在 ass 文件中对应行的原始内容
  • section:一个 string,表示在 ass 文件中所属的部分("[Script Info]" 一类)
  • 不同类型的特定内容:
    • info 类型:
      • key value,都是 string,当前行的信息
    • style 类型:
      • name fontname fontsize bold italic 等样式设置
      • color1 color2 color3 color4 等颜色,可用 extract_color 解析读取
    • dialogue 类型:
      • comment:一个 boolean,表示是否是注释行
      • layer start_time end_time style actor effect 等字幕行设置
      • margin_l ..._r ..._t ..._b:覆盖的 margin,为 0 则表示用 style 默认的
      • text:字幕内容

其他常用 API

aegisub.progress.set(percent)
设置执行进度条的百分比(0-100
aegisub.progress.task(fmt_str, ...)
在进度条下面显示当前正在执行的任务,参数第一个是格式化字符串,后面是格式化的参数。
aegisub.progress.title(fmt_str, ...)
设置进度窗口的标题,也是利用 string.format
aegisub.progress.is_cancelled()
返回一个 boolean 表示用户是否点击了进度窗口中的取消按钮。
aegisub.debug.out(level, fmt_str, ...)

用于输出,可以写为 aegisub.loglevel 可以省略(省略的话则始终显示

level 0-5 依次表示 fatal error warning hint debug trace,在 Preferences 里面可以选择自动化显示的输出等级。

aegisub.text_extends(style, text)

根据样式获取文字渲染后的信息,style 是一个 tablesubtitles API 中的那样text string。返回以下四个数字(像素为单位

  • width height:文字渲染后的宽高
  • descent ext_lead:文字渲染后的 descent leading
aegisub.frame_from_ms(ms) / aegisub.ms_from_frame(frame)
根据视频的帧速率将毫秒和帧号相互转换。没有帧速率相关信息的时候返回 nil
aegisub.video_size()

返回四个值:

  • xres yres:分辨率(像素单位)
  • ar artype:宽高比,artype 0 方形、1 4:32 16:93 2.354 ar 表示的宽高比
aegisub.keyframes()
获取关键帧帧号表,即一个排序好的数组。未加载关键帧则为空。

util 模块

通过 include("util.lua") 或者 util = require "aegisub.util" 引入。

  • 表拷贝相关
    • util.copy(t) 返回一个表的浅拷贝
    • util.deep_copy(t) 返回一个表的深拷贝
  • 颜色相关
    • util.ass_color(r, g, b) 返回 ass 颜色字符串
    • util.ass_style_color(r, g, b, a) 返回 ass 样式的颜色字符串
    • util.ass_alpha(a) 返回 alpha 字符串(&HAA&)
    • util.extract_color(str) 根据字符串解析颜色
      • 返回四个值分别表示 r g b a
      • 可以解析 ass 样式颜色、行内颜色、行内透明度以及 #RRGGBBAA 格式的字符串
      • 样式内不包含的部分返回 0,解析错误返回 nil
    • util.alpha_from_style(str) extract_color ass_alpha 组合
    • util.color_from_style(str) extract_color ass_color 组合
    • util.HSV_to_RGB(h, s, v) h [0, 360)s v [0, 1],返回 r g b [0, 256)
    • util.interpolate_color(t, color1, color2) 在颜色间插值,t [0, 1] 范围内,color1 color2 和返回值都是颜色字符串
    • util.interpolate_alpha(t, alpha1, alpha2) 在透明度间插值,同上
  • 字符串扩展
    • util.trim(str) 移除首尾空格
    • util.headtail(str) 按照第一个空格分割,返回前后两个部分字符串
    • util.words(str) 返回迭代器,相当于用 headtail 多次(即 split
    • 以上字符串扩展都可以将 util 改为 string
  • 数学函数
    • util.clamp(val, min, max) val 约束在 min max
    • util.interpolate(t, a, b) [a, b] 间插值,t 为比例在 [0, 1] 范围内

unicode 模块

Lua string 是字节序列,aegisub 提供了 unicode 模块来处理 UTF-8 字符串。通过 include("unicode.lua") 或者 unicode = require "aegisub.unicode" 引入。

  • unicode.charwidth(str, index) 字符串 str index 开始的字节表示的字符所占字节数
  • unicode.chars(str) 返回迭代器,用来遍历 UTF-8 字符串内所有字符
  • unicode.len(str) 字符个数
  • unicode.codepoint(str) str 中首字符的码位
  • unicode.to_upper_case(str) .to_lower_case .to_fold_case

clipboard 模块

通过 include("clipboard.lua") 或者 clipboard = require "aegisub.clipboard" 引入。

  • clipboard.set(str) 设置剪贴板内容,成功返回 true 否则返回 false
  • clipboard.get() 获取剪贴板内容,不包含文本或发生错误返回 nil

re 模块

Lua string 的模式匹配功能较少,re 模块封装了 boost::regex 实现 PRCE 标准的正则表达式。通过 include("re.lua") 或者 re = require "aegisub.re" 引入。但实际感觉其实也并不好用,这里就不写了。


最后更新: 2023年8月8日 23:28:15
创建日期: 2023年8月8日 23:28:15
回到页面顶部