From 59fd11512f0c3474c0df126ab499a860be337658 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Fri, 21 Nov 2025 22:29:27 -0500 Subject: [PATCH 1/8] common/playlist: add playlist_entry_from_id Will be used in later commits for commands using playlist entry id. --- common/playlist.c | 11 +++++++++++ common/playlist.h | 1 + 2 files changed, 12 insertions(+) diff --git a/common/playlist.c b/common/playlist.c index 2d2e426222723..e0a6b4ad14886 100644 --- a/common/playlist.c +++ b/common/playlist.c @@ -385,6 +385,17 @@ struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index) return index >= 0 && index < pl->num_entries ? pl->entries[index] : NULL; } +// Return entry for a specific entry id. +// Return NULL if not found. +struct playlist_entry *playlist_entry_from_id(struct playlist *pl, int64_t id) +{ + for (int i = 0; i < pl->num_entries; ++i) { + if (pl->entries[i]->id == (uint64_t)id) + return pl->entries[i]; + } + return NULL; +} + struct playlist *playlist_parse_file(const char *file, struct mp_cancel *cancel, struct mpv_global *global) { diff --git a/common/playlist.h b/common/playlist.h index 4b33958a51dc5..8f7e8eb483b24 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -119,6 +119,7 @@ int64_t playlist_append_entries(struct playlist *pl, struct playlist *source_pl) int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e); int playlist_entry_count(struct playlist *pl); struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index); +struct playlist_entry *playlist_entry_from_id(struct playlist *pl, int64_t id); struct mp_cancel; struct mpv_global; From e9dc77c22a81b13b1a889d2455c4326c66a0d82a Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sun, 5 Jul 2026 01:38:15 -0400 Subject: [PATCH 2/8] common/playlist: make playlist_entry_from_index argument int64_t This prevents overflow when specifying very large index values in later commits. --- common/playlist.c | 2 +- common/playlist.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/playlist.c b/common/playlist.c index e0a6b4ad14886..5cce0227899f4 100644 --- a/common/playlist.c +++ b/common/playlist.c @@ -380,7 +380,7 @@ int playlist_entry_count(struct playlist *pl) // Return entry for which playlist_entry_to_index() would return index. // Return NULL if not found. -struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index) +struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int64_t index) { return index >= 0 && index < pl->num_entries ? pl->entries[index] : NULL; } diff --git a/common/playlist.h b/common/playlist.h index 8f7e8eb483b24..28b7cd50c69bd 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -118,7 +118,7 @@ int64_t playlist_append_entries(struct playlist *pl, struct playlist *source_pl) int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e); int playlist_entry_count(struct playlist *pl); -struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index); +struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int64_t index); struct playlist_entry *playlist_entry_from_id(struct playlist *pl, int64_t id); struct mp_cancel; From 8723e0101ddcf5b4c0258eaff7a5df648f4f2bba Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Fri, 21 Nov 2025 22:37:26 -0500 Subject: [PATCH 3/8] command: add support for playlist entry id to playlist-play-index Add id flag which makes it use playlist entry id specified by the optional second argument for manipulation. This also removes the roundtrip entry->index->entry conversion when "current" is used as pos. --- player/command.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/player/command.c b/player/command.c index a5b5e7e6f5a82..666df56f8f55a 100644 --- a/player/command.c +++ b/player/command.c @@ -6247,14 +6247,20 @@ static void cmd_playlist_play_index(void *p) struct playlist *pl = mpctx->playlist; int pos = cmd->args[0].v.i; bool preserve_options = cmd->num_args >= 2 && cmd->args[1].v.b; + int64_t id = cmd->args[2].v.i64; - if (pos == -2) - pos = playlist_entry_to_index(pl, pl->current); + struct playlist_entry *entry; + if (pos == -3) + entry = playlist_entry_from_id(pl, id); + else if (pos == -2) + entry = pl->current; + else + entry = playlist_entry_from_index(pl, pos); if (preserve_options && pl->current && pos == pl->current->pl_index) pl->current->reloading = true; - mp_set_playlist_entry(mpctx, playlist_entry_from_index(pl, pos)); + mp_set_playlist_entry(mpctx, entry); if (cmd->on_osd & MP_ON_OSD_MSG) mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE; } @@ -7530,9 +7536,13 @@ const struct mp_cmd_def mp_cmds[] = { .priv = &(const int){-1} }, { "playlist-play-index", cmd_playlist_play_index, { - {"index", OPT_CHOICE(v.i, {"current", -2}, {"none", -1}), + {"index", OPT_CHOICE(v.i, + {"id", -3}, + {"current", -2}, + {"none", -1}), M_RANGE(-1, INT_MAX)}, {"preserve-options", OPT_BOOL(v.b), .flags = MP_CMD_OPT_ARG}, + {"id", OPT_INT64(v.i64), .flags = MP_CMD_OPT_ARG}, } }, { "playlist-shuffle", cmd_playlist_shuffle, }, From 7c0df983e2cac45e8a70fbd5f1bc04ecdd0830a8 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sat, 4 Jul 2026 23:50:55 -0400 Subject: [PATCH 4/8] player/command: remove redundant loadfile flag values Only 0,1,2,3,8 are read by get_load_action. --- player/command.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/player/command.c b/player/command.c index 666df56f8f55a..25d710cd32947 100644 --- a/player/command.c +++ b/player/command.c @@ -7736,15 +7736,15 @@ const struct mp_cmd_def mp_cmds[] = { { {"url", OPT_STRING(v.s)}, {"flags", OPT_FLAGS(v.i, - {"replace", 4|0}, - {"append", 4|1}, - {"insert-next", 4|2}, - {"insert-at", 4|3}, - {"play", 32|8}, + {"replace", 0}, + {"append", 1}, + {"insert-next", 2}, + {"insert-at", 3}, + {"play", 8}, // backwards compatibility - {"append-play", (4|1) + (16|8)}, - {"insert-next-play", (4|2) + (16|8)}, - {"insert-at-play", (4|3) + (16|8)}), + {"append-play", 1|8}, + {"insert-next-play", 2|8}, + {"insert-at-play", 3|8}), .flags = MP_CMD_OPT_ARG}, {"index", OPT_INT(v.i), OPTDEF_INT(-1)}, {"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG}, @@ -7754,15 +7754,15 @@ const struct mp_cmd_def mp_cmds[] = { { {"url", OPT_STRING(v.s)}, {"flags", OPT_FLAGS(v.i, - {"replace", 4|0}, - {"append", 4|1}, - {"insert-next", 4|2}, - {"insert-at", 4|3}, - {"play", 32|8}, + {"replace", 0}, + {"append", 1}, + {"insert-next", 2}, + {"insert-at", 3}, + {"play", 8}, // backwards compatibility - {"append-play", (4|1) + (16|8)}, - {"insert-next-play", (4|2) + (16|8)}, - {"insert-at-play", (4|3) + (16|8)}), + {"append-play", 1|8}, + {"insert-next-play", 2|8}, + {"insert-at-play", 3|8}), .flags = MP_CMD_OPT_ARG}, {"index", OPT_INT(v.i), OPTDEF_INT(-1)}, }, From 0026952ef6316c0925a76fe9f24e84feb0a29d54 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:26:31 -0400 Subject: [PATCH 5/8] command: add support for playlist entry id to loadfile/loadlist Add id flag which makes it interprets index parameter as playlist entry id. --- player/command.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/player/command.c b/player/command.c index 25d710cd32947..1d4f6ac2e3472 100644 --- a/player/command.c +++ b/player/command.c @@ -167,6 +167,7 @@ enum load_action_type { struct load_action { enum load_action_type type; bool play; + bool use_id; }; // U+00A0 NO-BREAK SPACE @@ -6387,29 +6388,34 @@ static void cmd_escape_ass(void *p) static struct load_action get_load_action(struct MPContext *mpctx, int action_flag) { int type = action_flag & 3; - bool play = (action_flag >> 3) & 1; + struct load_action action = { + .play = (action_flag >> 3) & 1, + .use_id = (action_flag >> 2) & 1, + }; switch (type) { case 0: - return (struct load_action){LOAD_TYPE_REPLACE, .play = play}; + action.type = LOAD_TYPE_REPLACE; break; case 1: - return (struct load_action){LOAD_TYPE_APPEND, .play = play}; + action.type = LOAD_TYPE_APPEND; break; case 2: - return (struct load_action){LOAD_TYPE_INSERT_NEXT, .play = play}; + action.type = LOAD_TYPE_INSERT_NEXT; break; case 3: - return (struct load_action){LOAD_TYPE_INSERT_AT, .play = play}; + action.type = LOAD_TYPE_INSERT_AT; break; default: // default: replace - return (struct load_action){LOAD_TYPE_REPLACE, .play = true}; + action.type = LOAD_TYPE_REPLACE; break; } + return action; } static struct playlist_entry *get_insert_entry(struct MPContext *mpctx, struct load_action *action, - int insert_at_idx) + int64_t insert_at_idx) { switch (action->type) { case LOAD_TYPE_INSERT_NEXT: return playlist_get_next(mpctx->playlist, +1); case LOAD_TYPE_INSERT_AT: - return playlist_entry_from_index(mpctx->playlist, insert_at_idx); + return action->use_id ? playlist_entry_from_id(mpctx->playlist, insert_at_idx) + : playlist_entry_from_index(mpctx->playlist, insert_at_idx); case LOAD_TYPE_REPLACE: case LOAD_TYPE_APPEND: default: @@ -6423,7 +6429,7 @@ static void cmd_loadfile(void *p) struct MPContext *mpctx = cmd->mpctx; char *filename = cmd->args[0].v.s; int action_flag = cmd->args[1].v.i; - int insert_at_idx = cmd->args[2].v.i; + int64_t insert_at_idx = cmd->args[2].v.i64; struct load_action action = get_load_action(mpctx, action_flag); @@ -6461,7 +6467,7 @@ static void cmd_loadlist(void *p) struct MPContext *mpctx = cmd->mpctx; char *filename = cmd->args[0].v.s; int action_flag = cmd->args[1].v.i; - int insert_at_idx = cmd->args[2].v.i; + int64_t insert_at_idx = cmd->args[2].v.i64; struct load_action action = get_load_action(mpctx, action_flag); @@ -7740,13 +7746,14 @@ const struct mp_cmd_def mp_cmds[] = { {"append", 1}, {"insert-next", 2}, {"insert-at", 3}, + {"id", 4}, {"play", 8}, // backwards compatibility {"append-play", 1|8}, {"insert-next-play", 2|8}, {"insert-at-play", 3|8}), .flags = MP_CMD_OPT_ARG}, - {"index", OPT_INT(v.i), OPTDEF_INT(-1)}, + {"index", OPT_INT64(v.i64), OPTDEF_INT64(-1)}, {"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG}, }, }, @@ -7758,13 +7765,14 @@ const struct mp_cmd_def mp_cmds[] = { {"append", 1}, {"insert-next", 2}, {"insert-at", 3}, + {"id", 4}, {"play", 8}, // backwards compatibility {"append-play", 1|8}, {"insert-next-play", 2|8}, {"insert-at-play", 3|8}), .flags = MP_CMD_OPT_ARG}, - {"index", OPT_INT(v.i), OPTDEF_INT(-1)}, + {"index", OPT_INT64(v.i64), OPTDEF_INT64(-1)}, }, .spawn_thread = true, .can_abort = true, From c9ae1ba6c51119937a1bac697a191e080a752639 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:37:05 -0400 Subject: [PATCH 6/8] command: add support for playlist entry id to playlist-remove Add id flag which makes it use playlist entry id specified by the optional second argument for manipulation. --- player/command.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/player/command.c b/player/command.c index 1d4f6ac2e3472..aefececac5afb 100644 --- a/player/command.c +++ b/player/command.c @@ -6534,10 +6534,15 @@ static void cmd_playlist_remove(void *p) struct mp_cmd_ctx *cmd = p; struct MPContext *mpctx = cmd->mpctx; - struct playlist_entry *e = playlist_entry_from_index(mpctx->playlist, - cmd->args[0].v.i); - if (cmd->args[0].v.i < 0) + int64_t id = cmd->args[1].v.i64; + struct playlist_entry *e = NULL; + if (cmd->args[0].v.i == -1) e = mpctx->playlist->current; + else if (cmd->args[0].v.i == -2) + e = playlist_entry_from_id(mpctx->playlist, id); + else + e = playlist_entry_from_index(mpctx->playlist, cmd->args[0].v.i); + if (!e) { cmd->success = false; return; @@ -7779,8 +7784,9 @@ const struct mp_cmd_def mp_cmds[] = { }, { "playlist-clear", cmd_playlist_clear }, { "playlist-remove", cmd_playlist_remove, { - {"index", OPT_CHOICE(v.i, {"current", -1}), - M_RANGE(0, INT_MAX)}, }}, + {"index", OPT_CHOICE(v.i, {"current", -1}, {"id", -2}), + M_RANGE(0, INT_MAX)}, + {"id", OPT_INT64(v.i64), .flags = MP_CMD_OPT_ARG}, }}, { "playlist-move", cmd_playlist_move, { {"index1", OPT_INT(v.i)}, {"index2", OPT_INT(v.i)}, }}, { "run", cmd_run, { {"command", OPT_STRING(v.s)}, From 17f82e515d2fd114bf6491eb012ca67ed1223fb2 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sun, 5 Jul 2026 01:08:29 -0400 Subject: [PATCH 7/8] command: add support for playlist entry id to playlist-move Add a flag which makes it use playlist entry id for the index arguments. --- player/command.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/player/command.c b/player/command.c index aefececac5afb..113752be6f467 100644 --- a/player/command.c +++ b/player/command.c @@ -6560,11 +6560,17 @@ static void cmd_playlist_move(void *p) { struct mp_cmd_ctx *cmd = p; struct MPContext *mpctx = cmd->mpctx; + bool use_id = cmd->args[2].v.i; + + struct playlist_entry *e1 = NULL, *e2 = NULL; + if (use_id) { + e1 = playlist_entry_from_id(mpctx->playlist, cmd->args[0].v.i64); + e2 = playlist_entry_from_id(mpctx->playlist, cmd->args[1].v.i64); + } else { + e1 = playlist_entry_from_index(mpctx->playlist, cmd->args[0].v.i64); + e2 = playlist_entry_from_index(mpctx->playlist, cmd->args[1].v.i64); + } - struct playlist_entry *e1 = playlist_entry_from_index(mpctx->playlist, - cmd->args[0].v.i); - struct playlist_entry *e2 = playlist_entry_from_index(mpctx->playlist, - cmd->args[1].v.i); if (!e1) { cmd->success = false; return; @@ -7787,8 +7793,11 @@ const struct mp_cmd_def mp_cmds[] = { {"index", OPT_CHOICE(v.i, {"current", -1}, {"id", -2}), M_RANGE(0, INT_MAX)}, {"id", OPT_INT64(v.i64), .flags = MP_CMD_OPT_ARG}, }}, - { "playlist-move", cmd_playlist_move, { {"index1", OPT_INT(v.i)}, - {"index2", OPT_INT(v.i)}, }}, + { "playlist-move", cmd_playlist_move, { + {"index1", OPT_INT64(v.i64)}, + {"index2", OPT_INT64(v.i64)}, + {"flags", OPT_FLAGS(v.i, {"index", 0}, {"id", 1}), + .flags = MP_CMD_OPT_ARG}, }}, { "run", cmd_run, { {"command", OPT_STRING(v.s)}, {"args", OPT_STRING(v.s)}, }, .vararg = true, From 3f39460b9898a6d6b194890d18a1cf426ae1ab70 Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:53:17 -0400 Subject: [PATCH 8/8] DOCS/man/input: add playlist entry id command docs --- DOCS/interface-changes/entry-id.txt | 1 + DOCS/man/input.rst | 33 ++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 DOCS/interface-changes/entry-id.txt diff --git a/DOCS/interface-changes/entry-id.txt b/DOCS/interface-changes/entry-id.txt new file mode 100644 index 0000000000000..297add053c0f2 --- /dev/null +++ b/DOCS/interface-changes/entry-id.txt @@ -0,0 +1 @@ +add support for using playlist entry id for `playlist-play-index/loadfile/loadlist/playlist-remove/playlist-move` commands diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 2de04ff287d73..0c6169e27f33a 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -513,7 +513,7 @@ Playlist Manipulation Go to the first of the previous entries on the playlist with a different ``playlist-path``. -``playlist-play-index [preserve-options]``] +``playlist-play-index [ []]``] Start (or restart) playback of the given playlist index. In addition to the 0-based playlist entry index, it supports the following values: @@ -522,10 +522,12 @@ Playlist Manipulation played again (unload and reload). If none is set, playback is stopped. (In corner cases, ``playlist-current-pos`` can point to a playlist entry even if playback is currently inactive, - Playback is stopped. If idle mode (``--idle``) is enabled, the player will enter idle mode, otherwise it will exit. + + The position is determined by the item with the playlist entry ID + specified by the ``id`` argument. Setting ``preserve-options`` (``MPV_FORMAT_FLAG``) will not reset file-local options when the playback of the current playlist index is restarted. @@ -561,6 +563,8 @@ Playlist Manipulation If nothing is currently playing, start playback. (Always starts with the added file, even if the playlist was not empty before running this command). + + The ``index`` argument is interpreted as a playlist entry ID. Multiple flags can be combined, e.g.: ``append+play``. @@ -588,8 +592,10 @@ Playlist Manipulation The third argument is an insertion index, used only by the ``insert-at`` action. When used with those actions, the new item will be inserted at the index position in the playlist, or appended to the end if index is less than - 0 or greater than the size of the playlist. This argument will be ignored for - all other actions. This argument was added in mpv 0.38.0. + 0 or greater than the size of the playlist. If the second argument contains + the ``id`` flag, then the position is determined by the playlist item with + the specified ID. This argument will be ignored for all other actions. + This argument was added in mpv 0.38.0. The fourth argument is a list of options and values which should be set while the file is playing. It is of the form ``opt1=value1,opt2=value2,..``. @@ -624,6 +630,8 @@ Playlist Manipulation If nothing is currently playing, start playback. (Always starts with the added playlist, even if the internal playlist was not empty before running this command). + + The ``index`` argument is interpreted as a playlist entry ID. Multiple flags can be combined, e.g.: ``append+play``. @@ -652,24 +660,29 @@ Playlist Manipulation The third argument is an insertion index, used only by the ``insert-at`` action. When used with those actions, the new playlist will be inserted at the index position in the internal playlist, or appended to the end if index is less - than 0 or greater than the size of the internal playlist. This argument will be - ignored for all other actions. This argument was added in mpv 0.38.0. + than 0 or greater than the size of the internal playlist. If the second argument + contains the ``id`` flag, then the position is determined by the playlist item + with the specified ID. This argument will be ignored for all other actions. + This argument was added in mpv 0.38.0. ``playlist-clear`` Clear the playlist, except the currently played file. -``playlist-remove `` +``playlist-remove []`` Remove the playlist entry at the given index. Index values start counting with 0. The special value ``current`` removes the current entry. Note that removing the current entry also stops playback and starts playing the next - entry. + entry. The special value ``id`` means the position is determined by the + item with the playlist entry ID specified by the ``id`` argument. -``playlist-move `` +``playlist-move []`` Move the playlist entry at index1, so that it takes the place of the entry index2. (Paradoxically, the moved playlist entry will not have the index value index2 after moving if index1 was lower than index2, because index2 refers to the target entry, not the index the entry - will have after moving.) + will have after moving.) If the ``flags`` argument has the special value + ``id``, then the positions are determined as the items with the playlist + entry ID specified by the first two arguments. ``playlist-shuffle`` Shuffle the playlist. This is similar to what is done on start if the