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 diff --git a/common/playlist.c b/common/playlist.c index 2d2e426222723..5cce0227899f4 100644 --- a/common/playlist.c +++ b/common/playlist.c @@ -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) { diff --git a/common/playlist.h b/common/playlist.h index 4b33958a51dc5..28b7cd50c69bd 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -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; diff --git a/player/command.c b/player/command.c index a5b5e7e6f5a82..113752be6f467 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 @@ -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; } @@ -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: @@ -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); @@ -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); @@ -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; @@ -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; @@ -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, }, @@ -7726,17 +7753,18 @@ 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}, }, }, @@ -7744,27 +7772,32 @@ 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)}, }, .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,