13 #include "sub/find_subfiles.h"
16 static struct bstr
strip_ext(struct bstr str
)
18 int dotpos
= bstrrchr(str
, '.');
21 return (struct bstr
){str
.start
, dotpos
};
24 static struct bstr
get_ext(struct bstr s
)
26 int dotpos
= bstrrchr(s
, '.');
28 return (struct bstr
){NULL
, 0};
29 return bstr_splice(s
, dotpos
+ 1, s
.len
);
37 static int compare_sub_priority(const void *a
, const void *b
)
39 const struct subfn
*s1
= a
;
40 const struct subfn
*s2
= b
;
41 if (s1
->priority
> s2
->priority
)
43 if (s1
->priority
< s2
->priority
)
45 return strcoll(s1
->fname
, s2
->fname
);
48 static struct bstr
guess_lang_from_filename(struct bstr name
)
51 return (struct bstr
){NULL
, 0};
56 if (name
.start
[i
] == ')' || name
.start
[i
] == ']')
58 while (i
>= 0 && isalpha(name
.start
[i
])) {
61 return (struct bstr
){NULL
, 0};
65 return (struct bstr
){NULL
, 0};
66 return (struct bstr
){name
.start
+ i
+ 1, n
};
70 struct subfn subs
[MAX_SUBTITLE_FILES
];
76 * @brief Append all the subtitles in the given path matching fname
77 * @param opts MPlayer options
78 * @param slist pointer to the subtitles list tallocated
79 * @param nsub pointer to the number of subtitles
80 * @param path Look for subtitles in this directory
81 * @param fname Subtitle filename (pattern)
82 * @param limit_fuzziness Ignore flag when sub_fuziness == 2
84 static void append_dir_subtitles(struct MPOpts
*opts
,
85 struct subfn
**slist
, int *nsub
,
86 struct bstr path
, const char *fname
,
89 char *sub_exts
[] = {"utf", "utf8", "utf-8", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL
};
90 void *tmpmem
= talloc_new(NULL
);
92 assert(strlen(fname
) < 1e6
);
94 struct bstr f_fname
= bstr(mp_basename(fname
));
95 struct bstr f_fname_noext
= bstrdup(tmpmem
, strip_ext(f_fname
));
96 bstr_lower(f_fname_noext
);
97 struct bstr f_fname_trim
= bstr_strip(f_fname_noext
);
100 // 1 = any subtitle file
101 // 2 = any sub file containing movie name
102 // 3 = sub file containing movie name and the lang extension
103 char *path0
= bstrdup0(tmpmem
, path
);
104 DIR *d
= opendir(path0
);
107 mp_msg(MSGT_SUBREADER
, MSGL_INFO
, "Load subtitles in %.*s\n", BSTR_P(path
));
109 while ((de
= readdir(d
))) {
110 struct bstr dename
= bstr(de
->d_name
);
111 void *tmpmem2
= talloc_new(tmpmem
);
113 // retrieve various parts of the filename
114 struct bstr tmp_fname_noext
= bstrdup(tmpmem2
, strip_ext(dename
));
115 bstr_lower(tmp_fname_noext
);
116 struct bstr tmp_fname_ext
= get_ext(dename
);
117 struct bstr tmp_fname_trim
= bstr_strip(tmp_fname_noext
);
119 // If it's a .sub, check if there is a .idx with the same name. If
120 // there is one, it's certainly a vobsub so we skip it.
121 if (bstrcasecmp(tmp_fname_ext
, bstr("sub")) == 0) {
122 char *idxname
= talloc_asprintf(tmpmem2
, "%.*s.idx",
123 (int)tmp_fname_noext
.len
,
125 char *idx
= mp_path_join(tmpmem2
, path
, bstr(idxname
));
126 f
= fopen(idx
, "rt");
133 // does it end with a subtitle extension?
136 int i
= (sub_cp
&& strncasecmp(sub_cp
, "enca", 4) != 0) ? 3 : 0;
138 int i
= sub_cp
? 3 : 0;
146 if (bstrcasecmp(bstr(sub_exts
[i
]), tmp_fname_ext
) == 0)
151 // we have a (likely) subtitle file
153 if (opts
->sub_lang
) {
154 if (bstr_startswith(tmp_fname_trim
, f_fname_trim
)) {
155 struct bstr lang
= guess_lang_from_filename(tmp_fname_trim
);
157 for (int n
= 0; opts
->sub_lang
[n
]; n
++) {
158 if (bstr_startswith(lang
,
159 bstr(opts
->sub_lang
[n
]))) {
160 prio
= 4; // matches the movie name + lang extension
167 if (!prio
&& bstrcmp(tmp_fname_trim
, f_fname_trim
) == 0)
168 prio
= 3; // matches the movie name
169 if (!prio
&& bstr_find(tmp_fname_trim
, f_fname_trim
) >= 0
170 && sub_match_fuzziness
>= 1)
171 prio
= 2; // contains the movie name
173 // doesn't contain the movie name
174 // don't try in the mplayer subtitle directory
175 if (!limit_fuzziness
&& sub_match_fuzziness
>= 2) {
180 mp_msg(MSGT_SUBREADER
, MSGL_DBG2
, "Potential sub file: "
181 "\"%s\" Priority: %d\n", de
->d_name
, prio
);
185 if (i
< 3) // prefer UTF-8 coded
188 char *subpath
= mp_path_join(*slist
, path
, dename
);
189 if ((f
= fopen(subpath
, "rt"))) {
190 MP_GROW_ARRAY(*slist
, *nsub
);
191 struct subfn
*sub
= *slist
+ (*nsub
)++;
194 sub
->priority
= prio
;
195 sub
->fname
= subpath
;
197 talloc_free(subpath
);
201 talloc_free(tmpmem2
);
209 char **find_text_subtitles(struct MPOpts
*opts
, const char *fname
)
211 char **subnames
= NULL
;
212 struct subfn
*slist
= talloc_array_ptrtype(NULL
, slist
, 1);
215 // Load subtitles from current media directory
216 append_dir_subtitles(opts
, &slist
, &n
, mp_dirname(fname
), fname
, 0);
218 // Load subtitles in dirs specified by sub-paths option
219 if (opts
->sub_paths
) {
220 for (int i
= 0; opts
->sub_paths
[i
]; i
++) {
221 char *path
= mp_path_join(slist
, mp_dirname(fname
),
222 bstr(opts
->sub_paths
[i
]));
223 append_dir_subtitles(opts
, &slist
, &n
, bstr(path
), fname
, 0);
227 // Load subtitles in ~/.mplayer/sub limiting sub fuzziness
228 char *mp_subdir
= get_path("sub/");
230 append_dir_subtitles(opts
, &slist
, &n
, bstr(mp_subdir
), fname
, 1);
233 // Sort subs by priority and append them
234 qsort(slist
, n
, sizeof(*slist
), compare_sub_priority
);
236 subnames
= talloc_array_ptrtype(NULL
, subnames
, n
);
237 for (int i
= 0; i
< n
; i
++)
238 subnames
[i
] = talloc_strdup(subnames
, slist
[i
].fname
);
244 char **find_vob_subtitles(struct MPOpts
*opts
, const char *fname
)
246 char **vobs
= talloc_array_ptrtype(NULL
, vobs
, 1);
249 // Potential vobsub in the media directory
250 struct bstr bname
= bstr(mp_basename(fname
));
251 int pdot
= bstrrchr(bname
, '.');
254 vobs
[n
++] = mp_path_join(vobs
, mp_dirname(fname
), bname
);
256 // Potential vobsubs in directories specified by sub-paths option
257 if (opts
->sub_paths
) {
258 for (int i
= 0; opts
->sub_paths
[i
]; i
++) {
259 char *path
= mp_path_join(NULL
, mp_dirname(fname
),
260 bstr(opts
->sub_paths
[i
]));
261 MP_GROW_ARRAY(vobs
, n
);
262 vobs
[n
++] = mp_path_join(vobs
, bstr(path
), bname
);
267 // Potential vobsub in ~/.mplayer/sub
268 char *mp_subdir
= get_path("sub/");
270 MP_GROW_ARRAY(vobs
, n
);
271 vobs
[n
++] = mp_path_join(vobs
, bstr(mp_subdir
), bname
);
275 MP_RESIZE_ARRAY(NULL
, vobs
, n
);