├── README.md
├── image
├── 1.cpp
├── menu.png
├── 删除1.png
├── 删除2.png
├── 歌词1.png
├── 歌词2.png
├── 添加内联特效1.png
└── 添加内联特效2.png
├── svg转ass绘图v1.2.zip
├── 【aeg插件】一键导出选中行音频v2.2.zip
├── 一键获取tc评论v1.1.zip
├── 多重边框生成v1.2.lua
├── 小工具集合v3.0.lua
├── 查闪轴1.0.lua
├── 歌词处理小插件2.0.lua
├── 给字幕两侧添加图片.lua
├── 获取up主视频数据v0.9.zip
└── 轴校工具v5.3修复bug2.zip
/README.md:
--------------------------------------------------------------------------------
1 | # 处理歌词插件
2 | 
3 |
4 | ## 1.中日歌词分离
5 |
6 | 用于分离你从网易云或者萌娘百科上直接复制粘贴进aeg里的插件。就省的你之前还要先粘贴进文本文档里删空白行,手动把中日分开之类的很繁琐的操作。
7 | 一般从网易云或者萌娘百科上,直接复制粘贴进aeg的形式会是这样的
8 |
9 | 
10 | 处理完之后将中日分开方便操作,会识别空白行分开
11 |
12 | 
13 |
14 | 歌词必须是严格的中日一行一行对应,空白行有多少行无所谓
15 |
16 | ## 2.全角空格转半角空格
17 | 全角空格好像会给位置坐标带来问题。顾名思义,替换选中行中的全角空格
18 |
19 | ## 3.删除所有K标签
20 | 
21 |
22 | 
23 |
24 | ## 4.一键添加内联特效标签
25 | 有时候需要给多行同时添加内联特效,有时候是整行,有时候是添加第一个。可以自行修改,第二个设为空就只设定第一个
26 |
27 | 
28 |
29 | 
30 |
--------------------------------------------------------------------------------
/image/1.cpp:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/image/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/menu.png
--------------------------------------------------------------------------------
/image/删除1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/删除1.png
--------------------------------------------------------------------------------
/image/删除2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/删除2.png
--------------------------------------------------------------------------------
/image/歌词1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/歌词1.png
--------------------------------------------------------------------------------
/image/歌词2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/歌词2.png
--------------------------------------------------------------------------------
/image/添加内联特效1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/添加内联特效1.png
--------------------------------------------------------------------------------
/image/添加内联特效2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/image/添加内联特效2.png
--------------------------------------------------------------------------------
/svg转ass绘图v1.2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/svg转ass绘图v1.2.zip
--------------------------------------------------------------------------------
/【aeg插件】一键导出选中行音频v2.2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/【aeg插件】一键导出选中行音频v2.2.zip
--------------------------------------------------------------------------------
/一键获取tc评论v1.1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/一键获取tc评论v1.1.zip
--------------------------------------------------------------------------------
/多重边框生成v1.2.lua:
--------------------------------------------------------------------------------
1 | -- 更新:
2 | -- 1.增加了对原有行存在的\frz(即绕z轴旋转标签)的自适应
3 | -- 2.增加了能够将常用边框效果存储为预设的功能,可以从预设打开之前存储的多层样式
4 | -- 3.新增了可以根据选中样式进行应用的模式,针对行数和样式都很多,且只想对某种样式应用,多选比较麻烦的情况下使用,非常方便快捷。(21.01.09
5 | -- 功能:
6 | -- 覆盖原有行边框,生成指定多重边框字幕
7 | -- 注意:
8 | -- 1.多重边框情况下不支持设置透明边框(暂时将原来计划的透明度效果去除)
9 | -- 2.会将原有行注释,生成新行代替原有字幕
10 | --
11 | local tr = aegisub.gettext
12 | script_name = tr("多重边框")
13 | script_description = tr("多重边框")
14 | script_author = "拉姆0v0"
15 | script_version = "v1.2"
16 |
17 | include("karaskel.lua")
18 |
19 | fp=aegisub.decode_path("?data").."\\border_data.lua"
20 | -- 序列化和反序列化方法
21 | function serialize(obj)
22 | local lua = ""
23 | local t = type(obj)
24 | if t == "number" then
25 | lua = lua .. obj
26 | elseif t == "boolean" then
27 | lua = lua .. tostring(obj)
28 | elseif t == "string" then
29 | lua = lua .. string.format("%q", obj)
30 | elseif t == "table" then
31 | lua = lua .. "{\n"
32 | for k, v in pairs(obj) do
33 | lua = lua .. "[" .. serialize(k) .. "]=" .. serialize(v) .. ",\n"
34 | end
35 | local metatable = getmetatable(obj)
36 | if metatable ~= nil and type(metatable.__index) == "table" then
37 | for k, v in pairs(metatable.__index) do
38 | lua = lua .. "[" .. serialize(k) .. "]=" .. serialize(v) .. ",\n"
39 | end
40 | end
41 | lua = lua .. "}"
42 | elseif t == "nil" then
43 | return nil
44 | else
45 | error("can not serialize a " .. t .. " type.")
46 | end
47 | return lua
48 | end
49 |
50 | function unserialize(lua)
51 | local t = type(lua)
52 | if t == "nil" or lua == "" then
53 | return nil
54 | elseif t == "number" or t == "string" or t == "boolean" then
55 | lua = tostring(lua)
56 | else
57 | error("can not unserialize a " .. t .. " type.")
58 | end
59 | lua = "return " .. lua
60 | local func = loadstring(lua)
61 | if func == nil then
62 | return nil
63 | end
64 | return func()
65 | end
66 |
67 | -- html颜色转#
68 | function coloralpha2assCA(coloralpha)
69 | local length = #coloralpha
70 | -- local A = coloralpha:sub(length-1, length)
71 | -- local B = coloralpha:sub(length-3, length-2)
72 | -- local G = coloralpha:sub(length-5, length-4)
73 | -- local R = coloralpha:sub(length-7, length-6)
74 | -- return "H"..B..G..R, "H"..A
75 | local B = coloralpha:sub(length-1, length)
76 | local G = coloralpha:sub(length-3, length-2)
77 | local R = coloralpha:sub(length-5, length-4)
78 | return "H"..B..G..R, "H00"
79 | end
80 |
81 | -- 获取字幕行的pos
82 | function getPosFromText(text)
83 | local out = text:match("[%-?%d+%.*%d*]+[,]+[%-?%d+%.*%d*]+")
84 | if out ~= nil then
85 | return out
86 | else
87 | return ""
88 | end
89 | end
90 |
91 | -- 获取字幕行的frz
92 | function getFrz(text)
93 | local frz = text:match("\\frz%-?%d+%.*%d*")
94 | if frz ~= nil then
95 | return frz
96 | else
97 | return ""
98 | end
99 | end
100 |
101 | -- 对选中行应用
102 | function apply_to_selected_rows(subs, sel, meta, styles, tags_template, border_data)
103 | -- 对每一行分别应用多层边框
104 | for i = 1, #sel do
105 | local pos_x
106 | local pos_y
107 | -- 分别判断每行是不是自带pos
108 | local l = subs[sel[i]]
109 | local simple_l = subs[sel[i]]
110 | karaskel.preproc_line(subs, meta, styles, l)
111 | local postag_str = getPosFromText(l.text)
112 | local frztag_str = getFrz(l.text)
113 | if postag_str == "" then
114 |
115 | pos_x = l.x
116 | pos_y = l.y
117 | else
118 | pos_x = tonumber(postag_str:sub(1,postag_str:find("[,]+")-1))
119 | pos_y = tonumber(postag_str:sub(postag_str:find("[,]+")+1,-1))
120 | end
121 | local bord = 0
122 | -- 对每个边框生成
123 | for j = 1, #border_data do
124 | bord = bord + tonumber(border_data[j].houdu)
125 | local text = tags_template:format(pos_x, pos_y, bord, border_data[j].color, border_data[j].alpha, (frztag_str == "" and "" or frztag_str))..l.text:gsub("{[^}]+}", "")
126 | l.layer = #border_data-j+1
127 | l.text = text
128 | subs.append(l)
129 | end
130 | simple_l.comment = true
131 | subs[sel[i]] = simple_l
132 | end
133 | end
134 |
135 | -- 对选中样式应用
136 | function apply_to_style(subs, sel, meta, styles, tags_template, border_data)
137 | local styles_name_table = {}
138 | for i=1,styles.n do
139 | table.insert(styles_name_table, styles[i].name)
140 | end
141 | local dialog_config4 = {
142 | [1] = { class = "label", x = 0, y = 0, label = "选择要应用的样式:" },
143 | [2] = { class="dropdown", name="seleted_style", x=1, y=0 , width=5, height=1, items={}, value=""},
144 | }
145 | dialog_config4[2].items = styles_name_table
146 | dialog_config4[2].value = dialog_config4[2].items[1]
147 | local buttons4, results4 = aegisub.dialog.display(dialog_config4, {"Ok", "Cancel"})
148 | if buttons4 == "Ok" then
149 | local seleted_style = results4["seleted_style"]
150 | if seleted_style ~= "" then
151 | -- 对每一行分别应用多层边框
152 | for i = 1, #subs do
153 | if subs[i].class == "dialogue" and subs[i].comment == false and subs[i].style == seleted_style then
154 | local pos_x
155 | local pos_y
156 | -- 分别判断每行是不是自带pos
157 | local l = subs[i]
158 | local simple_l = subs[i]
159 | karaskel.preproc_line(subs, meta, styles, l)
160 | local postag_str = getPosFromText(l.text)
161 | local frztag_str = getFrz(l.text)
162 | if postag_str == "" then
163 |
164 | pos_x = l.x
165 | pos_y = l.y
166 | else
167 | pos_x = tonumber(postag_str:sub(1,postag_str:find("[,]+")-1))
168 | pos_y = tonumber(postag_str:sub(postag_str:find("[,]+")+1,-1))
169 | end
170 | local bord = 0
171 | -- 对每个边框生成
172 | for j = 1, #border_data do
173 | bord = bord + tonumber(border_data[j].houdu)
174 | local text = tags_template:format(pos_x, pos_y, bord, border_data[j].color, border_data[j].alpha, (frztag_str == "" and "" or frztag_str))..l.text:gsub("{[^}]+}", "")
175 | l.layer = #border_data-j+1
176 | l.text = text
177 | subs.append(l)
178 | end
179 | simple_l.comment = true
180 | subs[i] = simple_l
181 | end
182 | end
183 | else
184 | aegisub.debug.out("你选择要应用的样式为空!")
185 | end
186 | else
187 | aegisub.debug.out("已取消!")
188 | end
189 | end
190 |
191 | -- 保存样式
192 | function save_as(dialog_config3,data_reader_table,border_num,fp)
193 | buttons3, results3 = aegisub.dialog.display(dialog_config3, {"OK", "Cancel"})
194 | if buttons3 == "OK" then
195 | local save_name = results3["yushename"]
196 | if save_name ~= "" then
197 | local alive = false
198 | for k, v in pairs(data_reader_table) do
199 | if v.name == save_name then
200 | alive = true
201 | break
202 | end
203 | end
204 | if alive == false then
205 | local border_data = {}
206 | for i = 1, border_num do
207 | local color, alpha = coloralpha2assCA(results2["ca_" .. i])
208 | local houdu = results2["houdu_" .. i]
209 | border_data[i] = {
210 | ["color"] = color,
211 | ["alpha"] = alpha,
212 | ["houdu"] = houdu
213 | }
214 | end
215 | table.insert(data_reader_table, {["name"] = save_name,["data"] = border_data})
216 | local data_w = io.open(fp, "w+")
217 | data_w:write(serialize(data_reader_table))
218 | data_w:close()
219 | aegisub.debug.out("已保存!")
220 | else
221 | aegisub.debug.out("已存在同名预设!")
222 | end
223 | else
224 | aegisub.debug.out("预设名不得为空!")
225 | end
226 | else
227 | aegisub.debug.out("已取消保存!")
228 | end
229 | end
230 |
231 | -- 生成边框设置界面config
232 | function get_border_setting_config(border_num_OR_data_table_yushe, conf_template)
233 | local dialog_config2={}
234 | for i = 1, (type(border_num_OR_data_table_yushe) == "table" and #border_num_OR_data_table_yushe or border_num_OR_data_table_yushe) do
235 | dialog_config2[(i-1)*5+1] = unserialize(conf_template[1]:format(i-1, i))
236 | dialog_config2[(i-1)*5+2] = unserialize(conf_template[2]:format(i-1))
237 | dialog_config2[(i-1)*5+3] = unserialize(conf_template[3]:format(i, i-1, (type(border_num_OR_data_table_yushe) == "table" and border_num_OR_data_table_yushe[i].color or "HFFFFFF")))
238 | dialog_config2[(i-1)*5+4] = unserialize(conf_template[4]:format(i-1))
239 | dialog_config2[(i-1)*5+5] = unserialize(conf_template[5]:format(i, i-1, (type(border_num_OR_data_table_yushe) == "table" and border_num_OR_data_table_yushe[i].houdu or "1")))
240 | end
241 | return dialog_config2
242 | end
243 |
244 | -- 边框数据转换
245 | function get_borderdata_form_results2(border_num,results2)
246 | local border_data = {}
247 | for i = 1, border_num do
248 | local color, alpha = coloralpha2assCA(results2["ca_" .. i])
249 | local houdu = results2["houdu_" .. i]
250 | border_data[i] = {
251 | ["color"] = color,
252 | ["alpha"] = alpha,
253 | ["houdu"] = houdu
254 | }
255 | end
256 | return border_data
257 | end
258 |
259 | dialog_config1=
260 | {
261 | [1]={class="label",x=0,y=0,label="新建多重边框层数:"},
262 | [2]={class="intedit",name="border_num",x=1,y=0,width=1,height=1,value="1",hint="请输入整数"},
263 | [3]={class="label",x=0,y=1,label="打开选择预设:"},
264 | [4]={class="dropdown",name="selete",x=1,y=1,width=5,height=1,items={},value=""},
265 | }
266 |
267 | dialog_config3=
268 | {
269 | [1]={class="label",x=0,y=0,label="给你的预设起个名字吧:"},
270 | [2]={class="edit",name="yushename",x=1,y=0,width=5,height=1,value="预设1",hint="输入你的名字"},
271 | }
272 |
273 | local conf_template ={
274 | [1]='{class="label",x=0,y=%s,label="【第%s层】"}',
275 | [2]='{class="label",x=1,y=%s,label="颜色:"}',
276 | [3]='{class="color",name="ca_%s",x=2,y=%s,width=1,height=1,value="%s"}',
277 | [4]='{class="label",x=3,y=%s,label="厚度:"}',
278 | [5]='{class="edit",name="houdu_%s",x=4,y=%s,width=1,height=1,value="%s"}',
279 | }
280 |
281 | local tags_template = "{\\pos(%s,%s)\\bord%s\\shad0\\3c&%s&\\3a&%s&%s}"
282 |
283 | function border(subs,sel)
284 | -- 读取库数据
285 | local data=io.open(fp,"a+")
286 | local data_str = data:read('*a')
287 | data:close()
288 | if data_str == "" then
289 | local data_w =io.open(fp,"w+")
290 | data_w:write(serialize({}))
291 | data_w:close()
292 | data_str = "{}"
293 | end
294 | -- config设置
295 | local data_reader_table = unserialize(data_str)
296 | local select_table = {}
297 | for k,v in pairs(data_reader_table) do
298 | table.insert(select_table,v.name)
299 | end
300 | dialog_config1[4].items = select_table
301 | dialog_config1[4].value = dialog_config1[4].items[1]
302 | -- 初始化层数
303 | local buttons1 = "Delete preset"
304 | while buttons1=="Delete preset" do
305 | buttons1,results1 = aegisub.dialog.display(dialog_config1,{"New","Open preset","Delete preset","Cancel"})
306 | if buttons1=="Delete preset" then
307 | local delete_name = results1["selete"]
308 | for k,v in pairs(data_reader_table) do
309 | if v.name == delete_name then
310 | table.remove(data_reader_table,k)
311 | local data_w = io.open(fp, "w+")
312 | data_w:write(serialize(data_reader_table))
313 | data_w:close()
314 | local after_select_table = {}
315 | for k,v in pairs(data_reader_table) do
316 | table.insert(after_select_table,v.name)
317 | end
318 | dialog_config1[4].items = after_select_table
319 | dialog_config1[4].value = dialog_config1[4].items[1]
320 | end
321 | end
322 | end
323 | end
324 | if buttons1 == "New" then
325 | local border_num = results1["border_num"]
326 | if border_num > 0 then
327 | -- 主体
328 | -- 生成dialog
329 | local dialog_config2=get_border_setting_config(border_num, conf_template)
330 | buttons2,results2 =aegisub.dialog.display(dialog_config2,{"Apply to selected rows","Apply to style", "save as", "Cancel"})
331 | if buttons2 == "Apply to selected rows" then
332 | local meta, styles = karaskel.collect_head(subs, false)
333 | local border_data = get_borderdata_form_results2(border_num,results2)
334 | apply_to_selected_rows(subs, sel, meta, styles, tags_template, border_data)
335 | elseif buttons2 == "Apply to style" then
336 | local meta, styles = karaskel.collect_head(subs, false)
337 | local border_data = get_borderdata_form_results2(border_num,results2)
338 | apply_to_style(subs, sel, meta, styles, tags_template, border_data)
339 | elseif buttons2 == "save as" then
340 | save_as(dialog_config3,data_reader_table,border_num,fp)
341 | else
342 | aegisub.debug.out("已取消!")
343 | end
344 | else
345 | aegisub.debug.out("层数应大于0!")
346 | end
347 | elseif buttons1 == "Open preset" then
348 | local yushe_name = results1["selete"]
349 | local data_table_yushe = ""
350 | for k,v in pairs(data_reader_table) do
351 | if v.name == yushe_name then
352 | data_table_yushe = v.data
353 | break
354 | else
355 | data_table_yushe = ""
356 | end
357 | end
358 | if data_table_yushe ~= "" then
359 | -- 主体
360 | -- 生成dialog
361 | local dialog_config2 = get_border_setting_config(data_table_yushe, conf_template)
362 | buttons2, results2 = aegisub.dialog.display(dialog_config2, {"Apply to selected rows","Apply to style", "save as", "Cancel"})
363 | if buttons2 == "Apply to selected rows" then
364 | local meta, styles = karaskel.collect_head(subs, false)
365 | local border_data = get_borderdata_form_results2(#data_table_yushe,results2)
366 | apply_to_selected_rows(subs, sel, meta, styles, tags_template, border_data)
367 | elseif buttons2 == "Apply to style" then
368 | local meta, styles = karaskel.collect_head(subs, false)
369 | local border_data = get_borderdata_form_results2(#data_table_yushe,results2)
370 | apply_to_style(subs, sel, meta, styles, tags_template, border_data)
371 | elseif buttons2 == "save as" then
372 | save_as(dialog_config3,data_reader_table,#data_table_yushe,fp)
373 | else
374 | aegisub.debug.out("已取消!")
375 | end
376 | else
377 | aegisub.debug.out("不可打开空预设!")
378 | end
379 | else
380 | aegisub.debug.out("已取消!")
381 | end
382 | end
383 |
384 | TLL_macros = {
385 | {
386 | script_name = "多重边框v1.2",
387 | script_description = "设置多重边框",
388 | entry = function(subs,sel) border(subs,sel) end,
389 | validation = false
390 | },
391 | }
392 |
393 | for i = 1, #TLL_macros do
394 | aegisub.register_macro(script_name.." "..script_version.."/"..TLL_macros[i]["script_name"], TLL_macros[i]["script_description"], TLL_macros[i]["entry"], TLL_macros[i]["validation"])
395 | end
--------------------------------------------------------------------------------
/小工具集合v3.0.lua:
--------------------------------------------------------------------------------
1 | local tr = aegisub.gettext
2 | script_name = tr("小工具合集")
3 | script_description = tr("用于处理你不知道从哪里找来的混搭歌词")
4 | script_author = "拉姆0v0"
5 | script_version = "v3.0"
6 |
7 | function text_processing(subs,sel)
8 | local line_storage1={}
9 | local line_storage2={}
10 | local line_storageblank={}
11 | local line_storagetext={}
12 | local num=#sel
13 | for i = 1, num do
14 | if (subs[sel[i]].text=="" or string.match(subs[sel[i]].text,"^[ ]*$") or string.match(subs[sel[i]].text,"^[ ]*$")) then
15 | table.insert(line_storageblank,subs[sel[i]])
16 | else
17 | table.insert(line_storagetext,subs[sel[i]])
18 | end
19 | end
20 | for i,v in ipairs(line_storagetext) do
21 | if i%2==1 then
22 | table.insert(line_storage1,v)
23 | else
24 | table.insert(line_storage2,v)
25 | end
26 | end
27 | for i = 1, num do
28 | aegisub.progress.set(i/num*100)
29 | if i<=#line_storagetext then
30 | if i<=(#line_storagetext/2) then
31 | subs[sel[i]]=line_storage1[i]
32 | else
33 | subs[sel[i]]=line_storage2[i-(#line_storagetext/2)]
34 | end
35 | else
36 | subs[sel[i]]=line_storageblank[i-#line_storagetext]
37 | end
38 | end
39 | aegisub.debug.out("已将中日歌词分开,空白行或者空格行位于最下方")
40 | end
41 |
42 | function full_to_half(subs,sel)
43 | for i = 1, #sel do
44 | aegisub.progress.set(i/#sel*100)
45 | local subp = subs[sel[i]]
46 | subp.text = string.gsub(subp.text, " ", " ")
47 | subs[sel[i]] = subp
48 | end
49 | end
50 |
51 | function delete_k(subs,sel)
52 | for i = 1, #sel do
53 | aegisub.progress.set(i/#sel*100)
54 | local subp = subs[sel[i]]
55 | subp.text = string.gsub(subp.text, "{\\k[1-9]%d*}", "")
56 | subs[sel[i]] = subp
57 | end
58 | end
59 |
60 | dialog_config1=
61 | {
62 |
63 | [1]={class="label",x=0,y=1,label="第二个音节可以设置为空,即只在第一个音节出设置内联特效"},
64 |
65 | [2]={class="label",x=0,y=1,label=""},
66 | [3]={class="label",x=0,y=2,label="在第一个音节设置内联特效"},
67 | [4]={class="edit",name="在第一个音节设置内联特效",x=1,y=2,width=1,height=1,items={},value="\\-A"},
68 |
69 | [5]={class="label",x=0,y=3,label=""},
70 | [6]={class="label",x=0,y=4,label="在第二个音节设置内联特效"},
71 | [7]={class="edit",name="在第二个音节设置内联特效",x=1,y=4,width=1,height=1,items={},value="\\-B"},
72 |
73 | [8]={class="label",x=0,y=5,label=""},
74 | [9]={class="label",x=0,y=6,label="小提示:按OK做处理后,可以ctrl-z撤销本处理,还有ctrl-y反撤销"},
75 |
76 | }
77 |
78 | function add_fx(subs,sel)
79 | buttons,results =aegisub.dialog.display(dialog_config1,{"OK","Cancel"})
80 | if buttons=="OK" then
81 | local fx1 = results["在第一个音节设置内联特效"]
82 | local fx2 = results["在第二个音节设置内联特效"]
83 | for i = 1, #sel do
84 | aegisub.progress.set(i/#sel*100)
85 | local subp = subs[sel[i]]
86 | local t = string.match(subp.text, "^[^}]+")
87 | subp.text = string.gsub(subp.text, "[}]", fx2.."}",2)
88 | subp.text = string.gsub(subp.text, "^[^}]+", t..fx1)
89 | subs[sel[i]] = subp
90 | end
91 | end
92 | end
93 |
94 | function hexstring2number(hexstring, len)
95 | if not len or len > 8 then return end
96 |
97 | local hexbyte = {}
98 | for i = 1, len do
99 | hexbyte[i] = string.byte(hexstring, i)
100 | end
101 |
102 | local detection=0x10
103 | local num_string = {}
104 | for i = 1, len do
105 | if hexbyte[i]>=detection then
106 | num_string[i]=string.format("%x", hexbyte[i])
107 | else
108 | num_string[i]="0"..string.format("%x", hexbyte[i])
109 | end
110 | end
111 |
112 |
113 | local num = tonumber("0x"..num_string[1]..num_string[2]..num_string[3]..num_string[4])
114 | return num
115 | end
116 |
117 | function get_png_size(path)
118 | local png_file = io.open(path, "rb")
119 | local data = png_file:read("*all")
120 |
121 |
122 | -- 保证png至少有37个字节,因为包含文件头等起码就超过这个数字了
123 | if #data < 37 then return end
124 |
125 | -- 文件头的相关信息请百度
126 | local png_header_info = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52}
127 | for i = 1, #png_header_info do
128 | if (string.byte(data, i) ~= png_header_info[i]) then
129 | return
130 | end
131 | end
132 |
133 | -- 这四个字节表示png的宽度
134 | data = string.sub(data, #png_header_info + 1)
135 | local width = hexstring2number(data, 4)
136 |
137 | data = string.sub(data, 5)
138 | local height = hexstring2number(data, 4)
139 |
140 | return width, height
141 | end
142 |
143 | --dialog_config2=
144 | -- {
145 | -- [1]={class="label",x=0,y=0,label="1.使用此功能时,请确认你的aegisub有安装VSFilterMod滤镜。\n2.VSFilterMod只支持24或32位带或不带透明通道的真彩色png格式的图片!\n3.该功能导入的图片无法修改显示大小,请选择大小合适的png格式图片!\nps:你的图片文件名如果过于诡异可能会失败,例如“7J`%TFT)K9]JUL3KF`@26$Y”之类的\n\nby 拉姆0v0"},
146 | -- }
147 |
148 | function pngmassage_test(subs,sel)
149 | filename = aegisub.dialog.open('请选择一张png图片', '', '','Text files (.png)|*.png', false, true)
150 | if filename==nil then
151 | return
152 | end
153 | local x,y=get_png_size(filename)
154 | local size_x,size_y
155 | for i=1,#subs do
156 | if subs[i].key == "PlayResX" then
157 | size_x=subs[i].value
158 | end
159 | if subs[i].key == "PlayResY" then
160 | size_y=subs[i].value
161 | end
162 | if subs[i].class == "dialogue" then
163 | local l=subs[i]
164 | l.start_time=0
165 | l.end_time=5000
166 | if size_x==nil then
167 | aegisub.debug.out("请打开一个视频或者使用空白视频,以获取ass脚本分辨率信息!!!!!")
168 | return
169 | end
170 | local text1="{\\p1\\an2\\bord0\\shad0\\1img("..filename..")\\pos("..tostring(tonumber(size_x)/2)..","..tostring(tonumber(size_y)-50)..")}m 0 0 l "..tostring(x).." 0 l "..tostring(x).." "..tostring(y).." l 0 "..tostring(y)
171 | l.text=text1
172 | l.effect=""
173 | l.style="Default"
174 | l.comment = false
175 | subs.insert(i,l)
176 | break
177 | end
178 | end
179 | aegisub.debug.out("已完成!!!!!!\n\n文件路径:"..filename.."\n图片分辨率:"..tostring(x).."x"..tostring(y).."\n\n若显示为白色空白:\n1.请检查是否安装了最新版本的VSFilterMod\n2.请检查你所选择的图片名称是否存在非法字符,可以试着修改文件名为比较正常的文件名\n\nby 拉姆0v0")
180 | end
181 |
182 | TLL_macros = {
183 | {
184 | script_name = "中日歌词分离v2.0",
185 | script_description = "用于将中日穿插排版的歌词分离开来",
186 | entry = function(subs,sel) text_processing(subs,sel) end,
187 | validation = false
188 | },
189 | {
190 | script_name = "全角空格 to 半角空格",
191 | script_description = "用于将歌词中的全角空格转换为半角空格",
192 | entry = function(subs,sel) full_to_half(subs,sel) end,
193 | validation = false
194 | },
195 | {
196 | script_name = "删除所选行k标签",
197 | script_description = "用于删除所选行k标签",
198 | entry = function(subs,sel) delete_k(subs,sel) end,
199 | validation = false
200 | },
201 | {
202 | script_name = "一键添加内联特效标签",
203 | script_description = "用于添加内联特效标签",
204 | entry = function(subs,sel) add_fx(subs,sel) end,
205 | validation = false
206 | },
207 | {
208 | script_name = "一键插入图片v2.0",
209 | script_description = "免去调整图片大小的功能,一键插入图片",
210 | entry = function(subs,sel) pngmassage_test(subs,sel) end,
211 | validation = false
212 | },
213 | }
214 |
215 | for i = 1, #TLL_macros do
216 | aegisub.register_macro(script_name.." "..script_version.."/"..TLL_macros[i]["script_name"], TLL_macros[i]["script_description"], TLL_macros[i]["entry"], TLL_macros[i]["validation"])
217 | end
218 |
--------------------------------------------------------------------------------
/查闪轴1.0.lua:
--------------------------------------------------------------------------------
1 | local tr = aegisub.gettext
2 | script_name = tr("轴检查")
3 | script_description = tr("脱裤子放屁工具")
4 | script_author = "拉姆0v0"
5 | script_version = "v1.0"
6 |
7 | dialog_config1=
8 | {
9 |
10 | [1]={class="label",x=0,y=0,label="可自由设置检查的时间间隔"},
11 | [2]={class="label",x=0,y=1,label="设置要检查的前后之间的时间间隔:"},
12 | [3]={class="intedit",name="时间间隔",x=1,y=1,width=1,height=1,items={},value=300,hint="请输入整数"},
13 |
14 | }
15 | function text_processing(subs,sel)
16 | buttons,results =aegisub.dialog.display(dialog_config1,{"OK","Cancel"})
17 | if buttons=="OK" then
18 | local timex = results["时间间隔"]
19 | local stylen={}
20 | local stylenline={}
21 | local shannum={}
22 | for i=1,#subs do
23 | if subs[i].class == "dialogue" and subs[i].comment == false then
24 | if #stylen == 0 then
25 | table.insert(stylen,subs[i].style)
26 | table.insert(shannum,0)
27 | table.insert(stylenline,{i})
28 | else
29 | local isin=0
30 | for j=1,#stylen do
31 | if subs[i].style == stylen[j] then
32 | table.insert(stylenline[j],i)
33 | isin=1
34 | break
35 | end
36 | end
37 | if isin==0 then
38 | table.insert(stylen,subs[i].style)
39 | table.insert(shannum,0)
40 | table.insert(stylenline,{i})
41 | end
42 | end
43 | end
44 | end
45 | --查找闪轴部分
46 | aegisub.debug.out("在不同样式中,前后相差小于"..tostring(timex).."毫秒的情况:\n\n")
47 | for i=1,#stylen do
48 | aegisub.debug.out(stylen[i]..":")
49 | for j=1,(#stylenline[i]-1) do
50 | if (subs[stylenline[i][j+1]].start_time-subs[stylenline[i][j]].end_time <= timex) and (subs[stylenline[i][j+1]].start_time-subs[stylenline[i][j]].end_time > 0) then
51 | local subp = subs[stylenline[i][j]]
52 | subp.actor = "(该样式的此行与下一行之间的间隔小于"..tostring(timex).."毫秒,请调整)"..subp.actor
53 | subs[stylenline[i][j]] = subp
54 |
55 |
56 | shannum[i]=shannum[i]+1
57 | end
58 | end
59 | aegisub.debug.out(tostring(shannum[i]).."处\n")
60 | end
61 | aegisub.debug.out("\n具体位置已标记在说话人一栏,请查看。\n\nby 拉姆0v0")
62 | end
63 | end
64 |
65 |
66 | TLL_macros = {
67 | {
68 | script_name = "检查闪轴",
69 | script_description = "检查闪轴",
70 | entry = function(subs,sel) text_processing(subs,sel) end,
71 | validation = false
72 | },
73 |
74 | }
75 |
76 | for i = 1, #TLL_macros do
77 | aegisub.register_macro(script_name.." "..script_version.."/"..TLL_macros[i]["script_name"], TLL_macros[i]["script_description"], TLL_macros[i]["entry"], TLL_macros[i]["validation"])
78 | end
79 |
--------------------------------------------------------------------------------
/歌词处理小插件2.0.lua:
--------------------------------------------------------------------------------
1 | local tr = aegisub.gettext
2 | script_name = tr("歌词处理")
3 | script_description = tr("用于处理你不知道从哪里找来的混搭歌词")
4 | script_author = "拉姆0v0"
5 | script_version = "2.0"
6 |
7 | function text_processing(subs,sel)
8 | local line_storage1={}
9 | local line_storage2={}
10 | local line_storageblank={}
11 | local line_storagetext={}
12 | local num=#sel
13 | for i = 1, num do
14 | if (subs[sel[i]].text=="" or string.match(subs[sel[i]].text,"^[ ]*$") or string.match(subs[sel[i]].text,"^[ ]*$")) then
15 | table.insert(line_storageblank,subs[sel[i]])
16 | else
17 | table.insert(line_storagetext,subs[sel[i]])
18 | end
19 | end
20 | for i,v in ipairs(line_storagetext) do
21 | if i%2==1 then
22 | table.insert(line_storage1,v)
23 | else
24 | table.insert(line_storage2,v)
25 | end
26 | end
27 | for i = 1, num do
28 | aegisub.progress.set(i/num*100)
29 | if i<=#line_storagetext then
30 | if i<=(#line_storagetext/2) then
31 | subs[sel[i]]=line_storage1[i]
32 | else
33 | subs[sel[i]]=line_storage2[i-(#line_storagetext/2)]
34 | end
35 | else
36 | subs[sel[i]]=line_storageblank[i-#line_storagetext]
37 | end
38 | end
39 | aegisub.debug.out("已将中日歌词分开,空白行或者空格行位于最下方")
40 | end
41 |
42 | function full_to_half(subs,sel)
43 | for i = 1, #sel do
44 | aegisub.progress.set(i/#sel*100)
45 | local subp = subs[sel[i]]
46 | subp.text = string.gsub(subp.text, " ", " ")
47 | subs[sel[i]] = subp
48 | end
49 | end
50 |
51 | function delete_k(subs,sel)
52 | for i = 1, #sel do
53 | aegisub.progress.set(i/#sel*100)
54 | local subp = subs[sel[i]]
55 | subp.text = string.gsub(subp.text, "{\\k[1-9]%d*}", "")
56 | subs[sel[i]] = subp
57 | end
58 | end
59 |
60 | dialog_config=
61 | {
62 |
63 | [1]={class="label",x=0,y=1,label="第二个音节可以设置为空,即只在第一个音节出设置内联特效"},
64 |
65 | [2]={class="label",x=0,y=1,label=""},
66 | [3]={class="label",x=0,y=2,label="在第一个音节设置内联特效"},
67 | [4]={class="edit",name="在第一个音节设置内联特效",x=1,y=2,width=1,height=1,items={},value="\\-A"},
68 |
69 | [5]={class="label",x=0,y=3,label=""},
70 | [6]={class="label",x=0,y=4,label="在第二个音节设置内联特效"},
71 | [7]={class="edit",name="在第二个音节设置内联特效",x=1,y=4,width=1,height=1,items={},value="\\-B"},
72 |
73 | [8]={class="label",x=0,y=5,label=""},
74 | [9]={class="label",x=0,y=6,label="小提示:按OK做处理后,可以ctrl-z撤销本处理,还有ctrl-y反撤销"},
75 |
76 | }
77 |
78 | function add_fx(subs,sel)
79 | buttons,results =aegisub.dialog.display(dialog_config,{"OK","Cancel"})
80 | if buttons=="OK" then
81 | local fx1 = results["在第一个音节设置内联特效"]
82 | local fx2 = results["在第二个音节设置内联特效"]
83 | for i = 1, #sel do
84 | aegisub.progress.set(i/#sel*100)
85 | local subp = subs[sel[i]]
86 | local t = string.match(subp.text, "^[^}]+")
87 | subp.text = string.gsub(subp.text, "[}]", fx2.."}",2)
88 | subp.text = string.gsub(subp.text, "^[^}]+", t..fx1)
89 | subs[sel[i]] = subp
90 | end
91 | end
92 | end
93 |
94 | TLL_macros = {
95 | {
96 | script_name = "中日分离2.0",
97 | script_description = "用于将中日穿插排版的歌词分离开来",
98 | entry = function(subs,sel) text_processing(subs,sel) end,
99 | validation = false
100 | },
101 | {
102 | script_name = "全角空格 to 半角空格",
103 | script_description = "用于将歌词中的全角空格转换为半角空格",
104 | entry = function(subs,sel) full_to_half(subs,sel) end,
105 | validation = false
106 | },
107 | {
108 | script_name = "删除所选行k标签",
109 | script_description = "用于删除所选行k标签",
110 | entry = function(subs,sel) delete_k(subs,sel) end,
111 | validation = false
112 | },
113 | {
114 | script_name = "一键添加内联特效",
115 | script_description = "用于添加内敛特效",
116 | entry = function(subs,sel) add_fx(subs,sel) end,
117 | validation = false
118 | },
119 | }
120 |
121 | for i = 1, #TLL_macros do
122 | aegisub.register_macro(script_name.." "..script_version.."/"..TLL_macros[i]["script_name"], TLL_macros[i]["script_description"], TLL_macros[i]["entry"], TLL_macros[i]["validation"])
123 | end
124 |
--------------------------------------------------------------------------------
/给字幕两侧添加图片.lua:
--------------------------------------------------------------------------------
1 | local tr = aegisub.gettext
2 | script_name = tr("给选中的字幕两侧添加图片v1.0")
3 | script_description = tr("给选中的字幕两侧添加图片v1.0")
4 | script_author = "拉姆0v0"
5 | script_version = "v1.0"
6 |
7 | function hexstring2number(hexstring, len)
8 | if not len or len > 8 then return end
9 |
10 | local hexbyte = {}
11 | for i = 1, len do
12 | hexbyte[i] = string.byte(hexstring, i)
13 | end
14 |
15 | local detection=0x10
16 | local num_string = {}
17 | for i = 1, len do
18 | if hexbyte[i]>=detection then
19 | num_string[i]=string.format("%x", hexbyte[i])
20 | else
21 | num_string[i]="0"..string.format("%x", hexbyte[i])
22 | end
23 | end
24 |
25 |
26 | local num = tonumber("0x"..num_string[1]..num_string[2]..num_string[3]..num_string[4])
27 | return num
28 | end
29 |
30 | function get_png_size(path)
31 | local png_file = io.open(path, "rb")
32 | local data = png_file:read("*all")
33 |
34 |
35 | -- 保证png至少有37个字节,因为包含文件头等起码就超过这个数字了
36 | if #data < 37 then return end
37 |
38 | -- 文件头的相关信息请百度
39 | local png_header_info = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52}
40 | for i = 1, #png_header_info do
41 | if (string.byte(data, i) ~= png_header_info[i]) then
42 | return
43 | end
44 | end
45 |
46 | -- 这四个字节表示png的宽度
47 | data = string.sub(data, #png_header_info + 1)
48 | local width = hexstring2number(data, 4)
49 |
50 | data = string.sub(data, 5)
51 | local height = hexstring2number(data, 4)
52 |
53 | return width, height
54 | end
55 |
56 | dialog_config2=
57 | {
58 |
59 | [1]={class="label",x=0,y=0,label="请设置图片的出现位置和设定纵向偏移"},
60 | [2]={class="label",x=0,y=2,label="设置纵向偏移-->>"},
61 | [3]={class="intedit",name="图片纵向偏移",x=1,y=2,width=1,height=1,items={},value=0,hint="请输入整数"},
62 | [4]={class="label",x=0,y=3,label="(可忽略,不可为空。正数为下移,负数为上移)"},
63 |
64 | [5]={class="label",x=0,y=5,label="设置图片出现位置(至少选择一个)"},
65 | [6]={class="label",x=0,y=6,label="字幕左侧-->>"},
66 | [7]={class="checkbox",name="字幕左侧",x=1,y=6,width=1,height=1,items={},value=true},
67 | [8]={class="label",x=0,y=7,label="字幕右侧-->>"},
68 | [9]={class="checkbox",name="字幕右侧",x=1,y=7,width=1,height=1,items={},value=true},
69 |
70 | }
71 |
72 | function pngmassage_test(subs,sel)
73 | filename = aegisub.dialog.open('请选择一张png图片', '', '','Text files (.png)|*.png', false, true)
74 | if filename==nil then
75 | return
76 | end
77 | buttons,results =aegisub.dialog.display(dialog_config2,{"OK","Cancel"})
78 | if buttons=="OK" then
79 | local ymove = results["图片纵向偏移"]
80 | local lc = results["字幕左侧"]
81 | local rc = results["字幕右侧"]
82 | local x,y=get_png_size(filename)
83 | local video_size_x,video_size_y
84 | for i=1,#subs do
85 | if subs[i].key == "PlayResX" then
86 | video_size_x=subs[i].value
87 | end
88 | if subs[i].key == "PlayResY" then
89 | video_size_y=subs[i].value
90 | end
91 | end
92 |
93 | for i=1,#sel do
94 | local l=subs[sel[i]]
95 | local alignx
96 | local posy
97 | for i=1,#subs do
98 | if (subs[i].class == "style" and subs[i].name == l.style) then
99 | style_table = subs[i]
100 | end
101 | end
102 | width, height, descent, ext_lead = aegisub.text_extents(style_table, l.text)
103 | if style_table.align == 2 then
104 | posy=video_size_y-style_table.margin_t
105 | else
106 | posy=style_table.margin_t+height
107 | end
108 | local textl="{\\p1\\an2\\bord0\\shad0\\1img("..filename..")\\pos("..tostring(tonumber(video_size_x)/2-width/2-x/2-10)..","..tostring(posy+ymove)..")}m 0 0 l "..tostring(x).." 0 l "..tostring(x).." "..tostring(y).." l 0 "..tostring(y)
109 | local textr="{\\p1\\an2\\bord0\\shad0\\1img("..filename..")\\pos("..tostring(tonumber(video_size_x)/2+width/2+x/2+10)..","..tostring(posy+ymove)..")}m 0 0 l "..tostring(x).." 0 l "..tostring(x).." "..tostring(y).." l 0 "..tostring(y)
110 | if lc==true then
111 | l.text=textl
112 | subs.append(l)
113 | end
114 | if rc==true then
115 | l.text=textr
116 | subs.append(l)
117 | end
118 | if lc==false and rc==false then
119 | aegisub.debug.out("请至少勾选左右中的一侧添加图片!")
120 | return
121 | end
122 | end
123 | aegisub.debug.out("已完成!!!!!!\n\n文件路径:"..filename.."\n图片分辨率:"..tostring(x).."x"..tostring(y).."\n\n若显示为白色空白:\n1.请检查是否安装了最新版本的VSFilterMod\n2.请检查你所选择的图片名称是否存在非法字符,可以试着修改文件名为比较正常的文件名\n\n提示:若图片生成位置不理想,需要调整纵向偏移,可以ctrl-z撤销本次处理重新设置纵向偏移,还有ctrl-y反撤销\n\nby 拉姆0v0")
124 | end
125 | end
126 |
127 |
128 | aegisub.register_macro(script_name, script_description, pngmassage_test)
129 |
--------------------------------------------------------------------------------
/获取up主视频数据v0.9.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/获取up主视频数据v0.9.zip
--------------------------------------------------------------------------------
/轴校工具v5.3修复bug2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dumpling233/aegisub_Automation/9aa12b55fca74410584e59d176c488aba1464f81/轴校工具v5.3修复bug2.zip
--------------------------------------------------------------------------------