diff --git a/demux/demux.c b/demux/demux.c index 348e582d12..b6f2c2efae 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -67,6 +67,7 @@ static const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_disc, &demuxer_desc_edl, &demuxer_desc_cue, + &demuxer_desc_playlist, &demuxer_desc_rawaudio, &demuxer_desc_rawvideo, &demuxer_desc_matroska, @@ -75,7 +76,6 @@ static const demuxer_desc_t *const demuxer_list[] = { #endif &demuxer_desc_lavf, &demuxer_desc_mf, - &demuxer_desc_playlist, &demuxer_desc_null, NULL }; @@ -117,6 +117,7 @@ const struct m_sub_options demux_conf = { {"demuxer-backward-playback-step", OPT_DOUBLE(back_seek_size), M_RANGE(0, DBL_MAX)}, {"metadata-codepage", OPT_STRING(meta_cp)}, + {"autocreate-playlist", OPT_BOOL(autocreate_playlist)}, {0} }, .size = sizeof(struct demux_opts), diff --git a/demux/demux.h b/demux/demux.h index 401f1d146c..d9cd9f7ea4 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -86,6 +86,7 @@ struct demux_opts { double back_seek_size; char *meta_cp; bool force_retry_eof; + bool autocreate_playlist; }; #define SEEK_FACTOR (1 << 1) // argument is in range [0,1] @@ -211,6 +212,7 @@ struct demuxer_params { bool stream_record; // if true, enable stream recording if option is set int stream_flags; struct stream *external_stream; // if set, use this, don't open or close streams + bool has_playlist; // result bool demuxer_failed; }; diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index b1108917d1..c90e69bfd5 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -85,6 +85,7 @@ struct pl_parser { bool force; bool add_base; bool line_allocated; + bool create_dir_playlist; enum demux_check check_level; struct stream *real_stream; char *format; @@ -463,14 +464,25 @@ static bool scan_dir(struct pl_parser *p, char *path, static int parse_dir(struct pl_parser *p) { - if (!p->real_stream->is_directory) - return -1; - if (p->probing) - return 0; + int ret = -1; + struct stream *stream = p->real_stream; + if (p->create_dir_playlist && p->real_stream->is_local_file && !p->real_stream->is_directory) { + int flags = STREAM_ORIGIN_DIRECT | STREAM_READ | STREAM_LOCAL_FS_ONLY | + STREAM_LESS_NOISE; + bstr dir = mp_dirname(p->real_stream->url); + if (dir.len) + stream = stream_create(bstrdup0(p, dir), flags, NULL, p->global); + } + if (!stream->is_directory) + goto done; + if (p->probing) { + ret = 0; + goto done; + } - char *path = mp_file_get_path(p, bstr0(p->real_stream->url)); + char *path = mp_file_get_path(p, bstr0(stream->url)); if (!path) - return -1; + goto done; struct stat dir_stack[MAX_DIR_STACK]; @@ -483,8 +495,12 @@ static int parse_dir(struct pl_parser *p) scan_dir(p, path, dir_stack, 0); p->add_base = false; + ret = p->pl->num_entries > 0 ? 0 : -1; - return p->pl->num_entries > 0 ? 0 : -1; +done: + if (stream != p->real_stream) + free_stream(stream); + return ret; } #define MIME_TYPES(...) \ @@ -497,7 +513,6 @@ struct pl_format { }; static const struct pl_format formats[] = { - {"directory", parse_dir}, {"m3u", parse_m3u, MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")}, {"ini", parse_ref_init}, @@ -505,6 +520,7 @@ static const struct pl_format formats[] = { MIME_TYPES("audio/x-scpls")}, {"url", parse_url}, {"txt", parse_txt}, + {"directory", parse_dir}, }; static const struct pl_format *probe_pl(struct pl_parser *p) @@ -549,6 +565,8 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) p->force = force; p->check_level = check; p->probing = true; + p->create_dir_playlist = !demuxer->params->has_playlist && opts->autocreate_playlist; + const struct pl_format *fmt = probe_pl(p); free_stream(p->s); playlist_clear(p->pl); diff --git a/player/loadfile.c b/player/loadfile.c index 93b5f11a1c..53500f4c30 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1041,6 +1041,17 @@ 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; ++i) { + if (!pl->entries[i]->playlist_path) + continue; + // If playlist_path exists as an element in the playlist itself, it means + // playlist was autogenerated. + if (!strcmp(pl->entries[i]->filename, pl->entries[i]->playlist_path)) { + pl->current = pl->entries[i]; + break; + } + } + if (opts->shuffle) playlist_shuffle(pl); @@ -1144,6 +1155,7 @@ static MP_THREAD_VOID open_demux_thread(void *ctx) .stream_flags = mpctx->open_url_flags, .stream_record = true, .is_top_level = true, + .has_playlist = mpctx->playlist->num_entries > 1, }; struct demuxer *demux = demux_open_url(mpctx->open_url, &p, mpctx->open_cancel, mpctx->global);