From 4f1e9e34c3df14e0699ae00aadc6b22f23beaaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 17 Jul 2024 00:58:59 +0200 Subject: [PATCH] demux_playlist: add --directory-filter-types --- .../interface-changes/autocreate-playlist.txt | 6 +- .../directory-filter-types.txt | 1 + DOCS/man/options.rst | 34 +++++---- common/playlist.h | 2 +- demux/demux.c | 2 +- demux/demux_playlist.c | 71 ++++++++++++------- player/loadfile.c | 14 ++-- 7 files changed, 82 insertions(+), 48 deletions(-) create mode 100644 DOCS/interface-changes/directory-filter-types.txt diff --git a/DOCS/interface-changes/autocreate-playlist.txt b/DOCS/interface-changes/autocreate-playlist.txt index f2d1d1113a..722a80d01d 100644 --- a/DOCS/interface-changes/autocreate-playlist.txt +++ b/DOCS/interface-changes/autocreate-playlist.txt @@ -1,4 +1,4 @@ add `--autocreate-playlist` -add `--autocreate-playlist-video-exts` -add `--autocreate-playlist-audio-exts` -add `--autocreate-playlist-image-exts` +add `--directory-video-exts` +add `--directory-audio-exts` +add `--directory-image-exts` diff --git a/DOCS/interface-changes/directory-filter-types.txt b/DOCS/interface-changes/directory-filter-types.txt new file mode 100644 index 0000000000..bb7aa3e8b8 --- /dev/null +++ b/DOCS/interface-changes/directory-filter-types.txt @@ -0,0 +1 @@ +add `--directory-filter-types` diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 37383f8de0..8b68fc282e 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4139,30 +4139,36 @@ Demuxer all. The default is ``auto``, which behaves like ``recursive`` with ``--shuffle``, and like ``lazy`` otherwise. -``--autocreate-playlist=`` +``--directory-filter-types=`` + Media file types to filter when opening directory. If the list is empty, + all files are added to the playlist. + + This is a string list option. See `List Options`_ for details. + +``--autocreate-playlist=`` When opening a local file, act as if the parent directory is opened and create a playlist automatically. - :no: Load a single file (default). - :any: Create a playlist from the parent directory with any file type. - :exts: Create a playlist from the parent directory with files matching - extensions from any list ``autocreate-playlist-*-exts``. - :same: Create a playlist from the parent directory with files matching the - same category as the currently loaded file. One of the - ``autocreate-playlist-*-exts`` is selected based on the input file - and only files with matching extensions are added to the playlist. - If the input file itself is not matched to any extension list, - the playlist is not autogenerated. + :no: Load a single file (default). + :any: Create a playlist from the parent directory with any file type. + :filter: Create a playlist from the parent directory with files matching + extensions from any list ``directory-*-exts``. + :same: Create a playlist from the parent directory with files matching the + same category as the currently loaded file. One of the + ``directory-*-exts`` is selected based on the input file + and only files with matching extensions are added to the playlist. + If the input file itself is not matched to any extension list, + the playlist is not autogenerated. -``--autocreate-playlist-video-exts=`` +``--directory-video-exts=`` Video file extension list that is used to match files when using ``--autocreate-playlist=``. -``--autocreate-playlist-audio-exts=`` +``--directory-audio-exts=`` Audio file extension list that is used to match files when using ``--autocreate-playlist=``. -``--autocreate-playlist-image-exts=`` +``--directory-image-exts=`` Image file extension list that is used to match files when using ``--autocreate-playlist=``. diff --git a/common/playlist.h b/common/playlist.h index d1d36e9236..5690ac8adc 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -72,7 +72,7 @@ struct playlist { bool current_was_replaced; bool playlist_completed; bool playlist_started; - bool autocreated; + char *playlist_dir; uint64_t id_alloc; }; diff --git a/demux/demux.c b/demux/demux.c index 842d8e7731..f74836a3c3 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -120,7 +120,7 @@ const struct m_sub_options demux_conf = { M_RANGE(0, DBL_MAX)}, {"metadata-codepage", OPT_STRING(meta_cp)}, {"autocreate-playlist", OPT_CHOICE(autocreate_playlist, - {"no", 0}, {"any", 1}, {"exts", 2}, {"same", 3})}, + {"no", 0}, {"any", 1}, {"filter", 2}, {"same", 3})}, {0} }, .size = sizeof(struct demux_opts), diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index cf1a0499b5..ee92e53685 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -53,9 +53,10 @@ enum autocreate_mode { #define OPT_BASE_STRUCT struct demux_playlist_opts struct demux_playlist_opts { int dir_mode; - char **autocreate_playlist_vid_exts; - char **autocreate_playlist_aud_exts; - char **autocreate_playlist_img_exts; + char **directory_filter; + char **directory_vid_exts; + char **directory_aud_exts; + char **directory_img_exts; }; struct m_sub_options demux_playlist_conf = { @@ -65,26 +66,31 @@ struct m_sub_options demux_playlist_conf = { {"lazy", DIR_LAZY}, {"recursive", DIR_RECURSIVE}, {"ignore", DIR_IGNORE})}, - {"autocreate-playlist-video-exts", - OPT_STRINGLIST(autocreate_playlist_vid_exts)}, - {"autocreate-playlist-audio-exts", - OPT_STRINGLIST(autocreate_playlist_aud_exts)}, - {"autocreate-playlist-image-exts", - OPT_STRINGLIST(autocreate_playlist_img_exts)}, + {"directory-filter-types", + OPT_STRINGLIST(directory_filter)}, + {"directory-video-exts", + OPT_STRINGLIST(directory_vid_exts)}, + {"directory-audio-exts", + OPT_STRINGLIST(directory_aud_exts)}, + {"directory-image-exts", + OPT_STRINGLIST(directory_img_exts)}, {0} }, .size = sizeof(struct demux_playlist_opts), .defaults = &(const struct demux_playlist_opts){ .dir_mode = DIR_AUTO, - .autocreate_playlist_vid_exts = (char *[]){ + .directory_filter = (char *[]){ + NULL + }, + .directory_vid_exts = (char *[]){ "3g2", "3gp", "avi", "flv", "m2ts", "m4v", "mj2", "mkv", "mov", "mp4", "mpeg", "mpg", "ogv", "rmvb", "webm", "wmv", "y4m", NULL }, - .autocreate_playlist_aud_exts = (char *[]){ + .directory_aud_exts = (char *[]){ "aiff", "ape", "au", "flac", "m4a", "mka", "mp3", "oga", "ogg", "ogm", "opus", "wav", "wma", NULL }, - .autocreate_playlist_img_exts = (char *[]){ + .directory_img_exts = (char *[]){ "avif", "bmp", "gif", "j2k", "jp2", "jpeg", "jpg", "jxl", "png", "svg", "tga", "tif", "tiff", "webp", NULL }, @@ -424,7 +430,7 @@ static int cmp_dir_entry(const void *a, const void *b) } } -static bool has_ext(bstr ext, char **list) +static bool has_str(bstr ext, char **list) { if (!list) return false; @@ -435,17 +441,17 @@ static bool has_ext(bstr ext, char **list) return false; } -static bool test_autocreate_path(struct pl_parser *p, char *path, int autocreate) +static bool test_path(struct pl_parser *p, char *path, int autocreate) { if (autocreate & AUTO_ANY) return true; bstr ext = bstr_get_ext(bstr0(path)); - if (autocreate & AUTO_VIDEO && has_ext(ext, p->opts->autocreate_playlist_vid_exts)) + if (autocreate & AUTO_VIDEO && has_str(ext, p->opts->directory_vid_exts)) return true; - if (autocreate & AUTO_AUDIO && has_ext(ext, p->opts->autocreate_playlist_aud_exts)) + if (autocreate & AUTO_AUDIO && has_str(ext, p->opts->directory_aud_exts)) return true; - if (autocreate & AUTO_IMAGE && has_ext(ext, p->opts->autocreate_playlist_img_exts)) + if (autocreate & AUTO_IMAGE && has_str(ext, p->opts->directory_img_exts)) return true; return false; @@ -505,13 +511,13 @@ static bool scan_dir(struct pl_parser *p, char *path, qsort(dir_entries, num_dir_entries, sizeof(dir_entries[0]), cmp_dir_entry); for (int n = 0; n < num_dir_entries; n++) { + char *file = dir_entries[n].path; if (dir_mode == DIR_RECURSIVE && dir_entries[n].is_dir) { dir_stack[num_dir_stack] = dir_entries[n].st; - char *file = dir_entries[n].path; scan_dir(p, file, dir_stack, num_dir_stack + 1, autocreate); } else { - if (autocreate == AUTO_NONE || test_autocreate_path(p, dir_entries[n].path, autocreate)) + if (dir_entries[n].is_dir || test_path(p, file, autocreate)) playlist_append_file(p->pl, dir_entries[n].path); } } @@ -524,21 +530,22 @@ static int parse_dir(struct pl_parser *p) int ret = -1; struct stream *stream = p->real_stream; int autocreate = AUTO_NONE; + p->pl->playlist_dir = NULL; if (p->autocreate_playlist && p->real_stream->is_local_file && !p->real_stream->is_directory) { bstr ext = bstr_get_ext(bstr0(p->real_stream->url)); switch (p->autocreate_playlist) { case 1: // any autocreate = AUTO_ANY; break; - case 2: // exts + case 2: // filter autocreate = AUTO_VIDEO | AUTO_AUDIO | AUTO_IMAGE; break; case 3: // same - if (has_ext(ext, p->opts->autocreate_playlist_vid_exts)) { + if (has_str(ext, p->opts->directory_vid_exts)) { autocreate = AUTO_VIDEO; - } else if (has_ext(ext, p->opts->autocreate_playlist_aud_exts)) { + } else if (has_str(ext, p->opts->directory_aud_exts)) { autocreate = AUTO_AUDIO; - } else if (has_ext(ext, p->opts->autocreate_playlist_img_exts)) { + } else if (has_str(ext, p->opts->directory_img_exts)) { autocreate = AUTO_IMAGE; } break; @@ -548,8 +555,20 @@ static int parse_dir(struct pl_parser *p) bstr dir = mp_dirname(p->real_stream->url); if (!dir.len) autocreate = AUTO_NONE; - if (autocreate != AUTO_NONE) + if (autocreate != AUTO_NONE) { stream = stream_create(bstrdup0(p, dir), flags, NULL, p->global); + p->pl->playlist_dir = bstrdup0(p->pl, dir); + } + } else { + autocreate = AUTO_NONE; + if (!p->opts->directory_filter[0]) + autocreate = AUTO_ANY; + if (has_str(bstr0("video"), p->opts->directory_filter)) + autocreate |= AUTO_VIDEO; + if (has_str(bstr0("audio"), p->opts->directory_filter)) + autocreate |= AUTO_AUDIO; + if (has_str(bstr0("image"), p->opts->directory_filter)) + autocreate |= AUTO_IMAGE; } if (!stream->is_directory) goto done; @@ -562,6 +581,9 @@ static int parse_dir(struct pl_parser *p) if (!path) goto done; + if (autocreate == AUTO_NONE) + goto done; + struct stat dir_stack[MAX_DIR_STACK]; if (p->opts->dir_mode == DIR_AUTO) { @@ -573,7 +595,6 @@ static int parse_dir(struct pl_parser *p) scan_dir(p, path, dir_stack, 0, autocreate); p->add_base = false; - p->pl->autocreated = autocreate != AUTO_NONE; ret = p->pl->num_entries > 0 ? 0 : -1; done: diff --git a/player/loadfile.c b/player/loadfile.c index e5791321b3..45c39ccb9b 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1042,10 +1042,16 @@ void prepare_playlist(struct MPContext *mpctx, struct playlist *pl) if (opts->playlist_pos >= 0) pl->current = playlist_entry_from_index(pl, opts->playlist_pos); - for (int i = 0; i < pl->num_entries && pl->autocreated; ++i) { + for (int i = 0; i < pl->num_entries && pl->playlist_dir; ++i) { if (!pl->entries[i]->playlist_path) continue; - if (!strcmp(pl->entries[i]->filename, pl->entries[i]->playlist_path)) { + char *path = pl->entries[i]->playlist_path; + if (path[0] != '.') + path = mp_path_join(NULL, pl->playlist_dir, pl->entries[i]->playlist_path); + bool same = !strcmp(pl->entries[i]->filename, path); + if (path != pl->entries[i]->playlist_path) + talloc_free(path); + if (same) { pl->current = pl->entries[i]; break; } @@ -1079,7 +1085,7 @@ static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl, playlist_remove(mpctx->playlist, mpctx->playlist->current); if (new) mpctx->playlist->current = new; - mpctx->playlist->autocreated = pl->autocreated; + mpctx->playlist->playlist_dir = talloc_steal(mpctx->playlist, pl->playlist_dir); } else { MP_WARN(mpctx, "Empty playlist!\n"); } @@ -1156,7 +1162,7 @@ static MP_THREAD_VOID open_demux_thread(void *ctx) .stream_record = true, .is_top_level = true, .allow_playlist_create = mpctx->playlist->num_entries <= 1 && - !mpctx->playlist->autocreated, + !mpctx->playlist->playlist_dir, }; struct demuxer *demux = demux_open_url(mpctx->open_url, &p, mpctx->open_cancel, mpctx->global);