diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 0cbc4b6ea2..10c51fcf0e 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -84,6 +84,7 @@ Interface changes passthrough the mpv window - icc and gpu-shader cache are now saved by default (use --no-icc-shader-cache and --no-gpu-shader-cache to disable) + - add `--directory-mode=recursive|lazy|ignore` --- mpv 0.35.0 --- - add the `--vo=gpu-next` video output driver, as well as the options `--allow-delayed-peak-detect`, `--builtin-scalers`, diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index da163b9d88..ecb2c77383 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3945,6 +3945,13 @@ Demuxer libarchive opens all volumes anyway when playing the main file, even though mpv iterated no archive entries yet. +``--directory-mode=`` + When opening a directory, open subdirectories recursively, lazily or not at + all (default: recursive). + + Values other then ``recursive`` can lead to problems with resuming playlists + (`RESUMING PLAYBACK`_) and possibly other things. + Input ----- diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index a5f9f0af35..6b6b2be144 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -24,6 +24,7 @@ #include "common/common.h" #include "options/options.h" +#include "options/m_config.h" #include "common/msg.h" #include "common/playlist.h" #include "misc/thread_tools.h" @@ -35,6 +36,31 @@ #define PROBE_SIZE (8 * 1024) +enum dir_mode { + DIR_RECURSIVE, + DIR_LAZY, + DIR_IGNORE, +}; + +#define OPT_BASE_STRUCT struct demux_playlist_opts +struct demux_playlist_opts { + int dir_mode; +}; + +struct m_sub_options demux_playlist_conf = { + .opts = (const struct m_option[]) { + {"directory-mode", OPT_CHOICE(dir_mode, + {"recursive", DIR_RECURSIVE}, + {"lazy", DIR_LAZY}, + {"ignore", DIR_IGNORE})}, + {0} + }, + .size = sizeof(struct demux_playlist_opts), + .defaults = &(const struct demux_playlist_opts){ + .dir_mode = DIR_RECURSIVE, + }, +}; + static bool check_mimetype(struct stream *s, const char *const *list) { if (s->mime_type) { @@ -59,6 +85,7 @@ struct pl_parser { enum demux_check check_level; struct stream *real_stream; char *format; + struct demux_playlist_opts *opts; }; @@ -323,6 +350,7 @@ static bool scan_dir(struct pl_parser *p, char *path, return false; } + int dir_mode = p->opts->dir_mode; struct dirent *ep; while ((ep = readdir(dp))) { if (ep->d_name[0] == '.') @@ -334,16 +362,18 @@ static bool scan_dir(struct pl_parser *p, char *path, char *file = mp_path_join(p, path, ep->d_name); struct stat st; - if (stat(file, &st) == 0 && S_ISDIR(st.st_mode)) { - for (int n = 0; n < num_dir_stack; n++) { - if (same_st(&dir_stack[n], &st)) { - MP_VERBOSE(p, "Skip recursive entry: %s\n", file); - goto skip; + if (dir_mode != DIR_LAZY && stat(file, &st) == 0 && S_ISDIR(st.st_mode)) { + if (dir_mode != DIR_IGNORE) { + for (int n = 0; n < num_dir_stack; n++) { + if (same_st(&dir_stack[n], &st)) { + MP_VERBOSE(p, "Skip recursive entry: %s\n", file); + goto skip; + } } - } - dir_stack[num_dir_stack] = st; - scan_dir(p, file, dir_stack, num_dir_stack + 1, files, num_files); + dir_stack[num_dir_stack] = st; + scan_dir(p, file, dir_stack, num_dir_stack + 1, files, num_files); + } } else { MP_TARRAY_APPEND(p, *files, *num_files, file); } @@ -458,6 +488,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) p->error = false; p->s = demuxer->stream; p->utf16 = stream_skip_bom(p->s); + p->opts = mp_get_config_group(demuxer, demuxer->global, &demux_playlist_conf); bool ok = fmt->parse(p) >= 0 && !p->error; if (p->add_base) playlist_add_base_path(p->pl, mp_dirname(demuxer->filename)); @@ -471,7 +502,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) return ok ? 0 : -1; } -const struct demuxer_desc demuxer_desc_playlist = { +const demuxer_desc_t demuxer_desc_playlist = { .name = "playlist", .desc = "Playlist file", .open = open_file, diff --git a/options/options.c b/options/options.c index 92790dfb01..86e5a7b724 100644 --- a/options/options.c +++ b/options/options.c @@ -63,6 +63,7 @@ extern const struct m_sub_options zimg_conf; extern const struct m_sub_options drm_conf; extern const struct m_sub_options demux_rawaudio_conf; extern const struct m_sub_options demux_rawvideo_conf; +extern const struct m_sub_options demux_playlist_conf; extern const struct m_sub_options demux_lavf_conf; extern const struct m_sub_options demux_mkv_conf; extern const struct m_sub_options demux_cue_conf; @@ -591,6 +592,7 @@ static const m_option_t mp_opts[] = { {"", OPT_SUBSTRUCT(demux_lavf, demux_lavf_conf)}, {"demuxer-rawaudio", OPT_SUBSTRUCT(demux_rawaudio, demux_rawaudio_conf)}, {"demuxer-rawvideo", OPT_SUBSTRUCT(demux_rawvideo, demux_rawvideo_conf)}, + {"", OPT_SUBSTRUCT(demux_playlist, demux_playlist_conf)}, {"demuxer-mkv", OPT_SUBSTRUCT(demux_mkv, demux_mkv_conf)}, {"demuxer-cue", OPT_SUBSTRUCT(demux_cue, demux_cue_conf)}, diff --git a/options/options.h b/options/options.h index 0125c433f5..0224e5609d 100644 --- a/options/options.h +++ b/options/options.h @@ -326,6 +326,7 @@ typedef struct MPOpts { struct demux_rawaudio_opts *demux_rawaudio; struct demux_rawvideo_opts *demux_rawvideo; + struct demux_playlist_opts *demux_playlist; struct demux_lavf_opts *demux_lavf; struct demux_mkv_opts *demux_mkv; struct demux_cue_opts *demux_cue;