10 #include "sub/find_subfiles.h"
13 static void strcpy_trim(char *d
, char *s
)
15 // skip leading whitespace
16 while (*s
&& isspace(*s
)) {
21 while (*s
&& !isspace(*s
)) {
27 // trim excess whitespace
28 while (*s
&& isspace(*s
)) {
38 static void strcpy_strip_ext(char *d
, char *s
)
40 char *tmp
= strrchr(s
, '.');
54 static void strcpy_get_ext(char *d
, char *s
)
56 char *tmp
= strrchr(s
, '.');
65 static int whiteonly(char *s
)
75 typedef struct subfn
{
80 static int compare_sub_priority(const void *a
, const void *b
)
82 if (((const subfn
*)a
)->priority
> ((const subfn
*)b
)->priority
) {
84 } else if (((const subfn
*)a
)->priority
< ((const subfn
*)b
)->priority
) {
87 return strcoll(((const subfn
*)a
)->fname
, ((const subfn
*)b
)->fname
);
92 * @brief Append all the subtitles in the given path matching fname
93 * @param slist pointer to the subtitles list tallocated
94 * @param nsub pointer to the number of subtitles
95 * @param path Look for subtitles in this directory
96 * @param fname Subtitle filename (pattern)
97 * @param limit_fuzziness Ignore flag when sub_fuziness == 2
99 static void append_dir_subtitles(struct subfn
**slist
, int *nsub
,
100 struct bstr path
, const char *fname
,
103 char *f_fname
, *f_fname_noext
, *f_fname_trim
, *tmp
, *tmp_sub_id
;
104 char *tmp_fname_noext
, *tmp_fname_trim
, *tmp_fname_ext
, *tmpresult
;
107 char *sub_exts
[] = {"utf", "utf8", "utf-8", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL
};
113 len
= (strlen(fname
) > 256 ? strlen(fname
) : 256)
114 + (path
.len
> 256 ? path
.len
: 256) + 2;
116 f_fname
= mp_basename(fname
);
117 f_fname_noext
= malloc(len
);
118 f_fname_trim
= malloc(len
);
120 tmp_fname_noext
= malloc(len
);
121 tmp_fname_trim
= malloc(len
);
122 tmp_fname_ext
= malloc(len
);
124 tmpresult
= malloc(len
);
126 strcpy_strip_ext(f_fname_noext
, f_fname
);
127 strcpy_trim(f_fname_trim
, f_fname_noext
);
129 /* The code using sub language here is broken - it assumes strict
130 * "videoname languagename" syntax for the subtitle file, which is
131 * very unlikely to match especially if language name uses "en,de"
135 if (dvdsub_lang
&& !whiteonly(dvdsub_lang
)) {
136 tmp_sub_id
= malloc(strlen(dvdsub_lang
) + 1);
137 strcpy_trim(tmp_sub_id
, dvdsub_lang
);
142 // 1 = any subtitle file
143 // 2 = any sub file containing movie name
144 // 3 = sub file containing movie name and the lang extension
145 char *path0
= bstrdup0(NULL
, path
);
149 mp_msg(MSGT_SUBREADER
, MSGL_INFO
, "Load subtitles in %.*s\n", BSTR_P(path
));
150 while ((de
= readdir(d
))) {
151 // retrieve various parts of the filename
152 strcpy_strip_ext(tmp_fname_noext
, de
->d_name
);
153 strcpy_get_ext(tmp_fname_ext
, de
->d_name
);
154 strcpy_trim(tmp_fname_trim
, tmp_fname_noext
);
156 // does it end with a subtitle extension?
160 for (i
= ((sub_cp
&& strncasecmp(sub_cp
, "enca", 4) != 0) ? 3 : 0); sub_exts
[i
]; i
++) {
162 for (i
= (sub_cp
? 3 : 0); sub_exts
[i
]; i
++) {
165 for (i
= 0; sub_exts
[i
]; i
++) {
167 if (strcasecmp(sub_exts
[i
], tmp_fname_ext
) == 0) {
173 // we have a (likely) subtitle file
176 if (!prio
&& tmp_sub_id
) {
177 sprintf(tmpresult
, "%s %s", f_fname_trim
, tmp_sub_id
);
178 if (strcmp(tmp_fname_trim
, tmpresult
) == 0 && sub_match_fuzziness
>= 1) {
179 // matches the movie name + lang extension
183 if (!prio
&& strcmp(tmp_fname_trim
, f_fname_trim
) == 0) {
184 // matches the movie name
187 if (!prio
&& (tmp
= strstr(tmp_fname_trim
, f_fname_trim
)) && sub_match_fuzziness
>= 1) {
188 // contains the movie name
189 tmp
+= strlen(f_fname_trim
);
190 if (tmp_sub_id
&& strstr(tmp
, tmp_sub_id
)) {
191 // with sub_id specified prefer localized subtitles
193 } else if ((tmp_sub_id
== NULL
) && whiteonly(tmp
)) {
194 // without sub_id prefer "plain" name
197 // with no localized subs found, try any else instead
202 // doesn't contain the movie name
203 // don't try in the mplayer subtitle directory
204 if (!limit_fuzziness
&& sub_match_fuzziness
>= 2) {
209 mp_msg(MSGT_SUBREADER
, MSGL_DBG2
, "Potential sub file: "
210 "\"%s\" Priority: %d\n", de
->d_name
, prio
);
214 if (i
< 3) // prefer UTF-8 coded
217 char *subpath
= mp_path_join(*slist
, path
, BSTR(de
->d_name
));
218 if ((f
= fopen(subpath
, "rt"))) {
219 MP_GROW_ARRAY(*slist
, *nsub
);
220 struct subfn
*sub
= *slist
+ (*nsub
)++;
223 sub
->priority
= prio
;
224 sub
->fname
= subpath
;
226 talloc_free(subpath
);
238 free(tmp_fname_noext
);
239 free(tmp_fname_trim
);
245 char **find_text_subtitles(struct MPOpts
*opts
, const char *fname
)
247 char **subnames
= NULL
;
248 struct subfn
*slist
= talloc_array_ptrtype(NULL
, slist
, 1);
251 // Load subtitles from current media directory
252 append_dir_subtitles(&slist
, &n
, mp_dirname(fname
), fname
, 0);
254 // Load subtitles in dirs specified by sub-paths option
255 if (opts
->sub_paths
) {
256 for (int i
= 0; opts
->sub_paths
[i
]; i
++) {
257 char *path
= mp_path_join(slist
, mp_dirname(fname
),
258 BSTR(opts
->sub_paths
[i
]));
259 append_dir_subtitles(&slist
, &n
, BSTR(path
), fname
, 0);
263 // Load subtitles in ~/.mplayer/sub limiting sub fuzziness
264 char *mp_subdir
= get_path("sub/");
266 append_dir_subtitles(&slist
, &n
, BSTR(mp_subdir
), fname
, 1);
269 // Sort subs by priority and append them
270 qsort(slist
, n
, sizeof(*slist
), compare_sub_priority
);
272 subnames
= talloc_array_ptrtype(NULL
, subnames
, n
);
273 for (int i
= 0; i
< n
; i
++)
274 subnames
[i
] = talloc_strdup(subnames
, slist
[i
].fname
);
280 char **find_vob_subtitles(struct MPOpts
*opts
, const char *fname
)
282 char **vobs
= talloc_array_ptrtype(NULL
, vobs
, 1);
285 // Potential vobsub in the media directory
286 struct bstr bname
= BSTR(mp_basename(fname
));
287 int pdot
= bstrrchr(bname
, '.');
290 vobs
[n
++] = mp_path_join(vobs
, mp_dirname(fname
), bname
);
292 // Potential vobsubs in directories specified by sub-paths option
293 if (opts
->sub_paths
) {
294 for (int i
= 0; opts
->sub_paths
[i
]; i
++) {
295 char *path
= mp_path_join(NULL
, mp_dirname(fname
),
296 BSTR(opts
->sub_paths
[i
]));
297 MP_GROW_ARRAY(vobs
, n
);
298 vobs
[n
++] = mp_path_join(vobs
, BSTR(path
), bname
);
303 // Potential vobsub in ~/.mplayer/sub
304 char *mp_subdir
= get_path("sub/");
306 MP_GROW_ARRAY(vobs
, n
);
307 vobs
[n
++] = mp_path_join(vobs
, BSTR(mp_subdir
), bname
);
311 MP_RESIZE_ARRAY(NULL
, vobs
, n
);