362 lines
13 KiB
Plaintext
362 lines
13 KiB
Plaintext
[[
|
|
README
|
|
|
|
This file is a library of commonly used functions across all my automation
|
|
scripts. This way, if there are errors or updates for any of these functions,
|
|
I'll only need to update one file.
|
|
|
|
The filename is a bit vain, perhaps, but I couldn't come up with anything else.
|
|
|
|
]]
|
|
|
|
DependencyControl = require("l0.DependencyControl")
|
|
version = DependencyControl{
|
|
name: "LibLyger",
|
|
version: "2.0.3",
|
|
description: "Library of commonly used functions across all of lyger's automation scripts.",
|
|
author: "lyger",
|
|
url: "http://github.com/TypesettingTools/lyger-Aegisub-Scripts",
|
|
moduleName: "lyger.LibLyger",
|
|
feed: "https://raw.githubusercontent.com/TypesettingTools/lyger-Aegisub-Scripts/master/DependencyControl.json",
|
|
{
|
|
"aegisub.util", "karaskel"
|
|
}
|
|
}
|
|
util = version\requireModules!
|
|
|
|
class LibLyger
|
|
msgs = {
|
|
preproc_lines: {
|
|
bad_type: "Error: argument #1 must be either a line object, an index into the subtitle object or a table of indexes; got a %s."
|
|
}
|
|
}
|
|
new: (sub, sel, generate_furigana) =>
|
|
@set_sub sub, sel, generate_furigana if sub
|
|
|
|
set_sub: (@sub, @sel = {}, generate_furigana = false) =>
|
|
@script_info, @lines, @dialogue, @dlg_cnt = {}, {}, {}, 0
|
|
for i, line in ipairs sub
|
|
@lines[i] = line
|
|
switch line.class
|
|
when "info" then @script_info[line.key] = line.value
|
|
when "dialogue"
|
|
@dlg_cnt += 1
|
|
@dialogue[@dlg_cnt], line.i = line, i
|
|
|
|
@meta, @styles = karaskel.collect_head @sub, generate_furigana
|
|
@preproc_lines @sel
|
|
|
|
insert_line: (line, i = #@lines + 1) =>
|
|
table.insert(@lines, i, line)
|
|
@sub.insert(i, line)
|
|
|
|
preproc_lines: (lines) =>
|
|
val_type = type lines
|
|
-- indexes into the subtitles object
|
|
if val_type == "number"
|
|
lines, val_type = {@lines[lines]}, "table"
|
|
assert val_type == "table", msgs.preproc_lines.bad_type\format val_type
|
|
|
|
-- line objects
|
|
if lines.raw and lines.section and not lines.duration
|
|
karaskel.preproc_line @sub, @meta, @styles, lines
|
|
-- tables of line numbers/objects such as the selection
|
|
else @preproc_lines line for line in *lines
|
|
|
|
-- returns a "Lua" portable version of the string
|
|
exportstring: (s) -> string.format "%q", s
|
|
|
|
--Lookup table for the nature of each kind of parameter
|
|
param_type: {
|
|
alpha: "alpha"
|
|
"1a": "alpha"
|
|
"2a": "alpha"
|
|
"3a": "alpha"
|
|
"4a": "alpha"
|
|
c: "color"
|
|
"1c": "color"
|
|
"2c": "color"
|
|
"3c": "color"
|
|
"4c": "color"
|
|
fscx: "number"
|
|
fscy: "number"
|
|
frz: "angle"
|
|
frx: "angle"
|
|
fry: "angle"
|
|
shad: "number"
|
|
bord: "number"
|
|
fsp: "number"
|
|
fs: "number"
|
|
fax: "number"
|
|
fay: "number"
|
|
blur: "number"
|
|
be: "number"
|
|
xbord: "number"
|
|
ybord: "number"
|
|
xshad: "number"
|
|
yshad: "number"
|
|
pos: "point"
|
|
org: "point"
|
|
clip: "clip"
|
|
}
|
|
|
|
--Convert float to neatly formatted string
|
|
float2str: (f) -> "%.3f"\format(f)\gsub("%.(%d-)0+$","%.%1")\gsub "%.$", ""
|
|
|
|
--Escapes string for use in gsub
|
|
esc: (str) -> str\gsub "([%%%(%)%[%]%.%*%-%+%?%$%^])","%%%1"
|
|
|
|
[[
|
|
Tags that can have any character after the tag declaration: \r, \fn
|
|
Otherwise, the first character after the tag declaration must be:
|
|
a number, decimal point, open parentheses, minus sign, or ampersand
|
|
]]
|
|
|
|
-- Remove listed tags from the given text
|
|
line_exclude: (text, exclude) ->
|
|
remove_t = false
|
|
new_text = text\gsub "\\([^\\{}]*)", (a) ->
|
|
if a\match "^r"
|
|
for val in *exclude
|
|
return "" if val == "r"
|
|
elseif a\match "^fn"
|
|
for val in *exclude
|
|
return "" if val == "fn"
|
|
else
|
|
tag = a\match "^[1-4]?%a+"
|
|
for val in *exclude
|
|
if val == tag
|
|
--Hacky exception handling for \t statements
|
|
if val == "t"
|
|
remove_t = true
|
|
return "\\#{a}"
|
|
elseif a\match "%)$"
|
|
return a\match("%b()") and "" or ")"
|
|
else
|
|
return ""
|
|
return "\\"..a
|
|
|
|
if remove_t
|
|
new_text = new_text\gsub "\\t%b()", ""
|
|
|
|
return new_text\gsub "{}", ""
|
|
|
|
-- Remove all tags except the given ones
|
|
line_exclude_except: (text, exclude) ->
|
|
remove_t = true
|
|
new_text = text\gsub "\\([^\\{}]*)", (a) ->
|
|
if a\match "^r"
|
|
for val in *exclude
|
|
return "\\#{a}" if val == "r"
|
|
elseif a\match "^fn"
|
|
for val in *exclude
|
|
return "\\#{a}" if val == "fn"
|
|
else
|
|
tag = a\match "^[1-4]?%a+"
|
|
for val in *exclude
|
|
if val == tag
|
|
remove_t = false if val == "t"
|
|
return "\\#{a}"
|
|
|
|
if a\match "^t"
|
|
return "\\#{a}"
|
|
elseif a\match "%)$"
|
|
return a\match("%b()") and "" or ")"
|
|
else return ""
|
|
|
|
if remove_t
|
|
new_text = new_text\gsub "\\t%b()", ""
|
|
|
|
return new_text
|
|
|
|
-- Returns the position of a line
|
|
get_default_pos: (line, align_x, align_y) =>
|
|
@preproc_lines line
|
|
x = {
|
|
@script_info.PlayResX - line.eff_margin_r,
|
|
line.eff_margin_l,
|
|
line.eff_margin_l + (@script_info.PlayResX - line.eff_margin_l - line.eff_margin_r) / 2
|
|
}
|
|
y = {
|
|
@script_info.PlayResY - line.eff_margin_b,
|
|
@script_info.PlayResY / 2
|
|
line.eff_margin_t
|
|
}
|
|
return x[align_x], y[align_y]
|
|
|
|
get_pos: (line) =>
|
|
posx, posy = line.text\match "\\pos%(([%d%.%-]*),([%d%.%-]*)%)"
|
|
unless posx
|
|
posx, posy = line.text\match "\\move%(([%d%.%-]*),([%d%.%-]*),"
|
|
return tonumber(posx), tonumber(posy) if posx
|
|
|
|
-- \an alignment
|
|
if align = tonumber line.text\match "\\an([%d%.%-]+)"
|
|
return @get_default_pos line, align%3 + 1, math.ceil align/3
|
|
-- \a alignment
|
|
elseif align = tonumber line.text\match "\\a([%d%.%-]+)"
|
|
return @get_default_pos line, align%4,
|
|
align > 8 and 2 or align> 4 and 3 or 1
|
|
-- no alignment tags (take karaskel values)
|
|
else return line.x, line.y
|
|
|
|
-- Returns the origin of a line
|
|
get_org: (line) =>
|
|
orgx, orgy = line.text\match "\\org%(([%d%.%-]*),([%d%.%-]*)%)"
|
|
if orgx
|
|
return orgx, orgy
|
|
else return @get_pos line
|
|
|
|
-- Returns a table of default values
|
|
style_lookup: (line) =>
|
|
@preproc_lines line
|
|
return {
|
|
alpha: "&H00&"
|
|
"1a": util.alpha_from_style line.styleref.color1
|
|
"2a": util.alpha_from_style line.styleref.color2
|
|
"3a": util.alpha_from_style line.styleref.color3
|
|
"4a": util.alpha_from_style line.styleref.color4
|
|
c: util.color_from_style line.styleref.color1
|
|
"1c": util.color_from_style line.styleref.color1
|
|
"2c": util.color_from_style line.styleref.color2
|
|
"3c": util.color_from_style line.styleref.color3
|
|
"4c": util.color_from_style line.styleref.color4
|
|
fscx: line.styleref.scale_x
|
|
fscy: line.styleref.scale_y
|
|
frz: line.styleref.angle
|
|
frx: 0
|
|
fry: 0
|
|
shad: line.styleref.shadow
|
|
bord: line.styleref.outline
|
|
fsp: line.styleref.spacing
|
|
fs: line.styleref.fontsize
|
|
fax: 0
|
|
fay: 0
|
|
xbord: line.styleref.outline
|
|
ybord: line.styleref.outline
|
|
xshad: line.styleref.shadow
|
|
yshad: line.styleref.shadow
|
|
blur: 0
|
|
be: 0
|
|
}
|
|
|
|
-- Modify the line tables so they are split at the same locations
|
|
match_splits: (line_table1, line_table2) ->
|
|
for i=1, #line_table1
|
|
text1 = line_table1[i].text
|
|
text2 = line_table2[i].text
|
|
|
|
insert = (target, text, i) ->
|
|
for j = #target, i+1, -1
|
|
target[j+1] = target[j]
|
|
|
|
target[i+1] = tag: "{}", text: target[i].text\match "#{LibLyger.esc(text)}(.*)"
|
|
target[i] = tag: target[i].tag, :text
|
|
|
|
if #text1 > #text2
|
|
-- If the table1 item has longer text, break it in two based on the text of table2
|
|
insert line_table1, text2, i
|
|
elseif #text2 > #text1
|
|
-- If the table2 item has longer text, break it in two based on the text of table1
|
|
insert line_table2, text1, i
|
|
|
|
return line_table1, line_table2
|
|
|
|
-- Remove listed tags from any \t functions in the text
|
|
time_exclude: (text, exclude) ->
|
|
text = text\gsub "(\\t%b())", (a) ->
|
|
b = a
|
|
for tag in *exclude
|
|
if a\match "\\#{tag}"
|
|
b = b\gsub(tag == "clip" and "\\#{tag}%b()" or "\\#{tag}[^\\%)]*", "")
|
|
return b
|
|
|
|
-- get rid of empty blocks
|
|
return text\gsub "\\t%([%-%.%d,]*%)", ""
|
|
|
|
-- Returns a state table, restricted by the tags given in "tag_table"
|
|
-- WILL NOT WORK FOR \fn AND \r
|
|
make_state_table: (line_table, tag_table) ->
|
|
this_state_table = {}
|
|
for i, val in ipairs line_table
|
|
temp_line_table = {}
|
|
pstate = LibLyger.line_exclude_except val.tag, tag_table
|
|
for j, ctag in ipairs tag_table
|
|
-- param MUST start in a non-alpha character, because ctag will never be \r or \fn
|
|
-- If it is, you fucked up
|
|
param = pstate\match "\\#{ctag}(%A[^\\{}]*)"
|
|
temp_line_table[ctag] = param if param
|
|
|
|
this_state_table[i] = temp_line_table
|
|
return this_state_table
|
|
interpolate: (this_table, start_state_table, end_state_table, factor, preset) ->
|
|
this_current_state = {}
|
|
|
|
rebuilt_text = for k, val in ipairs this_table
|
|
temp_tag = val.tag
|
|
-- Cycle through all the tag blocks and interpolate
|
|
for ctag, param in pairs start_state_table[k]
|
|
temp_tag = "{}" if #temp_tag == 0
|
|
temp_tag = temp_tag\gsub "}", ->
|
|
tval_start, tval_end = start_state_table[k][ctag], end_state_table[k][ctag]
|
|
tag_type = LibLyger.param_type[ctag]
|
|
ivalue = switch tag_type
|
|
when "alpha"
|
|
util.interpolate_alpha factor, tval_start, tval_end
|
|
when "color"
|
|
util.interpolate_color factor, tval_start, tval_end
|
|
when "number", "angle"
|
|
nstart, nend = tonumber(tval_start), tonumber(tval_end)
|
|
if tag_type == "angle" and preset.c.flip_rot
|
|
nstart %= 360
|
|
nend %= 360
|
|
ndelta = nend - nstart
|
|
if 180 < math.abs ndelta
|
|
nstart += ndelta * 360 / math.abs ndelta
|
|
|
|
nvalue = util.interpolate factor, nstart, nend
|
|
nvalue += 360 if tag_type == "angle" and nvalue < 0
|
|
|
|
LibLyger.float2str nvalue
|
|
when "point", "clip" then nil -- not touched by this function
|
|
else ""
|
|
|
|
-- check for redundancy
|
|
if this_current_state[ctag] == ivalue
|
|
return "}"
|
|
this_current_state[ctag] = ivalue
|
|
return "\\#{ctag..ivalue}}"
|
|
temp_tag .. val.text
|
|
|
|
return table.concat(rebuilt_text)\gsub "{}", ""
|
|
|
|
write_table: (my_table, file, indent) ->
|
|
indent or= ""
|
|
charS, charE = " ", "\n"
|
|
|
|
--Opening brace of the table
|
|
file\write "#{indent}{#{charE}"
|
|
|
|
for key,val in pairs my_table
|
|
file\write switch type key
|
|
when "number" then indent..charS
|
|
when "string" then table.concat {indent, charS, "[", LibLyger.exportstring(key), "]="}
|
|
else "#{indent}#{charS}#{key}="
|
|
|
|
switch type val
|
|
when "table"
|
|
file\write charE
|
|
LibLyger.write_table val, file, indent..charS
|
|
file\write indent..charS
|
|
when "string" then file\write LibLyger.exportstring val
|
|
when "number" then file\write tostring val
|
|
when "boolean" then file\write val and "true" or "false"
|
|
|
|
file\write ","..charE
|
|
|
|
-- Closing brace of the table
|
|
file\write "#{indent}}#{charE}"
|
|
|
|
:version
|
|
|
|
return version\register LibLyger |