Skip to content

Commit 0b0330f

Browse files
committed
misc/language: parse forced tag from external subtitle tracks
This also adds a `forced` argument to the `sub-add` command. Fixes: mpv-player#16060
1 parent 6c42182 commit 0b0330f

File tree

10 files changed

+70
-45
lines changed

10 files changed

+70
-45
lines changed

DOCS/interface-changes/forced.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add `forced` flag to sub-add command

DOCS/man/input.rst

+4
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,10 @@ Track Manipulation
673673

674674
Marks the track as suitable for the visually impaired.
675675

676+
<forced> (only for ``sub-add``)
677+
678+
Marks the track as forced.
679+
676680
<attached-picture> (only for ``video-add``)
677681

678682
Marks the track as an attached picture, same as ``albumart`` argument

misc/language.c

+12-5
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ int mp_match_lang(char **langs, const char *lang)
297297
return best_score;
298298
}
299299

300-
bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impaired)
300+
bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impaired, bool *forced)
301301
{
302302
name = bstr_strip(bstr_strip_ext(name));
303303

@@ -307,6 +307,9 @@ bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impai
307307
if (hearing_impaired)
308308
*hearing_impaired = false;
309309

310+
if (forced)
311+
*forced = false;
312+
310313
if (name.len < 2)
311314
return (bstr){0};
312315

@@ -325,16 +328,17 @@ bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impai
325328
}
326329

327330
bool *hi = hearing_impaired ? hearing_impaired : &(bool){0};
328-
bool checked_hi = false;
331+
bool *f = forced ? forced : &(bool){0};
332+
bool checked_tag = false;
329333

