This page describes the subtitle file interface use in Automation 4 Lua scripts to manipulate subtitle files.
There is one special object (the subtitles user data object) which has a number of functions, and a number of table formats defined.
Most Automation 4 Lua feature functions are passed a subtitles object when called. This object is used to obtain data from and manipulate the subtitles the feature is being applied on.
A subtitles object can have two special properties depending on the context it is created for:
To allow the most flexibility, the subtitles object represents a complete ASS format file, line by line, including all meta-lines such as section headers.
The subtitles object supports the following operations:
These operations are described in detail below. In all operation synopses and
examples, subtitles
is used for name of the subtitles object being operated
on.
Synopsis:
num_lines = #subtitles
num_lines = subtitles.n
This operation retrieves the total number of lines in the subtitle file currently. This number only changes by using the other operations on the subtitle object. It cannot change spontaneously during the execution of a script.
Note that this is not a constant-time lookup, but lua does cache the value if
used in for i = 1, #subs
.
num_lines
(number
)The first syntax is the preferred one, per normal Lua 5.1 coding style.
Synopsis: line = subtitles[i]
This retrieves the indexed line and creates a new table object with data about it.
line
(table
)i
(number
)Aegisub internally stores the subtitle file as a linked list, which means that random access is slow, but sequential access is fast. While Automation 4 Lua presents the subtitles as if it was an array, it internally maintains a cursor used to optimise for sequential access. It is faster to access a line with an index close to the one you last accessed than to access one further away. It is always fast to access lines near the beginning or end of the file.
Synopsis:
subtitles[0] = line
subtitles.append(line)
subtitles.append(line1, line2, ...)
Append one or more lines to the end of the appropriate section of the subtitles file. If the section does not exist, it will be created. In the first syntax, it is the number 0 (zero) used for index. (Setting index 0 causes an append operation.)
The third syntax supports appending multiple lines with one single operation.
line
(table
)The latter function-call syntax is preferred for readability. The table index setting syntax is slightly faster.
Appending a line does not move the cursor otherwise used to optimise sequential access.
Synopsis:
subtitles[-i] = line
subtitles.insert(i, line)
subtitles.insert(i, line1, line2, ...)
Inserts one or more lines into the subtitles file before the numbered line. In the first syntax, you supply a negative index. E.g. to insert a line before line 5 you supply index -5 (negative 5.)
Inserting lines will move lines after the inserted lines to move down in index, such that old indexes will no longer be valid.
Inserting lines into the wrong section of the subtitle file has undefined results, and may break in weird ways.
i
(number
)line
(table
)The latter function-call syntax is preferred for readability. The table index setting syntax is slightly faster.
Inserting lines uses the list cursor and will move it.
Synopsis: subtitles[i] = line
Delete the indexed line and insert the given line in its stead.
i
(number
)line
(table
)Replacing lines uses the list cursor and will move it.
Replacing lines with lines of a different type has undefined results, and may break in weird ways.
Synopsis:
subtitles[i] = nil
subtitles.delete(i)
subtitles.delete(i1, i2, ...)
subtitles.deleterange(first, last)
Remove one or more from the subtitles file. All lines after the deleted line(s) will move up to fill the deleted indexes, so old indexes will no longer be valid.
The third syntax supports deleting multiple indexed lines in one call. The indexes given must all be correct for the subtitle file's state before any lines are deleted.
Trying to delete a nonexistent line is an error, except for with deleterange.
The fourth syntax deletes a range of lines, both indexed lines inclusive.
i
(number
)first
(number
)last
(number
)Deleting lines uses the list cursor and will move it.
Synopsis: aegisub.set_undo_point(description)
You should always create an undo point at the end of any macro which made changes to the subtitles object. If you do not, one will automatically be set for you, but in future versions of Aegisub this may change to rolling back any changes made instead.
You can set multiple undo points in a single macro, but it is rarely a good idea to.
Only available in macro processing functions, as it doesn't make sense anywhere else either.
description
(string
)This is not really a function in the subtitles object, but it is still closely tied to it.
When you read lines from the subtitle file object they will always be one of a few classes of lines, and when you write lines back to the subtitle file they must also follow the format of one of those classes.
The line data objects are regular Lua tables with some specific fields defined.
Here's a list of the different classes of lines:
info
style
dialogue
unknown
There's three fields that always exist in all line data tables:
class
(string
)raw
(string
)section
(string
)nil
.info
classThis class defines two additional fields:
key
(string
)value
(string
)style
classThis class defines a large number of additional fields. It's usually processed by the karaskel and modified a bit by that. See the karaskel.lua section on style tables for more information about this class.
dialogue
classThis class defines a large number of additional fields. It's usually processed by the karaskel and has many calculated fields added by that. See the karaskel.lua section on dialogue line tables for more information on this class.
unknown
classNo additional fields are defined by this class, due to its nature. This might
be things like files embedded into the subtitles. You shouldn't try to work
with these lines unless you really know what you're doing. Deleting, modifying
and inserting unknown
lines has undefined consequences. (That means, even if
it works today it might not work tomorrow or in the next version of Aegisub.)