diff options
author | Guido Cella <guido@guidocella.xyz> | 2022-05-01 07:29:32 +0200 |
---|---|---|
committer | Kacper Michajłow <kasper93@gmail.com> | 2024-03-21 03:20:14 +0100 |
commit | d6610a5b2f34e398e2ceba2a4da2b79e556b1c9e (patch) | |
tree | cb5d6e8777179a4383067e05c52467d198096912 | |
parent | 520849dd48e34e68be09b5f4849fea1d5212fb44 (diff) | |
download | mpv-d6610a5b2f34e398e2ceba2a4da2b79e556b1c9e.tar.bz2 mpv-d6610a5b2f34e398e2ceba2a4da2b79e556b1c9e.tar.xz |
command: add escape-ass
This adds a command to escape ASS tags to remove code duplication
between sub/osd_libass.c, console.lua, osc.lua, stats.lua and any user
script that calls mp.create_osd_overlay().
A command is used instead of scripting functions so that all clients can
use this and not just use Lua and JS ones.
osd_mangle_ass() also interprets osd-sym-cc and osd-ass-cc/{0,1}, but
since they use invalid UTF-8 characters there is no risk of escape-ass
users using them by accident, like with any OSD message.
Always replacing \n with \\N in mangle_ass() even when it is not called
by escape-ass doesn't seem to cause any issue, but I made it conditional
anyway to avoid changing how all OSD messages are treated unnecessarily.
-rw-r--r-- | DOCS/interface-changes/escape-ass.txt | 1 | ||||
-rw-r--r-- | DOCS/man/input.rst | 12 | ||||
-rw-r--r-- | player/command.c | 15 | ||||
-rw-r--r-- | player/lua/console.lua | 14 | ||||
-rw-r--r-- | player/lua/stats.lua | 14 | ||||
-rw-r--r-- | sub/osd.h | 1 | ||||
-rw-r--r-- | sub/osd_libass.c | 12 |
7 files changed, 41 insertions, 28 deletions
diff --git a/DOCS/interface-changes/escape-ass.txt b/DOCS/interface-changes/escape-ass.txt new file mode 100644 index 0000000000..93ec1ca5e5 --- /dev/null +++ b/DOCS/interface-changes/escape-ass.txt @@ -0,0 +1 @@ +add the `escape-ass` command diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index cf4a43636b..bb353cd117 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1259,6 +1259,18 @@ Input Commands that are Possibly Subject to Change use the ``mp.create_osd_overlay()`` helper instead of invoking this command directly. +``escape-ass <text>`` + Modify ``text`` so that commands and functions that interpret ASS tags, + such as ``osd-overlay`` and ``mp.create_osd_overlay``, will display it + verbatim, and return it. This can only be used through the client API or + from a script using ``mp.command_native``. + + .. admonition:: Example + + ``mp.osd_message(mp.command_native({"escape-ass", "foo {bar}"}))`` + + This line of Lua prints "foo \\{bar}" on the OSD. + ``script-message [<arg1> [<arg2> [...]]]`` Send a message to all clients, and pass it the following list of arguments. What this message means, how many arguments it takes, and what the arguments diff --git a/player/command.c b/player/command.c index 27fadf91b1..ce7d6d5541 100644 --- a/player/command.c +++ b/player/command.c @@ -5582,6 +5582,19 @@ static void cmd_expand_path(void *p) }; } +static void cmd_escape_ass(void *p) +{ + struct mp_cmd_ctx *cmd = p; + bstr dst = {0}; + + osd_mangle_ass(&dst, cmd->args[0].v.s, true); + + cmd->result = (mpv_node){ + .format = MPV_FORMAT_STRING, + .u.string = dst.len ? (char *)dst.start : talloc_strdup(NULL, ""), + }; +} + static struct load_action get_load_action(struct MPContext *mpctx, int action_flag) { switch (action_flag) { @@ -6679,6 +6692,8 @@ const struct mp_cmd_def mp_cmds[] = { .is_noisy = true }, { "expand-path", cmd_expand_path, { {"text", OPT_STRING(v.s)} }, .is_noisy = true }, + { "escape-ass", cmd_escape_ass, { {"text", OPT_STRING(v.s)} }, + .is_noisy = true }, { "show-progress", cmd_show_progress, .allow_auto_repeat = true, .is_noisy = true }, diff --git a/player/lua/console.lua b/player/lua/console.lua index 02cf890791..238216445d 100644 --- a/player/lua/console.lua +++ b/player/lua/console.lua @@ -229,19 +229,7 @@ end -- Escape a string for verbatim display on the OSD function ass_escape(str) - -- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if - -- it isn't followed by a recognised character, so add a zero-width - -- non-breaking space - str = str:gsub('\\', '\\\239\187\191') - str = str:gsub('{', '\\{') - str = str:gsub('}', '\\}') - -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of - -- consecutive newlines - str = str:gsub('\n', '\239\187\191\\N') - -- Turn leading spaces into hard spaces to prevent ASS from stripping them - str = str:gsub('\\N ', '\\N\\h') - str = str:gsub('^ ', '\\h') - return str + return mp.command_native({'escape-ass', str}) end -- Takes a list of strings, a max width in characters and diff --git a/player/lua/stats.lua b/player/lua/stats.lua index 4d25a6c6bf..2feded2808 100644 --- a/player/lua/stats.lua +++ b/player/lua/stats.lua @@ -129,9 +129,6 @@ local function graph_add_value(graph, value) graph.max = max(graph.max, value) end --- "\\<U+2060>" in UTF-8 (U+2060 is WORD-JOINER) -local ESC_BACKSLASH = "\\" .. string.char(0xE2, 0x81, 0xA0) - local function no_ASS(t) if not o.use_ass then return t @@ -139,16 +136,7 @@ local function no_ASS(t) -- mp.osd_message supports ass-escape using osd-ass-cc/{0|1} return ass_stop .. t .. ass_start else - -- mp.set_osd_ass doesn't support ass-escape. roll our own. - -- similar to mpv's sub/osd_libass.c:mangle_ass(...), excluding - -- space after newlines because no_ASS is not used with multi-line. - -- space at the beginning is replaced with "\\h" because it matters - -- at the beginning of a line, and we can't know where our output - -- ends up. no issue if it ends up at the middle of a line. - return tostring(t) - :gsub("\\", ESC_BACKSLASH) - :gsub("{", "\\{") - :gsub("^ ", "\\h") + return mp.command_native({"escape-ass", tostring(t)}) end end @@ -245,5 +245,6 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov); void osd_set_external_remove_owner(struct osd_state *osd, void *owner); void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h); void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function); +void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines); #endif /* MPLAYER_SUB_H */ diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 16d94b3cbf..f2de27bd64 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -193,7 +193,7 @@ void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) snprintf(buffer, buffer_size, "\xFF%c", osd_function); } -static void mangle_ass(bstr *dst, const char *in) +void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines) { const char *start = in; bool escape_ass = true; @@ -213,6 +213,14 @@ static void mangle_ass(bstr *dst, const char *in) } if (escape_ass && *in == '{') bstr_xappend(NULL, dst, bstr0("\\")); + // Replace newlines with \N for escape-ass. This is necessary to apply + // ASS tags past newlines and to preserve consecutive newlines with + // osd-overlay because update_external() adds a ASS event per line. + if (replace_newlines && *in == '\n') { + bstr_xappend(NULL, dst, bstr0("\\N")); + in += 1; + continue; + } // Libass will strip leading whitespace if (in[0] == ' ' && (in == start || in[-1] == '\n')) { bstr_xappend(NULL, dst, bstr0("\\h")); @@ -231,7 +239,7 @@ static ASS_Event *add_osd_ass_event_escaped(ASS_Track *track, const char *style, const char *text) { bstr buf = {0}; - mangle_ass(&buf, text); + osd_mangle_ass(&buf, text, false); ASS_Event *e = add_osd_ass_event(track, style, buf.start); talloc_free(buf.start); return e; |