Skip to content
1 change: 1 addition & 0 deletions DOCS/interface-changes/entry-id.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add support for using playlist entry id for `playlist-play-index/loadfile/loadlist/playlist-remove/playlist-move` commands
33 changes: 23 additions & 10 deletions DOCS/man/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <integer|current|none> [preserve-options]``]
``playlist-play-index <index> [<preserve-options> [<id>]]``]
Start (or restart) playback of the given playlist index. In addition to the
0-based playlist entry index, it supports the following values:

Expand All @@ -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,

<none>
Playback is stopped. If idle mode (``--idle``) is enabled, the player
will enter idle mode, otherwise it will exit.
<id>
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.
Expand Down Expand Up @@ -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).
<id>
The ``index`` argument is interpreted as a playlist entry ID.

Multiple flags can be combined, e.g.: ``append+play``.

Expand Down Expand Up @@ -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,..``.
Expand Down Expand Up @@ -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).
<id>
The ``index`` argument is interpreted as a playlist entry ID.

Multiple flags can be combined, e.g.: ``append+play``.

Expand Down Expand Up @@ -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 <index>``
``playlist-remove <index> [<id>]``
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 <index1> <index2>``
``playlist-move <index1> <index2> [<flags>]``
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
Expand Down
13 changes: 12 additions & 1 deletion common/playlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,22 @@ 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;
}

// 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)
{
Expand Down
3 changes: 2 additions & 1 deletion common/playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ 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;
struct mpv_global;
Expand Down
119 changes: 76 additions & 43 deletions player/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -6247,14 +6248,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;
}
Expand Down Expand Up @@ -6381,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:
Expand All @@ -6417,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);

Expand Down Expand Up @@ -6455,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);

Expand Down Expand Up @@ -6522,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;
Expand All @@ -6543,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;
Expand Down Expand Up @@ -7530,9 +7553,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, },
Expand Down Expand Up @@ -7726,45 +7753,51 @@ 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},
{"id", 4},
{"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)},
{"index", OPT_INT64(v.i64), OPTDEF_INT64(-1)},
{"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG},
},
},
{ "loadlist", cmd_loadlist,
{
{"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},
{"id", 4},
{"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)},
{"index", OPT_INT64(v.i64), OPTDEF_INT64(-1)},
},
.spawn_thread = true,
.can_abort = true,
},
{ "playlist-clear", cmd_playlist_clear },
{ "playlist-remove", cmd_playlist_remove, {
{"index", OPT_CHOICE(v.i, {"current", -1}),
M_RANGE(0, INT_MAX)}, }},
{ "playlist-move", cmd_playlist_move, { {"index1", OPT_INT(v.i)},
{"index2", OPT_INT(v.i)}, }},
{"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_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,
Expand Down
Loading