summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido Cella <guido@guidocella.xyz>2023-10-07 16:53:52 +0200
committerDudemanguy <random342@airmail.cc>2023-10-09 15:09:35 +0000
commit81dea9031dec05559624b6d2a8ea9bf89667f755 (patch)
treeba78bb2183bccf8e73fff01932e0029057888c82
parentbcb9ed56fae7da59b495c5bddd7576821627dffb (diff)
downloadmpv-81dea9031dec05559624b6d2a8ea9bf89667f755.tar.bz2
mpv-81dea9031dec05559624b6d2a8ea9bf89667f755.tar.xz
command: add playlist-next-playlist and playlist-prev-playlist
playlist-prev-playlist goes to the beginning of the previous playlist because this seems more useful and symmetrical to playlist-next-playlist. It does not go to the beginning when the current playlist-path starts with the previous playlist-path, e.g. with mpv --loop-playlist foo/, which expands to foo/{1..9}.zip, the current playlist path foo/1.zip beings with the playlist-path foo/ of {2..9}.zip and thus playlist-prev-playlist goes to 9.zip rather than to 2.zip. Closes #12495.
-rw-r--r--DOCS/interface-changes.rst1
-rw-r--r--DOCS/man/input.rst7
-rw-r--r--common/playlist.c68
-rw-r--r--common/playlist.h4
-rw-r--r--player/command.c43
5 files changed, 123 insertions, 0 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 62d271bcb1..d398ab7987 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -98,6 +98,7 @@ Interface changes
- `--config-dir` no longer forces cache and state files to also reside in there
- deprecate `--demuxer-cue-codepage` in favor of `--metadata-codepage`
- change the default of `metadata-codepage` to `auto`
+ - add `playlist-next-playlist` and `playlist-prev-playlist` commands
--- mpv 0.36.0 ---
- add `--target-contrast`
- Target luminance value is now also applied when ICC profile is used.
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index b4c133953e..00ce20c846 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -422,6 +422,13 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
force
Terminate playback if the first file is being played.
+``playlist-next-playlist``
+ Go to the next entry on the playlist with a different ``playlist-path``.
+
+``playlist-prev-playlist``
+ Go to the first of the previous entries on the playlist with a different
+ ``playlist-path``.
+
``playlist-play-index <integer|current|none>``
Start (or restart) playback of the given playlist index. In addition to the
0-based playlist entry index, it supports the following values:
diff --git a/common/playlist.c b/common/playlist.c
index 78a7713462..e79a96b402 100644
--- a/common/playlist.c
+++ b/common/playlist.c
@@ -214,6 +214,74 @@ struct playlist_entry *playlist_entry_get_rel(struct playlist_entry *e,
return playlist_entry_from_index(e->pl, e->pl_index + direction);
}
+struct playlist_entry *playlist_get_first_in_next_playlist(struct playlist *pl,
+ int direction)
+{
+ struct playlist_entry *entry = playlist_get_next(pl, direction);
+ if (!entry)
+ return NULL;
+
+ while (entry && entry->playlist_path &&
+ strcmp(entry->playlist_path, pl->current->playlist_path) == 0)
+ entry = playlist_entry_get_rel(entry, direction);
+
+ if (direction < 0)
+ entry = playlist_get_first_in_same_playlist(entry,
+ pl->current->playlist_path);
+
+ return entry;
+}
+
+struct playlist_entry *playlist_get_first_in_same_playlist(
+ struct playlist_entry *entry, char *current_playlist_path)
+{
+ void *tmp = talloc_new(NULL);
+
+ if (!entry || !entry->playlist_path)
+ goto exit;
+
+ // Don't go to the beginning of the playlist when the current playlist-path
+ // starts with the previous playlist-path, e.g. with mpv --loop-playlist
+ // archive_dir/, which expands to archive_dir/{1..9}.zip, the current
+ // playlist path "archive_dir/1.zip" begins with the playlist-path
+ // "archive_dir/" of {2..9}.zip, so go to 9.zip instead of 2.zip. But
+ // playlist-prev-playlist from e.g. the directory "foobar" to the directory
+ // "foo" should still go to the first entry in "foo/", and this should all
+ // work whether mpv's arguments have trailing slashes or not, e.g. in the
+ // first example:
+ // mpv archive_dir results in the playlist-paths "archive_dir/1.zip" and
+ // "archive_dir"
+ // mpv archive_dir/ in "archive_dir/1.zip" and "archive_dir/"
+ // mpv archive_dir// in "archive_dir//1.zip" and "archive_dir//"
+ // Always adding a separator to entry->playlist_path to fix the foobar foo
+ // case would break the previous 2 cases instead. Stripping the separator
+ // from entry->playlist_path if present and appending it again makes this
+ // work in all cases.
+ char* playlist_path = talloc_strdup(tmp, entry->playlist_path);
+ mp_path_strip_trailing_separator(playlist_path);
+ if (bstr_startswith(bstr0(current_playlist_path),
+ bstr0(talloc_strdup_append(playlist_path, "/")))
+#if HAVE_DOS_PATHS
+ ||
+ bstr_startswith(bstr0(current_playlist_path),
+ bstr0(talloc_strdup_append(playlist_path, "\\")))
+#endif
+ )
+ goto exit;
+
+ struct playlist_entry *prev = playlist_entry_get_rel(entry, -1);
+
+ while (prev && prev->playlist_path &&
+ strcmp(prev->playlist_path, entry->playlist_path) == 0) {
+ entry = prev;
+ prev = playlist_entry_get_rel(entry, -1);
+ }
+
+exit:
+ talloc_free(tmp);
+ return entry;
+}
+
void playlist_add_base_path(struct playlist *pl, bstr base_path)
{
if (base_path.len == 0 || bstrcmp0(base_path, ".") == 0)
diff --git a/common/playlist.h b/common/playlist.h
index c5b82781e6..aecd53988b 100644
--- a/common/playlist.h
+++ b/common/playlist.h
@@ -98,6 +98,10 @@ struct playlist_entry *playlist_get_last(struct playlist *pl);
struct playlist_entry *playlist_get_next(struct playlist *pl, int direction);
struct playlist_entry *playlist_entry_get_rel(struct playlist_entry *e,
int direction);
+struct playlist_entry *playlist_get_first_in_next_playlist(struct playlist *pl,
+ int direction);
+struct playlist_entry *playlist_get_first_in_same_playlist(struct playlist_entry *entry,
+ char *current_playlist_path);
void playlist_add_base_path(struct playlist *pl, bstr base_path);
void playlist_set_stream_flags(struct playlist *pl, int flags);
int64_t playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl);
diff --git a/player/command.c b/player/command.c
index cf4971a4b3..8d7bc39c11 100644
--- a/player/command.c
+++ b/player/command.c
@@ -5321,6 +5321,45 @@ static void cmd_playlist_next_prev(void *p)
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
}
+static void cmd_playlist_next_prev_playlist(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int direction = *(int *)cmd->priv;
+
+ struct playlist_entry *entry =
+ playlist_get_first_in_next_playlist(mpctx->playlist, direction);
+
+ if (!entry && mpctx->opts->loop_times != 1 && mpctx->playlist->current) {
+ entry = direction > 0 ? playlist_get_first(mpctx->playlist)
+ : playlist_get_last(mpctx->playlist);
+
+ if (entry && entry->playlist_path &&
+ strcmp(entry->playlist_path,
+ mpctx->playlist->current->playlist_path) == 0)
+ entry = NULL;
+
+ if (direction > 0 && entry && mpctx->opts->loop_times > 1) {
+ mpctx->opts->loop_times--;
+ m_config_notify_change_opt_ptr(mpctx->mconfig,
+ &mpctx->opts->loop_times);
+ }
+
+ if (direction < 0)
+ entry = playlist_get_first_in_same_playlist(
+ entry, mpctx->playlist->current->playlist_path);
+ }
+
+ if (!entry) {
+ cmd->success = false;
+ return;
+ }
+
+ mp_set_playlist_entry(mpctx, entry);
+ if (cmd->on_osd & MP_ON_OSD_MSG)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
+}
+
static void cmd_playlist_play_index(void *p)
{
struct mp_cmd_ctx *cmd = p;
@@ -6373,6 +6412,10 @@ const struct mp_cmd_def mp_cmds[] = {
},
.priv = &(const int){-1},
},
+ { "playlist-next-playlist", cmd_playlist_next_prev_playlist,
+ .priv = &(const int){1} },
+ { "playlist-prev-playlist", cmd_playlist_next_prev_playlist,
+ .priv = &(const int){-1} },
{ "playlist-play-index", cmd_playlist_play_index,
{
{"index", OPT_CHOICE(v.i, {"current", -2}, {"none", -1}),