diff --git a/automation/autoload/clean-k-tags.lua b/automation/autoload/clean-k-tags.lua new file mode 100644 index 000000000..c1daf079e --- /dev/null +++ b/automation/autoload/clean-k-tags.lua @@ -0,0 +1,46 @@ +local tr = aegisub.gettext + +script_name = tr"Clean k tags" +script_description = tr"Remove double k tags" +script_author = "amoethyst" +script_version = "1.0" + +local double_k = "^(.-{\\k[^}]-)(\\k.+)$" +-- if the first tag is K/kf this would break the timing for the previous timing +local expr = "^(.-){\\(ko?)([0-9.]+)[^}]-}([^{]-){\\[kK][fo]?([0-9.]+)[^}]-}( -{(\\[kK][fo]?)[0-9.]+[^}]-}.*)$" + + +function _special_k(subs, i) + line = subs[i] + + before, after = line.text:match(double_k) + while after ~= nil do + line.text = before .. "}{" .. after + before, after = line.text:match(double_k) + end + + before, tag, k1, between, k2, after = line.text:match(expr) + while after ~= nil do + line.text = before .. "{\\" .. tag .. tonumber(k1) + tonumber(k2) .. "}" .. between .. after + before, tag, k1, between, k2, after = line.text:match(expr) + end + + return line +end + + +function special_k(subs, sel) + + for _, i in ipairs(sel) do + ok, res = pcall(_special_k, subs, i) + if ok then + subs[i] = res + else + aegisub.log("error on line " .. i .. ": " .. line.text .. "\n") + aegisub.log(res .. "\n") + end + end + +end + +aegisub.register_macro(script_name, script_description, special_k) diff --git a/automation/autoload/driftfix.lua b/automation/autoload/driftfix.lua new file mode 100644 index 000000000..6c922f4de --- /dev/null +++ b/automation/autoload/driftfix.lua @@ -0,0 +1,26 @@ +local tr = aegisub.gettext + +script_name = tr"driftfix" +script_description = tr"shift drifting lines" +script_author = "amoethyst" +script_version = "1.0" + + +function split_line(subs, sel) + local step = -200 -- drift step in milliseconds + local drift = step + + for _, i in ipairs(sel) do + line = subs[i] + + line.start_time = line.start_time + drift + line.end_time = line.end_time + drift + drift = drift + step + + subs[i] = line + end + + aegisub.set_undo_point(script_name) +end + +aegisub.register_macro(script_name, script_description, split_line) diff --git a/automation/autoload/duetto-meika.lua b/automation/autoload/duetto-meika.lua new file mode 100644 index 000000000..354db267f --- /dev/null +++ b/automation/autoload/duetto-meika.lua @@ -0,0 +1,175 @@ +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 + bracketed = "{s:" .. script_style.name .. bracketed:sub(2, #bracketed) + 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) diff --git a/automation/autoload/karaoke-adjust-1sec.lua b/automation/autoload/karaoke-adjust-1sec.lua new file mode 100644 index 000000000..e8e5764e9 --- /dev/null +++ b/automation/autoload/karaoke-adjust-1sec.lua @@ -0,0 +1,176 @@ +local tr = aegisub.gettext + +script_name = tr"Karaoke 1sec adjust lead-in" +script_description = tr"Adjust karaoke leadin to 1sec" +script_author = "Flore" +script_version = "1.00" + +include("cleantags.lua") + +leadinmsec = 1000 --lead in time can be changed here + +ktag = "\\[kK][fo]?%d+" --pattern used to detect karaoke tags + +-- KM template line definition +km_template_effect = "template pre-line all keeptags" +km_template_text = '!retime("line",$start < 900 and -$start or -900,200)!{!$start < 900 and "\\\\k" .. ($start/10) or "\\\\k90"!\\fad(!$start < 900 and $start or 300!,200)}' + +function hasleadin(line)--check if there is an existing lead in (2 consecutive bracket with karaoke tags at the start of the line) + return line.text:find("^{[^{}]-" .. ktag .. "[^{}]-}%s*{[^{}]-" .. ktag .. "[^{}]-}") +end + + +function removeleadin(line) + if not hasleadin(line) then + return line + end + + leadin = tonumber( line.text:match("^{[^{}]-\\[kK][fo]?(%d+)[^{}]-}%s*{[^{}]-" .. ktag .. "[^{}]-}") ) --read lead-in value + line.text = line.text:gsub("^({[^{}]-)\\[kK][fo]?%d+(.-}%s*{[^{}]-" .. ktag .. ".-})","%1%2") --remove lead in + + line.text = cleantags(line.text) --clean tags + + line.start_time = line.start_time + leadin*10 --adjust start time + + --aegisub.log(line.text) + + return line +end + + +function adjust_1sec(subs, sel) + + for _, i in ipairs(sel) do + local line = subs[i] + + line.text = cleantags(line.text) + + if( line.text:find(ktag)) then--don't do anything if there is no ktags in this line + + --start by removing existing lead-in + while hasleadin(line) do + if aegisub.progress.is_cancelled() then return end + line = removeleadin(line) + end + + --then add our lead in + + if line.start_time >= leadinmsec then + line.text = string.format("{\\k%d}%s",leadinmsec/10, line.text) + line.start_time = line.start_time - leadinmsec + + else --if line starts too early to put the needed lead in, make the line start at time 0 and fill with appropriate lead in + line.text = string.format("{\\k%d}%s",line.start_time/10, line.text) + line.start_time = 0 + end + + subs[i] = line + end + end + + aegisub.set_undo_point(tr"1sec adjust lead-in") +end + + +function remove_tag(line, tag) + local expr = "^(.-{[^}]*)\\" .. tag .. "[^\\}]*(.*)" + while true do + before, after = line.text:match(expr) + if before == nil then + return line + else + line.text = cleantags(before .. after) + end + end +end + + +function is_template_line(line) + return (line.class == "dialogue" + and line.effect == km_template_effect + and line.text == km_template_text) +end + + +function mugenizer(subs) + local first = nil + local styles_different = false + local styles = 0 + local i_styles = {} + local template_present = false + + for i, line in ipairs(subs) do + if line.class == "info" then + if line.key == "PlayResX" or line.key == "PlayResY" then + line.value = "0" + end + if line.key == "ScaledBorderAndShadow" then + line.value = "yes" + end + end + + if line.class == "style" then + line.fontname = "Arial" + line.fontsize = "24" + line.outline = "1.5" + line.shadow = "0" + line.margin_l = "15" + line.margin_r = "15" + line.margin_t = "20" + line.margin_b = "20" + + i_styles[styles] = i + if styles > 0 then + styles_different = styles_different or line.color1 ~= subs[i_styles[styles-1]].color1 or line.color2 ~= subs[i_styles[styles-1]].color2 or line.color3 ~= subs[i_styles[styles-1]].color3 or line.color4 ~= subs[i_styles[styles-1]].color4 + end + styles = styles + 1 + end + + if is_template_line(line) then + line.comment = true + template_present = true + end + + if line.class == "dialogue" and not line.comment and line.effect ~= "fx" then + if first == nil then + first = i + end + + line.text = cleantags(line.text) + + while hasleadin(line) do + if aegisub.progress.is_cancelled() then return end + line = removeleadin(line) + end + + line = remove_tag(line, "fad") + end + + subs[i] = line + end + + if not styles_different then + for i = 0, styles-1, 1 do + line = subs[i_styles[i]] + line.color1 = "&H008AFF" + line.color2 = "&HFFFFFF" + line.color3 = "&H000000" + line.color4 = "&H000000" + subs[i_styles[i]] = line + end + end + + if not template_present then + -- add mugen's magic line + line = subs[first] + line.comment = true + line.start_time = 0 + line.end_time = 0 + line.effect = km_template_effect + line.text = km_template_text + subs.insert(first, line) + end +end + +aegisub.register_macro(script_name, script_description, adjust_1sec) +aegisub.register_macro(tr"Mugenizer", tr"Mugenize your subs", mugenizer) diff --git a/automation/autoload/karaoke-split.lua b/automation/autoload/karaoke-split.lua new file mode 100644 index 000000000..a428b7198 --- /dev/null +++ b/automation/autoload/karaoke-split.lua @@ -0,0 +1,48 @@ +local tr = aegisub.gettext + +script_name = tr"Split karaoke line" +script_description = tr"Split line at {split} marker according to ktags" +script_author = "amoethyst" +script_version = "1.0" + +function split_line(subs, sel) + + function getduration(line) + d = 0 + + kduration = "{[^}]-\\[kK][fo]?(%d+)[^}]-}" + for match in line:gmatch(kduration) do + d = d + tonumber(match) + end + + return d * 10 + end + + insertions = 0 + for _, i in ipairs(sel) do + i = i + insertions + line1 = subs[i] + line2 = subs[i] + + split_expr = "(.-)%s*{split}%s*(.*)" + line1.text, line2.text = line1.text:match(split_expr) + + while line1.text ~= nil do + line1.end_time = line1.start_time + getduration(line1.text) + line2.start_time = line1.end_time + + subs[i] = line1 + i = i + 1 + insertions = insertions + 1 + subs.insert(i, line2) + line1 = subs[i] + + line1.text, line2.text = line1.text:match(split_expr) + end + + end + + aegisub.set_undo_point(tr"Karaoke split") +end + +aegisub.register_macro(script_name, script_description, split_line) diff --git a/automation/autoload/kf.lua b/automation/autoload/kf.lua new file mode 100644 index 000000000..afe77afe3 --- /dev/null +++ b/automation/autoload/kf.lua @@ -0,0 +1,39 @@ +local tr = aegisub.gettext + +script_name = tr"kf" +script_description = tr"add kf tag for 'long' syllables" +script_author = "amoethyst" +script_version = "1.0" + + +function split_line(subs, sel) + local expr_k = "(.-{[^}]*\\)[kK][of]?(%d+)([^{]*)" + local before, after, dur, text + + for _, i in ipairs(sel) do + line = subs[i] + + -- replace k tags + text = "" + for before, dur, after in line.text:gmatch(expr_k) do + if before == nil then + break + else + if tonumber(dur) >= 90 then + text = text .. before .. "kf" .. dur .. after + else + text = text .. before .. "k" .. dur .. after + end + end + end + + if text ~= "" then + line.text = text + subs[i] = line + end + end + + aegisub.set_undo_point(script_name) +end + +aegisub.register_macro(script_name, script_description, split_line) diff --git a/automation/autoload/unkf.lua b/automation/autoload/unkf.lua new file mode 100644 index 000000000..3513f1a2e --- /dev/null +++ b/automation/autoload/unkf.lua @@ -0,0 +1,43 @@ +local tr = aegisub.gettext + +script_name = tr"unkf" +script_description = tr"replace kf/ko tags in selected lines by regular k tags" +script_author = "amoethyst" +script_version = "1.0" + + +function split_line(subs, sel) + local expr_kof = "^(.-{[^}]*\\k)[of](.*)$" + local expr_K = "^(.-{[^}]*\\)K(.*)$" + local before, after + + for _, i in ipairs(sel) do + line = subs[i] + + -- replace ko and kf tags + while true do + before, after = line.text:match(expr_kof) + if before == nil then + break + else + line.text = before .. after + end + end + + -- replace K tags + while true do + before, after = line.text:match(expr_K) + if before == nil then + break + else + line.text = before .. "k" .. after + end + end + + subs[i] = line + end + + aegisub.set_undo_point(script_name) +end + +aegisub.register_macro(script_name, script_description, split_line) diff --git a/automation/autoload/wohe.lua b/automation/autoload/wohe.lua new file mode 100644 index 000000000..925917e07 --- /dev/null +++ b/automation/autoload/wohe.lua @@ -0,0 +1,55 @@ +local tr = aegisub.gettext + +script_name = tr"Nihongo wa muzukashii" +script_description = tr"Turn your \"o e\"s into \"wo he\"s" +script_author = "amoethyst" +script_version = "1.0" + +function wohe(subs, sel) + + -- "Unfortunately Lua patterns do not support this, only single characters can be repeated or chosen between, not sub-patterns or strings" + -- well, fuck + local exprs = { + "^(.* {[^}]*})([oe])({[^}]*} .*)$", + "^(.* )([oe])({[^}]*} .*)$", + "^(.* {[^}]*})([oe])( .*)$", + "^(.* )([oe])( .*)$", + "^()([oe])( .*)$", + } + + for _, i in ipairs(sel) do + line = subs[i] + line.text = line.text .. " " + + for _, expr in ipairs(exprs) do + local before, o_or_e, after = line.text:match(expr) + while o_or_e ~= nil do + line.text = "" + + if before ~= nil then + line.text = before + end + + if o_or_e == "o" then + line.text = line.text .. "wo" + else + line.text = line.text .. "he" + end + + if after ~= nil then + line.text = line.text .. after + end + + before, o_or_e, after = line.text:match(expr) + end + end + + line.text = line.text:gsub(" $", "") + + subs[i] = line + + end + +end + +aegisub.register_macro(script_name, script_description, wohe)