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 @@
1add 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
1259 use the ``mp.create_osd_overlay()`` helper instead of invoking this1259 use the ``mp.create_osd_overlay()`` helper instead of invoking this
1260 command directly.1260 command directly.
1261 1261
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
1262``script-message [<arg1> [<arg2> [...]]]``1274``script-message [<arg1> [<arg2> [...]]]``
1263 Send a message to all clients, and pass it the following list of arguments.1275 Send a message to all clients, and pass it the following list of arguments.
1264 What this message means, how many arguments it takes, and what the arguments1276 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
5582 };5582 };
5583}5583}
5584 5584
5585static 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
5585static struct load_action get_load_action(struct MPContext *mpctx, int action_flag)5598static struct load_action get_load_action(struct MPContext *mpctx, int action_flag)
5586{5599{
5587 switch (action_flag) {5600 switch (action_flag) {
@@ -6679,6 +6692,8 @@ const struct mp_cmd_def mp_cmds[] = { · 1091 unmodified lines
6679 .is_noisy = true },6692 .is_noisy = true },
6680 { "expand-path", cmd_expand_path, { {"text", OPT_STRING(v.s)} },6693 { "expand-path", cmd_expand_path, { {"text", OPT_STRING(v.s)} },
6681 .is_noisy = true },6694 .is_noisy = true },
6695 { "escape-ass", cmd_escape_ass, { {"text", OPT_STRING(v.s)} },
6696 .is_noisy = true },
6682 { "show-progress", cmd_show_progress, .allow_auto_repeat = true,6697 { "show-progress", cmd_show_progress, .allow_auto_repeat = true,
6683 .is_noisy = true },6698 .is_noisy = true },
6684 6699
player/lua/console.lua+1−13
@@ -229,19 +229,7 @@ end · 228 unmodified lines
229 229
230-- Escape a string for verbatim display on the OSD230-- Escape a string for verbatim display on the OSD
231function ass_escape(str)231function ass_escape(str)
232 -- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if232 return mp.command_native({'escape-ass', str})
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
245end233end
246 234
247-- Takes a list of strings, a max width in characters and235-- 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
129 graph.max = max(graph.max, value)129 graph.max = max(graph.max, value)
130end130end
131 131
132-- "\\<U+2060>" in UTF-8 (U+2060 is WORD-JOINER)
133local ESC_BACKSLASH = "\\" .. string.char(0xE2, 0x81, 0xA0)
134
135local function no_ASS(t)132local function no_ASS(t)
136 if not o.use_ass then133 if not o.use_ass then
137 return t134 return t
@@ -139,16 +136,7 @@ local function no_ASS(t) · 1 unmodified line
139 -- mp.osd_message supports ass-escape using osd-ass-cc/{0|1}136 -- mp.osd_message supports ass-escape using osd-ass-cc/{0|1}
140 return ass_stop .. t .. ass_start137 return ass_stop .. t .. ass_start
141 else138 else
142 -- mp.set_osd_ass doesn't support ass-escape. roll our own.139 return mp.command_native({"escape-ass", tostring(t)})
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")
152 end140 end
153end141end
154 142
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
245void osd_set_external_remove_owner(struct osd_state *osd, void *owner);245void osd_set_external_remove_owner(struct osd_state *osd, void *owner);
246void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h);246void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h);
247void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);247void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);
248void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines);
248 249
249#endif /* MPLAYER_SUB_H */250#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
193 snprintf(buffer, buffer_size, "\xFF%c", osd_function);193 snprintf(buffer, buffer_size, "\xFF%c", osd_function);
194}194}
195 195
196static void mangle_ass(bstr *dst, const char *in)196void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines)
197{197{
198 const char *start = in;198 const char *start = in;
199 bool escape_ass = true;199 bool escape_ass = true;
@@ -213,6 +213,14 @@ static void mangle_ass(bstr *dst, const char *in) · 13 unmodified lines
213 }213 }
214 if (escape_ass && *in == '{')214 if (escape_ass && *in == '{')
215 bstr_xappend(NULL, dst, bstr0("\\"));215 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 }
216 // Libass will strip leading whitespace224 // Libass will strip leading whitespace
217 if (in[0] == ' ' && (in == start || in[-1] == '\n')) {225 if (in[0] == ' ' && (in == start || in[-1] == '\n')) {
218 bstr_xappend(NULL, dst, bstr0("\\h"));226 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
231 const char *text)239 const char *text)
232{240{
233 bstr buf = {0};241 bstr buf = {0};
234 mangle_ass(&buf, text);242 osd_mangle_ass(&buf, text, false);
235 ASS_Event *e = add_osd_ass_event(track, style, buf.start);243 ASS_Event *e = add_osd_ass_event(track, style, buf.start);
236 talloc_free(buf.start);244 talloc_free(buf.start);
237 return e;245 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