330334
while (true) {
331335
while (i >= 0 && mp_isalpha(name.start[i])) {
332336
lang_length++;
333337
i--;
334338
}
335339

336-
if (i >= 0 && lang_length >= 2 && !checked_hi && name.start[i] == delimiter) {
337-
checked_hi = true;
340+
if (i >= 0 && lang_length >= 2 && !checked_tag && name.start[i] == delimiter) {
341+
checked_tag = true;
338342
static const char *const suffixes[] = { "sdh", "hi", "cc" };
339343
bstr tag = { name.start + i + 1, lang_length };
340344
for (int n = 0; n < MP_ARRAY_SIZE(suffixes); n++) {
@@ -343,7 +347,10 @@ bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impai
343347
break;
344348
}
345349
}
346-
if (*hi) {
350+
if (!bstrcasecmp0(tag, "forced")) {
351+
*f = true;
352+
}
353+
if (*hi || *f) {
347354
lang_length = 0;
348355
i -= (delimiter != '.') ? 2 : 1;
349356
continue;

misc/language.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@
2525
// Result numerically higher => better match. 0 == no match.
2626
int mp_match_lang(char **langs, const char *lang);
2727
char **mp_get_user_langs(void);
28-
bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impaired);
28+
bstr mp_guess_lang_from_filename(bstr name, int *lang_start, bool *hearing_impaired, bool *forced);
2929

3030
#endif /* MP_LANGUAGE_H */

player/command.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -6305,6 +6305,7 @@ static void cmd_track_reload(void *p)
63056305
flags |= t->attached_picture ? TRACK_ATTACHED_PICTURE : 0;
63066306
flags |= t->hearing_impaired_track ? TRACK_HEARING_IMPAIRED : 0;
63076307
flags |= t->visual_impaired_track ? TRACK_VISUAL_IMPAIRED : 0;
6308+
flags |= t->forced_track ? TRACK_FORCED : 0;
63086309
mp_remove_track(mpctx, t);
63096310
nt_num = mp_add_external_file(mpctx, filename, type, cmd->abort->cancel,
63106311
flags);
@@ -6320,7 +6321,7 @@ static void cmd_track_reload(void *p)
63206321

63216322
if (!nt->lang) {
63226323
bstr lang = mp_guess_lang_from_filename(bstr0(nt->external_filename), NULL,
6323-
&nt->hearing_impaired_track);
6324+
&nt->hearing_impaired_track, &nt->forced_track);
63246325
nt->lang = bstrto0(nt, lang);
63256326
}
63266327

@@ -7155,7 +7156,8 @@ const struct mp_cmd_def mp_cmds[] = {
71557156
{"flags", OPT_FLAGS(v.i,
71567157
{"select", 0}, {"auto", 1}, {"cached", 2},
71577158
{"hearing-impaired", TRACK_HEARING_IMPAIRED},
7158-
{"visual-impaired", TRACK_VISUAL_IMPAIRED}),
7159+
{"visual-impaired", TRACK_VISUAL_IMPAIRED},
7160+
{"forced", TRACK_FORCED}),
71597161
.flags = MP_CMD_OPT_ARG},
71607162
{"title", OPT_STRING(v.s), .flags = MP_CMD_OPT_ARG},
71617163
{"lang", OPT_STRING(v.s), .flags = MP_CMD_OPT_ARG},

player/core.h

+1
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ enum track_flags {
496496
TRACK_HEARING_IMPAIRED = 1 << 2,
497497
TRACK_VISUAL_IMPAIRED = 1 << 3,
498498
TRACK_ATTACHED_PICTURE = 1 << 4,
499+
TRACK_FORCED = 1 << 5,
499500
};
500501

501502
// audio.c

player/external_files.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ static void append_dir_subtitles(struct mpv_global *global, struct MPOpts *opts,
156156
bstr lang = {0};
157157
int start = 0;
158158
bool hearing_impaired = false;
159-
lang = mp_guess_lang_from_filename(dename, &start, &hearing_impaired);
159+
bool forced = false;
160+
lang = mp_guess_lang_from_filename(dename, &start, &hearing_impaired, &forced);
160161
if (bstr_case_startswith(tmp_fname_trim, f_fname_trim)) {
161162
if (lang.len && start == f_fname_trim.len)
162163
prio |= 16; // exact movie name + followed by lang
@@ -202,6 +203,7 @@ static void append_dir_subtitles(struct mpv_global *global, struct MPOpts *opts,
202203
sub->fname = subpath;
203204
sub->lang = lang.len ? bstrdup0(*slist, lang) : NULL;
204205
sub->hearing_impaired = hearing_impaired;
206+
sub->forced = forced;
205207
} else
206208
talloc_free(subpath);
207209
}

player/external_files.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct subfn {
2626
char *fname;
2727
char *lang;
2828
bool hearing_impaired;
29+
bool forced;
2930
};
3031

3132
struct mpv_global;

player/loadfile.c

+2
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ int mp_add_external_file(struct MPContext *mpctx, char *filename,
917917
t->no_auto_select = t->no_default;
918918
t->hearing_impaired_track = flags & TRACK_HEARING_IMPAIRED;
919919
t->visual_impaired_track = flags & TRACK_VISUAL_IMPAIRED;
920+
t->forced_track = flags & TRACK_FORCED;
920921
// if we found video, and we are loading cover art, flag as such.
921922
t->attached_picture = t->type == STREAM_VIDEO && (flags & TRACK_ATTACHED_PICTURE);
922923
if (first_num < 0 && (filter == STREAM_TYPE_COUNT || sh->type == filter))
@@ -989,6 +990,7 @@ void autoload_external_files(struct MPContext *mpctx, struct mp_cancel *cancel)
989990

990991
enum track_flags flags = 0;
991992
flags |= e->hearing_impaired ? TRACK_HEARING_IMPAIRED : 0;
993+
flags |= e->forced ? TRACK_FORCED : 0;
992994
// when given filter is set to video, we are loading up cover art
993995
flags |= e->type == STREAM_VIDEO ? TRACK_ATTACHED_PICTURE : 0;
994996
int first = mp_add_external_file(mpctx, e->fname, e->type, cancel, flags);

test/language.c

+41-36
Original file line numberDiff line numberDiff line change
@@ -57,47 +57,52 @@ int main(void)
5757

5858
void *ta_ctx = talloc_new(NULL);
5959

60-
#define TEST_LANG_GUESS(filename, expected_lang, expected_start, expected_hi) \
61-
do { \
62-
int start; \
63-
bool hearing_impaired; \
64-
bstr lang = mp_guess_lang_from_filename(bstr0(filename), &start, \
65-
&hearing_impaired); \
66-
assert_string_equal(bstrto0(ta_ctx, lang), expected_lang); \
67-
assert_int_equal(start, expected_start); \
68-
assert_true(hearing_impaired == expected_hi); \
60+
#define TEST_LANG_GUESS(filename, expected_lang, expected_start, expected_hi, expected_forced) \
61+
do { \
62+
int start; \
63+
bool hearing_impaired; \
64+
bool forced; \
65+
bstr lang = mp_guess_lang_from_filename(bstr0(filename), &start, \
66+
&hearing_impaired, &forced); \
67+
assert_string_equal(bstrto0(ta_ctx, lang), expected_lang); \
68+
assert_int_equal(start, expected_start); \
69+
assert_true(hearing_impaired == expected_hi); \
70+
assert_true(forced == expected_forced); \
6971
} while (0)
7072

71-
TEST_LANG_GUESS("foo.en.srt", "en", 3, false);
72-
TEST_LANG_GUESS("foo.eng.srt", "eng", 3, false);
73-
TEST_LANG_GUESS("foo.e.srt", "", -1, false);
74-
TEST_LANG_GUESS("foo.engg.srt", "", -1, false);
75-
TEST_LANG_GUESS("foo.00.srt", "", -1, false);
76-
TEST_LANG_GUESS("foo.srt", "", -1, false);
77-
TEST_LANG_GUESS(NULL, "", -1, false);
73+
TEST_LANG_GUESS("foo.en.srt", "en", 3, false, false);
74+
TEST_LANG_GUESS("foo.eng.srt", "eng", 3, false, false);
75+
TEST_LANG_GUESS("foo.e.srt", "", -1, false, false);
76+
TEST_LANG_GUESS("foo.engg.srt", "", -1, false, false);
77+
TEST_LANG_GUESS("foo.00.srt", "", -1, false, false);
78+
TEST_LANG_GUESS("foo.srt", "", -1, false, false);
79+
TEST_LANG_GUESS(NULL, "", -1, false, false);
7880

79-
TEST_LANG_GUESS("foo.en-US.srt", "en-US", 3, false);
80-
TEST_LANG_GUESS("foo.en-US.hi.srt", "en-US", 3, true);
81-
TEST_LANG_GUESS("foo.en-US.sdh.srt", "en-US", 3, true);
82-
TEST_LANG_GUESS("foo.en-simple.srt", "en-simple", 3, false);
83-
TEST_LANG_GUESS("foo.sgn-FSL.srt", "sgn-FSL", 3, false);
84-
TEST_LANG_GUESS("foo.gsw-u-sd-chzh.srt", "gsw-u-sd-chzh", 3, false);
85-
TEST_LANG_GUESS("foo.en-.srt", "", -1, false);
86-
TEST_LANG_GUESS("foo.en-US-.srt", "", -1, false);
87-
TEST_LANG_GUESS("foo.en-aaaaaaaaa.srt", "", -1, false);
88-
TEST_LANG_GUESS("foo.en-0.srt", "", -1, false);
81+
TEST_LANG_GUESS("foo.en-US.srt", "en-US", 3, false, false);
82+
TEST_LANG_GUESS("foo.en-US.hi.srt", "en-US", 3, true, false);
83+
TEST_LANG_GUESS("foo.en-US.sdh.srt", "en-US", 3, true, false);
84+
TEST_LANG_GUESS("foo.en-US.forced.srt", "en-US", 3, false, true);
85+
TEST_LANG_GUESS("foo.en-simple.srt", "en-simple", 3, false, false);
86+
TEST_LANG_GUESS("foo.sgn-FSL.srt", "sgn-FSL", 3, false, false);
87+
TEST_LANG_GUESS("foo.gsw-u-sd-chzh.srt", "gsw-u-sd-chzh", 3, false, false);
88+
TEST_LANG_GUESS("foo.en-.srt", "", -1, false, false);
89+
TEST_LANG_GUESS("foo.en-US-.srt", "", -1, false, false);
90+
TEST_LANG_GUESS("foo.en-aaaaaaaaa.srt", "", -1, false, false);
91+
TEST_LANG_GUESS("foo.en-0.srt", "", -1, false, false);
8992

90-
TEST_LANG_GUESS("foo[en].srt", "en", 3, false);
91-
TEST_LANG_GUESS("foo[en-US].srt", "en-US", 3, false);
92-
TEST_LANG_GUESS("foo[en-US][hi].srt", "en-US", 3, true);
93-
TEST_LANG_GUESS("foo[en-US][sdh].srt", "en-US", 3, true);
94-
TEST_LANG_GUESS("foo[].srt", "", -1, false);
93+
TEST_LANG_GUESS("foo[en].srt", "en", 3, false, false);
94+
TEST_LANG_GUESS("foo[en-US].srt", "en-US", 3, false, false);
95+
TEST_LANG_GUESS("foo[en-US][hi].srt", "en-US", 3, true, false);
96+
TEST_LANG_GUESS("foo[en-US][sdh].srt", "en-US", 3, true, false);
97+
TEST_LANG_GUESS("foo[en-US][forced].srt", "en-US", 3, false, true);
98+
TEST_LANG_GUESS("foo[].srt", "", -1, false, false);
9599

96-
TEST_LANG_GUESS("foo(en).srt", "en", 3, false);
97-
TEST_LANG_GUESS("foo(en-US).srt", "en-US", 3, false);
98-
TEST_LANG_GUESS("foo(en-US)(hi).srt", "en-US", 3, true);
99-
TEST_LANG_GUESS("foo(en-US)(sdh).srt", "en-US", 3, true);
100-
TEST_LANG_GUESS("foo().srt", "", -1, false);
100+
TEST_LANG_GUESS("foo(en).srt", "en", 3, false, false);
101+
TEST_LANG_GUESS("foo(en-US).srt", "en-US", 3, false, false);
102+
TEST_LANG_GUESS("foo(en-US)(hi).srt", "en-US", 3, true, false);
103+
TEST_LANG_GUESS("foo(en-US)(sdh).srt", "en-US", 3, true, false);
104+
TEST_LANG_GUESS("foo(en-US)(forced).srt", "en-US", 3, false, true);
105+
TEST_LANG_GUESS("foo().srt", "", -1, false, false);
101106

102107
talloc_free(ta_ctx);
103108
}

0 commit comments

Comments
 (0)