Skip to content

Instantly share code, notes, and snippets.

@louisroyer
Last active May 5, 2025 12:06
Show Gist options
  • Save louisroyer/f91baea8c71e458d50171ee1408fe232 to your computer and use it in GitHub Desktop.
Save louisroyer/f91baea8c71e458d50171ee1408fe232 to your computer and use it in GitHub Desktop.
local tr = aegisub.gettext
script_name = tr"Trim karaoke lines"
script_description = tr"Remove first and last k-tags and adjust start and end times accordingly"
l_script_description = tr"Remove first k-tag and adjust start time accordingly"
l_script_name = tr"Trim karaoke lines - Left"
r_script_name = tr"Trim karaoke lines - Right"
r_script_description = tr"Remove last k-tag and adjust end time accordingly"
script_author = "Louis Royer"
script_version = "1.1"
--[[
-- Check if the line is a karaoke line
--]]
function is_trimmable(line)
if line.comment then
return line.effect == "karaoke"
end
return line.class == "dialogue"
end
--[[
-- Compute duration of a line using k-tags
--]]
function get_duration(line)
local d = 0
local kduration = "{[^}]-\\[kK][fo]?(%d+)[^}]-}"
for match in line:gmatch(kduration) do
d = d + tonumber(match)
end
return d * 10
end
--[[
-- Trim left
--]]
function l_trim_line(subs, sel)
local txt_split_expr = "^[{[^}]-\\[kK][fo]?%d+[^}]-}%s*]*({[^}]-\\[kK][fo]?%d+[^}]-})(.*)"
for _, i in ipairs(sel) do
local line = subs[i]
if is_trimmable(line) then
local end_text_0, end_text_1 = line.text:match(txt_split_expr)
if end_text_0 then
local end_text = end_text_1 and (end_text_0 .. end_text_1) or end_text_0
local total_dur = get_duration(line.text)
local trim_dur = get_duration(end_text)
line.start_time = line.start_time + (total_dur - trim_dur)
line.text = end_text
subs[i] = line
end
end
end
end
--[[
-- Trim left, and set undo point
--]]
function l_trim_line_undo(subs, sel)
l_trim_line(subs, sel)
aegisub.set_undo_point(tr"Karaoke left-trim")
end
--[[
-- Trim right
--]]
function r_trim_line(subs, sel)
local split_expr = "(.-)%s*{[^}]-\\[kK][fo]?%d+[^}]-}%s*$"
for _, i in ipairs(sel) do
local line = subs[i]
if is_trimmable(line) then
local start_text = line.text:match(split_expr)
if start_text then
line.end_time = line.start_time + get_duration(start_text)
line.text = start_text
subs[i] = line
end
end
end
end
--[[
-- Trim right, and set undo point
--]]
function r_trim_line_undo(subs, sel)
r_trim_line(subs, sel)
aegisub.set_undo_point(tr"Karaoke right-trim")
end
--[[
-- Trim left, trim right, and set undo point
--]]
function trim_line(subs, sel)
l_trim_line(subs, sel)
r_trim_line(subs, sel)
aegisub.set_undo_point(tr"Karaoke trim")
end
aegisub.register_macro(script_name, script_description, trim_line)
aegisub.register_macro(l_script_name, l_script_description, l_trim_line_undo)
aegisub.register_macro(r_script_name, r_script_description, r_trim_line_undo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment