View Single Post
Old 2010-12-22, 16:53   Link #496
Quarkboy
Translator, Producer
 
 
Join Date: Nov 2003
Location: Tokyo, Japan
Age: 44
Well, I finally got around to it, and so I figured I might post it here:

Quarkboy's Smart Line Splitter v2.0

This lua automation script is now fully configurable with a configuration dialog.

Features include:

1. Adjustable maximum character length
2. Apply to selection only, and/or any subset of styles
3. Adjustable "overhang bias" from 1 = always top longer, to 0 = always bottom longer
4. Selectable behavior for existing \N... Either overwrite or ignore
5. Optional commenting out of any detected 3-liners for easy spotting and fixing.

Please pardon my crappy coding style, since I'm not exactly an LUA expert.
Code:
script_name = "Smart Linesplitter"
script_description = "Insert \N Linebreaks"
script_author = "Sam Pinansky"
script_version = "2.0"

function isininttab(tab,match)
	for i = 1, table.maxn(tab) do
		if tab[i]==match then return true end
	end
	return false
end

function smart_linebreaks(subtitles, selected_lines, active_line)
	local conf = {}
	conf[1]={class="label",label="Smart Linesplitter by Sam Pinansky v2.0",x=1,y=5,width=2}
	conf[2]={class="intedit",name="maxlinewidthconfig",hint="Lines will be split into two halves each less than this many characters.\nIf this is not possible, then a line break will be inserted such that the first half\nis less but the second half is too long, and a warning will be written.", value=45,min=1,max=3939,x=1,y=0}
	conf[3]={class="label",label="Max char per line",x=2,y=0}
	conf[4]={class="floatedit",name="lowerbias",hint="Determines whether to have the top line or bottom line longer.\nBased on character numbers and not actual width, so results may vary.",value=0.66,min=0,max=1,step=0.01,x=1,y=1}
	conf[5]={class="label",label="Overhang bias",x=2,y=1}
	conf[6]={class="label",label="Apply to styles:",x=0,y=0}
	conf[7]={class="checkbox",label="Apply to selection only",hint="Only apply to the currently selected lines.",name="selectedonly", value=false,x=1,y=2,width=2}
	conf[8]={class="checkbox",label="Overwrite existing linebreaks",hint="If checked, all \\N's in lines are replaced with new breaks at the desired max limit.\nUnchecked, any line with a \\N will be left as is.",name="overwrite",value=false,x=1,y=3,width=2}
	conf[9]={class="checkbox",label="Comment out 3-liners",hint="If checked, lines that are too long will be commented out.",name="markthree",value=false,x=1,y=4,width=2}
	local styleindex = 10
	for i = 1, subtitles.n do
		if subtitles[i].class == "style" then 
			conf[styleindex] = {class="checkbox",label=subtitles[i].name,name=subtitles[i].name, value=true,x=0,y=styleindex-9}
			styleindex = styleindex + 1
		end
	end
	local ok,configresult = aegisub.dialog.display(conf)
	local maxlinewidth = configresult.maxlinewidthconfig
	linecount = 0
	if not ok then return end
	for i = 1, subtitles.n do
		local l = subtitles[i]
		if l.class == "dialogue" then linecount = linecount + 1 end
		local process = true
		if configresult.selectedonly then 
			if isininttab(selected_lines,i) then 
				process = true 
			else process = false
			end
		else process = true 
		end
		if l.class == "dialogue" and configresult.overwrite then l.text = l.text:gsub("\\N","") end
		if l.class == "dialogue" and not l.comment and configresult[l.style] and process and not l.text:find("\\N") then
			local tstrip = l.text:gsub("%{.-%}","")
			local linelength = tstrip:len()
			local commentarray = {}
			local commentlocarray = {}
			for comit in l.text:gmatch("%{.-%}") do table.insert(commentarray,comit) end
			local loc1 , loc2 = l.text:find("%{.-%}",1)
			while loc1 do table.insert(commentlocarray,{loc1,loc2}) loc1 , loc2 = l.text:find("%{.-%}",loc2)  end
			local rebuilt = ""
			local pos = 0
			local split = false
			local insertionpoint = 0
			if linelength > maxlinewidth then
				for w in tstrip:gmatch("[^%s]+%s*") do
					pos = pos + w:len()
					if pos > linelength/2 and not split then 
						if pos > maxlinewidth or (pos-linelength/2) > (w:len()*configresult.lowerbias) then
							rebuilt = rebuilt .. "\\N" .. w 
							split = true
							insertionpoint = pos - w:len()
							pos = 0
							else
							rebuilt = rebuilt .. w .. "\\N" 
							split = true
							insertionpoint = pos
							pos = 0
							
						end
						else					
						rebuilt = rebuilt .. w
					end
				end
				if pos > maxlinewidth then aegisub.debug.out(2,"WARNING, 3+ line: %i\n",linecount) end
				if pos > maxlinewidth and configresult.markthree then l.comment = true end
				for j,com in ipairs(commentarray) do 
					if commentlocarray[j][1] < insertionpoint then 
						rebuilt = rebuilt:sub(1,commentlocarray[j][1]-1) .. com .. rebuilt:sub(commentlocarray[j][1])
						insertionpoint = insertionpoint + com:len()
						else
						rebuilt = rebuilt:sub(1,commentlocarray[j][1]+1) .. com .. rebuilt:sub(commentlocarray[j][1]+2)
					end
				end
				l.text = rebuilt
			end
			subtitles[i] = l
		end
	end
	aegisub.set_undo_point("Insert Linebreaks")
end

aegisub.register_macro("Smart Line Splitter", "Insert Manual \N Linebreaks", smart_linebreaks)
__________________
Read Light Novels in English at J-Novel Club!
Translator, Producer, Japan Media Export Expert
Founder and Owner of J-Novel Club
Sam Pinansky
Quarkboy is offline   Reply With Quote