mirror of https://github.com/odrling/Aegisub
178 lines
5.8 KiB
Lua
178 lines
5.8 KiB
Lua
|
local tr = aegisub.gettext
|
||
|
|
||
|
script_name = tr"Duetto Meika"
|
||
|
script_description = tr"The ultimate tool for karaoke duets"
|
||
|
script_author = "amoethyst"
|
||
|
|
||
|
include("utils.lua")
|
||
|
|
||
|
|
||
|
function replace_style(line, style_name, style_string)
|
||
|
before_style, after_style = line.text:match("^(.-{[^}]-)\\?s:".. style_name .."(.*)$")
|
||
|
return before_style .. style_string .. after_style
|
||
|
end
|
||
|
|
||
|
|
||
|
function duetto(subs, sel)
|
||
|
styles = {}
|
||
|
|
||
|
-- create the style map
|
||
|
for _, line in ipairs(subs) do
|
||
|
if line.class == "style" then
|
||
|
styles[line.name] = line
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- duetto~
|
||
|
for _, i in ipairs(sel) do
|
||
|
line = subs[i]
|
||
|
|
||
|
current_style = styles[line.style]
|
||
|
-- match every `s:` marker
|
||
|
for style_name in line.text:gmatch("{[^}]*s:([^}\\]*)[^}]*}") do
|
||
|
if style_name ~= current_style.name then
|
||
|
|
||
|
style = styles[style_name]
|
||
|
-- build the tags to use the new style
|
||
|
style_string = ""
|
||
|
if current_style.color1 ~= style.color1 then
|
||
|
style_string = style_string .. "\\c" .. style.color1
|
||
|
end
|
||
|
if current_style.color2 ~= style.color2 then
|
||
|
style_string = style_string .. "\\2c" .. style.color2
|
||
|
end
|
||
|
if current_style.color3 ~= style.color3 then
|
||
|
style_string = style_string .. "\\3c" .. style.color3
|
||
|
end
|
||
|
if current_style.color4 ~= style.color4 then
|
||
|
style_string = style_string .. "\\4c" .. style.color4
|
||
|
end
|
||
|
|
||
|
-- set style
|
||
|
line.text = replace_style(line, style_name, style_string)
|
||
|
current_style = style
|
||
|
else
|
||
|
-- remove marker to not break everything
|
||
|
line.text = replace_style(line, style_name, "")
|
||
|
end
|
||
|
end
|
||
|
subs[i] = line
|
||
|
end
|
||
|
|
||
|
aegisub.set_undo_point(script_name)
|
||
|
end
|
||
|
|
||
|
|
||
|
function test_colors(c1, c2)
|
||
|
return color_from_style(c1) == color_from_style(c2)
|
||
|
end
|
||
|
|
||
|
|
||
|
function get_script_style(style, styles)
|
||
|
for key, script_style in pairs(styles) do
|
||
|
if (test_colors(style.color1, script_style.color1)
|
||
|
and test_colors(style.color2, script_style.color2)
|
||
|
and test_colors(style.color3, script_style.color3)
|
||
|
and test_colors(style.color4, script_style.color4)
|
||
|
and tonumber(style.fontsize) == tonumber(script_style.fontsize)
|
||
|
and style.fontname == script_style.fontname) then
|
||
|
return script_style
|
||
|
end
|
||
|
end
|
||
|
return nil
|
||
|
end
|
||
|
|
||
|
|
||
|
function deduetto_meika(subs, sel)
|
||
|
local styles = {}
|
||
|
local last_style = -1
|
||
|
|
||
|
-- create the style map
|
||
|
for i, line in ipairs(subs) do
|
||
|
if line.class == "style" then
|
||
|
styles[line.name] = line
|
||
|
last_style = i
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local new_styles = {}
|
||
|
|
||
|
for _, i in ipairs(sel) do
|
||
|
local line = subs[i]
|
||
|
local current_style = table.copy(styles[line.style])
|
||
|
|
||
|
local search_index = 1
|
||
|
while search_index < #line.text do
|
||
|
local match_start, match_end = line.text:find("{[^}]*}", search_index)
|
||
|
if match_start == nil then
|
||
|
break
|
||
|
end
|
||
|
|
||
|
local bracketed = line.text:sub(match_start, match_end)
|
||
|
local new_style = false
|
||
|
|
||
|
-- change style's colors
|
||
|
for tag, value in bracketed:gmatch("\\([1-4]?c)([^}\\]*)") do
|
||
|
new_style = true
|
||
|
if tag == "c" or tag == "1c" then
|
||
|
current_style.color1 = value
|
||
|
elseif tag == "2c" then
|
||
|
current_style.color2 = value
|
||
|
elseif tag == "3c" then
|
||
|
current_style.color3 = value
|
||
|
elseif tag == "4c" then
|
||
|
current_style.color4 = value
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- change style's font
|
||
|
for tag, value in bracketed:gmatch("\\(f[sn])([^}\\]*)") do
|
||
|
new_style = true
|
||
|
if tag == "fs" then
|
||
|
current_style.fontsize = value
|
||
|
elseif tag == "fn" then
|
||
|
current_style.fontname = value
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if new_style then
|
||
|
local script_style = get_script_style(current_style, styles)
|
||
|
if script_style == nil then
|
||
|
if get_script_style(current_style, new_styles) == nil then
|
||
|
new_styles[#new_styles+1] = table.copy(current_style)
|
||
|
end
|
||
|
else
|
||
|
-- remove inline colors
|
||
|
bracketed = bracketed:gsub("\\[1-4]?c[^\\}]*", "")
|
||
|
bracketed = bracketed:gsub("\\[1-4]?a[^\\}]*", "")
|
||
|
-- remove inline fonts
|
||
|
bracketed = bracketed:gsub("\\f[sn][^\\}]*", "")
|
||
|
|
||
|
-- add style marker
|
||
|
if line.style ~= script_style.name then
|
||
|
bracketed = "{s:" .. script_style.name .. bracketed:sub(2, #bracketed)
|
||
|
end
|
||
|
line.text = line.text:sub(1, match_start-1) .. bracketed .. line.text:sub(match_end + 1, #line.text)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
search_index = match_start + 1
|
||
|
end
|
||
|
|
||
|
subs[i] = line
|
||
|
end
|
||
|
|
||
|
if #new_styles > 0 then
|
||
|
for i, new_style in ipairs(new_styles) do
|
||
|
new_style.name = "Deduetto style " .. i
|
||
|
subs.insert(last_style, new_style)
|
||
|
last_style = last_style + 1
|
||
|
aegisub.log("Created new style: " .. new_style.name .. "\n")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
aegisub.register_macro(script_name, script_description, duetto)
|
||
|
aegisub.register_macro(tr"Deduetto Meika", tr"Create styles from inline color tags", deduetto_meika)
|