diff --git a/aegisub/auto4_auto3.cpp b/aegisub/auto4_auto3.cpp index 935567de0..8cd3b0ed9 100644 --- a/aegisub/auto4_auto3.cpp +++ b/aegisub/auto4_auto3.cpp @@ -1251,13 +1251,13 @@ continue_invalid_option: // absolute path, do nothing } if (!fname.IsOk() || !fname.FileExists()) { - lua_pushfstring(L, "Could not find Automation 3 script for inclusion: %s", fnames.mb_str(wxConvUTF8).data()); + lua_pushfstring(L, "Automation 3 include not found: %s", fnames.mb_str(wxConvUTF8).data()); lua_error(L); } LuaScriptReader script_reader(fname.GetFullPath()); if (lua_load(L, script_reader.reader_func, &script_reader, s->GetFilename().mb_str(wxConvUTF8))) { - lua_pushfstring(L, "An error occurred loading the Automation 3 script file \"%s\":\n\n%s", fname.GetFullPath().mb_str(wxConvUTF8).data(), lua_tostring(L, -1)); + lua_pushfstring(L, "Error loading Automation 3 include \"%s\":\n\n%s", fname.GetFullPath().mb_str(wxConvUTF8).data(), lua_tostring(L, -1)); lua_error(L); return 0; } @@ -1361,7 +1361,7 @@ continue_invalid_option: LuaScriptReader script_reader(GetFilename()); if (lua_load(L, script_reader.reader_func, &script_reader, GetFilename().mb_str(wxConvUTF8))) { wxString *err = new wxString(lua_tostring(L, -1), wxConvUTF8); - err->Prepend(_T("An error occurred loading the Automation 3 script file \"") + GetFilename() + _T("\":\n\n")); + err->Prepend(_T("Error loading Automation 3 script \"") + GetFilename() + _T("\":\n\n")); throw err->c_str(); } // and run it @@ -1370,7 +1370,7 @@ continue_invalid_option: if (err) { // error occurred, assumed to be on top of Lua stack wxString *errs = new wxString(lua_tostring(L, -1), wxConvUTF8); - errs->Prepend(_T("An error occurred initialising the Automation 3 script file \"") + GetFilename() + _T("\":\n\n")); + errs->Prepend(_T("Error initialising Automation 3 script \"") + GetFilename() + _T("\":\n\n")); throw errs->c_str(); } } @@ -1452,7 +1452,7 @@ continue_invalid_option: virtual Script* Produce(const wxString &filename) const { - if (filename.Right(4).Lower() == _T(".auto3")) { + if (filename.Right(6).Lower() == _T(".auto3")) { return new Auto3Script(filename); } else { return 0; diff --git a/automation/autoload/kara-templater.lua b/automation/autoload/kara-templater.lua new file mode 100644 index 000000000..eaa542060 --- /dev/null +++ b/automation/autoload/kara-templater.lua @@ -0,0 +1,161 @@ +--[[ + Copyright (c) 2007, Niels Martin Hansen, Rodrigo Braz Monteiro + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the Aegisub Group nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +]] + +-- Aegisub Automation 4 Lua karaoke templater tool +-- Parse and apply a karaoke effect written in ASS karaoke template language +-- See help file and wiki for more information on this + +script_name = "Karaoke Templater" +script_description = "Macro and export filter to apply karaoke effects using the template language" +script_author = "Niels Martin Hansen" +script_version = 1 + + +include("karaskel.lua") + + +-- Find and parse/prepare all karaoke template lines +function parse_templates(meta, styles, subs) + local templates = { once = {}, line = {}, syl = {}, char = {}, furi = {} } + for l = 1, #subs do + local l = subs[i] + if l.class == "dialogue" and l.comment then + local fx, fxtail = string.headtail(l.effect) + fx = fx:lower() + if fx == "code" then + parse_code(meta, styles, l, templates, fxtail) + elseif fx == "template" then + parse_template(meta, styles, l, templates, fxtail) + end + end + end +end + +function parse_code(meta, styles, line, templates, mods) + local template = { code = line.text, loops = 1, all = false } + local inserted = false + + local rest = mods + while rest ~= "" do + local m, t = string.headtail(rest) + rest = t + m = m:lower() + if m == "once" then + table.insert(templates.once, template) + inserted = true + elseif m == "line" then + table.insert(templates.line, template) + inserted = true + elseif m == "syl" then + table.insert(templates.syl, template) + inserted = true + elseif m == "char" then + table.insert(templates.char, template) + inserted = true + elseif m == "furi" then + table.insert(templates.furi, template) + inserted = true + elseif m == "all" then + template.all = true + elseif m == "repeat" then + local times, t = string.headtail(rest) + template.loops = tonumber(times) + if not template.loops then + aegisub.out(3, "Failed reading this repeat-count to a number: %s\nIn template code line: %s\nEffect field: %s\n\n", times, line.text, line.effect) + template.loops = 1 + else + rest = t + end + end + end + + if not inserted then + table.insert(templates.once, template) + end +end + +function parse_template(meta, styles, line, templates, mods) +end + + +-- Apply the templates +function apply_templates(meta, styles, subs, templates) + -- the environment the templates will run in + local tenv = { + -- put in some standard libs + string = string, + math = math + } + + -- run all run-once code snippets + for k, t in pairs(templates.code) do + + end +end + + +-- Main function to do the templating +function filter_apply_templates(subs, config) + aegisub.progress.task("Collecting header data...") + local meta, styles = karaskel.collect_head(subs) + + aegisub.progress.task("Parsing templates...") + local templates = parse_templates(meta, styles, subs) + + aegisub.progress.task("Applying templates...") + apply_templates(meta, styles, subs, templates) +end + +function macro_apply_templates(subs, sel) + filter_apply_templates(subs, {ismacro=true, sel=sel}) + aegisub.set_undo_point("apply karaoke template") +end + +function macro_can_template(subs) + -- check if this file has templates in it, don't allow running the macro if it hasn't + local num_dia = 0 + for i = 1, #subs do + local l = subs[i] + if l.class == "dialogue" then + num_dia = num_dia + 1 + -- test if the line is a template + if (string.headtail(l.effect)):lower() == "template" then + return true + end + -- don't try forever, this has to be fast + if num_dia > 50 then + return false + end + end + end + return false +end + +aegisub.register_macro("Apply karaoke template", "Applies karaoke effects from templates", macro_apply_templates, macro_can_template) +aegisub.register_filter("Karaoke temokate", "Apply karaoke effect templates to the subtitles", 2000, filter_apply_templates) diff --git a/automation/include/utils.lua b/automation/include/utils.lua index fc798c223..4b54ee2f7 100644 --- a/automation/include/utils.lua +++ b/automation/include/utils.lua @@ -144,6 +144,20 @@ function string.headtail(s) end end +-- Iterator function for headtail +function string.words(s) + local t = s + local function wordloop() + if t == "" then + return nil + end + local head, tail = string.headtail(t) + t = tail + return head + end + return wordloop, nil, nil +end + -- Clamp a number value to a range function clamp(val, min, max) if val < min then diff --git a/automation/v4-docs/template-scripting-ideas.ass b/automation/v4-docs/template-scripting-ideas.ass new file mode 100644 index 000000000..fd71986e5 --- /dev/null +++ b/automation/v4-docs/template-scripting-ideas.ass @@ -0,0 +1,57 @@ +[Script Info] +; Script generated by Aegisub v2.00 PRE-RELEASE (SVN r939, jfs) +; http://www.aegisub.net +Title: Default Aegisub file +ScriptType: v4.00+ +WrapStyle: 0 +PlayResX: 640 +PlayResY: 480 +Video Aspect Ratio: 0 +Video Zoom: 6 +Video Position: 0 + +[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: Default,Arial,20,&H00FFFFFF,&H0000FFFF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,0 + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: 0,0:00:00.00,0:00:00.00,Default,,0000,0000,0000,,some ideas on how templated karaoke could work in auto4/lua +Comment: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,code once,-- here's some code that gets executed once at the very beginning of processing +Comment: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,code,-- this code is also executed just once, at the start of processing (ie. like "once") +Comment: 0,0:00:05.00,0:00:10.00,Default,,0000,0000,0000,code line,-- here's some code that gets executed once every line +Comment: 0,0:00:10.00,0:00:15.00,Default,,0000,0000,0000,code syl,-- here's some code that gets executed once every syllable +Comment: 0,0:00:10.00,0:00:15.00,Default,,0000,0000,0000,code syl all,-- this code gets executed for any style, not just the one specified in the template line +Comment: 0,0:00:15.00,0:00:20.00,Default,,0000,0000,0000,code char,-- here's some code that gets executed once every character +Comment: 0,0:00:15.00,0:00:20.00,Default,,0000,0000,0000,code furi,-- here's some code that gets executed once for every furigana part +Comment: 0,0:00:20.00,0:00:25.00,Default,,0000,0000,0000,template pre-line 1,{this gets inserted before every line 1} +Comment: 0,0:00:25.00,0:00:30.00,Default,,0000,0000,0000,template line 1,{this gets inserted into line 1 for every syllable, text automatically follows} +Comment: 0,0:00:30.00,0:00:35.00,Default,,0000,0000,0000,template pre-line 2,{this gets inserted before every line 2} +Comment: 0,0:00:35.00,0:00:40.00,Default,,0000,0000,0000,template line 2 notext,{this gets inserted into line 2 for every syllable, syllable text not automatically inserted} +Comment: 0,0:00:40.00,0:00:40.00,Default,,0000,0000,0000,template line 2,{this appends more tags to each syllable in every line 2, the notext from previous line 2 template is automatically "carried over"} +Comment: 0,0:00:40.00,0:00:40.00,Default,,0000,0000,0000,template line,{this generates an anonymous simple-k-replacer style template line} +Comment: 0,0:00:40.00,0:00:40.00,Default,,0000,0000,0000,template line keeptags,{this creates another anonymous simple-k-replacer style template line, and also keeps all tags from the original text. the lines built by this template are separate from those built by the previous anonymous one} +Comment: 0,0:00:40.00,0:00:45.00,Default,,0000,0000,0000,template syl,{each syllable genrates a line like this, with the syllable text appended} +Comment: 0,0:00:45.00,0:00:50.00,Default,,0000,0000,0000,template syl notext,{each syllable generates a line like this, syllable text not automatically appended} +Comment: 0,0:00:50.00,0:00:55.00,Default,,0000,0000,0000,template syl repeat 10,{each syllable generates 10 lines like this, syllable text automatically appended, repeat counter in variable j} +Comment: 0,0:00:55.00,0:01:00.00,Default,,0000,0000,0000,template syl all,{this template is used for any style, not just the one specified} +Comment: 0,0:00:55.00,0:01:00.00,Default,,0000,0000,0000,template syl multi,{every highlight of a syllable generates a line from this, timing is changed to match current highlight} +Comment: 0,0:00:55.00,0:01:00.00,Default,,0000,0000,0000,template syl fx foo,{only applied for syllables with inline-fx "foo"} +Comment: 0,0:00:55.00,0:01:00.00,Default,,0000,0000,0000,template syl notext repeat 10,{modifiers can be combined} +Comment: 0,0:01:00.00,0:01:05.00,Default,,0000,0000,0000,template char,{each character generates a line like this, with the character appended. positioning variables matches the character and timing matches syllable} +Comment: 0,0:01:05.00,0:01:10.00,Default,,0000,0000,0000,template char multi,{multi highlight also supported for char, as well as repeat and notext} +Comment: 0,0:01:10.00,0:01:15.00,Default,,0000,0000,0000,template furi,{each furigana part generates a line like this, a new style with changed font size is automatically generated and applied} +Comment: 0,0:01:15.00,0:01:20.00,Default,,0000,0000,0000,template syl furi,{this template generates both normal syllables and furigana, positionig/sizing info adjusted to match whatever the template produces at the time} +Dialogue: 0,0:01:20.00,0:01:25.00,Default,,0000,0000,0000,,for notext syl and char templates there are also variables $pretext and $posttext which hold the text before and after the syllable/character, to be able to create "build up" style effects +Dialogue: 0,0:01:25.00,0:01:30.00,Default,,0000,0000,0000,,template line timing doesn't matter but layer does (layer is copied directly to the output lines) +Dialogue: 0,0:01:30.00,0:01:35.00,Default,,0000,0000,0000,,style is used for matching again the text +Dialogue: 0,0:01:35.00,0:01:40.00,Default,,0000,0000,0000,,it's not possible to do furigana per-character +Dialogue: 0,0:01:40.00,0:01:45.00,Default,,0000,0000,0000,,templates are applied first in order of class, then in order of appearance +Dialogue: 0,0:01:45.00,0:01:50.00,Default,,0000,0000,0000,,class order: pre-line/line, syl, char, furi +Dialogue: 0,0:01:50.00,0:01:55.00,Default,,0000,0000,0000,,ie. first all pre-line/line templates are applied for a karaoke line, then all syl templates are, then all char templates, then all furi templates, then proceed to next karaoke line +Dialogue: 0,0:01:55.00,0:02:00.00,Default,,0000,0000,0000,,code and template lines within same class are executed intermixed as they appear +Dialogue: 0,0:02:00.00,0:02:05.00,Default,,0000,0000,0000,,(code lines are like template lines, they just don't generate any output) +Dialogue: 0,0:02:05.00,0:02:05.00,Default,,0000,0000,0000,,the 'all' modifier should be used carefully, it will catch *any* line, even those without karaoke tags in them +Dialogue: 0,0:02:05.00,0:02:05.00,Default,,0000,0000,0000,, +Comment: 0,0:02:05.00,0:02:10.00,Default,template,0000,0000,0000,,auto3 multi-template style is not supported, it'll need a different script (supporting it all in one will be more work than it's worth, probably, particularily because of differences in variables) +Dialogue: 0,0:02:10.00,0:02:15.00,Default,,0000,0000,0000,,