1196 lines
43 KiB
Lua
1196 lines
43 KiB
Lua
-- Use the Help button for some basic info.
|
|
-- Complete manual: http://unanimated.hostfree.pw/ts/scripts-manuals.htm#multicopy
|
|
|
|
script_name="MultiCopy"
|
|
script_description="Lossless transfer of data between compatible storage units"
|
|
script_author="unanimated"
|
|
script_version="4.0"
|
|
script_namespace="ua.MultiCopy"
|
|
|
|
local haveDepCtrl,DependencyControl,depRec=pcall(require,"l0.DependencyControl")
|
|
if haveDepCtrl then
|
|
script_version="4.0.0"
|
|
depRec=DependencyControl{feed="https://raw.githubusercontent.com/unanimated/luaegisub/master/DependencyControl.json"}
|
|
end
|
|
|
|
clipboard=require'aegisub.clipboard'
|
|
re=require'aegisub.re'
|
|
|
|
|
|
-- COPY PART --
|
|
|
|
function copy(subs,sel) -- tags
|
|
copytags=""
|
|
for z,i in ipairs(sel) do
|
|
progress("Copying from line: "..z.."/"..#sel)
|
|
text=subs[i].text
|
|
tags=text:match(STAG) or ""
|
|
copytags=copytags..tags.."\n"
|
|
if z==#sel then copytags=nRem(copytags) end
|
|
end
|
|
copydialog[2].label=""
|
|
copydialog[3].value=copytags
|
|
P=ADD(copydialog,cbut,{close='OK'})
|
|
if P=="Copy to clipboard" then clipboard.set(copytags) end
|
|
end
|
|
|
|
function copyt(subs,sel) -- text
|
|
copytekst=""
|
|
for z,i in ipairs(sel) do
|
|
progress("Copying from line: "..z.."/"..#sel)
|
|
text=subs[i].text
|
|
text=text:gsub(STAG,"")
|
|
visible=text:gsub("%b{}","")
|
|
if CM=="visible text" then text=visible end
|
|
if CM=="text pattern" then
|
|
pat=re.find(visible,res.dat)
|
|
if pat then text=pat[1].str else text="" end
|
|
end
|
|
copytekst=copytekst..text.."\n"
|
|
if z==#sel then copytekst=nRem(copytekst) end
|
|
end
|
|
words=0 for t in copytekst:gmatch("%S+") do words=words+1 end
|
|
copydialog[2].label="("..copytekst:len().." characters, "..words.." words)"
|
|
copydialog[3].value=copytekst
|
|
P=ADD(copydialog,cbut,{close='OK'})
|
|
if P=="Copy to clipboard" then clipboard.set(copytekst) end
|
|
end
|
|
|
|
function kopi(this)
|
|
if this then cc=cc..this end
|
|
end
|
|
|
|
function copyc(subs,sel) -- any tags; layeractoreffectetc.
|
|
cc=""
|
|
tagg=res.dat:gsub("\n","")
|
|
local Y=4
|
|
if CM=="combo" then
|
|
rez=rez or {}
|
|
local fields={"text","style","actor","effect","layer","start_time","end_time","margin_l","margin_r","margin_v"}
|
|
local G={
|
|
{x=0,y=0,width=2,class="label",label="Add to beginning:"},
|
|
{x=2,y=0,width=2,class="edit",name="st",hint="Add this to the beginning of the string for each line"},
|
|
{x=0,y=1,width=2,class="label",label="Add to end:"},
|
|
{x=2,y=1,width=2,class="edit",name="ed",hint="Add this to the end of the string for each line"},
|
|
{x=0,y=2,width=2,class="label",label="Separator:"},
|
|
{x=2,y=2,width=2,class="edit",name="sep",hint="Separator between fields"},
|
|
{x=0,y=3,class="label",label="Copy:"},
|
|
{x=1,y=3,width=2,class="dropdown",name='f3',items=fields,value="text"},
|
|
}
|
|
repeat
|
|
if P2=="Add line" or Y==4 then
|
|
table.insert(G,{x=0,y=Y,class="checkbox",name='c'..Y,label="+",value=true})
|
|
table.insert(G,{x=1,y=Y,width=2,class="dropdown",name='f'..Y,items=fields,value="text"})
|
|
Y=Y+1
|
|
end
|
|
for k,v in ipairs(G) do
|
|
if (v.class=="checkbox" or v.class=="dropdown" or v.class:match"edit") and rez[v.name]~=nil then v.value=rez[v.name] end
|
|
end
|
|
P2,rez=ADD(G,{"Copy","Add line","Esc"},{ok='Copy',close='Esc'})
|
|
until P2~="Add line"
|
|
if P2=="Esc" then ak() end
|
|
rez.c3=true
|
|
comb={}
|
|
for a=3,Y-1 do
|
|
for k,v in ipairs(G) do
|
|
if v.y==a and v.class=="dropdown" then
|
|
nam='c'..a
|
|
nom=rez[v.name]:gsub('_v','_t')
|
|
if rez[nam] then table.insert(comb,nom) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for z,i in ipairs(sel) do
|
|
progress("Copying from line: "..z.."/"..#sel)
|
|
line=subs[i]
|
|
text=line.text
|
|
vis=text:gsub("%b{}","")
|
|
nospace=vis:gsub(" ","")
|
|
comments=""
|
|
if tagg~="" then
|
|
comments=text:match("{[^\\}]-"..esc(tagg).."[^\\}]-}") or ""
|
|
else
|
|
for com in text:gmatch("{[^\\}]-}") do comments=comments..com end
|
|
end
|
|
tagst=text:match(STAG) or ""
|
|
tags=tagst:gsub("\\t%b()","")
|
|
|
|
if CM=="combo" then
|
|
local l=line[comb[1]]
|
|
if #comb>1 then
|
|
for c=2,#comb do
|
|
local txt=line[comb[c]]
|
|
if comb[c]:match("time") then txt=time2string(line[comb[c]]):gsub('^0:',''):gsub('%.00$','') end
|
|
l=l..rez.sep..txt
|
|
end
|
|
end
|
|
l=rez.st..l..rez.ed
|
|
kopi(l)
|
|
end
|
|
|
|
if CM=="clip" then kopi(tags:match("\\i?clip%b()")) end
|
|
if CM=="pos x" then kopi(tags:match("\\pos%(([^,]+)")) end
|
|
if CM=="pos y" then kopi(tags:match("\\pos%([^,]+,([^)]+)")) end
|
|
if CM=="colour(s)" and res.c1 then kopi(tags:match("\\1?c&H%x+&")) end
|
|
if CM=="colour(s)" and res.c2 then kopi(tags:match("\\2c&H%x+&")) end
|
|
if CM=="colour(s)" and res.c3 then kopi(tags:match("\\3c&H%x+&")) end
|
|
if CM=="colour(s)" and res.c4 then kopi(tags:match("\\4c&H%x+&")) end
|
|
if CM=="alpha" and res.alf then kopi(tags:match("\\alpha&H%x+&")) end
|
|
if CM=="alpha" and res.a1 then kopi(tags:match("\\1a&H%x+&")) end
|
|
if CM=="alpha" and res.a2 then kopi(tags:match("\\2a&H%x+&")) end
|
|
if CM=="alpha" and res.a3 then kopi(tags:match("\\3a&H%x+&")) end
|
|
if CM=="alpha" and res.a4 then kopi(tags:match("\\4a&H%x+&")) end
|
|
|
|
if CM=="any tag" then
|
|
for tag in tagg:gmatch("[^,]+") do
|
|
tag=tag:gsub(" ",""):gsub("\\","")
|
|
tak=nil
|
|
if tag=="t" then
|
|
if tagst:match("\\t") then tak=""
|
|
for t in tagst:gmatch("\\t%b()") do tak=tak..t end
|
|
end
|
|
elseif tag:match("^[abikps]$") then tak=tags:match("(\\"..tag.."%d*)[\\}]")
|
|
elseif tag=="fs" then tak=tags:match("(\\fs%d*)[\\}]")
|
|
elseif tag=="c" then tak=tags:match("(\\c&[^\\}]*)")
|
|
elseif tag=="fad" then tak=tags:match("\\fad%b()")
|
|
else
|
|
tak=tags:match("(\\"..tag.."[^\\}]*)")
|
|
end
|
|
kopi(tak)
|
|
end
|
|
end
|
|
|
|
if CM=="layer" then cc=cc..line.layer end
|
|
if CM=="margin l" then cc=cc..line.margin_l end
|
|
if CM=="margin r" then cc=cc..line.margin_r end
|
|
if CM=="margin v" then cc=cc..line.margin_t end
|
|
if CM=="actor" then cc=cc..line.actor end
|
|
if CM=="effect" then cc=cc..line.effect end
|
|
if CM=="style" then cc=cc..line.style end
|
|
if CM=="duration" then cc=cc..line.end_time-line.start_time end
|
|
if CM=="comments" then cc=cc..comments end
|
|
if CM=="# of characters" then cc=cc..vis:len() end
|
|
if CM=="# of chars (no space)" then cc=cc..nospace:len() end
|
|
|
|
if z~=#sel then cc=cc.."\n" end
|
|
end
|
|
copydialog[1].label="Data to export:"
|
|
copydialog[2].label=""
|
|
copydialog[3].value=cc
|
|
P=ADD(copydialog,cbut,{close='OK'})
|
|
if P=="Copy to clipboard" then clipboard.set(cc) end
|
|
end
|
|
|
|
function copyall(subs,sel) -- all
|
|
copylines=""
|
|
for z,i in ipairs(sel) do
|
|
progress("Copying from line: "..z.."/"..#sel)
|
|
text=subs[i].text
|
|
copylines=copylines..text.."\n"
|
|
if z==#sel then copylines=nRem(copylines) end
|
|
end
|
|
words=0 for t in copylines:gmatch("%S+") do words=words+1 end
|
|
copydialog[2].label="("..copylines:len().." characters, "..words.." words)"
|
|
copydialog[3].value=copylines
|
|
P=ADD(copydialog,cbut,{close='OK'})
|
|
if P=="Copy to clipboard" then clipboard.set(copylines) end
|
|
end
|
|
|
|
-- CR Export for Pad --
|
|
function crmod(subs,sel)
|
|
for i=1,#subs do
|
|
progress("Crunching line: "..i.."/"..#subs)
|
|
if subs[i].class=="dialogue" then
|
|
line=subs[i]
|
|
text=line.text
|
|
style=line.style
|
|
text=text
|
|
:gsub("^ *","")
|
|
:gsub(" +"," ")
|
|
:gsub("{\\i0}$","")
|
|
|
|
-- change main style to Default
|
|
style=style:gsub("[Ii]nternal","Italics")
|
|
if style:match("[Ii]talics") and not style:match("[Ff]lashback") and not text:match("\\i1") then text="{\\i1}"..text end
|
|
if style:match("[Mm]ain") or style:match("[Oo]verlap") or style:match("[Ii]talics")
|
|
or style:match("[Ii]nternal") or style:match("[Ff]lashback") or style:match("[Nn]arrat") or style:match("^[Tt]op$")
|
|
then style="Default" end
|
|
|
|
-- nuke tags from signs, set actor to "Sign", add timecode
|
|
if not style:match("Defa") then
|
|
text=text:gsub("{[^}]-}","")
|
|
actor="Sign"
|
|
timecode=math.floor(line.start_time/1000)
|
|
tc1=math.floor(timecode/60)
|
|
tc2=timecode%60+1
|
|
if tc2==60 then tc2=0 tc1=tc1+1 end
|
|
if tc1<10 then tc1="0"..tc1 end
|
|
if tc2<10 then tc2="0"..tc2 end
|
|
text="{TS "..tc1..":"..tc2.."}"..text
|
|
if style:match("[Tt]itle") then text=text:gsub("({TS %d%d:%d%d)}","%1 Title}") end
|
|
|
|
else
|
|
text=text:gsub(" *\\[Nn] *"," ") :gsub("\\a6","\\an8")
|
|
line.text=text
|
|
end
|
|
line.actor=""
|
|
line.style=style
|
|
line.text=text
|
|
subs[i]=line
|
|
end
|
|
end
|
|
-- move signs to the top of the script
|
|
progress("Sorting")
|
|
i=1 moved=0
|
|
while i<=(#subs-moved) do
|
|
line=subs[i]
|
|
if line.class=="dialogue" and line.style=="Default" then
|
|
subs.delete(i)
|
|
moved=moved+1
|
|
subs.append(line)
|
|
else
|
|
i=i+1
|
|
end
|
|
end
|
|
-- copy text from all lines
|
|
copylines=""
|
|
for i=1,#subs do
|
|
progress("Copying from line: "..i.."/"..#subs)
|
|
if subs[i].class=="dialogue" then
|
|
line=subs[i]
|
|
text=line.text
|
|
copylines=copylines..text.."\n"
|
|
if i==#subs then copylines=nRem(copylines) end
|
|
subs[i]=line
|
|
end
|
|
end
|
|
words=0 for t in copylines:gmatch("%S+") do words=words+1 end
|
|
copydialog[2].label="("..copylines:len().." characters, "..words.." words)"
|
|
copydialog[3].value=copylines
|
|
P=ADD(copydialog,cbut,{close='OK'})
|
|
if P=="Copy to clipboard" then clipboard.set(copylines) end
|
|
end
|
|
|
|
-- COPY BETWEEN COLUMNS --
|
|
function copycol(subs,sel)
|
|
l="" r=""
|
|
if res.attach then
|
|
atgui={
|
|
{x=1,y=1,width=2,class="edit",name="merge",hint="Something to place between the two attached strings.\nA space or ' - ' may be useful."},
|
|
{x=0,y=0,class="label",label="Before / "},
|
|
{x=1,y=0,class="checkbox",name="after",label="&After",hint="Attach '"..res.copyfrom.."' to the end of '"..res.copyto.."'.\n\n(Default is to the beginning.)"},
|
|
{x=2,y=0,class="checkbox",name="delor",label="&Delete orig.",hint="Delete content of the 'copy from' column."},
|
|
{x=0,y=1,class="label",label="Link: "}
|
|
}
|
|
if res.copyto=='text' then table.insert(atgui,{x=0,y=2,width=3,class="checkbox",name="kom",label="Attach <"..res.copyfrom.."> as {a &comment}"}) end
|
|
for key,val in ipairs(atgui) do
|
|
if rez and val.name then val.value=rez[val.name] end
|
|
end
|
|
CBC,rez=ADD(atgui,{"OK","Cancel"},{ok='OK',close='Cancel'})
|
|
if CBC=="Cancel" then ak() end
|
|
merge=rez.merge
|
|
if rez.kom then l="{" r="}" end
|
|
end
|
|
for z,i in ipairs(sel) do
|
|
line=subs[i]
|
|
source=line[res.copyfrom]
|
|
target=line[res.copyto]
|
|
if type(target)=="number" then data=tonumber(source) else data=source end
|
|
if data then
|
|
if res.attach then
|
|
if rez.after then data=target..l..merge..data..r
|
|
else data=l..data..merge..r..target
|
|
end
|
|
end
|
|
line[res.copyto]=data
|
|
if res.attach and rez.delor then
|
|
line[res.copyfrom]=""
|
|
if type(source)=="number" then line[res.copyfrom]=0 end
|
|
end
|
|
end
|
|
if res.switch and not res.attach then
|
|
if type(source)=="number" then data2=tonumber(target) else data2=target end
|
|
if data2 then line[res.copyfrom]=data2 end
|
|
end
|
|
subs[i]=line
|
|
end
|
|
end
|
|
|
|
-- PASTE PART --
|
|
|
|
function paste(subs,sel) -- tags
|
|
data={} raw=res.dat.."\n" loop=nil over=nil
|
|
for dataline in raw:gmatch("(.-)\n") do table.insert(data,dataline) end
|
|
if #data~=#sel then mispaste(subs,sel) end
|
|
overloop(subs,sel)
|
|
for z,i in ipairs(sel) do
|
|
if data[z] then
|
|
line=subs[i]
|
|
text=line.text
|
|
text=text:gsub(STAG,"")
|
|
text=data[z]..text
|
|
line.text=text
|
|
subs[i]=line
|
|
end
|
|
end
|
|
end
|
|
|
|
function pastet(subs,sel) -- text
|
|
data={} raw=res.dat.."\n" loop=nil over=nil
|
|
for dataline in raw:gmatch("(.-)\n") do table.insert(data,dataline) end
|
|
if #data~=#sel then mispaste(subs,sel) end
|
|
overloop(subs,sel)
|
|
for z,i in ipairs(sel) do
|
|
if data[z] then
|
|
line=subs[i]
|
|
text=line.text
|
|
tags=text:match(STAG) or ""
|
|
text=text:gsub(esc(tags),"")
|
|
txt2=data[z]
|
|
matchfail=false
|
|
-- using orig. line's inline tags
|
|
if text:match(" {\\[^}]*}%w%w+") and not txt2:match(ATAG) then
|
|
-- match same words if found
|
|
for tgs,wrd in text:gmatch(" ({\\[^}]*})(%w%w+)") do
|
|
if txt2:match("^"..wrd.."%W") or txt2:match(" "..wrd.."%W") or txt2:match(" "..wrd.."$") then
|
|
txt2=txt2:gsub(wrd,tgs..wrd)
|
|
else matchfail=true
|
|
end
|
|
end
|
|
-- apply tags by word count
|
|
if txt2==data[z] or matchfail then
|
|
txt2=data[z]
|
|
text=text:gsub("{[^\\}]-}","")
|
|
words=0
|
|
tagtab={}
|
|
for w in text:gmatch("%S+") do
|
|
words=words+1
|
|
tag1=w:match(STAG)
|
|
tag2=w:match(ATAG.."$")
|
|
tagtab[words]={t1=tag1,t2=tag2}
|
|
end
|
|
wrds2=0
|
|
txt3=""
|
|
for w in txt2:gmatch("%S+") do
|
|
wrds2=wrds2+1
|
|
if tagtab[wrds2] and tagtab[wrds2].t1 then w=tagtab[wrds2].t1..w end
|
|
if tagtab[wrds2] and tagtab[wrds2].t2 then w=w..tagtab[wrds2].t2 end
|
|
txt3=txt3..w.." "
|
|
end
|
|
txt2=txt3:gsub(" $","")
|
|
end
|
|
end
|
|
text=tags..txt2
|
|
text=text:gsub("{(\\[^}]-)}{(\\[^}]-)}","{%1%2}")
|
|
line.text=text
|
|
subs[i]=line
|
|
end
|
|
end
|
|
end
|
|
|
|
function gbctext(text,text2)
|
|
text=text:gsub("\\c&","\\1c&")
|
|
stags=text:match(STAG) or ""
|
|
lastag=text:match("("..ATAG..").$")
|
|
ntext=text2:gsub("(.)$",lastag.."%1")
|
|
if lastag:match("\\[1234]c") then
|
|
textseq={}
|
|
ltrs=re.find(text2,".")
|
|
for l=1,#ltrs do
|
|
table.insert(textseq,ltrs[l].str)
|
|
end
|
|
tagfirst={}
|
|
taglast={}
|
|
sc1="\\c"..styleref.color1:gsub("H%x%x","H")
|
|
sc2="\\2c"..styleref.color2:gsub("H%x%x","H")
|
|
sc3="\\3c"..styleref.color3:gsub("H%x%x","H")
|
|
sc4="\\4c"..styleref.color4:gsub("H%x%x","H")
|
|
stylecol={sc1,sc2,sc3,sc4}
|
|
for c=1,4 do
|
|
cfirst=stags:match("\\"..c.."c&H%x+&")
|
|
clast=lastag:match("\\"..c.."c&H%x+&")
|
|
if cfirst==nil and clast~=nil then cfirst=stylecol[c] end
|
|
if cfirst~=nil and clast~=nil then table.insert(tagfirst,cfirst) table.insert(taglast,clast) end
|
|
end
|
|
grtext=textseq[1]
|
|
tsn=#textseq
|
|
for c=2,tsn-1 do
|
|
coltag=""
|
|
if textseq[c]~=" " then
|
|
for t=1,#taglast do
|
|
col1=tagfirst[t]
|
|
col2=taglast[t]
|
|
B1,G1,R1=col1:match("(%x%x)(%x%x)(%x%x)")
|
|
B2,G2,R2=col2:match("(%x%x)(%x%x)(%x%x)")
|
|
nR1=(tonumber(R1,16)) nR2=(tonumber(R2,16))
|
|
nG1=(tonumber(G1,16)) nG2=(tonumber(G2,16))
|
|
nB1=(tonumber(B1,16)) nB2=(tonumber(B2,16))
|
|
Rdiff=(nR2-nR1)/tsn R=nR1+Rdiff*(c-1)
|
|
Gdiff=(nG2-nG1)/tsn G=nG1+Gdiff*(c-1)
|
|
Bdiff=(nB2-nB1)/tsn B=nB1+Bdiff*(c-1)
|
|
R=tohex(round(R))
|
|
G=tohex(round(G))
|
|
B=tohex(round(B))
|
|
coltag=coltag..col1:gsub("(%x%x)(%x%x)(%x%x)",B..G..R)
|
|
end
|
|
grtext=grtext.."{*"..coltag.."}"..textseq[c]
|
|
else grtext=grtext.." "
|
|
end
|
|
end
|
|
ntext=grtext..lastag..textseq[tsn]
|
|
end
|
|
text=stags..ntext
|
|
return text
|
|
end
|
|
|
|
-- pasted data / selection mismatch --
|
|
function mispaste(subs,sel)
|
|
if raw=="\n" or raw=="" then t_error("No data provided.",1) end
|
|
mispastegui={{class="label",label="Selected lines: "..#sel.." ... Pasted lines: "..#data}}
|
|
if #data<#sel then
|
|
B1="Loop paste"
|
|
B2="Paste only "..#data.." lines"
|
|
else
|
|
B1="Paste only "..#sel.." lines"
|
|
B2="Paste all "..#data.." lines"
|
|
end
|
|
B1=B1:gsub(" 1 lines"," 1 line")
|
|
B2=B2:gsub(" 1 lines"," 1 line")
|
|
P=ADD(mispastegui,{B1,B2,"Cancel"},{close='Cancel'})
|
|
if P=="Cancel" then ak() end
|
|
if P=="Loop paste" then loop=true end
|
|
if P=="Paste all "..#data.." lines" then addlines(subs,sel) over=true end
|
|
end
|
|
|
|
function overloop(subs,sel)
|
|
if over then
|
|
ldiff=#data-#sel
|
|
last=#sel
|
|
for a=1,ldiff do if sel[last]+a<=#subs then table.insert(sel,sel[last]+a) end end
|
|
end
|
|
if loop then
|
|
y=1
|
|
maxd=#data
|
|
repeat
|
|
table.insert(data,data[y])
|
|
y=y+1 if y==maxd+1 then y=1 end
|
|
until #data>=#sel
|
|
end
|
|
end
|
|
|
|
function addlines(subs,sel)
|
|
if sel[#sel]==#subs then
|
|
moar=#data-#sel
|
|
line=subs[#subs]
|
|
if moar>0 then
|
|
for a=1,moar do
|
|
subs.append(line)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- MAIN PASTE PART --
|
|
|
|
function pastec(subs,sel)
|
|
pasteover=0 podetails="" loop=nil over=nil
|
|
data={} raw=res.dat.."\n" raw=raw:gsub("\n\n$","\n")
|
|
for dataline in raw:gmatch("(.-)\n") do table.insert(data,dataline) end
|
|
if PM=="superpasta" or PM=="all" or PM=="pasteover+" then special=true else special=false end
|
|
if #data~=#sel and not special then mispaste(subs,sel) end
|
|
|
|
-- PASTE OVER WITH CHECK
|
|
if PM=="all" then pasteover=1 pasterep="" pnum="" m100=0 m0=0 mtotal=0 om=0 omtotal=0 alter="Default"
|
|
for i=1,#subs do
|
|
if subs[i].class=="style" and subs[i].name:match("Alt") then alter=subs[i].name end
|
|
if subs[i].class=="dialogue" then z0=i-1 break end
|
|
end
|
|
susp="" suspL=0 suspT=0 sustab={}
|
|
for z,i in ipairs(sel) do
|
|
line=subs[i]
|
|
T1l=line.text T2l=data[z] or "" T2l=T2l:gsub("^%w+:(%S)","%1")
|
|
T1=T1l:gsub("%b{}","") :gsub(" ?\\N"," ") T2=T2l:gsub("%b{}","") :gsub(" ?\\N"," ")
|
|
L1=T1:len() L2=T2:len()
|
|
ln=i-z0 if ln<10 then ln="00"..ln elseif ln<100 then ln="0"..ln end
|
|
|
|
-- comparing words between current and pasted
|
|
TC=T1:gsub("[%.,%?!\":;%—]","") TD=T2:gsub("[%.,%?!\":;%—]","") ml=""
|
|
for c in TC:gmatch("[%w']+") do
|
|
for d in TD:gmatch("[%w']+") do
|
|
if c:lower()==d:lower() then
|
|
TD=TD:gsub("^.-"..d,"")
|
|
ml=ml..c.." "
|
|
break
|
|
end
|
|
end
|
|
end
|
|
ml=ml:gsub(" $","")
|
|
M1=ml:len()
|
|
M2=TC:len() if M2==0 then M2=1 end
|
|
match1=math.floor((M1*100/M2+0.5))
|
|
if M1==0 and M2==1 then match1=100 end
|
|
|
|
-- other direction
|
|
TC=T1:gsub("[%.,%?!\":;%—]","") TD=T2:gsub("[%.,%?!\":;%—]","") mr=""
|
|
for c in TD:gmatch("[%w']+") do
|
|
for d in TC:gmatch("[%w']+") do
|
|
if c:lower()==d:lower() then
|
|
TC=TC:gsub("^.-"..d,"")
|
|
mr=mr..c.." "
|
|
break
|
|
end
|
|
end
|
|
end
|
|
mr=mr:gsub(" $","")
|
|
M1=mr:len()
|
|
M2=TD:len() if M2==0 then M2=1 end
|
|
match2=math.floor((M1*100/M2+0.5))
|
|
if M1==0 and M2==1 then match2=100 end
|
|
|
|
if match1>match2 then match=match1 othermatch=match2 ma=ml else match=match2 othermatch=match1 ma=mr end
|
|
pasterep=pasterep..ln.." "..match.."% "..ma.."\n"
|
|
if match==100 then m100=m100+1 if othermatch==100 then om=om+1 end end
|
|
if match==0 then m0=m0+1 end
|
|
mtotal=mtotal+match
|
|
omtotal=omtotal+othermatch
|
|
line.effect=line.effect.."["..othermatch.."%]"
|
|
line.text=T2l
|
|
if T2l:match("{%*ALT%*}") then line.style=alter end
|
|
if T2l:match("^%#") then line.comment=true end
|
|
subs[i]=line
|
|
end
|
|
|
|
if #sel~=#data then
|
|
for s=1,#sustab do susp=susp..sustab[s] ..", " end
|
|
susp=susp:gsub(", $","")
|
|
ldiff=#sel-#data
|
|
if math.abs(ldiff)==1 then es="" else es="s" end
|
|
if ldiff>0 then LD="The pasted data is "..ldiff.." line"..es.." shorter than your selection" else
|
|
LD="The pasted data is ".. 0-ldiff.." line"..es.." longer than your selection" end
|
|
podetails="Line count of the selection doesn't match pasted data.\n"..LD.."\nIf you're pasting over edited text from a pad,\nwhere you start getting too many 0% is where it's probably a line off."
|
|
else
|
|
fullm=math.floor(m100*100/#sel+0.5) zerom=math.floor(m0*100/#sel+0.5) totalm=math.floor(mtotal*10/#sel+0.5)/10
|
|
otherm=math.floor(om*100/#sel+0.5) totalom=math.floor(omtotal*10/#sel+0.5)/10
|
|
podetails="Line count of the selection matched pasted data. ("..#sel.." lines)\nFull match: "..m100.."/"..#sel.." ("..fullm.."%) Both ways: "..om.."/"..#sel.." ("..otherm.."%, ie. "..#sel-om.." lines changed - ".. 100-otherm.."%)\nZero match: "..m0.."/"..#sel.." ("..zerom.."%)\nOverall match: "..totalm.."% (".. 100-totalm.."% change / ".. 100-totalom.."% both ways)"
|
|
end
|
|
end -- of paste over with check
|
|
|
|
|
|
-- PASTEOVER+
|
|
if PM=="pasteover+" then
|
|
rez=nil finished=nil
|
|
tada={} pasted={}
|
|
LL="" RR=""
|
|
MIS="!!! --- Line count mismatch: "
|
|
for z,i in ipairs(sel) do table.insert(tada,subs[i].text) end
|
|
for i=1,13 do
|
|
LL=LL..tada[i].."\n"
|
|
RR=RR..data[i].."\n"
|
|
end
|
|
LL=nRem(LL) RR=nRem(RR) zl=13 zr=13
|
|
POG={
|
|
{x=0,y=0,width=2,class="label",label="Original text. Don't modify this. Number of lines to be sent with each 'Send':"},
|
|
{x=3,y=0,width=3,class="label",label="Pasted text. Modify this so that the lines you're sending on both sides match. Numbers at the bottom = lines to add."},
|
|
{x=3,y=1,width=3,height=20,class="textbox",name="rite",value=RR},
|
|
{x=0,y=1,width=3,height=20,class="textbox",name="left",value=LL},
|
|
{x=2,y=0,class="intedit",name="send",value=5,min=1},
|
|
{x=0,y=21,class="intedit",name="a1",value=AL or 10,min=1},
|
|
{x=3,y=21,class="intedit",name="a2",value=AR or 10,min=1},
|
|
{x=1,y=21,width=2,class="edit",name="i1",value=#tada.." lines total in original script. "..#tada-13 .." remaining."},
|
|
{x=4,y=21,width=2,class="edit",name="i2",value=#data.." lines total in pasted data. "..#data-13 .." remaining."},
|
|
}
|
|
POP=""
|
|
repeat
|
|
POP,rez=ADD(POG,{"Add Left","Add Both","Send Next and Add Both","Send Next","Add Right","Unsend","Cancel"},
|
|
{ok='Send Next',close='Cancel'})
|
|
AL=rez.a1 AR=rez.a2 LL=rez.left RR=rez.rite
|
|
-- Send
|
|
sent=true
|
|
if POP:match("Send Next") then S=0 sent=nil
|
|
_,brl=LL:gsub("\n","") _,brr=RR:gsub("\n","")
|
|
if brr~=brl then
|
|
logL=MIS..brl+1 .." lines here. (End of script.) --- !!!"
|
|
logR=MIS..brr+1 .." lines here. (End of pasted data.) --- !!!"
|
|
end
|
|
-- Not Enough on Left
|
|
if brl<(rez.send) then
|
|
if zl<#tada then S=1 logL="!!! --- You don't have "..rez.send.." lines to send. Add more lines. "..#tada-zl.." remaining. --- !!!" end
|
|
if zl==#tada and zr<#data then S=1 logL="--- End of script. Some pasted data remaining. ---" end
|
|
if zl==#tada and zr==#data and brr~=brl then S=1 end
|
|
elseif zr==#data and zl<#tada then logL=MIS..brl+1 .." lines here. "..#tada-zl.." more to add. --- !!!"
|
|
end
|
|
-- Not Enough on Right
|
|
if brr<(rez.send) then
|
|
if zr<#data then S=1 logR="!!! --- You don't have "..rez.send.." lines to send. Add more lines. "..#data-zr.." remaining. --- !!!" end
|
|
if zr==#data and zl<#tada then S=1 logR="--- End of pasted data. Some lines in the script remaining. ---" end
|
|
if zr==#data and zl==#tada and brr~=brl then S=1 end
|
|
elseif zl==#tada and zr<#data then logR=MIS..brr+1 .." lines here. "..#data-zr.." more to add. --- !!!"
|
|
end
|
|
-- sending --
|
|
if S==0 then
|
|
LL=LL.."\n" RR=RR.."\n"
|
|
for l=1,rez.send do
|
|
table.insert(pasted,RR:match("^(.-)\n")) RR=RR:gsub("^.-\n","") LL=LL:gsub("^.-\n","")
|
|
end
|
|
LL=nRem(LL) RR=nRem(RR)
|
|
if #tada==zl and #data==zr and LL=="" and RR=="" then finished=true end
|
|
sent=true
|
|
end
|
|
end
|
|
-- Add Left
|
|
if sent and POP:match("Add Left") or sent and POP:match("Add Both") then
|
|
if LL~="" then LL=LL.."\n" end
|
|
for i=zl+1,AL+zl do
|
|
if tada[i] then
|
|
LL=LL..tada[i].."\n"
|
|
zl=zl+1
|
|
end
|
|
end
|
|
LL=nRem(LL)
|
|
end
|
|
-- Add Right
|
|
if sent and POP:match("Add Right") or sent and POP:match("Add Both") then
|
|
if RR~="" then RR=RR.."\n" end
|
|
for i=zr+1,AR+zr do
|
|
if data[i] then
|
|
RR=RR..data[i].."\n"
|
|
zr=zr+1
|
|
end
|
|
end
|
|
RR=nRem(RR)
|
|
end
|
|
if sent then
|
|
logL=#tada-zl.." lines remaining in original script."
|
|
logR=#data-zr.." lines remaining in pasted data."
|
|
if zl==#tada then logL="--- End of script. ---" end
|
|
if zr==#data then logR="--- End of data. ---" end
|
|
end
|
|
-- Unsend
|
|
if POP=="Unsend" then
|
|
for u=#pasted,#pasted-rez.send+1,-1 do
|
|
LL=tada[u].."\n"..LL
|
|
RR=pasted[u].."\n"..RR
|
|
table.remove(pasted,u)
|
|
end
|
|
end
|
|
-- rebuild GUI
|
|
if rez then for k,v in ipairs(POG) do
|
|
if v.name=="left" then v.value=LL end
|
|
if v.name=="rite" then v.value=RR end
|
|
if v.name=="i1" then v.value=logL end
|
|
if v.name=="i2" then v.value=logR end
|
|
if v.class=="intedit" then v.value=rez[v.name] end
|
|
end end
|
|
until POP=="Cancel" or finished
|
|
|
|
if POP=="Cancel" then ak() end
|
|
for z,i in ipairs(sel) do line=subs[i] line.text=pasted[z] subs[i]=line end
|
|
end -- of pasteover+
|
|
|
|
|
|
-- SUPER PASTA - advanced paste over
|
|
if PM=="superpasta" then
|
|
styles=""
|
|
warningstyles=""
|
|
for i=1,#subs do
|
|
if subs[i].class=="style" then
|
|
styles=styles..","..subs[i].name..","
|
|
end
|
|
end
|
|
if #data<10 then spg=#data else spg=10 end
|
|
saet={"style","actor","effect","text"}
|
|
seaet={"start time","end time","actor","effect","text"}
|
|
lrvlaet={"L","R","V","layer","actor","effect","text"}
|
|
spgui={
|
|
{x=0,y=0,class="checkbox",name="clay",label="layer"},
|
|
{x=1,y=0,class="checkbox",name="cstart",label="start time"},
|
|
{x=2,y=0,class="checkbox",name="cendt",label="end time"},
|
|
{x=3,y=0,class="checkbox",name="cstyle",label="style"},
|
|
{x=4,y=0,class="checkbox",name="cactor",label="actor"},
|
|
{x=5,y=0,class="checkbox",name="ceffect",label="effect"},
|
|
{x=6,y=0,class="checkbox",name="cL",label="L"},
|
|
{x=7,y=0,class="checkbox",name="cR",label="R"},
|
|
{x=8,y=0,class="checkbox",name="cV",label="V"},
|
|
{x=9,y=0,class="checkbox",name="ctext",label="text"},
|
|
{x=10,y=0,class="label",label="<-- check columns to use"},
|
|
{x=0,y=spg+1,class="dropdown",name="dlay",value="layer",items={"layer","L","R","V","style","actor","effect","text"}},
|
|
{x=1,y=spg+1,class="dropdown",name="dstart",value="start time",items=seaet},
|
|
{x=2,y=spg+1,class="dropdown",name="dendt",value="end time",items=seaet},
|
|
{x=3,y=spg+1,class="dropdown",name="dstyle",value="style",items=saet},
|
|
{x=4,y=spg+1,class="dropdown",name="dactor",value="actor",items=saet},
|
|
{x=5,y=spg+1,class="dropdown",name="deffect",value="effect",items=saet},
|
|
{x=6,y=spg+1,class="dropdown",name="dL",value="L",items=lrvlaet},
|
|
{x=7,y=spg+1,class="dropdown",name="dR",value="R",items=lrvlaet},
|
|
{x=8,y=spg+1,class="dropdown",name="dV",value="V",items=lrvlaet},
|
|
{x=9,y=spg+1,class="dropdown",name="dtext",value="text",items=saet},
|
|
{x=10,y=spg+1,class="label",label="<-- columns to apply to"},
|
|
{x=0,y=spg+2,width=10,class="label",label="Paste over selected columns or copy the content of one column to another. (GUI shows only first 10 lines for reference.)"},
|
|
}
|
|
lines={}
|
|
for li=1,#data do dtext=data[li]
|
|
if not dtext:match("^Dialogue") and not dtext:match("^Comment") then
|
|
ADD({{class="label",label="»"..dtext.."\nNot a valid/complete dialogue line."}},{"OK"},{close='OK'}) ak() end
|
|
dline=string2line(dtext) table.insert(lines,dline) end
|
|
for d=1,spg do
|
|
dtext=data[d] dline=lines[d]
|
|
table.insert(spgui,{x=0,y=d,class="label",name="lay"..d,label=dline.layer})
|
|
table.insert(spgui,{x=1,y=d,class="label",name="start"..d,label=dline.start_time})
|
|
table.insert(spgui,{x=2,y=d,class="label",name="endt"..d,label=dline.end_time})
|
|
table.insert(spgui,{x=3,y=d,class="label",name="style"..d,label=dline.style})
|
|
table.insert(spgui,{x=4,y=d,class="label",name="actor"..d,label=dline.actor})
|
|
table.insert(spgui,{x=5,y=d,class="label",name="effect"..d,label=dline.effect})
|
|
table.insert(spgui,{x=6,y=d,class="label",name="margl"..d,label=dline.margin_l})
|
|
table.insert(spgui,{x=7,y=d,class="label",name="margr"..d,label=dline.margin_r})
|
|
table.insert(spgui,{x=8,y=d,class="label",name="margt"..d,label=dline.margin_t})
|
|
table.insert(spgui,{x=9,y=d,width=25,class="edit",name="text"..d,value=dline.text})
|
|
end
|
|
-- run gui
|
|
repeat
|
|
if press=="Check all" then
|
|
for key,val in ipairs(spgui) do
|
|
if val.class=="checkbox" then val.value=true end
|
|
end
|
|
end
|
|
if press=="Uncheck all" then
|
|
for key,val in ipairs(spgui) do
|
|
if val.class=="checkbox" then val.value=false end
|
|
end
|
|
end
|
|
press,rez=ADD(spgui,{"OK","Check all","Uncheck all","Cancel"},{ok='OK',close='Cancel'})
|
|
until press~="Check all" and press~="Uncheck all"
|
|
if press=="Cancel" then ak() end
|
|
|
|
-- Apply pasteover
|
|
for z,i in ipairs(sel) do
|
|
line=subs[i]
|
|
if lines[z]~=nil then
|
|
if rez.clay then target=rez.dlay source=lines[z].layer line=shoot(line) end
|
|
if rez.cstart then target=rez.dstart source=lines[z].start_time line=shoot(line) end
|
|
if rez.cendt then target=rez.dendt source=lines[z].end_time line=shoot(line) end
|
|
if rez.cstyle then target=rez.dstyle source=lines[z].style line=shoot(line) end
|
|
if rez.cactor then target=rez.dactor source=lines[z].actor line=shoot(line) end
|
|
if rez.ceffect then target=rez.deffect source=lines[z].effect line=shoot(line) end
|
|
if rez.cL then target=rez.dL source=lines[z].margin_l line=shoot(line) end
|
|
if rez.cR then target=rez.dR source=lines[z].margin_r line=shoot(line) end
|
|
if rez.cV then target=rez.dV source=lines[z].margin_t line=shoot(line) end
|
|
if rez.ctext then target=rez.dtext source=lines[z].text line=shoot(line) end
|
|
end
|
|
subs[i]=line
|
|
end
|
|
end -- of superpasta
|
|
|
|
|
|
-- PASTE ANY TAG --
|
|
if not special then
|
|
overloop(subs,sel)
|
|
warningstyles=""
|
|
for z,i in ipairs(sel) do
|
|
if data[z] then
|
|
line=subs[i]
|
|
text=line.text
|
|
text2=data[z]
|
|
if not text:match("^{\\") then text="{\\mc}"..text end
|
|
if PM=="any tag" then
|
|
if text:match("^{[^}]-\\t") then text=text:gsub("^({[^}]-)\\t","%1"..text2.."\\t")
|
|
else text=text:gsub("^({\\[^}]-)}","%1"..text2.."}") end
|
|
end
|
|
if PM=="pos x" then text=text:gsub("(\\pos%()[^,]+","%1"..text2) end
|
|
if PM=="pos y" then text=text:gsub("(\\pos%([^,]+,)[^,)]+","%1"..text2) end
|
|
if PM=="layer" and text2:match('^%d+$') then line.layer=text2 end
|
|
if PM=="margin l" and text2:match('^%d+$') then line.margin_l=text2 end
|
|
if PM=="margin r" and text2:match('^%d+$') then line.margin_r=text2 end
|
|
if PM=="margin v" and text2:match('^%d+$') then line.margin_t=text2 end
|
|
if PM=="actor" then line.actor=text2 end
|
|
if PM=="effect" then line.effect=text2 end
|
|
if PM=="style" then
|
|
sr=stylechk(subs,text2)
|
|
if not sr and not warningstyles:match(","..esc(text2)..",") then
|
|
warningstyles=warningstyles..","..text2..","
|
|
end
|
|
line.style=text2
|
|
end
|
|
if PM=="duration" then line.end_time=line.start_time+text2 end
|
|
if PM=="comments" then text2=text2:gsub("^([^{]-)(.*)([^}]-)$","{%1%2%3}") text=text..text2 end
|
|
if PM=="text mod." then text=textmod2(text2) end
|
|
if PM=="gbc text" then styleref=stylechk(subs,line.style) text=gbctext(text,text2) end
|
|
if PM=="de-irc" then
|
|
line=string2line(text2)
|
|
text=line.text
|
|
end
|
|
if PM=="attach2text" then text=text..' '..text2 end
|
|
|
|
text=text
|
|
:gsub(ATAG,function(tg) tg=duplikill(tg) tg=extrakill(tg,2) return tg end)
|
|
:gsub("\\mc","")
|
|
:gsub("{+}+","")
|
|
line.text=text
|
|
subs[i]=line
|
|
end
|
|
end
|
|
end
|
|
|
|
if warningstyles and warningstyles~="" then warningstyles=warningstyles:gsub(",,",", ") :gsub("^,","") :gsub(",$","")
|
|
ADD({{class="label",label="Warning! These styles don't exist: "..warningstyles}},{"OK"},{close='OK'})
|
|
end
|
|
|
|
if pasteover==1 then pr,rs=ADD({
|
|
{width=40,class="label",name="ch1",label="line % matched matched words"},
|
|
{x=0,y=1,width=40,height=18,class="textbox",name="ch2",value=pasterep},
|
|
{x=0,y=19,width=40,height=4,class="textbox",name="ch3",value=podetails},
|
|
{x=0,y=23,width=40,class="checkbox",name="ef",label="% in effect",value=false},
|
|
},{"OK"},{close='OK'})
|
|
if not rs.ef then
|
|
for z,i in ipairs(sel) do l=subs[i] l.effect=l.effect:gsub("%[%d+%%%]","") subs[i]=l end
|
|
end
|
|
end
|
|
end
|
|
|
|
function shoot(line)
|
|
if target=="layer" then line.layer=source end
|
|
if target=="start time" then line.start_time=source end
|
|
if target=="end time" then line.end_time=source end
|
|
if target=="style" then line.style=source
|
|
if source=="" then source="[unnamed style]" end
|
|
if not styles:match(","..esc(source)..",") and not warningstyles:match(","..esc(source)..",") then
|
|
warningstyles=warningstyles..","..source..","
|
|
end
|
|
end
|
|
if target=="actor" then line.actor=source end
|
|
if target=="effect" then line.effect=source end
|
|
if target=="L" then line.margin_l=source end
|
|
if target=="R" then line.margin_r=source end
|
|
if target=="V" then line.margin_t=source end
|
|
if target=="text" then line.text=source end
|
|
return line
|
|
end
|
|
|
|
-- paste text over while keeping tags --
|
|
function textmod2(text2)
|
|
tk={}
|
|
tg={}
|
|
text=text:gsub("{\\\\k0}","")
|
|
repeat text,r=text:gsub("{(\\[^}]-)}{(\\[^}]-)}","{%1%2}") until r==0
|
|
vis=text2:gsub("%b{}","")
|
|
ltrs=re.find(vis,".")
|
|
for l=1,#ltrs do
|
|
table.insert(tk,ltrs[l].str)
|
|
end
|
|
stags=text:match(STAG) or ""
|
|
text=text:gsub(STAG,"")
|
|
count=0
|
|
for seq in text:gmatch("[^{]-"..ATAG) do
|
|
chars,as,tak=seq:match("([^{]-){(%*?)(\\[^}]-)}")
|
|
pos=re.find(chars,".")
|
|
if pos then ps=#pos+count else ps=0+count end
|
|
tgl={p=ps,t=tak,a=as}
|
|
table.insert(tg,tgl)
|
|
count=ps
|
|
end
|
|
newline=""
|
|
for i=1,#tk do
|
|
newline=newline..tk[i]
|
|
newt=""
|
|
for n,t in ipairs(tg) do
|
|
if t.p==i then newt=newt..t.t as=t.a end
|
|
end
|
|
if newt~="" then newline=newline.."{"..as..newt.."}" end
|
|
end
|
|
newtext=stags..newline
|
|
text=newtext:gsub("{}","")
|
|
return text
|
|
end
|
|
|
|
-- reanimatools ---------------------------------------------------------------------------
|
|
function esc(str) str=str:gsub("[%%%(%)%[%]%.%-%+%*%?%^%$]","%%%1") return str end
|
|
function round(n,dec) dec=dec or 0 n=math.floor(n*10^dec+0.5)/10^dec return n end
|
|
function tagmerge(t) repeat t,r=t:gsub("({\\[^}]-)}{(\\[^}]-})","%1%2") until r==0 return t end
|
|
function logg(m) m=tf(m) or "nil" aegisub.log("\n "..m) end
|
|
function progress(msg) if aegisub.progress.is_cancelled() then ak() end aegisub.progress.title(msg) end
|
|
function t_error(message,cancel) ADD({{class="label",label=message}},{"OK"},{close='OK'}) if cancel then ak() end end
|
|
|
|
function tohex(num)
|
|
n1=math.floor(num/16)
|
|
n2=math.floor(num%16)
|
|
num=tohex1(n1)..tohex1(n2)
|
|
return num
|
|
end
|
|
|
|
function tohex1(num)
|
|
HEX={"1","2","3","4","5","6","7","8","9","A","B","C","D","E"}
|
|
if num<1 then num="0" elseif num>14 then num="F" else num=HEX[num] end
|
|
return num
|
|
end
|
|
|
|
function string2line(str)
|
|
local ltype,layer,s_time,e_time,style,actor,margl,margr,margv,eff,txt=str:match("(%a+): (%d+),([^,]-),([^,]-),([^,]-),([^,]-),([^,]-),([^,]-),([^,]-),([^,]-),(.*)")
|
|
l2={}
|
|
l2.class="dialogue"
|
|
if ltype=="Comment" then l2.comment=true else l2.comment=false end
|
|
l2.layer=layer
|
|
l2.start_time=string2time(s_time)
|
|
l2.end_time=string2time(e_time)
|
|
l2.style=style
|
|
l2.actor=actor
|
|
l2.margin_l=margl
|
|
l2.margin_r=margr
|
|
l2.margin_t=margv
|
|
l2.effect=eff
|
|
l2.text=txt
|
|
l2.extra={}
|
|
return l2
|
|
end
|
|
|
|
function string2time(timecode)
|
|
if timecode==nil then t_error("Invalid timecode.",123) end
|
|
timecode=timecode:gsub("(%d):(%d%d):(%d%d)%.(%d%d)",function(a,b,c,d) return d*10+c*1000+b*60000+a*3600000 end)
|
|
return timecode
|
|
end
|
|
|
|
function time2string(num)
|
|
timecode=math.floor(num/1000)
|
|
tc0=0
|
|
tc1=math.floor(timecode/60)
|
|
tc2=timecode%60
|
|
numstr="00"..num
|
|
tc3=numstr:match("(%d%d)%d$")
|
|
repeat
|
|
if tc2>=60 then tc2=tc2-60 tc1=tc1+1 end
|
|
if tc1>=60 then tc1=tc1-60 tc0=tc0+1 end
|
|
until tc2<60 and tc1<60
|
|
if res and res.mega=="export" and tc0==1 and tc1<30 then tc0=0 tc1=tc1+60 end
|
|
if tc1<10 then tc1="0"..tc1 end
|
|
if tc2<10 then tc2="0"..tc2 end
|
|
tc0=tostring(tc0)
|
|
tc1=tostring(tc1)
|
|
tc2=tostring(tc2)
|
|
timestring=tc0..":"..tc1..":"..tc2.."."..tc3
|
|
return timestring
|
|
end
|
|
|
|
function duplikill(tagz)
|
|
local tags1={"blur","be","bord","shad","xbord","xshad","ybord","yshad","fs","fsp","fscx","fscy","frz","frx","fry","fax","fay"}
|
|
local tags2={"c","2c","3c","4c","1a","2a","3a","4a","alpha"}
|
|
tagz=tagz:gsub("\\t%b()",function(t) return t:gsub("\\","|") end)
|
|
for i=1,#tags1 do
|
|
tag=tags1[i]
|
|
repeat tagz,c=tagz:gsub("|"..tag.."[%d%.%-]+([^}]-)(\\"..tag.."[%d%.%-]+)","%1%2") until c==0
|
|
repeat tagz,c=tagz:gsub("\\"..tag.."[%d%.%-]+([^}]-)(\\"..tag.."[%d%.%-]+)","%2%1") until c==0
|
|
end
|
|
tagz=tagz:gsub("\\1c&","\\c&")
|
|
for i=1,#tags2 do
|
|
tag=tags2[i]
|
|
repeat tagz,c=tagz:gsub("|"..tag.."&H%x+&([^}]-)(\\"..tag.."&H%x+&)","%1%2") until c==0
|
|
repeat tagz,c=tagz:gsub("\\"..tag.."&H%x+&([^}]-)(\\"..tag.."&H%x+&)","%2%1") until c==0
|
|
end
|
|
repeat tagz,c=tagz:gsub("\\fn[^\\}]+([^}]-)(\\fn[^\\}]+)","%2%1") until c==0
|
|
repeat tagz,c=tagz:gsub("(\\[ibusq])%d(.-)(%1%d)","%2%3") until c==0
|
|
repeat tagz,c=tagz:gsub("(\\an)%d(.-)(%1%d)","%3%2") until c==0
|
|
tagz=tagz:gsub("(|i?clip%(%A-%))(.-)(\\i?clip%(%A-%))","%2%3")
|
|
:gsub("(\\i?clip%b())(.-)(\\i?clip%b())",function(a,b,c)
|
|
if a:match("m") and c:match("m") or not a:match("m") and not c:match("m") then return b..c else return a..b..c end end)
|
|
tagz=tagz:gsub("|","\\"):gsub("\\t%([^\\%)]-%)","")
|
|
return tagz
|
|
end
|
|
|
|
function extrakill(text,o)
|
|
local tags3={"pos","move","org","fad"}
|
|
for i=1,#tags3 do
|
|
tag=tags3[i]
|
|
if o==2 then
|
|
repeat text,c=text:gsub("(\\"..tag.."[^\\}]+)([^}]-)(\\"..tag.."[^\\}]+)","%3%2") until c==0
|
|
else
|
|
repeat text,c=text:gsub("(\\"..tag.."[^\\}]+)([^}]-)(\\"..tag.."[^\\}]+)","%1%2") until c==0
|
|
end
|
|
end
|
|
repeat text,c=text:gsub("(\\pos[^\\}]+)([^}]-)(\\move[^\\}]+)","%1%2") until c==0
|
|
repeat text,c=text:gsub("(\\move[^\\}]+)([^}]-)(\\pos[^\\}]+)","%1%2") until c==0
|
|
return text
|
|
end
|
|
|
|
function stylechk(subs,sn)
|
|
for i=1,#subs do
|
|
if subs[i].class=="style" then
|
|
local st=subs[i]
|
|
if sn==st.name then sr=st break end
|
|
end
|
|
end
|
|
if sr==nil then t_error("Style '"..sn.."' doesn't exist.",1) end
|
|
return sr
|
|
end
|
|
|
|
function nRem(x) x=x:gsub("\n$","") return x end
|
|
|
|
cbut={"OK","Copy to clipboard"}
|
|
copydialog=
|
|
{{class="label",label="Text to export:"},
|
|
{x=1,width=49,class="label"},
|
|
{y=1,width=50,height=20,class="textbox",name="copytext"}}
|
|
|
|
herp=[[
|
|
COPY part copies specified things line by line. PASTE part pastes these things line by line.
|
|
The main idea is to copy something from X lines and paste it to another X lines.
|
|
'Copy from-to' is a quick copy function between columns. 'Switch' switches them. Copying strings to number fields does nothing.
|
|
'Attach' adds the copied value to the target value by combining them.
|
|
|
|
tags = initial tags; text = text AFTER initial tags (will include inline tags)
|
|
all = tags+text, ie. everything in the Text field
|
|
any tag = copies whatever tag(s) you specify by typing in this field, like "org", "fad", "t", or "blur,c,alpha".
|
|
|
|
export CR for pad: signs go to top with {TS} timecodes; nukes linebreaks and other CR garbage, fixes styles, etc.
|
|
|
|
Paste part:
|
|
all: this is like regular paste over from a pad, but with checks to help identify where stuff breaks if the line count is different or shifted somewhere. If you're pasting over a script that has different line splitting than it should, this will show you pretty reliably where the discrepancies are. pasteover+ goes even a bit further.
|
|
|
|
text mod.: this pastes over text while keeping inline tags. If your line is {\t1}a{\t2}b{\t3}c and you paste "def", you will get {\t1}d{\t2}e{\t3}f. This simply counts characters, so if you paste "defgh", you get {\t1}d{\t2}e{\t3}fgh, and for "d", you get {\t1}d. Comments get nuked.
|
|
|
|
gbc text: for pasting over lines with gradient by character. You get this:
|
|
[initial tags][pasted text without last character][tag that was before last character][last character of pasted text]
|
|
For colours, the gradient should be replicated in full.
|
|
|
|
de-irc: paste straight from irc with timecodes and nicknames, and stuff gets parsed correctly.
|
|
|
|
If pasted data doesn't match line count of selection, you get choices as for what you want to do.
|
|
|
|
You can use Replacer on pasted data: copy 'bord', replace 'bord' with 'shad', and paste border values as shadow values.]]
|
|
|
|
-- Config --
|
|
function saveconfig()
|
|
mckonf="MC config\n\n"
|
|
for key,val in ipairs(gui) do
|
|
if val.class:match"edit" or val.class=="dropdown" then
|
|
mckonf=mckonf..val.name..":"..res[val.name].."\n"
|
|
end
|
|
if val.class=="checkbox" and val.name~="save" then
|
|
mckonf=mckonf..val.name..":"..tf(res[val.name]).."\n"
|
|
end
|
|
end
|
|
mckonfig=ADP("?user").."\\mc_config.conf"
|
|
file=io.open(mckonfig,"w")
|
|
file:write(mckonf)
|
|
file:close()
|
|
ADD({{class="label",label="Config saved to:\n"..mckonfig}},{"OK"},{close='OK'})
|
|
end
|
|
|
|
function loadconfig()
|
|
fconfig=ADP("?user").."\\mc_config.conf"
|
|
file=io.open(fconfig)
|
|
if file~=nil then
|
|
konf=file:read("*all")
|
|
io.close(file)
|
|
for key,val in ipairs(gui) do
|
|
if val.class:match"edit" or val.class=="checkbox" or val.class=="dropdown" then
|
|
if konf:match(val.name) then val.value=detf(konf:match(val.name..":(.-)\n")) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function tf(val)
|
|
if val==true then ret="true"
|
|
elseif val==false then ret="false"
|
|
else ret=val end
|
|
return ret
|
|
end
|
|
|
|
function detf(txt)
|
|
if txt=="true" then ret=true
|
|
elseif txt=="false" then ret=false
|
|
else ret=txt end
|
|
return ret
|
|
end
|
|
|
|
-- GUI PART
|
|
function multicopy(subs,sel)
|
|
ADD=aegisub.dialog.display
|
|
ADP=aegisub.decode_path
|
|
ak=aegisub.cancel
|
|
ATAG="{%*?\\[^}]-}"
|
|
STAG="^{\\[^}]-}"
|
|
copytab={"tags","text","visible text","all","text pattern","------","export CR for pad","------","any tag","pos x","pos y","colour(s)","alpha","clip","------","actor","effect","style","comments","layer","margin l","margin r","margin v","duration","# of characters","# of chars (no space)","combo"}
|
|
pastab={"all","pasteover+","any tag","pos x","pos y","superpasta","gbc text","text mod.","de-irc","attach2text","------","actor","effect","style","comments","layer","margin l","margin r","margin v","duration"}
|
|
fields={"style","actor","effect","text","layer","start_time","end_time","margin_l","margin_r","margin_t"}
|
|
gui={
|
|
{x=0,y=19,class="label",label="Copy:"},
|
|
{x=1,y=19,width=3,class="dropdown",name="copymode",value=CM or "tags",items=copytab},
|
|
{x=4,y=19,class="label",label="Paste extra:"},
|
|
{x=5,y=19,width=2,class="dropdown",name="pastemode",value=PM or "all",items=pastab},
|
|
{x=0,y=0,width=13,height=17,class="textbox",name="dat"},
|
|
|
|
{x=0,y=17,width=2,class="checkbox",name="col",label="Copy &from",hint="Copy from one column to another"},
|
|
{x=2,y=17,width=2,class="dropdown",name="copyfrom",value=CF or "actor",items=fields},
|
|
{x=4,y=17,class="label",label=" to"},
|
|
{x=5,y=17,width=2,class="dropdown",name="copyto",value=CT or "effect",items=fields},
|
|
{x=7,y=17,width=2,class="checkbox",name="switch",label="&Switch",hint="Switch the content of selected columns"},
|
|
{x=9,y=17,width=2,class="checkbox",name="attach",label="&Attach",hint="Attach content from one column to that of another"},
|
|
|
|
{x=0,y=18,class="checkbox",name="c1",label="\\c",value=true},
|
|
{x=1,y=18,class="checkbox",name="c2",label="\\2c"},
|
|
{x=2,y=18,class="checkbox",name="c3",label="\\3c"},
|
|
{x=3,y=18,class="checkbox",name="c4",label="\\4c"},
|
|
{x=4,y=18,class="checkbox",name="alf",label="\\alpha",value=true},
|
|
{x=5,y=18,class="checkbox",name="a1",label="\\1a"},
|
|
{x=6,y=18,class="checkbox",name="a2",label="\\2a"},
|
|
{x=7,y=18,class="checkbox",name="a3",label="\\3a"},
|
|
{x=8,y=18,width=2,class="checkbox",name="a4",label="\\4a"},
|
|
|
|
{x=11,y=17,class="checkbox",name="rpt",label="Repeat last"},
|
|
{x=12,y=18,class="checkbox",name="save",label="Save config",value=false},
|
|
{x=8,y=19,width=2,class="label",label="Replacer:"},
|
|
{x=10,y=19,width=2,class="edit",name="rep1",value=lastrep1 or "",hint="Replace this..."},
|
|
{x=12,y=19,class="edit",name="rep2",value=lastrep2 or "",hint="...with this."},
|
|
{x=10,y=18,width=2,class="checkbox",name="add",label="Add",hint="Replacer will instead add to the beginning/end of lines"},
|
|
{x=12,y=17,class="label",label="MultiCopy version "..script_version}
|
|
}
|
|
buttons={"&Copy","Paste ta&gs","Paste &text","Paste e&xtra","Paste from clipboard","&Replace","Help","Escape"}
|
|
repeat
|
|
if P=="Paste from clipboard" then
|
|
klipboard=clipboard.get()
|
|
for key,val in ipairs(gui) do
|
|
if val.name=="dat" then val.value=klipboard
|
|
else val.value=res[val.name] end
|
|
end
|
|
end
|
|
if P=="Help" then
|
|
for k,v in ipairs(gui) do
|
|
if v.name=="dat" then v.value=herp
|
|
else v.value=res[v.name] end
|
|
end
|
|
end
|
|
if P=="&Replace" then
|
|
for k,v in ipairs(gui) do
|
|
if v.name=="dat" then
|
|
if res.add then
|
|
v.value=res.dat:gsub("([^\n]+)",res.rep1.."%1"..res.rep2)
|
|
else
|
|
v.value=res.dat:gsub(esc(res.rep1),res.rep2)
|
|
end
|
|
else v.value=res[v.name] end
|
|
end
|
|
end
|
|
if res and res.save then saveconfig() res.save=false P="" break end
|
|
P,res=ADD(gui,buttons,{close='Escape'})
|
|
until P~="Paste from clipboard" and P~="Help" and P~="&Replace"
|
|
if P=="Escape" then ak() end
|
|
|
|
if res.rpt and lastres then res=lastres end
|
|
CM=res.copymode PM=res.pastemode CF=res.copyfrom CT=res.copyto
|
|
lastres=res
|
|
if P=="&Copy" then
|
|
if res.col or res.attach or res.switch then copycol(subs,sel)
|
|
else
|
|
if res.copymode=="tags" then copy(subs,sel)
|
|
elseif res.copymode:match("text") then copyt(subs,sel)
|
|
elseif res.copymode=="all" then copyall(subs,sel)
|
|
elseif res.copymode=="export CR for pad" then crmod(subs,sel)
|
|
else copyc(subs,sel) end
|
|
end
|
|
end
|
|
if P=="Paste ta&gs" then paste(subs,sel) end
|
|
if P=="Paste &text" then pastet(subs,sel) end
|
|
if P=="Paste e&xtra" then pastec(subs,sel) end
|
|
aegisub.set_undo_point(script_name.." - "..P)
|
|
return sel
|
|
end
|
|
|
|
if haveDepCtrl then depRec:registerMacro(multicopy) else aegisub.register_macro(script_name,script_description,multicopy) end |