History

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.

Guido Cella committed 4 years ago

Commit d6610a51 parent 520849d7 files · +41 −28Browse files

Unified · Split

7 files
  1. DOCS/interface-changes/escape-ass.txt +1 −0
  2. DOCS/man/input.rst +12 −0
  3. player/command.c +15 −0
  4. player/lua/console.lua +1 −13
  5. player/lua/stats.lua +1 −13
  6. sub/osd.h +1 −0
  7. sub/osd_libass.c +10 −2
DOCS/interface-changes/escape-ass.txt+1−0
@@ -0,0 +1 @@
1+add the `escape-ass` command
DOCS/man/input.rst+12−0
@@ -1259,6 +1259,18 @@ Input Commands that are Possibly Subject to Change · 1258 unmodified lines
12591259 use the ``mp.create_osd_overlay()`` helper instead of invoking this
12601260 command directly.
12611261
1262+``escape-ass <text>``
1263+ Modify ``text`` so that commands and functions that interpret ASS tags,
1264+ such as ``osd-overlay`` and ``mp.create_osd_overlay``, will display it
1265+ verbatim, and return it. This can only be used through the client API or
1266+ from a script using ``mp.command_native``.
1267+
1268+ .. admonition:: Example
1269+
1270+ ``mp.osd_message(mp.command_native({"escape-ass", "foo {bar}"}))``
1271+
1272+ This line of Lua prints "foo \\{bar}" on the OSD.
1273+
12621274 ``script-message [<arg1> [<arg2> [...]]]``
12631275 Send a message to all clients, and pass it the following list of arguments.
12641276 What this message means, how many arguments it takes, and what the arguments
player/command.c+15−0
@@ -5582,6 +5582,19 @@ static void cmd_expand_path(void *p) · 5581 unmodified lines
55825582 };
55835583 }
55845584
5585+static void cmd_escape_ass(void *p)
5586+{
5587+ struct mp_cmd_ctx *cmd = p;
5588+ bstr dst = {0};
5589+
5590+ osd_mangle_ass(&dst, cmd->args[0].v.s, true);
5591+
5592+ cmd->result = (mpv_node){
5593+ .format = MPV_FORMAT_STRING,
5594+ .u.string = dst.len ? (char *)dst.start : talloc_strdup(NULL, ""),
5595+ };
5596+}
5597+
55855598 static struct load_action get_load_action(struct MPContext *mpctx, int action_flag)
55865599 {
55875600 switch (action_flag) {
@@ -6679,6 +6692,8 @@ const struct mp_cmd_def mp_cmds[] = { · 1091 unmodified lines
66796692 .is_noisy = true },
66806693 { "expand-path", cmd_expand_path, { {"text", OPT_STRING(v.s)} },
66816694 .is_noisy = true },
6695+ { "escape-ass", cmd_escape_ass, { {"text", OPT_STRING(v.s)} },
6696+ .is_noisy = true },
66826697 { "show-progress", cmd_show_progress, .allow_auto_repeat = true,
66836698 .is_noisy = true },
66846699
player/lua/console.lua+1−13
@@ -229,19 +229,7 @@ end · 228 unmodified lines
229229
230230 -- Escape a string for verbatim display on the OSD
231231 function ass_escape(str)
232− -- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if
233− -- it isn't followed by a recognised character, so add a zero-width
234− -- non-breaking space
235− str = str:gsub('\\', '\\\239\187\191')
236− str = str:gsub('{', '\\{')
237− str = str:gsub('}', '\\}')
238− -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
239− -- consecutive newlines
240− str = str:gsub('\n', '\239\187\191\\N')
241− -- Turn leading spaces into hard spaces to prevent ASS from stripping them
242− str = str:gsub('\\N ', '\\N\\h')
243− str = str:gsub('^ ', '\\h')
244− return str
232+ return mp.command_native({'escape-ass', str})
245233 end
246234
247235 -- Takes a list of strings, a max width in characters and
player/lua/stats.lua+1−13
@@ -129,9 +129,6 @@ local function graph_add_value(graph, value) · 128 unmodified lines
129129 graph.max = max(graph.max, value)
130130 end
131131
132−-- "\\<U+2060>" in UTF-8 (U+2060 is WORD-JOINER)
133−local ESC_BACKSLASH = "\\" .. string.char(0xE2, 0x81, 0xA0)
134−
135132 local function no_ASS(t)
136133 if not o.use_ass then
137134 return t
@@ -139,16 +136,7 @@ local function no_ASS(t) · 1 unmodified line
139136 -- mp.osd_message supports ass-escape using osd-ass-cc/{0|1}
140137 return ass_stop .. t .. ass_start
141138 else
142− -- mp.set_osd_ass doesn't support ass-escape. roll our own.
143− -- similar to mpv's sub/osd_libass.c:mangle_ass(...), excluding
144− -- space after newlines because no_ASS is not used with multi-line.
145− -- space at the beginning is replaced with "\\h" because it matters
146− -- at the beginning of a line, and we can't know where our output
147− -- ends up. no issue if it ends up at the middle of a line.
148− return tostring(t)
149− :gsub("\\", ESC_BACKSLASH)
150− :gsub("{", "\\{")
151− :gsub("^ ", "\\h")
139+ return mp.command_native({"escape-ass", tostring(t)})
152140 end
153141 end
154142
sub/osd.h+1−0
@@ -245,5 +245,6 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov); · 244 unmodified lines
245245 void osd_set_external_remove_owner(struct osd_state *osd, void *owner);
246246 void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h);
247247 void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);
248+void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines);
248249
249250 #endif /* MPLAYER_SUB_H */
sub/osd_libass.c+10−2
@@ -193,7 +193,7 @@ void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) · 192 unmodified lines
193193 snprintf(buffer, buffer_size, "\xFF%c", osd_function);
194194 }
195195
196−static void mangle_ass(bstr *dst, const char *in)
196+void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines)
197197 {
198198 const char *start = in;
199199 bool escape_ass = true;
@@ -213,6 +213,14 @@ static void mangle_ass(bstr *dst, const char *in) · 13 unmodified lines
213213 }
214214 if (escape_ass && *in == '{')
215215 bstr_xappend(NULL, dst, bstr0("\\"));
216+ // Replace newlines with \N for escape-ass. This is necessary to apply
217+ // ASS tags past newlines and to preserve consecutive newlines with
218+ // osd-overlay because update_external() adds a ASS event per line.
219+ if (replace_newlines && *in == '\n') {
220+ bstr_xappend(NULL, dst, bstr0("\\N"));
221+ in += 1;
222+ continue;
223+ }
216224 // Libass will strip leading whitespace
217225 if (in[0] == ' ' && (in == start || in[-1] == '\n')) {
218226 bstr_xappend(NULL, dst, bstr0("\\h"));
@@ -231,7 +239,7 @@ static ASS_Event *add_osd_ass_event_escaped(ASS_Track *track, const char *style, · 12 unmodified lines
231239 const char *text)
232240 {
233241 bstr buf = {0};
234− mangle_ass(&buf, text);
242+ osd_mangle_ass(&buf, text, false);
235243 ASS_Event *e = add_osd_ass_event(track, style, buf.start);
236244 talloc_free(buf.start);
237245 return e;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t