[Script Info] ScriptType: v4.00+ PlayResX: 1920 PlayResY: 1080 LayoutResX: 1920 LayoutResY: 1080 WrapStyle: 2 ScaledBorderAndShadow: yes YCbCr Matrix: TV.709 Original Script: 極彩花夢 Language: JPN [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Ex-invisible,请勿安装此子集化字体 - niA5qkn4,60,&H00FFFFFF,&H00FFFFFF,&H00FFFFFF,&H00FFFFFF,0,0,0,0,100,100,0,0,1,0,0,7,0,0,0,1 Style: Ex-effects,请勿安装此子集化字体 - niA5qkn4,60,&H00FFFFFF,&H00FFFFFF,&H00FFFFFF,&H00FFFFFF,0,0,0,0,100,100,0,0,1,0,0,7,0,0,0,1 Style: Sx-zh,请勿安装此子集化字体 - Gc1VJRKb,62,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,100,100,0,0,1,2.42,0,2,0,0,65,1 Style: Sx-jp,请勿安装此子集化字体 - xjxWu0dc,64,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,99,100,0.5,0,1,2.42,0,2,0,0,15,128 Style: Rx-annotation,请勿安装此子集化字体 - p5ZdRqSJ,36,&H1E000000,&H00FFFFFF,&H1EFFFFFF,&H50FFFFFF,0,0,0,0,100,100,0,0,3,1,0,9,70,70,10,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁字幕说明▁▁▁▁▁▁▁▁▁▁ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔字幕说明▔▔▔▔▔▔▔▔▔▔ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁署名▁▁▁▁▁▁▁▁▁▁ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔署名▔▔▔▔▔▔▔▔▔▔ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁特殊效果▁▁▁▁▁▁▁▁▁▁ Comment: 0,0:03:12.76,0:03:16.76,Ex-effects,,0,0,0,karaoke,{\an7\p1\pos(0,0)\1c&HF0EFFF&}m 62 60 l 230 60 l 230 520 l 62 520 Comment: 0,0:03:12.76,0:03:16.76,Ex-effects,,0,0,0,karaoke,{\an5\pos(158,312)\1c&H020204&\fn@方正准圆_GBK\frz-90\fs160\fsp10\be1}已认证 Comment: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,karaoke,{\an7\p1\pos(0,0)\1c&HCAFCFE&\blur4}m 798 11 l 984 70 l 710 750 l 560 667 Comment: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,karaoke,{\fn请勿安装此子集化字体 - 3vuiO7gZ\1c&H6763D6&\3c&H020202&\b1\bord2\be1\fs180\org(-4000,-2000)\pos(1160,-1060)\frz-18\t(101,101,\frz-16.8)\t(184,184,\frz-15.5)\t(268,268,\frz-13.8)}抚 Comment: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,karaoke,{\fn请勿安装此子集化字体 - 3vuiO7gZ\1c&H6763D6&\3c&H020202&\b1\bord2\be1\fs180\org(-4000,-2000)\pos(1210,-1060)\alpha&HFF&\frz-18\t(101,101,\alpha&H00&)\t(184,184,\frz-16.8)\t(268,268,\frz-15.15)}| Comment: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,karaoke,{\fn请勿安装此子集化字体 - 3vuiO7gZ\1c&H6763D6&\3c&H020202&\b1\bord2\be1\fs180\org(-4000,-2000)\pos(1160,-1060)\alpha&HFF&\frz-18\t(268,268,\frz-16.5)}{\fscx30\alpha&HFF&}.{\fscx\t(184,184,\alpha&H00&)}子 Comment: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,karaoke,{\fn请勿安装此子集化字体 - 3vuiO7gZ\1c&H6763D6&\3c&H020202&\b1\bord2\be1\fs180\org(-4000,-2000)\pos(1240,-1050)\alpha&HFF&\frz-17.8\t(268,268,\alpha&H00&)}| Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔特殊效果▔▔▔▔▔▔▔▔▔▔ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁喵▁▁▁▁▁▁▁▁▁▁ Comment: 0,0:00:00.00,0:00:00.00,Ex-effects,AME,0,0,0,code line,fxgroup.IGNORE = false if string.lower(line.actor) == "fx-chs" and not ksy.sub(meta["language"], 1, 3):lower() == "chs" then fxgroup.IGNORE = true elseif string.lower(line.actor) == "fx-cht" and not ksy.sub(meta["language"], 1, 3):lower() == "cht" then fxgroup.IGNORE = true elseif string.lower(line.actor) == "fx-zh" and not ksy.sub(meta["language"], 1, 2):lower() == "ch" then fxgroup.IGNORE = true elseif string.lower(line.actor) == "fx-en" and not ksy.sub(meta["language"], 1, 3):lower() == "eng" then fxgroup.IGNORE = true elseif config.JPN_only then fxgroup.IGNORE = true end fxgroup.eff = not fxgroup.IGNORE if fxgroup.eff then fxgroup.eff = re.find(orgline.text, "![^!]+!") ~= nil and line.actor ~= "no-eff" end Comment: 0,0:00:00.00,0:00:00.00,Ex-effects,AME,0,0,0,template line notext fxgroup IGNORE,!""! Comment: 0,0:00:00.00,0:00:00.00,Ex-effects,AME,0,0,0,template line notext fxgroup eff,!ksy.func(function() line.layer = orgline.layer _G.flag = nil local content = orgline.text local effects = re.find(content, "\\{[^\\}]+\\}") if effects ~= nil then content = re.sub(content, "\\{[^\\}]+\\}", "{}") end if effects ~= nil then for _, effect in ipairs(effects) do effect["str"] = re.sub(effect["str"], "\x21[^\x21]+\x21", function(_eff) local value = ksy.eval(ksy.sub(_eff, 2, -2)) return type(value) == "number" and tostring(value) or value end) end content = re.sub(content, "\\{\\}", function() return table.remove(effects, 1)["str"] end) end return content end).run()! Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,cache,0,0,0,code once,styles = {} function addCache(style, styleref) styles[style] = styleref return "" end Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,cache,0,0,0,code line all,fxgroup.cache = line.actor == "fx-cache" Comment: 0,0:00:00.00,0:00:00.00,Sx-jp,cache,0,0,0,template line fxgroup cache,!addCache(line.styleref.name,line.styleref)! Comment: 0,0:00:00.00,0:00:00.00,Sx-zh,cache,0,0,0,template line fxgroup cache,!addCache(line.styleref.name,line.styleref)! Comment: 0,0:00:00.00,0:00:00.00,Sx-jp,fx-cache,0,0,0,karaoke, Comment: 0,0:00:00.00,0:00:00.00,Sx-zh,fx-cache,0,0,0,karaoke, Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,角色配置,0,0,0,code once,characters = {["Basic"]="{\\blur2}", ["津田あかね"]="{\\3c&H0312D2&}", ["撫子"]="{\\3c&HC10494&}", ["伊藤さん"]="{\\3c&H0256B4&}", ["Blank"]="{\\3c&H974C06&}"} Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,Project.Paulownia,0,0,0,code once,--[[by HanaCream]] aegisub = _G.aegisub pairs = _G.pairs ipairs = _G.ipairs type = _G.type tonumber = _G.tonumber tostring = _G.tostring next = _G.next select = _G.select pcall = _G.pcall unpack = _G.unpack os = _G.os require = _G.require load = _G.load assert = _G.assert re = require("re") string = require("string") table = require("table") util = require("aegisub.util") karaskel = require("karaskel") unicode = require("unicode") json = require("json") ffi = require("ffi") gseed = os.clock() _G.retime = retime _G.relayer = relayer _G.maxloop = maxloop _G.restyle = restyle _G.meta = meta pcall(function() ffi.cdef([[ enum{CP_UTF8 = 65001}; enum{MM_TEXT = 1}; enum{TRANSPARENT = 1}; enum{PT_MOVETO = 0x6,PT_LINETO = 0x2,PT_BEZIERTO = 0x4,PT_CLOSEFIGURE = 0x1}; enum{FW_NORMAL = 400,FW_BOLD = 700}; enum{DEFAULT_CHARSET = 1}; enum{OUT_TT_PRECIS = 4}; enum{CLIP_DEFAULT_PRECIS = 0}; enum{ANTIALIASED_QUALITY = 4}; enum{DEFAULT_PITCH = 0x0}; enum{FF_DONTCARE = 0x0}; ]]) end) ffi.cdef([[ typedef unsigned int UINT; typedef unsigned long DWORD; typedef DWORD* LPDWORD; typedef const char* LPCSTR; typedef const wchar_t* LPCWSTR; typedef wchar_t* LPWSTR; typedef char* LPSTR; typedef void* HANDLE; typedef HANDLE HDC; typedef int BOOL; typedef BOOL* LPBOOL; typedef unsigned int size_t; typedef HANDLE HFONT; typedef HANDLE HGDIOBJ; typedef long LONG; typedef wchar_t WCHAR; typedef unsigned char BYTE; typedef BYTE* LPBYTE; typedef int INT; typedef long LPARAM; typedef struct{LONG cx;LONG cy;}SIZE, *LPSIZE; typedef struct{LONG left;LONG top;LONG right;LONG bottom;}RECT; typedef const RECT* LPCRECT; typedef struct{LONG x;LONG y;}POINT, *LPPOINT; BOOL AbortPath(HDC); BOOL GetTextExtentPoint32W(HDC, LPCWSTR, int, LPSIZE); BOOL BeginPath(HDC); BOOL ExtTextOutW(HDC, int, int, UINT, LPCRECT, LPCWSTR, UINT, const INT*); BOOL EndPath(HDC); BOOL DeleteObject(HGDIOBJ); BOOL DeleteDC(HDC); int MultiByteToWideChar(UINT, DWORD, LPCSTR, int, LPWSTR, int); int SetMapMode(HDC, int); int SetBkMode(HDC, int); int GetPath(HDC, LPPOINT, LPBYTE, int); HDC CreateCompatibleDC(HDC); HFONT CreateFontW(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCWSTR); HGDIOBJ SelectObject(HDC, HGDIOBJ); size_t wcslen(const wchar_t*); ]]) ksy = { t1 = "\x7D", --[[方便使用花括号 } ]] t2 = "\x7B", --[[方便使用花括号 { ]] --[[@param n integer 帧数]] --[[@return integer]] fdur = function(n) --[[根据帧数获取时间长度]] return aegisub.ms_from_frame(aegisub.frame_from_ms(line.start_time) + n) - line.start_time end, --[[@return integer]] flen = function() --[[当前行总帧数]] return aegisub.frame_from_ms(line.end_time - line.start_time) - 1 end, --[[@param fstart integer|nil 开始帧数]] --[[@param fend integer|nil 结束帧数]] retime = function(fstart, fend) --[[修改行时间]] fstart = fstart or 0 fend = fend or ksy.flen() fstart = fstart < 0 and (ksy.flen() + fstart) or fstart fend = fend < 0 and (ksy.flen() + fend) or fend retime("preline", ksy.fdur(fstart), ksy.fdur(fend)) return "" end, --[[@param str string HEX(#FA4276)或ASS(&H7642FA&)颜色代码]] --[[@return string]] c2c = function(str) --[[HEX颜色代码与ASS颜色代码互转]] local color = "" if re.find(str, "#") ~= nil then match = re.match(str, "#([A-Za-z0-9]{2})([A-Za-z0-9]{2})([A-Za-z0-9]{2})") color = "&H" .. match[4]["str"] .. match[3]["str"] .. match[2]["str"] .. "&" else match = re.match(str, "&H([A-Za-z0-9]{2})([A-Za-z0-9]{2})([A-Za-z0-9]{2})&") color = "#" .. match[4]["str"] .. match[3]["str"] .. match[2]["str"] end return color end, --[[@param str string 输入字符串]] --[[@return integer]] len = function(str) --[[获取字符串长度]] local tmp = str local count = 0 local byteCount = 0 while (string.len(tmp) > 0) do local code = string.byte(tmp) if (code <= 127) then byteCount = byteCount + 1 elseif (code <= 223) then byteCount = byteCount + 2 elseif (code <= 239) then byteCount = byteCount + 3 else byteCount = byteCount + 4 end tmp = string.sub(str, byteCount + 1) count = count + 1 end return count end, --[[@param str string 输入字符串]] --[[@param start integer 起始索引]] --[[@param length integer|nil 结束索引]] --[[@return string]] sub = function(str, start, length) --[[截取字符串]] if start < 0 then return ksy.sub(str, ksy.len(str) - (-start) + 1, (-start)) end start = start - 1 if length == 0 then return "" end length = length > 0 and length or ksy.len(str) + length local tmp = str local count = 0 local byteCount = 0 local byteSubStart = 1 local byteSubEnd = -1 while (string.len(tmp) > 0) do if (count == start) then byteSubStart = byteCount + 1 elseif (count == start + length) then byteSubEnd = byteCount break end local code = string.byte(tmp) if code < 0xC0 then byteCount = byteCount + 1 elseif code < 0xE0 then byteCount = byteCount + 2 elseif code < 0xF0 then byteCount = byteCount + 3 else byteCount = byteCount + 4 end tmp = string.sub(str, byteCount + 1) count = count + 1 end return string.sub(str, byteSubStart, byteSubEnd) end, --[[@param str string 输入字符串]] --[[@param search string 查找字符串]] --[[@param replace string 目标字符串]] --[[@return string]] rep = function(str, search, replace) --[[替换字符串]] local res = "" for i = 0, ksy.len(str) - 1 do local current = ksy.sub(str, i + 1, 1) if current == search then res = res .. replace else res = res .. current end end return res end, _rotate = function(x, y, z, center_x, center_y, center_z, theta1, theta2, theta3) x, y, z = ksy._rotate_x(x - center_x, y - center_y, z - center_z, theta1) x, y, z = ksy._rotate_y(x, y, z, theta2) x, y, z = ksy._rotate_z(x, y, z, theta3) x, y, z = x + center_x, y + center_y, z + center_z return x, y end, _rotate_x = function(x, y, z, a) local rad = math.rad(a) local cos_a = math.cos(rad) local sin_a = math.sin(rad) local y1 = y * cos_a - z * sin_a local z1 = y * sin_a + z * cos_a return x, y1, z1 end, _rotate_y = function(x, y, z, a) local rad = math.rad(a) local cos_a = math.cos(rad) local sin_a = math.sin(rad) local x1 = x * cos_a + z * sin_a local z1 = -x * sin_a + z * cos_a return x1, y, z1 end, _rotate_z = function(x, y, z, a) local rad = math.rad(a) local cos_a = math.cos(rad) local sin_a = math.sin(rad) local x1 = x * cos_a - y * sin_a local y1 = x * sin_a + y * cos_a return x1, y1, z end, --[[@param width number 宽度]] --[[@param height number 高度]] square = function(width, height) --[[矩形]] return ksy.shape(("m 0 0 l 0 %s l %s %s l %s 0 l 0 0"):format(height, width, height, width)) .move(-width / 2, -height / 2) end, --[[@param length number 长度]] --[[@param radius number 圆角高度]] line = function(length, radius) --[[圆角线段]] radius = radius / 2 local shape = ("m 0 -%s l %s -%s b %s -%s %s 0 %s 0 b %s %s %s %s %s %s l 0 %s b -%s %s -%s 0 -%s 0 b -%s -%s 0 -%s 0 -%s") :format(radius, length, radius, length + radius, radius, length + radius, length + radius, length + radius, radius, length, radius, length, radius, radius, radius, radius, radius, radius, radius, radius, radius, radius) return ksy.shape(shape) end, --[[@param r number 半径]] circle = function(r) --[[贝塞尔圆]] local x = r * (2 ^ .5 - 1) * 4 / 3 local c = ("m 0 -%s b -%s -%s -%s -%s -%s 0 b -%s %s -%s %s 0 %s b %s %s %s %s %s 0 b %s -%s %s -%s 0 -%s") :format(r, x, r, r, x, r, r, x, x, r, r, x, r, r, x, r, r, x, x, r, r) return ksy.shape(c) end, --[[@param angles integer 角数量]] --[[@param majorAxis number 长轴长度]] --[[@param minorAxis number 短轴长度]] --[[@param frz number|nil 旋转角度]] star = function(angles, majorAxis, minorAxis, frz) --[[等边半正凹多边形]] frz = frz or 0 local points = ksy.table() local angle = math.pi / angles for i = 0, angles * 2 - 1 do local r = (i % 2 == 0) and majorAxis or minorAxis local theta = i * angle local x = r * math.cos(theta) local y = r * math.sin(theta) points.add(string.format("%.2f %.2f", x, y)) end draw = "m " .. points.join(" l ") return ksy.shape(draw).rotate(0, 0, 0, 0, frz - 90) end, --[[@param x1 number]] --[[@param y1 number]] --[[@param x2 number]] --[[@param y2 number]] --[[@return number]] deg = function(x1, y1, x2, y2) --[[相对角度]] local dx, dy = x2 - x1, y2 - y1 return math.deg(math.atan2(dy, dx)) end, --[[@param x1 number]] --[[@param y1 number]] --[[@param x2 number]] --[[@param y2 number]] --[[@return number]] dist = function(x1, y1, x2, y2) --[[坐标距离]] local dx, dy = x2 - x1, y2 - y1 return math.sqrt(dx * dx + dy * dy) end, extend = function(x1, y1, x2, y2, d) local dx = x2 - x1 local dy = y2 - y1 local len = math.sqrt(dx * dx + dy * dy) if len == 0 then return x2, y2 end local ux = dx / len local uy = dy / len local x3 = x2 + ux * d local y3 = y2 + uy * d return x3, y3 end, --[[@param x1 number]] --[[@param y1 number]] --[[@param x2 number]] --[[@param y2 number]] --[[@param x3 number]] --[[@param y3 number]] --[[@param x4 number]] --[[@param y4 number]] --[[@return number|boolean, number|boolean]] intersect = function(x1, y1, x2, y2, x3, y3, x4, y4, epsSin) --[[计算直线交点坐标]] epsSin = epsSin or 1e-06 local dx1, dy1 = x1 - x2, y1 - y2 local dx2, dy2 = x3 - x4, y3 - y4 local denom = dx1 * dy2 - dy1 * dx2 local l1 = dx1 * dx1 + dy1 * dy1 local l2 = dx2 * dx2 + dy2 * dy2 if l1 == 0 or l2 == 0 or denom * denom <= (epsSin * epsSin) * l1 * l2 then return false, false end local c1 = x1 * y2 - y1 * x2 local c2 = x3 * y4 - y3 * x4 return (c1 * dx2 - dx1 * c2) / denom, (c1 * dy2 - dy1 * c2) / denom end, --[[@param x1 number]] --[[@param y1 number]] --[[@param x2 number]] --[[@param y2 number]] --[[@param x3 number]] --[[@param y3 number]] --[[@param x4 number]] --[[@param y4 number]] --[[@return boolean]] is_intersect = function(x1, y1, x2, y2, x3, y3, x4, y4) --[[判断线段是否相交]] local eps = 1e-08 local o1 = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1) local o2 = (x2 - x1) * (y4 - y1) - (y2 - y1) * (x4 - x1) if o1 * o2 >= eps then return false end local o3 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3) local o4 = (x4 - x3) * (y2 - y3) - (y4 - y3) * (x2 - x3) return o3 * o4 < eps end, is_notinbboxfast = function(xmin, ymin, xmax, ymax, x1, y1, x2, y2) local eps = 1e-08 if x2 == nil then return (x1 < xmin - eps or x1 > xmax + eps or y1 < ymin - eps or y1 > ymax + eps) end return (math.max(x1, x2) < xmin - eps) or (math.max(y1, y2) < ymin - eps) or (math.min(x1, x2) > xmax + eps) or (math.min(y1, y2) > ymax + eps) end, is_samedirection = function(x1, y1, x2, y2, x3, y3, x4, y4) local v1x, v1y = x2 - x1, y2 - y1 local v2x, v2y = x4 - x3, y4 - y3 local len1 = math.sqrt(v1x * v1x + v1y * v1y) local len2 = math.sqrt(v2x * v2x + v2y * v2y) if len1 < 1e-08 or len2 < 1e-08 then return nil end local dot = v1x * v2x + v1y * v2y local cosv = dot / (len1 * len2) if cosv > 0.99 then return true elseif cosv < -0.99 then return false else return nil end end, --[[@param e any]] --[[@return nil]] debug = function(e) local function _sanitize(v, seen) seen = seen or {} local t = type(v) if t == "nil" or t == "boolean" or t == "string" then return v elseif t == "number" then if v ~= v then return "NaN" end if v == math.huge then return "Infinity" end if v == -math.huge then return "-Infinity" end return v elseif t == "table" then if seen[v] then return "" end seen[v] = true local out = {} for k, val in pairs(v) do local kk = (type(k) == "string" or type(k) == "number") and k or tostring(k) local ok, sv = pcall(_sanitize, val, seen) out[kk] = ok and sv or tostring(val) end return out else local ok, s = pcall(tostring, v) return ok and s or ("<" .. t .. ">") end end if type(e) == "table" then e = json.encode(_sanitize(e, {})) elseif e == nil then e = "nil" elseif e == true then e = "true" elseif e == false then e = "false" end aegisub.debug.out(2, e .. "\n") end, --[[@param tbl table 输入表]] --[[@param depth integer|nil 拷贝深度]] --[[@return table]] copy = function(tbl, depth) --[[深拷贝]] if type(tbl) ~= "table" then return tbl end if depth ~= nil and depth <= 0 then return tbl end local new_tbl = {} for k, v in pairs(tbl) do if type(v) == "table" then new_tbl[k] = ksy.copy(v, depth and (depth - 1) or nil) else new_tbl[k] = v end end return new_tbl end, --[[@param value number 输入数值]] --[[@param precision integer|nil 小数精度]] --[[@return number]] round = function(value, precision) --[[取整]] value = tonumber(value) or 0 return precision and math.floor(value * 10 ^ precision + .5) / 10 ^ precision or math.floor(value + .5) end, --[[@param seed string|number 种子]] --[[@return integer]] sign = function(seed) --[[随机±1]] if seed == nil then return math.random(2) * 2 - 3 end local s = tostring(seed) .. gseed local h = 2166136261 for i = 1, #s do h = (h * 131 + s:byte(i)) % 4294967296 end return (h % 2 == 0) and -1 or 1 end, --[[@param str string]] --[[@return ffi.cdata*]] utf8_to_utf16 = function(str) local wlen = ffi.C.MultiByteToWideChar(ffi.C.CP_UTF8, 0x0, str, -1, nil, 0) local ws = ffi.new("wchar_t[?]", wlen) ffi.C.MultiByteToWideChar(ffi.C.CP_UTF8, 0x0, str, -1, ws, wlen) return ws end, --[[@param str string|function 输入字符串]] --[[@param styleref table|nil 输入样式表]] str = function(str, styleref) if type(str) == "function" then str = str() end styleref = styleref or line.styleref return { info = function() --[[获取指定字符串的几何属性]] local width, height, descent, extlead = aegisub.text_extents(styleref, str) return { width = width, height = height, descent = descent, extlead = extlead } end, --[[@return number]] getw = function() --[[获取指定字符串的宽度]] return ksy.str(str, styleref).info().width end, --[[@return number]] geth = function() --[[获取指定字符串的高度]] return ksy.str(str, styleref).info().height end, --[[@param font_precision integer|nil 文字精度倍率]] --[[@param fp_precision integer|nil 小数精度]] toshape = function(font_precision, fp_precision) --[[文字转绘图, 主要代码来自Yutils]] font_precision = font_precision or 64 fp_precision = fp_precision or 3 local resources_deleter local dc = ffi.gc(ffi.C.CreateCompatibleDC(nil), function() resources_deleter() end) ffi.C.SetMapMode(dc, ffi.C.MM_TEXT) ffi.C.SetBkMode(dc, ffi.C.TRANSPARENT) local font = ffi.C.CreateFontW( styleref.fontsize * font_precision, 0, 0, 0, styleref.bold and ffi.C.FW_BOLD or ffi.C.FW_NORMAL, styleref.italic and 1 or 0, styleref.underline and 1 or 0, styleref.strikeout and 1 or 0, ffi.C.DEFAULT_CHARSET, ffi.C.OUT_TT_PRECIS, ffi.C.CLIP_DEFAULT_PRECIS, ffi.C.ANTIALIASED_QUALITY, ffi.C.DEFAULT_PITCH + ffi.C.FF_DONTCARE, ksy.utf8_to_utf16(styleref.fontname) ) local old_font = ffi.C.SelectObject(dc, font) resources_deleter = function() ffi.C.SelectObject(dc, old_font) ffi.C.DeleteObject(font) ffi.C.DeleteDC(dc) end local shape, shape_n = {}, 0 text = ksy.utf8_to_utf16(str) local text_len = tonumber(ffi.C.wcslen(text)) local char_widths if styleref.spacing ~= 0 then char_widths = ffi.new("INT[?]", text_len) local size, space = ffi.new("SIZE[1]"), styleref.spacing * font_precision for i = 0, text_len - 1 do ffi.C.GetTextExtentPoint32W(dc, text + i, 1, size) char_widths[i] = size[0].cx + space end end ffi.C.BeginPath(dc) ffi.C.ExtTextOutW(dc, 0, 0, 0x0, nil, text, text_len, char_widths) ffi.C.EndPath(dc) local points_n = ffi.C.GetPath(dc, nil, nil, 0) if points_n > 0 then local points, types = ffi.new("POINT[?]", points_n), ffi.new("BYTE[?]", points_n) ffi.C.GetPath(dc, points, types, points_n) local i = 0 local cur_type, cur_point while i < points_n do cur_type, cur_point = types[i], points[i] if cur_type == ffi.C.PT_MOVETO then shape_n = shape_n + 1 shape[shape_n] = "m" shape[shape_n + 1] = ksy.round(cur_point.x / font_precision * styleref.scale_x * .01, fp_precision) shape[shape_n + 2] = ksy.round(cur_point.y / font_precision * styleref.scale_y * .01, fp_precision) shape_n = shape_n + 2 i = i + 1 elseif cur_type == ffi.C.PT_LINETO or cur_type == (ffi.C.PT_LINETO + ffi.C.PT_CLOSEFIGURE) then shape_n = shape_n + 1 shape[shape_n] = "l" shape[shape_n + 1] = ksy.round(cur_point.x / font_precision * styleref.scale_x * .01, fp_precision) shape[shape_n + 2] = ksy.round(cur_point.y / font_precision * styleref.scale_y * .01, fp_precision) shape_n = shape_n + 2 i = i + 1 elseif cur_type == ffi.C.PT_BEZIERTO or cur_type == (ffi.C.PT_BEZIERTO + ffi.C.PT_CLOSEFIGURE) then shape_n = shape_n + 1 shape[shape_n] = "b" shape[shape_n + 1] = ksy.round(cur_point.x / font_precision * styleref.scale_x * .01, fp_precision) shape[shape_n + 2] = ksy.round(cur_point.y / font_precision * styleref.scale_y * .01, fp_precision) shape[shape_n + 3] = ksy.round(points[i + 1].x / font_precision * styleref.scale_x * .01, fp_precision) shape[shape_n + 4] = ksy.round(points[i + 1].y / font_precision * styleref.scale_y * .01, fp_precision) shape[shape_n + 5] = ksy.round(points[i + 2].x / font_precision * styleref.scale_x * .01, fp_precision) shape[shape_n + 6] = ksy.round(points[i + 2].y / font_precision * styleref.scale_y * .01, fp_precision) shape_n = shape_n + 6 i = i + 3 else i = i + 1 end end end ffi.C.AbortPath(dc) local info = ksy.str(str, styleref).info() local an = styleref.align local middle, center = info.height / 2, info.width / 2 local x, y if ksy.table({ 1, 4, 7 }).contains(an) then x = 0 elseif ksy.table({ 2, 5, 8 }).contains(an) then x = center elseif ksy.table({ 3, 6, 9 }).contains(an) then x = info.width end if ksy.table({ 1, 2, 3 }).contains(an) then y = info.height elseif ksy.table({ 4, 5, 6 }).contains(an) then y = middle elseif ksy.table({ 7, 8, 9 }).contains(an) then y = 0 end return ksy.shape(ksy.table(shape).join(" ")).move(-x, -y) end } end, --[[@param tbl table|nil 输入表]] table = function(tbl) tbl = tbl or {} return { --[[@param value any 查找值]] --[[@param ... any 查找值]] --[[@return boolean]] contains = function(value, ...) --[[判断是否包含指定值]] if value == nil then return true end local lookup = {} for _, v in ipairs(tbl) do lookup[v] = true end for i = 1, select("#", value, ...) do local _value = select(i, value, ...) if not lookup[_value] then return false end end return true end, --[[@param key any 查找键]] --[[@param ... any 查找键]] --[[@return boolean]] containsKey = function(key, ...) --[[判断是否包含指定键]] if key == nil then return true end for i = 1, select("#", key, ...) do local _key = select(i, key, ...) if tbl[_key] == nil then return false end end return true end, --[[@param separator string|function 用于拼接的字符串]] --[[@return string]] join = function(separator) --[[转字符串]] if type(separator) == "string" then return table.concat(tbl, separator) end local result = tbl[1] for i = 2, #tbl do result = result .. separator() .. tbl[i] end return result end, dedup = function() --[[去重]] local seen = {} local removeindices = {} for i, value in ipairs(tbl) do if seen[value] then ksy.table(removeindices).add(i) else seen[value] = true end end return ksy.table(tbl).removeAt(unpack(removeindices)) end, --[[@param value any 目标值]] --[[@param ... any 目标值]] remove = function(value, ...) --[[移除指定值]] for i = #tbl, 1, -1 do for _i = 1, select("#", value, ...) do local _value = select(_i, value, ...) if tbl[i] == _value then table.remove(tbl, i) end end end return ksy.table(tbl) end, --[[@param index integer 目标索引]] --[[@param ... integer 目标索引]] removeAt = function(index, ...) --[[移除指定索引]] local indices = { index, ... } table.sort(indices, function(a, b) return a > b end) local _prev for _, _index in ipairs(indices) do if _index ~= _prev then table.remove(tbl, _index) end _prev = _index end return ksy.table(tbl) end, --[[@param key any 目标键]] --[[@param ... any 目标键]] removeKey = function(key, ...) --[[移除指定键]] for i = 1, select("#", key, ...) do local _key = select(i, key, ...) tbl[_key] = nil end return ksy.table(tbl) end, --[[@param value any 目标值]] --[[@param ... any 目标值]] removeValue = function(value, ...) --[[移除指定值]] for k, v in pairs(tbl) do for i = 1, select("#", value, ...) do local _value = select(i, value, ...) if v == _value then tbl[k] = nil end end end return ksy.table(tbl) end, --[[@param value any 添加值]] --[[@param ... any 添加值]] add = function(value, ...) --[[添加指定值]] for i = 1, select("#", value, ...) do local _value = select(i, value, ...) table.insert(tbl, _value) end return ksy.table(tbl) end, --[[@param index integer 插入索引]] --[[@param value any 插入值]] --[[@param ... any 插入值]] insert = function(index, value, ...) --[[添加指定值]] for i = select("#", value, ...), 1, -1 do local _value = select(i, value, ...) table.insert(tbl, index, _value) end return ksy.table(tbl) end, --[[@param value table 目标表]] --[[@param ... table 目标表]] plus = function(value, ...) --[[拼接表]] local k = #tbl for i = 1, select("#", value, ...) do local _value = select(i, value, ...) for j = 1, #_value do k = k + 1 tbl[k] = _value[j] end end return ksy.table(tbl) end, reverse = function() --[[反转]] local reversed = {} for i = #tbl, 1, -1 do table.insert(reversed, tbl[i]) end return ksy.table(reversed) end, --[[@param depth integer|nil 拷贝深度]] copy = function(depth) --[[深拷贝]] return ksy.table(ksy.copy(tbl, depth)) end, --[[@param idx integer 进入索引]] --[[@param ... integer 进入索引]] index = function(idx, ...) --[[切换到指定索引的表]] local subTbl = tbl for i = 1, select("#", idx, ...) do local _idx = select(i, idx, ...) _idx = _idx > 0 and _idx or (#subTbl + _idx + 1) subTbl[_idx] = subTbl[_idx] or {} subTbl = subTbl[_idx] end return ksy.table(subTbl) end, --[[@param new_tbl table 新表]] edit = function(new_tbl) --[[修改表]] for k in pairs(tbl) do tbl[k] = nil end for k, v in pairs(new_tbl) do tbl[k] = v end return ksy.table(tbl) end, --[[@param filter function 处理函数,传入(shape,tbl,index,prev)输出shape]] filter = function(filter) --[[对绘图进行自定义处理]] local prev = nil for i = 1, #tbl do tbl[i], prev = filter(tbl[i], tbl, i, prev) end return ksy.table(tbl) end, fixshape = function() --[[重整一系列绘图的坐标]] return ksy.table(tbl).filter(function(shape, _tbl, index, prev) shape = ksy.shape(shape) if index == 1 then local hmax = 0 for i = 1, #_tbl do local h = ksy.shape(_tbl[i]).height if h > hmax or hmax == 0 then hmax = h end end return shape.move(0, hmax > shape.height and (shape.height - hmax) or 0).out(), table.pack(0, hmax) end local width = ksy.shape(_tbl[index - 1]).width return shape.move(-(width + prev[1]), shape.height - prev[2]).out(), table.pack(width + prev[1], prev[2]) end) end, --[[@param idx integer 索引]] --[[@param ... integer 索引]] at = function(idx, ...) --[[返回索引处的值]] local result = {} for i = 1, select("#", idx, ...) do local _idx = select(i, idx, ...) _idx = _idx > 0 and _idx or (#tbl + _idx + 1) table.insert(result, tbl[_idx]) end return unpack(result) end, --[[@param func function]] map = function(func) --[[遍历,传入(index,value)]] for index, value in ipairs(tbl) do local result = func(index, value) if result ~= nil then tbl[index] = result end end return ksy.table(tbl) end, value = tbl, } end, --[[@param func function|string 输入函数(表达式)]] func = function(func) return { parse = function() --[[解析表达式]] if _G.rawget(_G, "ASSCommandCompile") == nil then ASSCommandCompile = re.compile("\\\\([^(]+)\\(([^)]*)\\)") end local match = ASSCommandCompile:match(func) return { func = match[2]["str"], args = re.split(match[3]["str"], ",") } end, --[[@param param any 固定参数]] --[[@param ... any 固定参数]] --[[@return function]] partial = function(param, ...) --[[绑定参数]] local fixedparams = { param, ... } return function(...) local args = { ... } local merged = {} local nfixed = #fixedparams for i = 1, nfixed do merged[i] = fixedparams[i] end local nargs = #args for i = 1, nargs do merged[nfixed + i] = args[i] end return func(unpack(merged, 1, nfixed + nargs)) end end, --[[@return any]] run = function() --[[执行函数]] local value = func() if value ~= nil then return value end return "" end, } end, --[[@param start_time integer|nil 计时起始时间]] --[[@param end_time integer|nil 计时结束时间]] clock = function(start_time, end_time) if start_time == nil then start_time = os.clock() end return { fin = function() end_time = os.clock() return ksy.clock(start_time, end_time) end, --[[@return integer]] dur = function() return end_time - start_time end, } end, lazy = function(values) return { fix = function(name, value) if not ksy.table(values).containsKey(name) then values[name] = value end end, set = function(name, value) values[name] = value end, get = function(name) local result = values[name] if type(result) == "function" then result = result() values[name] = result end return result end, } end, --[[@param x number 传入坐标]] --[[@param y number 传入坐标]] xy = function(x, y) local function _arc(model, cx, cy, w, h, bend, deg, H, V) local hw = (w ~= 0) and (w * 0.5) or 1 local hh = (h ~= 0) and (h * 0.5) or 1 local rad = math.rad(deg or 0) local c, s = math.cos(rad), math.sin(rad) local b = ((bend or 0) / 100) local hS = (H or 0) / 100 local vS = (V or 0) / 100 local dx, dy = x - cx, y - cy local u0 = (c * dx + s * dy) / hw local v0 = (-s * dx + c * dy) / hh local u, v = model(u0, v0, b, hw, hh) local U2 = (u + hS * v0) * hw local V2 = (v + vS * u0) * hh local dx2 = c * U2 - s * V2 local dy2 = s * U2 + c * V2 return cx + dx2, cy + dy2 end return { arc = function(cx, cy, w, h, bend, deg, H, V) return _arc(function(u0, v0, b, hw, hh) local ab = math.abs(b) if ab < 1e-08 then return u0, v0 end local A = ab * (math.pi / 2) local sA = math.sin(A) if sA == 0 then return u0, v0 end local R = hw / sA local ucl = (u0 > 1 and 1) or (u0 < -1 and -1) or u0 local th = ucl * A local r = R + v0 * hh local U2 = r * math.sin(th) local C = math.cos(th) local V2 = b < 0 and (R - r * C) or (r * C - R) local u = U2 / hw local v = V2 / hh return u, v end, cx, cy, w, h, bend, deg, H, V) end, arch = function(cx, cy, w, h, bend, deg, H, V) return _arc(function(u0, v0, b) local k = 1 - u0 * u0 if k < 0 then k = 0 end local v = v0 + b * k return u0, v end, cx, cy, w, h, bend, deg, H, V) end, arcul = function(cx, cy, w, h, bend, deg, H, V) return _arc(function(u0, v0, b) local k = 1 - u0 * u0 if k < 0 then k = 0 end local v = v0 * (1 + b * k) return u0, v end, cx, cy, w, h, bend, deg, H, V) end, --[[@param bend number bend=100时1/4圆弧,bend=200时1/2圆弧]] arcseg = function(cx, cy, w, h, bend, deg, H, V) return _arc(function(u0, v0, b, hw, hh) local ab = math.abs(b) if ab < 1e-08 then return u0, v0 end local theta = ab * (math.pi / 2) if theta < 1e-08 then return u0, v0 end local ucl = (u0 > 1 and 1) or (u0 < -1 and -1) or u0 local th = ucl * (theta * 0.5) local R = (2 * hw) / theta local r = R + v0 * hh local U2 = r * math.sin(th) local V2 = r * math.cos(th) - R if b < 0 then V2 = -V2 end local u = U2 / hw local v = V2 / hh return u, v end, cx, cy, w, h, bend, deg, H, V) end, } end, --[[@param shape string|table|function 传入绘图字符串/表]] shape = function(shape) local points, commands = {}, {} if type(shape) == "function" then shape = shape() end if type(shape) == "table" then points = ksy.copy(shape.points) if shape.commands == nil then shape.commands = { "m" } for _ = 2, #points do ksy.table(shape.commands).add("l") end end commands = ksy.copy(shape.commands) else local tokens = {} for token in string.gmatch(shape, "%S+") do ksy.table(tokens).add(token) if tonumber(token) then if points[#points] == nil or points[#points].y ~= nil then ksy.table(points).add({ x = tonumber(token) }) else points[#points].y = tonumber(token) end if #points > #commands then ksy.table(commands).add(commands[#commands]) end else ksy.table(commands).add(token) end end end local _out = function(move, precision) local _commands, _points = ksy.copy(move.commands), ksy.copy(move.points) local _shape = {} for i = 1, #_commands do if _commands[i] == nil then goto continue elseif _commands[i] == "b" then _commands[i + 1] = nil _commands[i + 2] = nil ksy.table(_shape).add(_commands[i]) else ksy.table(_shape).add(_commands[i]) end ::continue:: local x, y = _points[i].x, _points[i].y if precision then x = ksy.round(x, precision) y = ksy.round(y, precision) end ksy.table(_shape).add(tostring(x)) ksy.table(_shape).add(tostring(y)) _commands[i] = nil end return ksy.table(_shape).join(" ") end if type(shape) == "table" then shape = _out(shape) end --[[@param precision integer|nil 小数精度]] local _out1 = function(precision) return _out({ commands = commands, points = points }, precision) end local moves = {} --[[@param precision integer|nil 小数精度]] local _out2 = function(precision) local _shapes = ksy.table() for _, move in ipairs(moves) do _shapes.add(_out(move, precision)) end return _shapes end local function _xMinMax() local xmin, xmax = points[1].x, points[1].x for i = 2, #points do local _x = points[i].x if _x > xmax then xmax = _x elseif _x < xmin then xmin = _x end end return xmin, xmax end local function _yMinMax() local ymin, ymax = points[1].y, points[1].y for i = 2, #points do local _y = points[i].y if _y > ymax then ymax = _y elseif _y < ymin then ymin = _y end end return ymin, ymax end local function _calc_windings(vertex, move, tolerance, maxdepth) --[[计算环绕数]] move = ksy.shape(move) local _vertex, _commands, _points = ksy.copy(vertex), ksy.copy(move.commands), ksy.copy(move.points) local x, y = _vertex.x, _vertex.y local windings = 0 local eps = 1e-08 local xmin, _, xmax, ymax = move.xyMinMax() if x < xmin - eps or x > xmax + eps or y > ymax + eps then return windings end for i = 1, #_commands do if i == 1 then goto continue end if _commands[i] == nil then goto continue elseif _commands[i] == "b" then _commands[i + 1] = nil _commands[i + 2] = nil if x < math.min(_points[i - 1].x, _points[i].x, _points[i + 1].x, _points[i + 2].x) or x > math.max(_points[i - 1].x, _points[i].x, _points[i + 1].x, _points[i + 2].x) then goto continue end local _bezier = ksy.shape(("m %s %s b %s %s %s %s %s %s"):format(_points[i - 1].x, _points[i - 1].y, _points[i].x, _points[i].y, _points[i + 1].x, _points[i + 1].y, _points[i + 2].x, _points[i + 2] .y)) windings = windings + _calc_windings(_vertex, _bezier.bezier2line(tolerance, maxdepth).out(), tolerance, maxdepth) else local x1, y1 = _points[i - 1].x, _points[i - 1].y local x2, y2 = _points[i].x, _points[i].y if x < math.min(x1, x2) - eps or x > math.max(x1, x2) + eps or y > math.max(y1, y2) + eps then goto continue end local y0 = y1 + (y2 - y1) * (x - x1) / (x2 - x1) if y0 > y - eps then if math.abs(x - math.min(x1, x2)) < eps then windings = windings + (x2 > x1 and 1 or -1) elseif math.abs(x - math.max(x1, x2)) < eps then windings = windings + 0 else windings = windings + (x2 > x1 and 1 or -1) end end end ::continue:: _commands[i] = nil end return windings end local function _separate_moves() --[[分离绘图]] for i, command in ipairs(commands) do if command == "m" then ksy.table(moves).add({ commands = {}, points = {} }) end ksy.table(moves[#moves].commands).add(command) ksy.table(moves[#moves].points).add(ksy.copy(points[i])) end for _, move in ipairs(moves) do if move.points[#move.points].x ~= move.points[1].x or move.points[#move.points].y ~= move.points[1].y then ksy.table(move.commands).add("l") ksy.table(move.points).add(ksy.copy(move.points[1])) end end end local function _separate_domains(tolerance, maxdepth) --[[分离连通域]] local _intersections = {} for i, move in ipairs(moves) do _intersections[i] = {} local _vertex = move.points[1] for _i, _move in ipairs(moves) do if i == _i then goto continue end if _calc_windings(_vertex, _move, tolerance, maxdepth) ~= 0 then ksy.table(_intersections[i]).add(_i) end ::continue:: end end local removeindices = {} for i, move in ipairs(moves) do if #_intersections[i] % 2 == 0 then goto continue end for _, index in ipairs(_intersections[i]) do if #_intersections[index] == #_intersections[i] - 1 and ksy.table(_intersections[index]).contains(unpack(ksy.table(_intersections[i]).copy().remove(index).value)) then ksy.table(moves[index].commands).add(unpack(move.commands)) ksy.table(moves[index].points).add(unpack(move.points)) ksy.table(removeindices).add(i) break end end ::continue:: end ksy.table(moves).removeAt(unpack(removeindices)) end return { width = (function(...) --[[绘图宽度]] local a, b = ... return b - a end)(_xMinMax()), --[[@return number]] height = (function(...) --[[绘图高度]] local a, b = ... return b - a end)(_yMinMax()), --[[@return number]] center = (function(...) --[[绘图x轴中点]] local a, b = ... return (a + b) / 2 end)(_xMinMax()), --[[@return number]] middle = (function(...) --[[绘图y轴中点]] local a, b = ... return (a + b) / 2 end)(_yMinMax()), --[[@return number]] --[[@return table]] commands = commands, --[[@return table]] points = points, --[[@return table]] moves = moves, --[[@return number,number,number,number]] xyMinMax = function() --[[xmin, ymin, xmax, ymax]] local xmin, xmax, ymin, ymax = points[1].x, points[1].x, points[1].y, points[1].y for i = 2, #points do local _x, _y = points[i].x, points[i].y if _x > xmax then xmax = _x elseif _x < xmin then xmin = _x end if _y > ymax then ymax = _y elseif _y < ymin then ymin = _y end end return xmin, ymin, xmax, ymax end, --[[@param t number 指定参数]] --[[@return number,number]] bezier = function(t) --[[计算贝塞尔曲线在参数t处的值]] local x1, y1 = points[1].x, points[1].y local x2, y2 = points[2].x, points[2].y local x3, y3 = points[3].x, points[3].y local x4, y4 = points[4].x, points[4].y local u = 1 - t local uu = u * u local uuu = uu * u local tt = t * t local ttt = tt * t local pX = uuu * x1 + 3 * uu * t * x2 + 3 * u * tt * x3 + ttt * x4 local pY = uuu * y1 + 3 * uu * t * y2 + 3 * u * tt * y3 + ttt * y4 return pX, pY end, --[[@param tolerance number|nil 容忍度/精确度,越低二分越细]] --[[@param maxdepth number|nil 二分最深深度]] bezier2line = function(tolerance, maxdepth) --[[将绘图中的贝塞尔曲线转换成线段]] tolerance = tolerance or 4e-01 maxdepth = maxdepth or 8 local function _point_to_seg_dist(px, py, x1, y1, x2, y2) local vx, vy = x2 - x1, y2 - y1 local wx, wy = px - x1, py - y1 local vv = vx * vx + vy * vy if vv == 0 then return ksy.dist(px, py, x1, y1) end local t = (wx * vx + wy * vy) / vv if t < 0 then t = 0 elseif t > 1 then t = 1 end local projx, projy = x1 + t * vx, y1 + t * vy return ksy.dist(px, py, projx, projy) end shape = shape:gsub("%S+ %S+ b", function(b) return (b:sub(1, -2)):rep(2) .. "b" end) shape = shape:gsub("%S+ %S+ b %S+ %S+ %S+ %S+ %S+ %S+", function(b) b = "m " .. b local result = "" local stack = { { 0.0, 1.0, 0 } } while #stack > 0 do local node = table.remove(stack) local t0, t1, depth = node[1], node[2], node[3] local ax, ay = ksy.shape(b).bezier(t0) local bx, by = ksy.shape(b).bezier(t1) local tm = 0.5 * (t0 + t1) local mx, my = ksy.shape(b).bezier(tm) local d = _point_to_seg_dist(mx, my, ax, ay, bx, by) if d <= tolerance or depth >= maxdepth then result = ("%s l %s %s"):format(result, bx, by) else table.insert(stack, { tm, t1, depth + 1 }) table.insert(stack, { t0, tm, depth + 1 }) end end return result end) return ksy.shape(shape) end, line2bezier = function() --[[将绘图中的线段转换成贝塞尔曲线]] local _commands, _points = ksy.table(), ksy.table() for i = 1, #commands do if commands[i] == "l" then _commands.add("b", "b", "b") _points.add(points[i], points[i], points[i]) else _commands.add(commands[i]) _points.add(points[i]) end end return ksy.shape({ commands = _commands.value, points = _points.value }) end, --[[@param tolerance number|nil 容忍度/精确度,越低取样越细]] --[[@param _tolerance number|nil bezier2line参数]] --[[@param _maxdepth number|nil bezier2line参数]] sampling = function(tolerance, _tolerance, _maxdepth) --[[将绘图转换成大量短线段]] tolerance = tolerance or 1 local _shape = ksy.shape(shape).close().bezier2line(_tolerance, _maxdepth) local _commands, _points = ksy.table({ "m" }), ksy.table({ _shape.points[1] }) for i = 2, #_shape.commands do if math.abs(_shape.points[i].x - _shape.points[i - 1].x) < tolerance and math.abs(_shape.points[i].y - _shape.points[i - 1].y) < tolerance then _commands.add("l") _points.add(_shape.points[i]) else local n = math.ceil(math.max(math.abs(_shape.points[i].x - _shape.points[i - 1].x) / tolerance, math.abs(_shape.points[i].y - _shape.points[i - 1].y) / tolerance)) for _i = 1, n - 1 do _commands.add("l") _points.add({ x = _shape.points[i - 1].x + (_shape.points[i].x - _shape.points[i - 1].x) / n * _i, y = _shape.points[i - 1].y + (_shape.points[i].y - _shape.points[i - 1].y) / n * _i }) end end end return ksy.shape({ commands = _commands.value, points = _points.value }) end, windings = function(x, y, tolerance, maxdepth) return _calc_windings({ x = x, y = y }, shape, tolerance, maxdepth) end, --[[@param x number 目标坐标]] --[[@param y number 目标坐标]] --[[@param tolerance integer|nil]] --[[@param maxdepth integer|nil]] --[[@return boolean]] is_intersect = function(x, y, tolerance, maxdepth) --[[点是否与绘图相交]] return ksy.shape(shape).windings(x, y, tolerance, maxdepth) ~= 0 end, --[[@param x1 number]] --[[@param y1 number]] --[[@param x2 number]] --[[@param y2 number]] --[[@param single boolean|nil 是否只取一个交点]] intersect = function(x1, y1, x2, y2, single) --[[线段与简单绘图交点]] single = (single == nil) and true or single local _shape = ksy.shape(shape) local xmin, ymin, xmax, ymax = _shape.xyMinMax() if ksy.is_notinbboxfast(xmin, ymin, xmax, ymax, x1, y1, x2, y2) then return false end local _points = _shape.points local intersections = ksy.table() for i = 1, #_points - 1 do if ksy.is_intersect(x1, y1, x2, y2, _points[i].x, _points[i].y, _points[i + 1].x, _points[i + 1].y) then local px, py = ksy.intersect(x1, y1, x2, y2, _points[i].x, _points[i].y, _points[i + 1].x, _points[i + 1].y) if single then return { x = px, y = py, i = i } end intersections.add({ x = px, y = py, i = i }) end end if #intersections.value == 0 then return false end return intersections end, --[[@param _shape string|table|function 传入绘图字符串/表]] add = function(_shape) _shape = ksy.shape(_shape) local _commands, _points = _shape.commands, _shape.points return ksy.shape({ commands = ksy.table(commands).plus(_commands).value, points = ksy.table(points).plus(_points).value }) end, --[[@param d number 距离]] dpoint = function(d) local p1, p2 = points[1], points[2] local dx, dy = p2.x - p1.x, p2.y - p1.y local eps = 1e-08 if math.abs(dx) < eps and math.abs(dy) < eps then return { x = p1.x, y = p1.y }, { x = p2.x, y = p2.y }, { x = p1.x, y = p1.y }, { x = p2.x, y = p2.y } end local L = math.sqrt(dx * dx + dy * dy) local nx, ny = (-dy / L) * d, (dx / L) * d return { x = p1.x + nx, y = p1.y + ny }, { x = p2.x + nx, y = p2.y + ny }, { x = p1.x - nx, y = p1.y - ny }, { x = p2.x - nx, y = p2.y - ny } end, --[[@param filter function 处理函数,传入(x,y,shape)输出x,y]] filter = function(filter) --[[对绘图进行自定义处理]] local lazy = {} for i, point in ipairs(points) do local x, y = filter(point.x, point.y, shape, lazy) points[i] = { x = x, y = y } end return ksy.shape({ commands = commands, points = points }) end, --[[@param x number|nil]] --[[@param y number|nil]] move = function(x, y) --[[平移]] x = x or 0 y = y or 0 return ksy.shape(shape).filter(function(_x, _y) return _x + x, _y + y end) end, --[[@param x number fscx]] --[[@param y number|nil fscy]] fsc = function(x, y) --[[缩放]] x = x or 1 y = y or x return ksy.shape(shape).filter(function(_x, _y) return _x * x, _y * y end) end, --[[@param an integer|nil 使用对齐]] reset = function(an) --[[平移至坐标原点]] an = an or 5 local xmin, ymin, xmax, ymax = ksy.shape(shape).xyMinMax() local middle, center = (ymax + ymin) / 2, (xmax + xmin) / 2 local x, y if ksy.table({ 1, 4, 7 }).contains(an) then x = xmin elseif ksy.table({ 2, 5, 8 }).contains(an) then x = center elseif ksy.table({ 3, 6, 9 }).contains(an) then x = xmax end if ksy.table({ 1, 2, 3 }).contains(an) then y = ymax elseif ksy.table({ 4, 5, 6 }).contains(an) then y = middle elseif ksy.table({ 7, 8, 9 }).contains(an) then y = ymin end return ksy.shape({ commands = commands, points = points }).move(-x, -y) end, reverse = function() --[[反向]] commands = ksy.table(commands).removeAt(1).reverse().insert(1, "m").value points = ksy.table(points).reverse().value return ksy.shape({ commands = commands, points = points }) end, --[[@param center_x number 旋转中心]] --[[@param center_y number 旋转中心]] --[[@param theta1 number 旋转角度(绕x轴)]] --[[@param theta2 number 旋转角度(绕y轴)]] --[[@param theta3 number 旋转角度(绕z轴)]] rotate = function(center_x, center_y, theta1, theta2, theta3) --[[旋转绘图]] return ksy.shape(shape).filter(function(x, y) return ksy._rotate(x, y, 0, center_x, center_y, 0, theta1, theta2, theta3) end) end, --[[@param xmin number]] --[[@param xmax number]] clampX = function(xmin, xmax) --[[横坐标归一化]] return ksy.shape(shape).filter(function(x, y) return math.max(xmin, math.min(x, xmax)), y end) end, --[[@param ymin number]] --[[@param ymax number]] clampY = function(ymin, ymax) --[[纵坐标归一化]] return ksy.shape(shape).filter(function(x, y) return x, math.max(ymin, math.min(y, ymax)) end) end, declose = function() _separate_moves() local _shapes = ksy.table() for _, move in ipairs(moves) do ksy.table(move.commands).removeAt(-1) ksy.table(move.points).removeAt(-1) _shapes.add(_out(move)) end return ksy.shape(_shapes.join(" ")) end, close = function() --[[封闭绘图]] _separate_moves() local _shapes = ksy.table() for _, move in ipairs(moves) do _shapes.add(_out(move)) end return ksy.shape(_shapes.join(" ")) end, --[[@param offset integer 偏移值]] shiftM = function(offset) --[[调整起点]] local _shape = ksy.shape(shape).declose() local n = #_shape.points offset = offset % n local _points = {} for i = 1, n do _points[i] = _shape.points[((i + offset - 1) % n) + 1] end return ksy.shape({ commands = _shape.commands, points = _points }) end, is_clockwise = function() --[[绘图是否是顺时针CW]] local _shape = ksy.shape(shape).close() local _points = _shape.points local sum = 0 for i = 1, #_points do local j = (i % #_points) + 1 local xi, yi = _points[i].x, _points[i].y local xj, yj = _points[j].x, _points[j].y sum = sum + (xi * yj - xj * yi) end return sum < 0 end, --[[@param CW boolean|nil 绘图方向是否要按顺时针]] clockwise = function(CW) --[[将绘图转换成顺时针CW/逆时针CCW]] CW = (CW == nil) and true or CW local is_clockwise = ksy.shape(shape).is_clockwise() if CW ~= is_clockwise then return ksy.shape(shape).reverse() end return ksy.shape(shape) end, --[[@param bord number 边框像素宽度]] --[[@param outlineOnly boolean|nil 是否镂空]] --[[@param mode integer|nil 边框模式,1.直边,2.曲边]] --[[@param tolerance integer|nil]] bord = function(bord, outlineOnly, mode, tolerance) --[[生成边框绘图]] outlineOnly = (outlineOnly == nil) and true or outlineOnly mode = mode or 1 tolerance = tolerance or 1e-01 _shape = ksy.shape(shape).close().bezier2line() xmin, ymin, xmax, ymax = _shape.xyMinMax() _shape = string.gsub(_shape.out(), "m [^m]+%d", function(m) m = ksy.shape(m) local _m = m.add({ commands = { "l" }, points = { m.points[2] } }) local xys = ksy.table() for i = 1, #_m.points - 2 do local p1, p2 = _m.points[i], _m.points[i + 1] if ksy.dist(p1.x, p1.y, p2.x, p2.y) < tolerance then goto skip end local _, _, p1b, p2b = ksy.shape({ points = { p1, p2 } }).dpoint(bord) xys.add(p1b, p2b) ::skip:: end local _commands, _points = ksy.table({ "m" }), ksy.table({ xys.at(1) }) xys.add(xys.at(1), xys.at(2), xys.at(3)) for i = 1, #xys.value - 3, 2 do if mode == 1 then _commands.add("l", "l") _points.add(xys.at(i + 1, i + 2)) elseif mode == 2 then local is_intersect = ksy.is_intersect(xys.at(i).x, xys.at(i).y, xys.at(i + 1).x, xys.at(i + 1).y, xys.at(i + 2).x, xys.at(i + 2).y, xys.at(i + 3).x, xys.at(i + 3).y) local px, py = ksy.intersect(xys.at(i).x, xys.at(i).y, xys.at(i + 1).x, xys.at(i + 1).y, xys.at(i + 2).x, xys.at(i + 2).y, xys.at(i + 3).x, xys.at(i + 3).y) if not px then elseif is_intersect then _commands.add("l") _points.add({ x = px, y = py }) else _commands.add("l", "b", "b", "b") _points.add(xys.at(i + 1, i + 1)) _points.add({ x = px, y = py }, xys.at(i + 2)) end end end local outline = ksy.shape({ commands = _commands.value, points = _points.value }) return (outlineOnly and outline.add(m.clockwise(not m.is_clockwise())) or outline).out() end) return ksy.shape(_shape) end, --[[@param _shape string|function|table 要裁剪出去的绘图]] --[[@param tolerance number|nil bezier2line参数]] --[[@param maxdepth number|nil bezier2line参数]] cutout = function(_shape, tolerance, maxdepth) --[[裁剪绘图]] local shapeA = ksy.shape(shape).close().bezier2line(tolerance, maxdepth) local shapeB = ksy.shape(_shape).close().bezier2line(tolerance, maxdepth) if shapeA.is_clockwise() == shapeB.is_clockwise() then shapeB = shapeB.reverse() end local _offset = 0 for i = 1, #shapeA.commands do if shapeB.is_intersect(shapeA.points[i].x, shapeA.points[i].y) then _offset = _offset + 1 else break end end shapeA = shapeA.shiftM(_offset) local curline, curshape, isA, curindex = shapeA, shapeB, true, 1 points = ksy.table({ curline.points[1] }) for _ = 1, #shapeA.commands + #shapeB.commands do if isA and curindex == #shapeA.commands then break end local p = curshape.intersect(curline.points[curindex].x, curline.points[curindex].y, curline.points[curindex + 1].x, curline.points[curindex + 1].y) if p then points.add({ x = p.x, y = p.y }, { x = curshape.points[p.i + 1].x, y = curshape.points[p.i + 1] .y }) curline = isA and shapeB or shapeA curshape = isA and shapeA or shapeB curindex = p.i + 1 isA = not isA else points.add({ x = curline.points[curindex + 1].x, y = curline.points[curindex + 1].y }) curindex = curindex + 1 end end commands = { "m" } for i = 2, #points.value do commands[i] = "l" end return ksy.shape({ commands = commands, points = points.value }) end, --[[@param tolerance integer|nil]] --[[@param maxdepth integer|nil]] split = function(tolerance, maxdepth) --[[拆分连通域]] _separate_moves() _separate_domains(tolerance, maxdepth) return { out = _out2, bord = function(bord, outlineOnly, CW, _tolerance, _maxdepth) --[[生成边框绘图]] moves = _out2().filter( function(_shape) return ksy.shape(_shape).clockwise(CW).bord(bord, outlineOnly, _tolerance, _maxdepth) end).value return { out = _out2 } end, } end, toline = function() --[[绘图转路径]] commands = ksy.table(commands).copy().removeAt(1).reverse().insert(1, "m").plus(commands).value points = ksy.table(points).copy().reverse().plus(points).value return ksy.shape({ commands = commands, points = points }) end, out = _out1, } end, --[[@param s string|number 输入表达式]] --[[@return string|number|boolean]] eval = function(s) --[[解析表达式]] _G.line = line _G.orgline = orgline _G.j = j _G.maxj = maxj local f = load("return " .. s, "eval", "t", _G) if not f then return s end local ok, res = pcall(f) return ok and res or assert(false, res) end, --[[@param frame integer 帧数]] --[[@return integer]] frame2t = function(frame) --[[帧数转时间]] return aegisub.ms_from_frame(frame) - line.start_time end, --[[@param str string 输入效果表达式]] --[[@param ... string 输入效果表达式]] eff = function(str, ...) local fixedstr = { str, ... } local result = "" return { --[[@param istag boolean|nil 是否为标签内容]] --[[@return string]] genEff = function(istag) --[[生成效果字符串]] istag = istag == nil and true or istag for _, _str in ipairs(fixedstr) do result = result .. ksy.eval(_str) end return istag and result or "}" .. result .. "{" end, --[[@param dur_frame integer|nil 持续帧数]] --[[@param gap_frame integer|nil 间隔帧数]] --[[@param start_time integer|nil 起始时间]] --[[@param end_time integer|nil 结束时间]] --[[@param factor string|number|nil 速度系数(表达式)]] --[[@return string]] genAni = function(dur_frame, gap_frame, start_time, end_time, factor) --[[生成往复动画]] dur_frame = dur_frame or 1 gap_frame = gap_frame or 0 start_time = start_time or 0 end_time = end_time or line.duration factor = factor and ("," .. ksy.eval(factor)) or "" local cur_frame = aegisub.frame_from_ms(line.start_time + start_time) local end_frame = aegisub.frame_from_ms(line.start_time + end_time) while cur_frame < end_frame do result = result .. "\\t(" .. ksy.frame2t(cur_frame) .. "," .. ksy.frame2t(cur_frame + dur_frame) .. factor .. "," .. ksy.eff(unpack(fixedstr)).genEff() .. ")" cur_frame = cur_frame + dur_frame + gap_frame end return result end, --[[@param dur_frame integer|nil 持续帧数]] --[[@param gap_frame integer|nil 间隔帧数]] --[[@param start_frame integer|nil 起始帧数]] --[[@param end_frame integer|nil 结束帧数]] --[[@param factor string|number|nil 速度系数(表达式)]] --[[@return string]] genAniF = function(dur_frame, gap_frame, start_frame, end_frame, factor) --[[生成往复动画]] dur_frame = dur_frame or 1 gap_frame = gap_frame or 0 start_frame = start_frame or 0 end_frame = end_frame or (aegisub.frame_from_ms(line.end_time) - aegisub.frame_from_ms(line.start_time)) factor = factor and ("," .. ksy.eval(factor)) or "" local cur_frame = aegisub.frame_from_ms(line.start_time) + start_frame end_frame = aegisub.frame_from_ms(line.start_time) + end_frame while cur_frame < end_frame do result = result .. "\\t(" .. ksy.frame2t(cur_frame) .. "," .. ksy.frame2t(cur_frame + dur_frame) .. factor .. "," .. ksy.eff(unpack(fixedstr)).genEff() .. ")" cur_frame = cur_frame + dur_frame + gap_frame end return result end, } end, } _G.ksy = ksy --[[極彩花夢 - 正文字幕样式配置自动化]] --[[———————————————————————————————]] --[[为不同角色配置不同的效果]] --[[修正标点符号显示效果,为句首、句尾含有标点符号的行调整重心]] --[[将开始时间、结束时间设为最近的帧]] --[[添加\furi(num,text,fsc,fsp)]] --[[检查字幕是否超出画布或接近边缘]] --[[检查字幕持续时间是否过短]] --[[检查字幕开始时间、结束时间周围是否有关键帧]] --[[检查字幕是否闪轴]] --[[为特殊对话框样式进行适配]] function ksy_shuusei() if meta["language"] == "ENG" then if line.styleref.name == "Sx-jp" then return "" end local res = characters["Basic"] res = res .. ksy_character() res = res .. orgline.text ksy_layer() ksy_time() return res end line.text = orgline.text if type(ksy_fix) == "function" then ksy_fix() end ksy_style() local res = ksy_effect(true) res = res .. characters["Basic"] res = res .. ksy_character() res = res .. ksy_content() ksy_layer() ksy_margin() ksy_time() res = ksy_relocate(res) ksy_check() return res end function ksy_menu() local function _generate_dropdown(menu, name, label, items, description) menu[#menu + 1] = { class = "label", x = 0, y = menu[#menu].y + menu[#menu].height + 1, width = 4, height = 1, label = label .. ":" } menu[#menu + 1] = { name = name, class = "dropdown", x = 5, y = menu[#menu].y, width = 4, height = 1, items = items, value = items[1] } menu[#menu + 1] = { class = "label", x = 0, y = menu[#menu].y + 1, width = 9, height = select(2, description:gsub("\n", "")) + 1, label = description } end local menu = { { class = "label", x = 2, y = 0, width = 5, height = 1, label = "極彩花夢 - 正文字幕样式配置自动化v241001" } } local function _add(_list, _elements) for _, _value in ipairs(_elements) do if _value ~= _list[1] then table.insert(_list, _value) end end return _list end local _lang = {} if meta["language"] ~= nil and meta["language"] == "JPN" then table.insert(_lang, "日语字幕") end _lang = _add(_lang, { "中日双语", "日语字幕" }) local _styles = {} table.insert(_styles, " ") _styles = _add(_styles, { "kawaii", "sans", "serif" }) _generate_dropdown(menu, "lang", "选择字幕配置", _lang, "将双语字幕按照预设转变为日语字幕。\n如果字幕贴近边缘、超出画布会进行提示。") _generate_dropdown(menu, "style", "应用样式", _styles, "忽略默认配置强制应用预设的字幕样式,如果与默认配置相同则此选项不会生效。\n仅用于调试,部分标签会表达出错误的效果。") _generate_dropdown(menu, "check_duration", "字幕持续时间检测阈值", { "10帧", "15帧", "12帧" }, "如果持续时间低于设定帧数会提示。") _generate_dropdown(menu, "check_start_frame", "字幕开始时间关键帧检测阈值", { "3帧", "5帧", "7帧" }, "如果开始时间离最近的关键帧的差值小于设定帧数会提示。") _generate_dropdown(menu, "check_end_frame", "字幕结束时间关键帧检测阈值", { "4帧", "8帧", "12帧" }, "如果结束时间离最近的关键帧的差值小于设定帧数会提示。") _generate_dropdown(menu, "check_time_interval", "字幕闪轴检测阈值", { "6帧", "10帧", "15帧" }, "如果开始时间与前一行字幕的结束时间差值小于设定帧数会提示。") menu[#menu + 1] = { name = "change_characters", class = "checkbox", x = 0, y = menu[#menu].y + menu[#menu].height + 1, width = 1, height = 1, label = "修改效果表", value = false } menu[#menu + 1] = { class = "label", x = 0, y = menu[#menu].y + menu[#menu].height, width = 1, height = 1, label = "基础效果:" } menu[#menu + 1] = { name = "characters_Basic", class = "edit", x = 1, y = menu[#menu].y, width = 2, height = 1, text = re.match(characters["Basic"], "\\{(.+)\\}")[2]["str"] } menu[#menu + 1] = { class = "label", x = 3, y = menu[#menu].y, width = 1, height = 1, label = "空白效果:" } menu[#menu + 1] = { name = "characters_Blank", class = "color", x = 4, y = menu[#menu].y, width = 2, height = 1, value = ksy.c2c(re.match(characters["Blank"], "\\\\3c(&H[0-9A-F]{6}&)")[2]["str"]) } for _character, _effect in pairs(characters) do if _character ~= "Basic" and _character ~= "Blank" then menu[#menu + 1] = { class = "label", x = menu[#menu - 1].x + 3 > 6 and 0 or menu[#menu - 1].x + 3, y = menu[#menu].y + (menu[#menu - 1].x + 3 > 6 and 1 or 0), width = 1, height = 1, label = _character .. ":" } menu[#menu + 1] = { name = "characters_" .. _character, class = "color", x = menu[#menu].x + 1, y = menu[#menu].y, width = 2, height = 1, value = ksy.c2c(re.match(_effect, "\\\\3c(&H[0-9A-F]{6}&)")[2]["str"]) } end end local space = string.rep("\xE3\x80\x80", 9) local button, _config = aegisub.dialog.display( menu, { space .. "应用" .. space, space .. "取消" .. space } ) if button == space .. "取消" .. space then aegisub.cancel() end local function _generate_style(str) local _styleref = { ["name"] = "Sx-jp", ["fontname"] = "", ["fontsize"] = 0, ["color1"] = "&H00FFFFFF&", ["color2"] = "&HFFFFFFFF&", ["color3"] = "&H00000000&", ["color4"] = "&H00000000&", ["bold"] = false, ["italic"] = false, ["underline"] = false, ["strikeout"] = false, ["scale_x"] = 100, ["scale_y"] = 100, ["spacing"] = 0, ["angle"] = 0, ["borderstyle"] = 1, ["outline"] = 0, ["shadow"] = 0, ["align"] = 2, ["margin_l"] = 0, ["margin_r"] = 0, ["margin_v"] = 0, ["margin_t"] = 0, ["margin_b"] = 0, ["encoding"] = 1, ["class"] = "style", ["raw"] = str, ["section"] = "[V4+ Styles]", ["relative_to"] = 2, } local _asstag = { ["name"] = false, ["fontname"] = "fn", ["fontsize"] = "fs", ["color1"] = "1c", ["color2"] = "2c", ["color3"] = "3c", ["color4"] = "4c", ["bold"] = "b", ["italic"] = "i", ["underline"] = "u", ["strikeout"] = "s", ["scale_x"] = "fscx", ["scale_y"] = "fscy", ["spacing"] = "fsp", ["angle"] = "frz", ["borderstyle"] = false, ["outline"] = "bord", ["shadow"] = "shad", ["align"] = "an", ["margin_l"] = function(_value) line.margin_l = _value + line.margin_l end, ["margin_r"] = function(_value) line.margin_r = _value + line.margin_r end, ["margin_v"] = function(_value) line.margin_v = _value + line.margin_v line.margin_t = line.margin_v line.margin_b = line.margin_v end, ["margin_t"] = false, ["margin_b"] = false, ["encoding"] = "fe", } match = re.match(str, "^Style: ?([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)$") table.remove(match, 1) local _keys = { "name", "fontname", "fontsize", "color1", "color2", "color3", "color4", "bold", "italic", "underline", "strikeout", "scale_x", "scale_y", "spacing", "angle", "borderstyle", "outline", "shadow", "align", "margin_l", "margin_r", "margin_v", "encoding" } local _effect = "{" local _margin = {} for _index in pairs(_keys) do if type(_styleref[_keys[_index]]) == "string" then _styleref[_keys[_index]] = match[_index]["str"] elseif type(_styleref[_keys[_index]]) == "boolean" then _styleref[_keys[_index]] = match[_index]["str"] == "1" elseif type(_styleref[_keys[_index]]) == "number" then if _keys[_index] == "margin_v" then _styleref["margin_t"] = tonumber(match[_index]["str"]) _styleref["margin_b"] = tonumber(match[_index]["str"]) end _styleref[_keys[_index]] = tonumber(match[_index]["str"]) end if _asstag[_keys[_index]] == false then goto continue elseif type(_asstag[_keys[_index]]) == "string" then _effect = _effect .. "\\" .. _asstag[_keys[_index]] .. ((_index >= 4 and _index <= 7) and util.color_from_style(match[_index]["str"]) or match[_index]["str"]) elseif type(_asstag[_keys[_index]]) == "function" then _margin[#_margin + 1] = { _asstag[_keys[_index]], tonumber(match[_index]["str"]) } end ::continue:: end _effect = _effect .. "}" return _styleref, _effect, _margin end local _generated_style_jp = { {}, "", {} } local _generated_style_zh = { {}, "", {} } config = { ["JPN_only"] = _config["lang"] ~= "中日双语", ["style_force"] = _config["style"] ~= " ", ["style"] = "", ["styleref"] = { ["Sx-jp"] = {}, ["Sx-zh"] = {}, }, ["stylerefs"] = { ["kawaii"] = { ["Sx-jp"] = _generate_style( "Style: Sx-jp,A-OTF Shin Maru Go Pr6N DB,64,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,99,100,0.5,0,1,2.42,0,2,0,0,15,128"), ["Sx-zh"] = _generate_style( "Style: Sx-zh,方正兰亭圆_GBK_中,62,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,100,100,0,0,1,2.42,0,2,0,0,65,1"), }, ["sans"] = { ["Sx-jp"] = _generate_style( "Style: Sx-jp,Noto Sans JP Medium,64,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H00000000,0,0,0,0,99,100,0.5,0,1,2.42,0,2,0,0,15,128"), ["Sx-zh"] = _generate_style( "Style: Sx-zh,Noto Sans SC Medium,78,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,99,100,0.5,0,1,2.42,0,2,0,0,65,1"), }, ["serif"] = { ["Sx-jp"] = _generate_style( "Style: Sx-jp,A-OTF Ryumin Pr6N H-KL,60,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,99,100,1,0,1,2.42,0,2,0,0,15,128"), ["Sx-zh"] = _generate_style( "Style: Sx-zh,方正中粗雅宋_GBK,66,&H00FFFFFF,&HFFFFFFFF,&H00000000,&H64000000,0,0,0,0,95,100,2,0,1,2.42,0,2,0,0,65,1"), }, }, ["effect"] = { ["Sx-jp"] = _generated_style_jp[2], ["Sx-zh"] = _generated_style_zh[2], }, ["margin"] = { ["Sx-jp"] = _generated_style_jp[3], ["Sx-zh"] = _generated_style_zh[3], }, ["check_duration"] = tonumber(re.match(_config["check_duration"], "(\\d+)")[1]["str"]), ["check_start_frame"] = tonumber(re.match(_config["check_start_frame"], "(\\d+)")[1]["str"]), ["check_end_frame"] = tonumber(re.match(_config["check_end_frame"], "(\\d+)")[1]["str"]), ["check_time_interval"] = tonumber(re.match(_config["check_time_interval"], "(\\d+)")[1]["str"]), } if _config["change_characters"] == true then for key, value in pairs(_config) do if re.find(key, "^characters_") ~= nil then local _character = re.match(key, "^characters_(.+)$")[2]["str"] if _character == "Basic" then characters["Basic"] = re.sub(characters["Basic"], "\\{(.+)\\}", "{" .. re.sub(value, "\\\\", "\\\\\\\\") .. "}") else characters[_character] = re.sub(characters[_character], "\\\\3c(&H[0-9A-F]{6}&)", "\\\\3c" .. ksy.c2c(value)) end end end end end ksy_menu() keyframes = {} for _, v in pairs(aegisub.keyframes()) do keyframes[v] = true end prev_end_frame = 0 ksy_pandora = { ["A-OTF Shin Maru Go Pr6N DB"] = { ["style"] = "kawaii", ["margin_t"] = 8, ["contentrep"] = { ["?"] = "?", ["!"] = "!", ["…"] = "…", ["「"] = "「", [" "] = "{\\fscx200} {\\fscx}", ["」"] = "」", ["・"] = "・", ["♥"] = "{\\p1\\pbo-12}m 39.8 26.4 b 38.7 25.2 37.6 24 36.8 23 b 35.9 21.9 35.2 20.7 34.7 19.5 b 34.5 19 34.3 18.3 34.3 17.6 b 34.3 16.9 34.5 16.2 34.8 15.6 b 35.2 15 35.8 14.5 36.8 14.3 b 37.7 14 38.6 14 39.3 14.4 b 40 14.8 40.6 15.4 40.8 16.2 b 41.4 15.4 42.1 14.8 43 14.4 b 43.8 14 44.7 14 45.6 14.3 b 46.4 14.5 47 15 47.3 15.6 b 47.6 16.2 47.7 16.9 47.7 17.6 b 47.6 18.3 47.3 19 47 19.5 b 46.1 20.7 45 21.9 43.9 23 b 42.8 24 41.4 25.2 39.8 26.4 l 39.8 26.4 m 16 50.3 b 13.3 47.5 11 44.9 9.1 42.5 b 7.2 40.1 5.6 37.5 4.3 34.8 b 4 33.9 3.7 32.8 3.6 31.7 b 3.6 30.5 3.7 29.3 4 28.2 b 4.3 27 4.9 26 5.8 25.1 b 6.7 24.1 7.9 23.4 9.5 22.9 b 11.6 22.2 13.5 22.3 15.2 23.2 b 16.8 24.1 18 25.4 18.8 27.2 b 19.6 26 20.5 25 21.7 24.2 b 22.8 23.4 24 22.9 25.3 22.6 b 26.6 22.3 27.9 22.4 29.3 22.9 b 30.7 23.4 31.7 24.1 32.4 25.1 b 33.1 26 33.6 27 33.7 28.2 b 33.9 29.3 33.8 30.5 33.5 31.7 b 33.2 32.8 32.7 33.9 32.1 34.8 b 30.1 37.5 27.8 40.1 25.2 42.5 b 22.6 44.9 19.6 47.5 16 50.3 l 16 50.3{\\p0}", }, ["relocate"] = { }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 8, ["Yoffset2"] = -8, ["Yoffset3"] = -6, ["fscx"] = 84, ["fscy"] = 82, }, ["JPN_only"] = { ["fs"] = 78, ["Yoffset"] = 8, ["Yoffset2"] = 6, }, }, ["方正兰亭圆_GBK_中"] = { ["style"] = "kawaii", ["margin_t"] = 64, ["contentrep"] = { ["?"] = "{\\alpha&HFF&}喵{\\alpha}", ["!"] = "{\\fscx50} {\\fscx110}!{\\fscx150} {\\fscx0}!{\\fscx}", ["…"] = "{\\alpha&HFF&\\fscx90}喵{\\alpha\\fscx}", ["「"] = "「", [" "] = "{\\fscx180} {\\fscx}", ["」"] = "」", ["・"] = "{\\alpha&HFF&}喵{\\alpha}", ["♥"] = "{\\p1\\pbo-15}m 39.8 26.4 b 38.7 25.2 37.6 24 36.8 23 b 35.9 21.9 35.2 20.7 34.7 19.5 b 34.5 19 34.3 18.3 34.3 17.6 b 34.3 16.9 34.5 16.2 34.8 15.6 b 35.2 15 35.8 14.5 36.8 14.3 b 37.7 14 38.6 14 39.3 14.4 b 40 14.8 40.6 15.4 40.8 16.2 b 41.4 15.4 42.1 14.8 43 14.4 b 43.8 14 44.7 14 45.6 14.3 b 46.4 14.5 47 15 47.3 15.6 b 47.6 16.2 47.7 16.9 47.7 17.6 b 47.6 18.3 47.3 19 47 19.5 b 46.1 20.7 45 21.9 43.9 23 b 42.8 24 41.4 25.2 39.8 26.4 l 39.8 26.4 m 16 50.3 b 13.3 47.5 11 44.9 9.1 42.5 b 7.2 40.1 5.6 37.5 4.3 34.8 b 4 33.9 3.7 32.8 3.6 31.7 b 3.6 30.5 3.7 29.3 4 28.2 b 4.3 27 4.9 26 5.8 25.1 b 6.7 24.1 7.9 23.4 9.5 22.9 b 11.6 22.2 13.5 22.3 15.2 23.2 b 16.8 24.1 18 25.4 18.8 27.2 b 19.6 26 20.5 25 21.7 24.2 b 22.8 23.4 24 22.9 25.3 22.6 b 26.6 22.3 27.9 22.4 29.3 22.9 b 30.7 23.4 31.7 24.1 32.4 25.1 b 33.1 26 33.6 27 33.7 28.2 b 33.9 29.3 33.8 30.5 33.5 31.7 b 33.2 32.8 32.7 33.9 32.1 34.8 b 30.1 37.5 27.8 40.1 25.2 42.5 b 22.6 44.9 19.6 47.5 16 50.3 l 16 50.3{\\p0}", --[[得意黑/60]] }, ["relocate"] = { ["?"] = { ["content"] = "{\\an4\\fn请勿安装此子集化字体 - xjxWu0dc\\fscx116\\fscy128\\pos(%s,%s)}?", ["Xoffset"] = -3, ["Yoffset"] = -2, ["Yoffset2"] = -2, }, ["…"] = { ["content"] = "{\\an4\\fn请勿安装此子集化字体 - xjxWu0dc\\fscx78\\fscy78\\pos(%s,%s)\\fsp-22}・・・", ["Xoffset"] = -8, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, ["・"] = { ["content"] = "{\\an5\\fn请勿安装此子集化字体 - xjxWu0dc\\fscx116\\fscy116\\pos(%s,%s)}・", ["Xoffset"] = 0, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 6, ["Yoffset2"] = -10, ["Yoffset3"] = -8, ["fscx"] = 82, ["fscy"] = 80, }, }, ["Noto Sans JP Medium"] = { ["style"] = "sans", ["margin_t"] = 4, ["contentrep"] = { ["?"] = "{\\fscx20} {\\fscx}?{\\fscx80} {\\fscx0}?{\\fscx}", ["!"] = "{\\fscx30} {\\fscx}!{\\fscx70} {\\fscx0}!{\\fscx}", ["…"] = "…", ["「"] = "「", [" "] = "{\\fscx200} {\\fscx}", ["」"] = "」", ["・"] = "・", ["♥"] = "{\\p1\\pbo-2}m 37.9 6.9 b 41.5 8.2 44.1 10.6 45.6 14.1 b 47.1 17.5 47.3 21 46.2 24.7 b 44.4 29.6 41.6 34 37.8 37.6 b 34 41.3 29.7 44.3 25 46.5 b 20.3 44.3 16 41.3 12.2 37.6 b 8.4 34 5.6 29.6 3.8 24.7 b 2.6 21 2.8 17.5 4.3 14.1 b 5.8 10.6 8.4 8.2 12.1 6.9 b 16.8 5.6 21.2 6.5 25 9.7 b 28.8 6.5 33.1 5.6 37.9 6.9 l 37.9 6.9{\\p0}", }, ["relocate"] = { }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 8, ["Yoffset2"] = -10, ["Yoffset3"] = -8, ["fscx"] = 84, ["fscy"] = 82, }, ["JPN_only"] = { ["fs"] = 74, ["Yoffset"] = 8, ["Yoffset2"] = 6, }, }, ["Noto Sans SC Medium"] = { ["style"] = "sans", ["margin_t"] = 50, ["contentrep"] = { ["?"] = "{\\fscx20} {\\fscx}?{\\fscx80} {\\fscx0}?{\\fscx}", ["!"] = "{\\fscx30} {\\fscx}!{\\fscx70} {\\fscx0}!{\\fscx}", ["…"] = "{\\alpha&HFF&}喵{\\alpha}", ["「"] = "「", [" "] = "{\\fscx200} {\\fscx}", ["」"] = "」", ["・"] = "{\\alpha&HFF&\\fscx72}喵{\\alpha\\fscx}", ["♥"] = "{\\p1\\pbo-5}m 37.9 6.9 b 41.5 8.2 44.1 10.6 45.6 14.1 b 47.1 17.5 47.3 21 46.2 24.7 b 44.4 29.6 41.6 34 37.8 37.6 b 34 41.3 29.7 44.3 25 46.5 b 20.3 44.3 16 41.3 12.2 37.6 b 8.4 34 5.6 29.6 3.8 24.7 b 2.6 21 2.8 17.5 4.3 14.1 b 5.8 10.6 8.4 8.2 12.1 6.9 b 16.8 5.6 21.2 6.5 25 9.7 b 28.8 6.5 33.1 5.6 37.9 6.9 l 37.9 6.9{\\p0}", --[[panda bakery/50]] }, ["relocate"] = { ["…"] = { ["content"] = "{\\an4\\fn请勿安装此子集化字体 - hTJWvkOI\\fscx55\\fscy55\\pos(%s,%s)\\fsp-25}・・・", ["Xoffset"] = -6, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, ["・"] = { ["content"] = "{\\an5\\fn请勿安装此子集化字体 - hTJWvkOI\\fscx76\\fscy76\\pos(%s,%s)}・", ["Xoffset"] = 0, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 22, ["Yoffset2"] = -27, ["Yoffset3"] = -8, ["fscx"] = 84, ["fscy"] = 82, }, }, ["A-OTF Ryumin Pr6N H-KL"] = { ["style"] = "serif", ["margin_t"] = 10, ["contentrep"] = { ["?"] = "?", ["!"] = "!", ["…"] = "…", ["「"] = "「", [" "] = "{\\fscx200} {\\fscx}", ["」"] = "」", ["・"] = "・", ["♥"] = "{\\p1\\pbo-12\\1a&H30&}m 29.5 15.1 b 25.6 15.1 22.1 17.1 20.9 21.7 b 20.9 21.8 20.8 22 20.7 22 b 20.6 22 20.6 21.8 20.5 21.7 b 19.3 17.1 15.8 15.1 11.9 15.1 b 7.2 15.1 3.3 19.4 3.3 25.1 b 3.3 31.2 8.2 35.6 11.3 38.6 b 15.1 42.2 19.1 47.1 20.6 49.6 b 20.7 49.7 20.8 49.7 20.8 49.6 b 22.3 47.1 26.3 42.2 30.1 38.6 b 33.2 35.6 38.2 31.2 38.2 25.1 b 38.2 19.4 34.2 15.1 29.5 15.1{\\p0}", }, ["relocate"] = { }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 7, ["Yoffset2"] = -12, ["Yoffset3"] = -7, ["fscx"] = 80, ["fscy"] = 78, }, ["JPN_only"] = { ["fs"] = 68, ["Yoffset"] = 8, ["Yoffset2"] = 6, }, }, ["方正中粗雅宋_GBK"] = { ["style"] = "serif", ["margin_t"] = 62, ["contentrep"] = { ["?"] = "?", ["!"] = "{\\fscx10} {\\fscx}!{\\fscx90} {\\fscx0}!{\\fscx}", ["…"] = "{\\alpha&HFF&}喵{\\alpha}", ["「"] = "「", [" "] = " ", ["」"] = "」", ["・"] = "{\\alpha&HFF&}喵{\\alpha}", ["♥"] = "{\\p1\\pbo-15\\1a&H30&}m 29.5 15.1 b 25.6 15.1 22.1 17.1 20.9 21.7 b 20.9 21.8 20.8 22 20.7 22 b 20.6 22 20.6 21.8 20.5 21.7 b 19.3 17.1 15.8 15.1 11.9 15.1 b 7.2 15.1 3.3 19.4 3.3 25.1 b 3.3 31.2 8.2 35.6 11.3 38.6 b 15.1 42.2 19.1 47.1 20.6 49.6 b 20.7 49.7 20.8 49.7 20.8 49.6 b 22.3 47.1 26.3 42.2 30.1 38.6 b 33.2 35.6 38.2 31.2 38.2 25.1 b 38.2 19.4 34.2 15.1 29.5 15.1{\\p0}", --[[Source Han Sans/60]] }, ["relocate"] = { ["…"] = { ["content"] = "{\\an4\\fn请勿安装此子集化字体 - BSDI0GF0\\fscx80\\fscy80\\pos(%s,%s)\\fsp-24.5}・・・", ["Xoffset"] = -8, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, ["・"] = { ["content"] = "{\\an5\\fn请勿安装此子集化字体 - BSDI0GF0\\fscx96\\fscy96\\pos(%s,%s)}・", ["Xoffset"] = 0, ["Yoffset"] = 0, ["Yoffset2"] = 0, }, }, ["furigana"] = { ["content"] = "{\\an%s\\fs%s\\fscx%s\\fscy%s\\fsp%s\\pos(%s,%s)}%s", ["Yoffset"] = 8, ["Yoffset2"] = -10, ["Yoffset3"] = -7, ["fscx"] = 76, ["fscy"] = 74, }, }, } ksy_pandora["Noto Sans TC Medium"] = ksy_pandora["Noto Sans SC Medium"] local function _calwidth(str) local styleref = ksy.copy(line.styleref, 1) if config.JPN_only == true then styleref.fontsize = ksy_pandora[line.styleref.fontname]["JPN_only"]["fs"] end if orgline.styleref["align"] == 7 then str = re.sub(str, "^.*\\\\N", "") end local width = ksy.str(str, styleref).getw() for _search, _replace in pairs(ksy_pandora[line.styleref.fontname]["contentrep"]) do if re.find(str, _search) ~= nil then local _styleref = ksy.copy(styleref, 1) local _width = 0 for _part in re.gsplit(_replace, "\\{", true) do match = re.match(_part, "\\\\fn(.+)\\}") if match ~= nil then _styleref.fontname = match[2]["str"] end match = re.match(_part, "\\\\fscx(\\d*)") if match ~= nil then _styleref.scale_x = tonumber(match[2]["str"]) or _styleref.scale_x if match[2]["str"] == "" then _styleref.scale_x = styleref.scale_x end end _width = _width + ksy.str(re.sub(_part, ".+\\}", ""), _styleref).getw() end width = width + (_width - ksy.str(_search, styleref).getw()) * #re.find(str, _search) end end return width end local function _callineleft(init) init = init ~= nil and init or false if init == true then ksy_margin() end if orgline.styleref["align"] == 7 then return orgline.styleref["margin_l"] end local _lineleft = 0 _lineleft = (meta.res_x - _calwidth(line.text_stripped)) * .5 return _lineleft + (math.floor(line.margin_l) - math.floor(line.margin_r)) / 2 end local function _getlineeffects(text) text = text and text or line.text local _effects = "" for str, _, _ in re.gfind(text, "{.*?}") do _effects = _effects .. str end _effects = re.sub(_effects, "\\\\an\\d", "") _effects = re.sub(_effects, "{}", "") return _effects end function ksy_effect(fix_margin) if fix_margin then for _, exec in pairs(config["margin"][line.styleref.name]) do exec[1](exec[2]) end end local effect = config["effect"][line.styleref.name] effect = re.sub(effect, "\\\\an\\d+", "") return effect end function ksy_character() local actor = characters[line.actor] and line.actor or "Blank" if config.JPN_only == true then return characters[actor] .. string.format("{\\fs%s}", ksy_pandora[line.styleref.fontname]["JPN_only"]["fs"]) end return characters[actor] end function ksy_content() local content = line.text local effects = re.find(content, "\\{[^\\}]+\\}") if effects ~= nil then content = re.sub(content, "\\{[^\\}]+\\}", "{}") end if orgline.styleref["align"] == 7 then content = re.sub(content, "^([{}]*)(\\\\N)+", "\\1") line.text_stripped = re.sub(line.text_stripped, "^([{}]*)(\\\\N)+", "\\1") end if orgline.styleref["align"] == 7 and orgline.actor ~= "" then if orgline.layer ~= 9 then content = content .. "」" line.text_stripped = line.text_stripped .. "」" end content = re.sub(content, "^([\\{\\}]*)", "\\1「") line.text_stripped = "「" .. line.text_stripped end content = ksy.rep(content, " ", ksy_pandora[line.styleref.fontname]["contentrep"][" "]) for search, replace in pairs(ksy_pandora[line.styleref.fontname]["contentrep"]) do if search ~= " " then content = ksy.rep(content, search, replace) end end if effects ~= nil then for _, effect in ipairs(effects) do effect["str"] = re.sub(effect["str"], "![^!]+!", function(_eff) return ksy.eval(ksy.sub(_eff, 2, -2)) end) end content = re.sub(content, "\\{\\}", function() return table.remove(effects, 1)["str"] end) end if orgline.styleref["align"] == 7 and re.find(content, "\\\\N") ~= nil then content = re.split(content, "\\\\N") content = content[j] ~= nil and content[j] or content[1] end return content end function ksy_style() if orgline.styleref["align"] == 7 then return end config["style"] = ksy_pandora[line.styleref.fontname]["style"] if config["stylerefs"][config["style"]]["Sx-jp"].fontname ~= styles["Sx-jp"].fontname then line.styleref = config["stylerefs"][config["style"]][line.styleref.name] config["styleref"]["Sx-jp"] = config["stylerefs"][config["style"]]["Sx-jp"] config["styleref"]["Sx-zh"] = config["stylerefs"][config["style"]]["Sx-zh"] else config["styleref"]["Sx-jp"] = styles["Sx-jp"] config["styleref"]["Sx-zh"] = styles["Sx-zh"] end end function ksy_layer() if line.styleref.name == "Sx-zh" or line.styleref.name == "Sx-en" then line.layer = 1 end if orgline.styleref["align"] == 7 and re.find(line.text_stripped, "\\\\N") ~= nil then line.layer = j > #re.find(line.text_stripped, "\\\\N") + 1 and 1 or j end end function ksy_margin() if orgline.styleref["align"] == 7 then if line.margin_t == 0 and re.find(line.text_stripped, "\\\\N") ~= nil then line.margin_t = line.styleref.margin_t + ksy_pandora[line.styleref.fontname]["line_height"] * #re.find(line.text_stripped, "\\\\N") line.margin_t = line.margin_t + ksy_pandora[line.styleref.fontname]["line_height"] * ((j > #re.find(line.text_stripped, "\\\\N") + 1 and 1 or j) - 1) end return end if line.margin_t ~= 0 then if line.styleref.name == "Sx-zh" then local margin_t_diff = config["styleref"]["Sx-zh"]["margin_t"] margin_t_diff = margin_t_diff - config["styleref"]["Sx-jp"]["margin_t"] line.margin_t = line.margin_t + margin_t_diff end end if re.find(line.text, "\\\\an8") ~= nil then line.margin_t = line.margin_t + ksy_pandora[line.styleref.fontname]["margin_t"] end local dialog_start = ksy.sub(line.text_stripped, 1, 1) if dialog_start == "…" then line.margin_r = line.margin_r + _calwidth(dialog_start) + .5 end if dialog_start == "「" then line.margin_r = line.margin_r + _calwidth(dialog_start) * .5 + .5 end local dialog_end = ksy.sub(line.text_stripped, ksy.len(line.text_stripped), 1) if dialog_end == "?" or dialog_end == "!" or dialog_end == "…" then line.margin_l = line.margin_l + _calwidth(dialog_end) + .5 end if dialog_end == "」" then line.margin_l = line.margin_l + _calwidth(dialog_end) * .5 + .5 end if config.JPN_only == true then line.margin_t = (line.margin_t == 0 and line.styleref.margin_t or line.margin_t) + (re.find(line.text, "\\\\an8") ~= nil and ksy_pandora[line.styleref.fontname]["JPN_only"]["Yoffset2"] or ksy_pandora[line.styleref.fontname]["JPN_only"]["Yoffset"]) end end function ksy_time() local start_time = line.start_time local end_time = line.end_time local start_frame = aegisub.frame_from_ms(start_time) local end_frame = aegisub.frame_from_ms(end_time) local start_time_fix = aegisub.ms_from_frame(start_frame) local end_time_fix = aegisub.ms_from_frame(end_frame) line.start_time = math.floor(start_time_fix / 10 + .5) * 10 line.end_time = math.floor(end_time_fix / 10 + .5) * 10 end ksy.elf = function(line, elfraws, elfindex) local styleref = line.styleref local command_index = elfraws[elfindex]["first"] return { furi = function(num, text, fsc, fsp) if config.JPN_only ~= true and ksy_pandora[styleref.fontname]["JPN_only"] ~= nil then return nil end text = text and text or num num = tonumber(num) and num or ksy.len(num) fsc = tonumber(fsc) and fsc or 100 fsp = tonumber(fsp) and fsp or 0 local befores = string.sub(line.text, 1, command_index - 1) .. "}" befores = re.sub(befores, "{.*?}", "") local init = function() local gjpqy = false local autofsc = true local minfsc = fsc for _, elfraw in ipairs(elfraws) do local ame = ksy.func(elfraw["str"]).parse() local _length = tonumber(ame.args[1]) and tonumber(ame.args[1]) or ksy.len(ame.args[1]) local _text = #ame.args >= 2 and ame.args[2] or ame.args[1] if re.find(_text, "[gjpqy]") ~= nil then gjpqy = true end if #ame.args > 2 then autofsc = false end if autofsc then local width = _calwidth(ksy.sub( re.sub(string.sub(line.text, 1, elfraw["first"] - 1) .. "}", "{.*?}", ""), -_length)) local _width = _calwidth(_text) * ksy_pandora[styleref.fontname]["furigana"]["fscx"] * .01 local _fsc = math.floor(width / _width * 100) if _fsc < minfsc then minfsc = _fsc end end end if autofsc then local width = _calwidth(ksy.sub(befores, -num)) local _width = _calwidth(text) * ksy_pandora[styleref.fontname]["furigana"]["fscx"] * .01 * minfsc * .01 fsp = (width - _width) / (ksy.len(text) + 1) fsp = ksy.round(fsp, 1) fsp = math.max(fsp, 0) end return gjpqy, minfsc end local gjpqy, minfsc = init() local x = _callineleft() + _calwidth(befores) - _calwidth(ksy.sub(befores, -num)) / 2 local y = meta.res_y - ksy.str(line.text_stripped, styleref).geth() - (line.margin_t == 0 and styleref.margin_t or line.margin_t) y = y + ksy_pandora[styleref.fontname]["furigana"]["Yoffset"] if re.find(line.text, "\\\\an8") ~= nil then y = meta.res_y - y + ksy_pandora[styleref.fontname]["furigana"]["Yoffset"] + ksy_pandora[styleref.fontname]["furigana"]["Yoffset2"] elseif gjpqy then y = y + ksy_pandora[styleref.fontname]["furigana"]["Yoffset3"] end text = ("%s{\\fsp}%s"):format(ksy.sub(text, 1, ksy.len(text) - 1), ksy.sub(text, -1)) return { characters["Basic"] .. ksy_effect(false) .. ksy_character() .. _getlineeffects(string.sub(line.text, 1, command_index - 1) .. "}") .. string.format(ksy_pandora[styleref.fontname]["furigana"]["content"], re.find(line.text, "\\\\an8") ~= nil and "8" or "2", minfsc * .01 * (config.JPN_only == true and ksy_pandora[styleref.fontname]["JPN_only"]["fs"] or styleref.fontsize), ksy_pandora[styleref.fontname]["furigana"]["fscx"] * styleref.scale_x * .01, ksy_pandora[styleref.fontname]["furigana"]["fscy"] * styleref.scale_y * .01, (fsp == 0 and "" or fsp), ksy.round(x, 1), ksy.round(y, 1), text) } end, } end function ksy_relocate(res) local relocates = { res } if orgline.styleref["align"] == 7 then for i = 1, (re.find(line.text_stripped, "\\\\N") ~= nil and #re.find(line.text_stripped, "\\\\N") or 0) + 1 do relocates[i] = res end end local in_eff = false for i = 1, ksy.len(line.text) do local char_cur = ksy.sub(line.text, i, 1) if char_cur == "{" then in_eff = true elseif char_cur == "}" then in_eff = false end if in_eff then goto continue end for search, relocate in pairs(ksy_pandora[line.styleref.fontname]["relocate"]) do if char_cur == search then local befores = ksy.sub(line.text, 1, i - 1) befores = re.sub(befores, "{.*?}", "") local twidth, theight = _calwidth(befores), ksy.str(line.text_stripped).geth() local x = _callineleft() + twidth if re.find(relocate["content"], "\\\\an5") ~= nil then x = x + _calwidth(search) / 2 elseif re.find(relocate["content"], "\\\\an6") ~= nil then x = x + _calwidth(search) end local y = meta.res_y - theight / 2 - (line.margin_t == 0 and line.styleref.margin_t or line.margin_t) if orgline.styleref["align"] == 7 then y = meta.res_y - y y = y + ksy_pandora[line.styleref.fontname]["line_height"] * (re.find(befores, "\\\\N") ~= nil and #re.find(befores, "\\\\N") or 0) end x = x + relocate["Xoffset"] y = y + relocate["Yoffset"] if re.find(line.text, "\\\\an8") ~= nil then y = meta.res_y - y + relocate["Yoffset"] + relocate["Yoffset2"] end relocates[#relocates + 1] = characters["Basic"] .. ksy_effect(false) .. ksy_character() .. _getlineeffects(ksy.sub(line.text, 1, i - 1)) .. string.format(relocate["content"], x, y) end end ::continue:: end local elfraws = re.find(line.text, "\\\\[^(]+\\([^)]*\\)") if elfraws ~= nil then for elfindex, elfraw in ipairs(elfraws) do local ame = ksy.func(elfraw["str"]).parse() local elf = ksy.elf(line, elfraws, elfindex) if elf[ame.func] ~= nil then local elf_lines = elf[ame.func](unpack(ame.args)) if elf_lines then ksy.table(relocates).add(unpack(elf_lines)) end end end end if orgline.styleref["align"] == 7 and orgline.actor ~= "" then fad = re.find(line.text, "\\\\fad") ~= nil and "{\\fad" .. re.match(line.text, "\\\\fad(\\([^\\)]+\\))")[2]["str"] .. "}" or "" relocates[#relocates + 1] = characters["actor"] .. fad .. line.actor if j == #relocates then restyle("Rx-actor") end end res = relocates[j] maxloop(#relocates) return res end function output_info(str) function _formatMilliseconds(milliseconds) local seconds = math.floor(milliseconds / 1000) local minutes = math.floor(seconds / 60) local hours = math.floor(minutes / 60) local remainingMinutes = minutes % 60 local remainingSeconds = seconds % 60 local millisecondsPart = milliseconds % 1000 local formattedTime = string.format("%d:%02d:%02d.%02d", hours, remainingMinutes, remainingSeconds, millisecondsPart / 10) return formattedTime end local _info = _formatMilliseconds(line.start_time) .. ": " .. str ksy.debug(_info) end function ksy_check() if orgline.styleref["align"] == 7 then return end local width = _calwidth(line.text_stripped) if width > meta.res_x * .9 then output_info("※Invalid width") end if width > meta.res_x * .8 then output_info("Dangerous width") end local x = (meta.res_x - width) / 2 if x - math.abs((line.margin_l - line.margin_r) / 2) < 0 then output_info("※Invalid edge") end if x - math.abs((line.margin_l - line.margin_r) / 2) < meta.res_x / 2 * (1 - .8) then output_info("Dangerous edge") end if aegisub.frame_from_ms(line.end_time) - aegisub.frame_from_ms(line.start_time) <= 6 then output_info("※Invalid duration") end if aegisub.frame_from_ms(line.end_time) - aegisub.frame_from_ms(line.start_time) <= config["check_duration"] then output_info("Dangerous duration") end local start_frame = aegisub.frame_from_ms(line.start_time) local end_frame = aegisub.frame_from_ms(line.end_time) local start_frame_min_diff = config["check_start_frame"] local end_frame_min_diff = config["check_end_frame"] if keyframes[start_frame] ~= true then for i = start_frame - start_frame_min_diff, start_frame + start_frame_min_diff, 1 do if keyframes[i] then output_info("Dangerous start_frame") end end end if keyframes[end_frame] ~= true then for i = end_frame - end_frame_min_diff, end_frame + end_frame_min_diff, 1 do if keyframes[i] then output_info("Dangerous end_frame") end end end if start_frame - prev_end_frame > 0 and start_frame - prev_end_frame <= 4 then output_info("※Invalid time_interval") end if start_frame - prev_end_frame > 0 and start_frame - prev_end_frame <= config["check_time_interval"] then output_info("Dangerous time_interval") end prev_end_frame = end_frame end Comment: 0,0:00:00.00,0:00:00.00,Sx-jp,AME,0,0,0,code line,fxgroup.SX = (line.styleref.name ~= "Sx-zh" or config.JPN_only ~= true) if ksy.sub(line.actor, 1, 3) == "fx-" then fxgroup.SX = false end Comment: 0,0:00:00.00,0:00:00.00,Sx-jp,AME,0,0,0,template pre-line Paulownia-jp fxgroup SX,!ksy_shuusei()! Comment: 0,0:00:00.00,0:00:00.00,Sx-jp,AME,0,0,0,template line Paulownia-jp notext fxgroup SX,!""! Comment: 0,0:00:00.00,0:00:00.00,Sx-zh,AME,0,0,0,code line,fxgroup.SX = (line.styleref.name ~= "Sx-zh" or config.JPN_only ~= true) if ksy.sub(line.actor, 1, 3) == "fx-" then fxgroup.SX = false if string.lower(line.actor) == "fx-chs" and string.lower(ksy.sub(meta["language"], 1, 3)) == "chs" then fxgroup.SX = true elseif string.lower(line.actor) == "fx-cht" and string.lower(ksy.sub(meta["language"], 1, 3)) == "cht" then fxgroup.SX = true end end Comment: 0,0:00:00.00,0:00:00.00,Sx-zh,AME,0,0,0,template pre-line Paulownia-zh fxgroup SX,!ksy_shuusei()! Comment: 0,0:00:00.00,0:00:00.00,Sx-zh,AME,0,0,0,template line Paulownia-zh notext fxgroup SX,!""! Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,AME,0,0,0,code line all,fxgroup.ZH = (config.JPN_only ~= true) Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,code line,fxgroup.RX1 = (line.styleref.fontname == "方正悠宋+ GBK 509R" and fxgroup.ZH) fxgroup.RX2 = (line.styleref.fontname == "方正中粗雅宋_GBK" and fxgroup.ZH) fxgroup.RX3 = (line.styleref.fontname == "方正准雅宋_GBK" and fxgroup.ZH) Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,code line,alignment = 7 match = re.match(orgline.text, "\\\\an(\\d)") if match then alignment = match[2]["str"] alignment = tonumber(alignment) end start_fad = true end_fad = true if line.layer == 1 then start_fad = false elseif line.layer == 2 then end_fad = false elseif line.layer == 3 then start_fad = false end_fad = false end Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX1,!relayer(2)!!ksy.func(function() local text = strrep(line.text_stripped, "?", "? ") remember("text", text) end).run()!!ksy.func(function() local height = ksy.str(recall.text).geth() * (re.find(recall.text, "\\\\N") ~= nil and #re.find(recall.text, "\\\\N") + 1 or 1) remember("height", height) end).run()!!ksy.func(function() local max_width = 0 for part in re.gsplit(recall.text, "\\\\N", true) do if ksy.str(part).getw() > max_width then max_width = ksy.str(part).getw() end end if alignment == 1 or alignment == 7 then max_width = max_width - ksy.str("。").getw() * .5 end remember("width", max_width) end).run()!{\an!alignment!\p1\pos(!ksy.func(function() if alignment == 7 or alignment == 1 then return 25 elseif alignment == 9 or alignment == 3 then return meta.res_x - 25 end end).run()!,!ksy.func(function() if alignment == 7 or alignment == 9 then return 25 elseif alignment == 1 or alignment == 3 then return meta.res_y - 25 end end).run()!)\1c&HFFFFFF&\bord16\blur6\fad(!start_fad and 300 or 0!,!end_fad and 300 or 0!)\fscx100}m 0 0 l 0 !recall.height! l !recall.width! !recall.height! l !recall.width! 0 Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX1,!relayer(3)!!ksy.func(function() local max_width = 0 for part in re.gsplit(recall.text, "\\\\N", true) do if ksy.str(part).getw() > max_width then max_width = ksy.str(part).getw() end end if alignment == 1 or alignment == 7 then max_width = max_width - ksy.str("。").getw() * .5 end remember("width", max_width) end).run()!{\an!ksy.func(function() if alignment == 7 or alignment == 9 then return 7 elseif alignment == 1 or alignment == 3 then return 1 end end).run()!\pos(!ksy.func(function() if alignment == 7 or alignment == 1 then return 25 elseif alignment == 9 or alignment == 3 then return meta.res_x - 25 - recall.width end end).run()!,!ksy.func(function() if alignment == 7 or alignment == 9 then return 25 elseif alignment == 1 or alignment == 3 then return meta.res_y - 25 end end).run()!)\fad(!start_fad and 300 or 0!,!end_fad and 300 or 0!)\3a&HFF&}!strrep(orgline.text,"?","? ")! Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX2,!relayer(2)!!ksy.func(function() local max_width = 0 for part in re.gsplit(line.text_stripped, "\\\\N", true) do if ksy.str(part).getw() > max_width then max_width = ksy.str(part).getw() end end max_width = max_width - ksy.str("。").getw() * .5 if alignment == 9 or alignment == 3 then max_width = max_width + ksy.str("喵").getw() end remember("width", max_width) end).run()!!ksy.func(function() local height = ksy.str(line.text_stripped).geth() * (re.find(line.text_stripped, "\\\\N") ~= nil and #re.find(line.text_stripped, "\\\\N") + 1 or 1) + 5 * 2 remember("height", height) end).run()!{\an!alignment!\p1\pos(!remember("x", ksy.func(function() if alignment == 7 or alignment == 1 then return 0 elseif alignment == 9 or alignment == 3 then return meta.res_x - 0 end end)).run()!,!remember("y", ksy.func(function() if alignment == 7 or alignment == 9 then return 10 elseif alignment == 1 or alignment == 3 then return meta.res_y - 10 end end)).run()!)\clip(!recall.x > meta.res_x * .5 and meta.res_x - recall.width * 1.1 or 0!,!recall.y > meta.res_y * .5 and meta.res_y - recall.height - 10 or 10!,!recall.x > meta.res_x * .5 and meta.res_x or recall.width * 1.1!,!recall.y > meta.res_y * .5 and meta.res_y - 10 or recall.height + 10!)\3c&HFFFFFF&\bord!recall.width*.1!\be!recall.width*.1*.5*1.5!\1c&HFFFFFF&\fscx0\t(0,!start_fad and 500 or 1!,.4,\1c&H000000&\3c&H000000&\fscx100)\t(!$ldur - (end_fad and 500 or 0)!,!$ldur!,2,)\1c&HFFFFFF&\3c&HFFFFFF&\clip(!recall.x > meta.res_x * .5 and meta.res_x or recall.width * 1.1!)}m 0 0 l 0 !recall.height! l !recall.width*.9! !recall.height! l !recall.width*.9! 0 Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX2,!relayer(3)!{\an!alignment!\pos(!remember("x", ksy.func(function() if alignment == 7 or alignment == 1 then return 0 elseif alignment == 9 or alignment == 3 then return meta.res_x - 0 end end)).run()!,!remember("y", ksy.func(function() if alignment == 7 or alignment == 9 then return 10 elseif alignment == 1 or alignment == 3 then return meta.res_y - 10 end end)).run()!)\alpha&HFF&\1c&H000000&\blur16\t(!start_fad and 500 or 1!,!start_fad and 650 or 1!,.5,\alpha&H00&)\t(!start_fad and 500 or 1!,!start_fad and 800 or 1!,.4,\1c&HFFFFFF&\blur0)\t(!$ldur - (end_fad and 800 or 0)!,!$ldur - (end_fad and 500 or 0)!,2,)\alpha&HFF&\1c&H000000&\blur16)}!orgline.text! Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX3,!relayer(2)!!ksy.func(function() local text = line.text_stripped local height = ksy.str(text).geth() * (re.find(text, "\\\\N") ~= nil and #re.find(text, "\\\\N") + 1 or 1) local max_width = 0 for part in re.gsplit(text, "\\\\N", true) do if ksy.str(part).getw() > max_width then max_width = ksy.str(part).getw() end end max_width = max_width - ksy.str("。").getw() local bord = 24 local shape = string.format("m 0 0 l 0 %s b 0 %s 0 %s %s %s l %s %s b %s %s %s %s %s %s l %s 0 ", height, height + bord, height + bord, -bord, height + bord, -bord - max_width, height + bord, -bord - bord - max_width, height + bord, -bord - bord - max_width, height + bord, -bord - bord - max_width, height, -bord - bord - max_width) remember("shape", shape) remember("x", meta.res_x - line.styleref.margin_r + 4) remember("frz", 0.025 + height / 10 ^ 5 * 180 / math.pi) local effects = "" local fade_in = "\\org(100000,0)\\frz-" .. recall.frz .. "\\t(0,400,.8,\\frz0)" local fade_out = "\\fad(0,400)" if start_fad then effects = fade_in end if end_fad then effects = effects .. fade_out end remember("effects", effects) end).run()!{\an7\p1\pos(!recall.x!,0)\1c&HFFF9F0&\3c&HCCCCCC&\bord1\blur4\4c&H000000&\4a&HF0&\xshad12\yshad8!recall.effects!}!recall.shape!!restyle("Ex-effects")! Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX3,!relayer(3)!!ksy.func(function() local text = line.text_stripped local size = 0 local y = 0 local lines = re.find(text, "\\\\N") ~= nil and #re.find(text, "\\\\N") + 1 or 1 if lines == 1 then size = 24 y = 12 elseif lines == 2 then size = 30 y = 20 elseif lines >= 3 then size = 40 y = 24 end remember("size", size) remember("x", meta.res_x - line.styleref.margin_r - 4) remember("y", y) end).run()!!restyle("Ex-effects")!{\an7\p1\pos(!recall.x!,!recall.y!)\1c&H7642FA&\fscx!recall.size!\fscy!recall.size!\be1!recall.effects!}m 0 0 b 6.794 -6.232 28.105 -39.321 21.837 -54.177 b 12.203 -72.863 -23.644 -72.952 -34.366 -57.524 b -39.428 -52.292 -34.758 -34.203 -30.758 -27.275 b -40.222 -35.667 -47.687 -40.595 -57.615 -41.792 b -72.971 -36.39 -72.524 8.385 -59.328 19.242 b -54.095 24.304 -28.945 17.866 -13.49 6.634 b -31.981 4.608 -54.658 37.33 -54.488 47.624 b -54.55 61.517 -34.158 72.837 -16.935 68.667 b -12.256 116.772 15.084 184.126 56.137 211.231 b 56.869 208.499 57.833 202.169 56.333 199.571 b 14.878 165.77 -8.131 95.916 -10.909 57.105 b -8.579 51.141 -6.651 38.481 -6.687 30.419 b -7.615 44.811 -2.445 63.765 4.519 67.828 b 7.885 71.658 16.179 68.024 22.242 64.524 b 34.242 85.308 73.464 119.244 86.366 147.59 b 88.464 145.224 90.794 139.26 88.294 134.93 b 80.026 116.61 40.536 78.21 29.536 59.158 b 34.732 56.158 44.722 43.462 44.954 39.863 b 37.687 23.275 11.928 4.66 2 3.464 b -1.428 13.526 22.33 28.677 38.687 25.007 b 52.543 17.007 50.863 -25.902 40.033 -34.66 b 30.971 -36.356 -3.536 -14.124 0 0 m -0.536 -8.928 l -4.134 -9.16 l -9.598 -10.624 l -9.33 -6.16 b -12.696 -9.99 -17.062 -15.553 -22.294 -20.615 b -27.428 -31.507 -33.196 -45.497 -31 -53.694 b -21.742 -63.658 5.909 -65.765 15.141 -53.775 b 17.909 -44.981 8.49 -15.294 -0.536 -8.928 m -16.99 0.572 b -19.588 2.072 -24.285 5.938 -28.481 10.67 b -35.909 13.804 -47.435 15.84 -55.131 14.51 b -68.863 -5.275 -62.641 -28.497 -57.579 -33.729 b -49.017 -32.899 -36.454 -25.141 -26.99 -16.749 b -24.856 -11.053 -18.49 -2.026 -16.99 0.572 m -12.99 7.5 b -16.419 17.562 -19.775 43.749 -17.605 57.507 b -17.471 59.739 -18.203 62.471 -19.935 63.471 b -28.229 67.105 -47.122 58.383 -49.524 48.222 b -46.595 37.294 -34.141 20.866 -26.847 15.5 b -20.285 12.866 -15.954 10.366 -12.99 7.5 m 1.536 10.66 b 7.268 16.588 17.098 23.615 24.794 24.945 b 29.392 26.909 34.758 34.203 37.758 39.399 b 37.526 42.997 29.5 51.095 25.67 54.462 b 17.304 41.971 1.438 16.49 1.536 10.66 m -2.392 19.856 b -0.124 27.785 12.376 49.435 18.742 58.462 b 14.412 60.962 10.081 63.462 7.349 62.729 b 0.483 52.837 -3.954 31.151 -2.392 19.856 m 0 0 b 4.696 -3.866 7.526 -8.964 9.624 -11.33 b 18.517 -19.928 32.507 -25.696 37.337 -27.33 b 44.703 -16.572 46.043 5.749 36.553 19.311 b 33.954 20.811 31.222 20.079 28.49 19.347 b 22.258 12.553 9.696 4.794 4.232 3.33 b 2.866 2.964 1 1.732 0 0 Comment: 0,0:00:00.00,0:00:00.00,Rx-annotation,AME,0,0,0,template line notext fxgroup RX3,!relayer(4)!!ksy.func(function() local text = line.text_stripped local max_width = 0 for part in re.gsplit(text, "\\\\N", true) do if ksy.str(part).getw() > max_width then max_width = ksy.str(part).getw() end end remember("max_width", max_width) end).run()!{\bord0\an7\pos(!meta.res_x-line.styleref.margin_r-recall.max_width!,!line.styleref.margin_t!)!recall.effects!}!ksy.func(function() text = orgline.text text = re.sub(text, "・", "·") return text end).run()! Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔喵▔▔▔▔▔▔▔▔▔▔ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁原文▁▁▁▁▁▁▁▁▁▁ Comment: 0,0:00:00.73,0:00:03.94,Sx-jp,部長,0,0,0,karaoke,津田 ロマンスロイド買ったって本当か? Comment: 0,0:00:03.94,0:00:05.32,Sx-jp,津田あかね,0,0,0,karaoke,えっ?ぶちょ… Comment: 0,0:00:05.32,0:00:08.20,Sx-jp,伊藤さん,0,0,0,karaoke,嘘ですよね 津田さんがそんな犯罪… Comment: 0,0:00:08.20,0:00:09.32,Sx-jp,津田あかね,0,0,0,karaoke,みんな… Comment: 0,0:00:10.20,0:00:12.53,Sx-jp,撫子,0,0,0,karaoke,大丈夫です マスター Comment: 0,0:00:12.53,0:00:15.08,Sx-jp,撫子,0,0,0,karaoke,私といつまでも一緒にいましょう? Comment: 0,0:00:21.83,0:00:23.80,Sx-jp,津田あかね,0,0,0,karaoke,ゆ 夢… Comment: 0,0:00:26.67,0:00:29.05,Sx-jp,津田あかね,0,0,0,karaoke,気持ちよさそうに寝ちゃって Comment: 0,0:00:30.09,0:00:31.76,Sx-jp,津田あかね,0,0,0,karaoke,ん あれ Comment: 0,0:00:31.76,0:00:33.35,Sx-jp,津田あかね,0,0,0,karaoke,ロボットって寝なくない? Comment: 0,0:00:34.51,0:00:36.35,Sx-jp,津田あかね,0,0,0,karaoke,こ 壊れた? Comment: 0,0:00:37.23,0:00:39.48,Sx-jp,津田あかね,0,0,0,karaoke,もしかして充電切れ? Comment: 0,0:00:39.48,0:00:42.11,Sx-jp,津田あかね,0,0,0,karaoke,そういえばずっと動きっぱなしだったわね Comment: 0,0:00:44.15,0:00:46.48,Sx-jp,津田あかね,0,0,0,karaoke,よし これでオッケー Comment: 0,0:00:49.65,0:00:52.24,Sx-jp,津田あかね,0,0,0,karaoke,って どこに電源ボタンあるの? Comment: 0,0:00:52.49,0:00:55.74,Sx-jp,津田あかね,0,0,0,karaoke,え えっと…背中とか? Comment: 0,0:00:57.16,0:00:58.25,Sx-jp,津田あかね,0,0,0,karaoke,ない Comment: 0,0:00:58.66,0:00:59.91,Sx-jp,津田あかね,0,0,0,karaoke,前は… Comment: 0,0:01:01.62,0:01:03.13,Sx-jp,津田あかね,200,0,0,karaoke,ほくろしかない… Comment: 0,0:01:04.13,0:01:06.25,Sx-jp,津田あかね,200,0,0,karaoke,今のアタシ完全に変態 Comment: 0,0:01:06.84,0:01:08.72,Sx-jp,津田あかね,0,0,0,karaoke,でも このままじゃ… Comment: 0,0:01:13.97,0:01:14.97,Sx-jp,津田あかね,600,0,0,karaoke,これ… Comment: 0,0:01:15.68,0:01:17.10,Sx-jp,津田あかね,950,0,0,karaoke,QRコード! Comment: 0,0:01:18.27,0:01:19.81,Sx-jp,津田あかね,0,0,0,karaoke,何かわかるかも Comment: 0,0:01:21.14,0:01:23.65,Sx-jp,画像,0,0,0,karaoke,お買い上げ ありがとうございま~す Comment: 0,0:01:23.65,0:01:29.03,Sx-jp,画像,0,0,0,karaoke,本動画では セックス用アンドロイド「撫子」の取り扱い説明をしていきたいと思います Comment: 0,0:01:29.53,0:01:31.57,Sx-jp,画像,0,0,0,karaoke,まずは起動方法から! Comment: 0,0:01:35.37,0:01:38.79,Sx-jp,津田あかね,0,0,0,karaoke,そもそも再起動させる必要あるのかな Comment: 0,0:01:38.79,0:01:41.33,Sx-jp,津田あかね,0,0,0,karaoke,処分…とまではいかなくても Comment: 0,0:01:41.33,0:01:43.29,Sx-jp,津田あかね,0,0,0,karaoke,このままにしておいたほうが… Comment: 0,0:01:46.25,0:01:49.88,Sx-jp,津田あかね,0,0,0,karaoke,そっかあ もうこれ頼んでたっけ… Comment: 0,0:01:49.88,0:01:51.13,Sx-jp,津田あかね,0,0,0,karaoke,よし! Comment: 0,0:01:51.38,0:01:55.43,Sx-jp,画像,0,0,0,karaoke,{\fad(500,0)}起動方法はズバリ フレンチキッス Comment: 0,0:01:55.43,0:01:59.10,Sx-jp,画像,0,0,0,karaoke,口の中にあるスイッチを 優しく押してください Comment: 0,0:02:03.85,0:02:07.02,Sx-jp,津田あかね,0,0,0,karaoke,どこ…どこにあるのスイッチ! Comment: 0,0:02:09.82,0:02:10.90,Sx-jp,撫子,0,0,0,karaoke,マスター? Comment: 0,0:02:11.28,0:02:12.53,Sx-jp,津田あかね,0,0,0,karaoke,起きた! Comment: 0,0:02:12.53,0:02:15.66,Sx-jp,津田あかね,0,0,0,karaoke,全然起きないからホントに壊れたかと思った Comment: 0,0:02:16.16,0:02:18.62,Sx-jp,津田あかね,0,0,0,karaoke,{\fad(0,800)}よかった~ Comment: 0,0:02:20.16,0:02:22.91,Sx-jp,撫子,0,0,0,karaoke,充電のことをすっかり忘れていまして… Comment: 0,0:02:22.91,0:02:26.29,Sx-jp,津田あかね,0,0,0,karaoke,大丈夫 アタシも気が回らなくてごめん Comment: 0,0:02:26.29,0:02:28.21,Sx-jp,津田あかね,0,0,0,karaoke,それより ちょっと Comment: 0,0:02:28.46,0:02:30.59,Sx-jp,撫子,0,0,0,karaoke,あの…マスター これって Comment: 0,0:02:30.59,0:02:34.34,Sx-jp,津田あかね,0,0,0,karaoke,サイズ合うのセーラー服だけだったからポチっておいたの Comment: 0,0:02:34.34,0:02:36.72,Sx-jp,津田あかね,0,0,0,karaoke,思ったよりコスプレ感あるけど Comment: 0,0:02:37.68,0:02:39.72,Sx-jp,津田あかね,0,0,0,karaoke,やっぱりよく似合ってる Comment: 0,0:02:39.72,0:02:41.60,Sx-jp,津田あかね,0,0,0,karaoke,かわいいよ 撫子 Comment: 0,0:02:41.85,0:02:45.10,Sx-jp,撫子,0,0,0,karaoke,今 私の名前を呼んでくださいましたか? Comment: 0,0:02:45.10,0:02:48.36,Sx-jp,撫子,0,0,0,karaoke,初めてですよね 名前で呼んでくださったのは Comment: 0,0:02:48.73,0:02:50.98,Sx-jp,撫子,0,0,0,karaoke,すごくうれしいです Comment: 0,0:02:50.98,0:02:53.99,Sx-jp,撫子,0,0,0,karaoke,これからもっともっとたくさん呼んでください Comment: 0,0:02:54.20,0:02:56.16,Sx-jp,津田あかね,0,0,0,karaoke,や ヤバい… Comment: 0,0:02:56.16,0:02:57.99,Sx-jp,津田あかね,0,0,0,karaoke,めちゃくちゃかわいい Comment: 0,0:02:58.74,0:03:02.87,Sx-jp,撫子,0,0,0,karaoke,今後はマスターの就寝中は私もスリープモードへ移行しますね Comment: 0,0:03:02.87,0:03:03.87,Sx-jp,津田あかね,0,0,0,karaoke,う うん Comment: 0,0:03:03.87,0:03:08.17,Sx-jp,撫子,0,0,0,karaoke,ただスリープ解除には 再起動と同じ手順が必要ですが Comment: 0,0:03:08.17,0:03:08.63,Sx-jp,津田あかね,0,0,0,karaoke,えっ? Comment: 0,0:03:09.00,0:03:10.21,Sx-jp,津田あかね,0,0,0,karaoke,再起動と? Comment: 0,0:03:10.21,0:03:12.76,Sx-jp,撫子,0,0,0,karaoke,マスター認証の機能制限の一つです Comment: 0,0:03:13.30,0:03:16.76,Sx-jp,撫子,0,0,0,karaoke,{\an8}認証済みなら呼びかけでスリープ解除されるのですが Comment: 0,0:03:17.14,0:03:21.14,Sx-jp,撫子,0,0,0,karaoke,マスター認証と 毎朝のスリープ解除 Comment: 0,0:03:21.39,0:03:22.97,Sx-jp,撫子,0,0,0,karaoke,どっちがいいですか? Comment: 0,0:03:26.69,0:03:30.02,Sx-jp,津田あかね,0,0,0,karaoke,{\fad(0,800)}どっちも無理ー! Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔原文▔▔▔▔▔▔▔▔▔▔ Comment: 1,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁译文▁▁▁▁▁▁▁▁▁▁ Comment: 1,0:00:00.73,0:00:03.94,Sx-zh,部長,0,0,0,karaoke,津田 你真的买了性爱用机器人? Comment: 1,0:00:03.94,0:00:05.32,Sx-zh,津田あかね,0,0,0,karaoke,诶?经理… Comment: 1,0:00:05.32,0:00:08.20,Sx-zh,伊藤さん,0,0,0,karaoke,这不是真的吧 津田前辈怎么会犯罪… Comment: 1,0:00:08.20,0:00:09.32,Sx-zh,津田あかね,0,0,0,karaoke,大伙… Comment: 1,0:00:10.20,0:00:12.53,Sx-zh,撫子,0,0,0,karaoke,不用担心 主人 Comment: 1,0:00:12.53,0:00:15.08,Sx-zh,撫子,0,0,0,karaoke,来跟我待一起一辈子吧? Comment: 1,0:00:21.83,0:00:23.80,Sx-zh,津田あかね,0,0,0,karaoke,是 是梦… Comment: 1,0:00:26.67,0:00:29.05,Sx-zh,津田あかね,0,0,0,karaoke,亏你还睡得这么香 Comment: 1,0:00:30.09,0:00:31.76,Sx-zh,津田あかね,0,0,0,karaoke,诶 不对 Comment: 1,0:00:31.76,0:00:33.35,Sx-zh,津田あかね,0,0,0,karaoke,机器人需要睡觉吗? Comment: 1,0:00:34.51,0:00:36.35,Sx-zh,津田あかね,0,0,0,karaoke,坏 坏掉了吗? Comment: 1,0:00:37.23,0:00:39.48,Sx-zh,津田あかね,0,0,0,karaoke,难道是电池用完了? Comment: 1,0:00:39.48,0:00:42.11,Sx-zh,津田あかね,0,0,0,karaoke,说起来确实一直开着没关过机 Comment: 1,0:00:44.15,0:00:46.48,Sx-zh,津田あかね,0,0,0,karaoke,好 这样应该就行了 Comment: 1,0:00:49.65,0:00:52.24,Sx-zh,津田あかね,0,0,0,karaoke,不对 电源开关在哪里啊? Comment: 1,0:00:52.49,0:00:55.74,Sx-zh,津田あかね,0,0,0,karaoke,我看看…在背后吗? Comment: 1,0:00:57.16,0:00:58.25,Sx-zh,津田あかね,0,0,0,karaoke,没有 Comment: 1,0:00:58.66,0:00:59.91,Sx-zh,津田あかね,0,0,0,karaoke,前面呢… Comment: 1,0:01:01.62,0:01:03.13,Sx-zh,津田あかね,200,0,0,karaoke,只看到有痣… Comment: 1,0:01:04.13,0:01:06.25,Sx-zh,津田あかね,200,0,0,karaoke,我这不妥妥的变态吗 Comment: 1,0:01:06.84,0:01:08.72,Sx-zh,津田あかね,0,0,0,karaoke,但是 也不能放着不管… Comment: 1,0:01:13.97,0:01:14.97,Sx-zh,津田あかね,600,0,0,karaoke,这是… Comment: 1,0:01:15.68,0:01:17.10,Sx-zh,津田あかね,950,0,0,karaoke,二维码! Comment: 2,0:01:15.47,0:01:17.77,Rx-annotation,,950,0,0,karaoke,二维码内容是动画的官网网址: https://hanisuka.deregula.com/ 。 Comment: 1,0:01:18.27,0:01:19.81,Sx-zh,津田あかね,0,0,0,karaoke,说不定能知道些什么 Comment: 1,0:01:21.14,0:01:23.65,Sx-zh,画像,0,0,0,karaoke,非常感谢您购买该产品 Comment: 1,0:01:23.65,0:01:29.03,Sx-zh,画像,0,0,0,karaoke,本视频将会为您介绍性爱用机器人「抚子」的使用方法 Comment: 1,0:01:29.53,0:01:31.57,Sx-zh,画像,0,0,0,karaoke,首先是启动方式! Comment: 1,0:01:35.37,0:01:38.79,Sx-zh,津田あかね,0,0,0,karaoke,说起来有必要给她重启吗 Comment: 1,0:01:38.79,0:01:41.33,Sx-zh,津田あかね,0,0,0,karaoke,丢掉…倒也不至于 Comment: 1,0:01:41.33,0:01:43.29,Sx-zh,津田あかね,0,0,0,karaoke,不如就这么把她放着… Comment: 1,0:01:46.25,0:01:49.88,Sx-zh,津田あかね,0,0,0,karaoke,对啊 我都下单买这个了… Comment: 1,0:01:49.88,0:01:51.13,Sx-zh,津田あかね,0,0,0,karaoke,好! Comment: 1,0:01:51.38,0:01:55.43,Sx-zh,画像,0,0,0,karaoke,{\fad(500,0)}启动方式简单来说 就是舌吻 Comment: 1,0:01:55.43,0:01:59.10,Sx-zh,画像,0,0,0,karaoke,请温柔地按下她嘴里的开关 Comment: 0,0:01:55.43,0:01:59.10,Rx-annotation,,0,0,0,karaoke,设定上,抚子口腔里有非常容易坏掉的电源开关。\N因而不能直接用手指,而是要用舌头按下。 Comment: 1,0:02:03.85,0:02:07.02,Sx-zh,津田あかね,0,0,0,karaoke,在哪…那个按钮在哪呀! Comment: 1,0:02:09.82,0:02:10.90,Sx-zh,撫子,0,0,0,karaoke,主人? Comment: 1,0:02:11.28,0:02:12.53,Sx-zh,津田あかね,0,0,0,karaoke,你醒了! Comment: 1,0:02:12.53,0:02:15.66,Sx-zh,津田あかね,0,0,0,karaoke,一直醒不过来我还以为你坏掉了 Comment: 1,0:02:16.16,0:02:18.62,Sx-zh,津田あかね,0,0,0,karaoke,{\fad(0,800)}太好了 Comment: 1,0:02:20.16,0:02:22.91,Sx-zh,撫子,0,0,0,karaoke,我完全没想起来要充电的事… Comment: 1,0:02:22.91,0:02:26.29,Sx-zh,津田あかね,0,0,0,karaoke,没事啦 我也没注意到抱歉了 Comment: 1,0:02:26.29,0:02:28.21,Sx-zh,津田あかね,0,0,0,karaoke,比起这些 快过来 Comment: 1,0:02:28.46,0:02:30.59,Sx-zh,撫子,0,0,0,karaoke,那个…主人 请问这是 Comment: 1,0:02:30.59,0:02:34.34,Sx-zh,津田あかね,0,0,0,karaoke,看到你穿着应该合身的水手服我就下单了 Comment: 1,0:02:34.34,0:02:36.72,Sx-zh,津田あかね,0,0,0,karaoke,虽然没想到还是很{\fsp10}像{\fsp}Cospla{\fsp10}y{\fsp} Comment: 1,0:02:37.68,0:02:39.72,Sx-zh,津田あかね,0,0,0,karaoke,果然很合你身 Comment: 1,0:02:39.72,0:02:41.60,Sx-zh,津田あかね,0,0,0,karaoke,很可爱喔 抚子 Comment: 1,0:02:41.85,0:02:45.10,Sx-zh,撫子,0,0,0,karaoke,主人刚才叫我的名字了吗? Comment: 1,0:02:45.10,0:02:48.36,Sx-zh,撫子,0,0,0,karaoke,这还是主人第一次直接叫我名字吧 Comment: 1,0:02:48.73,0:02:50.98,Sx-zh,撫子,0,0,0,karaoke,我真的好开心 Comment: 1,0:02:50.98,0:02:53.99,Sx-zh,撫子,0,0,0,karaoke,从今往后请主人再多多这样叫我吧 Comment: 1,0:02:54.20,0:02:56.16,Sx-zh,津田あかね,0,0,0,karaoke,不 不妙… Comment: 1,0:02:56.16,0:02:57.99,Sx-zh,津田あかね,0,0,0,karaoke,她真的好可爱啊 Comment: 1,0:02:58.74,0:03:02.87,Sx-zh,撫子,0,0,0,karaoke,之后主人睡觉的时候我也切换到睡眠模式吧 Comment: 1,0:03:02.87,0:03:03.87,Sx-zh,津田あかね,0,0,0,karaoke,嗯 Comment: 1,0:03:03.87,0:03:08.17,Sx-zh,撫子,0,0,0,karaoke,不过解除睡眠模式 需要和重启一样的步骤 Comment: 1,0:03:08.17,0:03:08.63,Sx-zh,津田あかね,0,0,0,karaoke,诶? Comment: 1,0:03:09.00,0:03:10.21,Sx-zh,津田あかね,0,0,0,karaoke,和重启一样? Comment: 1,0:03:10.21,0:03:12.76,Sx-zh,撫子,0,0,0,karaoke,这也是未进行主人认证的一个限制 Comment: 1,0:03:13.30,0:03:16.76,Sx-zh,撫子,0,0,0,karaoke,{\an8}已认证的话只要打个招呼就能解除睡眠模式 Comment: 1,0:03:17.14,0:03:21.14,Sx-zh,撫子,0,0,0,karaoke,主人认证 和每天早上解除睡眠模式 Comment: 1,0:03:21.39,0:03:22.97,Sx-zh,撫子,0,0,0,karaoke,主人想选哪一个呢? Comment: 1,0:03:26.69,0:03:30.02,Sx-zh,津田あかね,0,0,0,karaoke,{\fad(0,800)}哪个都不想! Comment: 1,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▔▔▔▔▔▔▔▔▔▔译文▔▔▔▔▔▔▔▔▔▔ Comment: 0,0:00:00.00,0:00:00.00,Ex-invisible,,0,0,0,,▁▁▁▁▁▁▁▁▁▁特效生成行▁▁▁▁▁▁▁▁▁▁ Dialogue: 0,0:03:12.76,0:03:16.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:12.76,0:03:16.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:03:14.26,0:03:15.76,Ex-effects,,0,0,0,fx, Dialogue: 0,0:00:00.00,0:00:00.00,Sx-jp,fx-cache,0,0,0,fx, Dialogue: 0,0:00:00.00,0:00:00.00,Sx-zh,fx-cache,0,0,0,fx, Dialogue: 0,0:00:00.73,0:00:03.94,Sx-jp,部長,50,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}津田{\fscx200} {\fscx}ロマンスロイド買ったって本当か? Dialogue: 0,0:00:03.94,0:00:05.32,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}えっ?ぶちょ… Dialogue: 0,0:00:05.32,0:00:08.20,Sx-jp,伊藤さん,50,0,23,fx,{\blur2}{\3c&H0256B4&}{\fs78}嘘ですよね{\fscx200} {\fscx}津田さんがそんな犯罪… Dialogue: 0,0:00:08.20,0:00:09.32,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}みんな… Dialogue: 0,0:00:10.20,0:00:12.53,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}大丈夫です{\fscx200} {\fscx}マスター Dialogue: 0,0:00:12.53,0:00:15.08,Sx-jp,撫子,50,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}私といつまでも一緒にいましょう? Dialogue: 0,0:00:21.83,0:00:23.80,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}ゆ{\fscx200} {\fscx}夢… Dialogue: 0,0:00:26.67,0:00:29.05,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}気持ちよさそうに寝ちゃって Dialogue: 0,0:00:30.09,0:00:31.76,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}ん{\fscx200} {\fscx}あれ Dialogue: 0,0:00:31.76,0:00:33.35,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}ロボットって寝なくない? Dialogue: 0,0:00:34.51,0:00:36.35,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}こ{\fscx200} {\fscx}壊れた? Dialogue: 0,0:00:37.23,0:00:39.48,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}もしかして充電切れ? Dialogue: 0,0:00:39.48,0:00:42.11,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}そういえばずっと動きっぱなしだったわね Dialogue: 0,0:00:44.15,0:00:46.48,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}よし{\fscx200} {\fscx}これでオッケー Dialogue: 0,0:00:49.65,0:00:52.24,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}って{\fscx200} {\fscx}どこに電源ボタンあるの? Dialogue: 0,0:00:52.49,0:00:55.74,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}え{\fscx200} {\fscx}えっと…背中とか? Dialogue: 0,0:00:57.16,0:00:58.25,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}ない Dialogue: 0,0:00:58.66,0:00:59.91,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}前は… Dialogue: 0,0:01:01.62,0:01:03.13,Sx-jp,津田あかね,250,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}ほくろしかない… Dialogue: 0,0:01:04.13,0:01:06.25,Sx-jp,津田あかね,200,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}今のアタシ完全に変態 Dialogue: 0,0:01:06.84,0:01:08.72,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}でも{\fscx200} {\fscx}このままじゃ… Dialogue: 0,0:01:13.97,0:01:14.97,Sx-jp,津田あかね,650,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}これ… Dialogue: 0,0:01:15.68,0:01:17.10,Sx-jp,津田あかね,1000,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}QRコード! Dialogue: 0,0:01:18.27,0:01:19.81,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}何かわかるかも Dialogue: 0,0:01:21.14,0:01:23.65,Sx-jp,画像,0,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}お買い上げ{\fscx200} {\fscx}ありがとうございま~す Dialogue: 0,0:01:23.65,0:01:29.03,Sx-jp,画像,0,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}本動画では{\fscx200} {\fscx}セックス用アンドロイド「撫子」の取り扱い説明をしていきたいと思います Dialogue: 0,0:01:29.53,0:01:31.57,Sx-jp,画像,50,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}まずは起動方法から! Dialogue: 0,0:01:35.37,0:01:38.79,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}そもそも再起動させる必要あるのかな Dialogue: 0,0:01:38.79,0:01:41.33,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}処分…とまではいかなくても Dialogue: 0,0:01:41.33,0:01:43.29,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}このままにしておいたほうが… Dialogue: 0,0:01:46.25,0:01:49.88,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}そっかあ{\fscx200} {\fscx}もうこれ頼んでたっけ… Dialogue: 0,0:01:49.88,0:01:51.13,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}よし! Dialogue: 0,0:01:51.38,0:01:55.43,Sx-jp,画像,0,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}{\fad(500,0)}起動方法はズバリ{\fscx200} {\fscx}フレンチキッス Dialogue: 0,0:01:55.43,0:01:59.10,Sx-jp,画像,0,0,23,fx,{\blur2}{\3c&H974C06&}{\fs78}口の中にあるスイッチを{\fscx200} {\fscx}優しく押してください Dialogue: 0,0:02:03.85,0:02:07.02,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}どこ…どこにあるのスイッチ! Dialogue: 0,0:02:09.82,0:02:10.90,Sx-jp,撫子,50,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}マスター? Dialogue: 0,0:02:11.28,0:02:12.53,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}起きた! Dialogue: 0,0:02:12.53,0:02:15.66,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}全然起きないからホントに壊れたかと思った Dialogue: 0,0:02:16.16,0:02:18.62,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}{\fad(0,800)}よかった~ Dialogue: 0,0:02:20.16,0:02:22.91,Sx-jp,撫子,50,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}充電のことをすっかり忘れていまして… Dialogue: 0,0:02:22.91,0:02:26.29,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}大丈夫{\fscx200} {\fscx}アタシも気が回らなくてごめん Dialogue: 0,0:02:26.29,0:02:28.21,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}それより{\fscx200} {\fscx}ちょっと Dialogue: 0,0:02:28.46,0:02:30.59,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}あの…マスター{\fscx200} {\fscx}これって Dialogue: 0,0:02:30.59,0:02:34.34,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}サイズ合うのセーラー服だけだったからポチっておいたの Dialogue: 0,0:02:34.34,0:02:36.72,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}思ったよりコスプレ感あるけど Dialogue: 0,0:02:37.68,0:02:39.72,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}やっぱりよく似合ってる Dialogue: 0,0:02:39.72,0:02:41.60,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}かわいいよ{\fscx200} {\fscx}撫子 Dialogue: 0,0:02:41.85,0:02:45.10,Sx-jp,撫子,50,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}今{\fscx200} {\fscx}私の名前を呼んでくださいましたか? Dialogue: 0,0:02:45.10,0:02:48.36,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}初めてですよね{\fscx200} {\fscx}名前で呼んでくださったのは Dialogue: 0,0:02:48.73,0:02:50.98,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}すごくうれしいです Dialogue: 0,0:02:50.98,0:02:53.99,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}これからもっともっとたくさん呼んでください Dialogue: 0,0:02:54.20,0:02:56.16,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}や{\fscx200} {\fscx}ヤバい… Dialogue: 0,0:02:56.16,0:02:57.99,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}めちゃくちゃかわいい Dialogue: 0,0:02:58.74,0:03:02.87,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}今後はマスターの就寝中は私もスリープモードへ移行しますね Dialogue: 0,0:03:02.87,0:03:03.87,Sx-jp,津田あかね,0,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}う{\fscx200} {\fscx}うん Dialogue: 0,0:03:03.87,0:03:08.17,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}ただスリープ解除には{\fscx200} {\fscx}再起動と同じ手順が必要ですが Dialogue: 0,0:03:08.17,0:03:08.63,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}えっ? Dialogue: 0,0:03:09.00,0:03:10.21,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}再起動と? Dialogue: 0,0:03:10.21,0:03:12.76,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}マスター認証の機能制限の一つです Dialogue: 0,0:03:13.30,0:03:16.76,Sx-jp,撫子,0,0,14,fx,{\blur2}{\3c&HC10494&}{\fs78}{\an8}認証済みなら呼びかけでスリープ解除されるのですが Dialogue: 0,0:03:17.14,0:03:21.14,Sx-jp,撫子,0,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}マスター認証と{\fscx200} {\fscx}毎朝のスリープ解除 Dialogue: 0,0:03:21.39,0:03:22.97,Sx-jp,撫子,50,0,23,fx,{\blur2}{\3c&HC10494&}{\fs78}どっちがいいですか? Dialogue: 0,0:03:26.69,0:03:30.02,Sx-jp,津田あかね,50,0,23,fx,{\blur2}{\3c&H0312D2&}{\fs78}{\fad(0,800)}どっちも無理ー!