summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vaughan <david@davidv.xyz>2024-02-13 13:24:58 -0800
committerDudemanguy <random342@airmail.cc>2024-02-26 02:03:21 +0000
commitc678033c1d60b48ae02fbbe4815869b9504a17f6 (patch)
treed3a8c7482a4568f648dc422d93a1fb7010f7652a
parentda753196af6593b2d6e94f691c9d1287b3ea093b (diff)
downloadmpv-c678033c1d60b48ae02fbbe4815869b9504a17f6.tar.bz2
mpv-c678033c1d60b48ae02fbbe4815869b9504a17f6.tar.xz
input/player: add loadfile/loadlist insert-at command
-rw-r--r--DOCS/man/input.rst36
-rw-r--r--common/playlist.c4
-rw-r--r--common/playlist.h2
-rw-r--r--player/command.c100
4 files changed, 113 insertions, 29 deletions
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index e0b8210df1..f277b52f02 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -452,9 +452,9 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
restarted if for example the new playlist entry is the same as the previous
one.
-``loadfile <url> [<flags> [<options>]]``
+``loadfile <url> [<flags> [<index> [<options>]]]``
Load the given file or URL and play it. Technically, this is just a playlist
- manipulation command (which either replaces the playlist or appends an entry
+ manipulation command (which either replaces the playlist or adds an entry
to it). Actual file loading happens independently. For example, a
``loadfile`` command that replaces the current file with a new one returns
before the current file is stopped, and the new file even begins loading.
@@ -475,15 +475,28 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
Insert the file next, and 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 third argument is a list of options and values which should be set
+ <insert-at>
+ Insert the file into the playlist, at the index given in the third
+ argument.
+ <insert-at-play>
+ Insert the file at the index given in the third argument, and 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 third argument is an insertion index, used only by the `insert-at` and
+ `insert-at-play` actions. When used with those actions, the new item will be
+ insert 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.
+
+ 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,..``.
When using the client API, this can be a ``MPV_FORMAT_NODE_MAP`` (or a Lua
table), however the values themselves must be strings currently. These
options are set during playback, and restored to the previous value at end
of playback (see `Per-File Options`_).
-``loadlist <url> [<flags>]``
+``loadlist <url> [<flags> [<index>]]``
Load the given playlist file or URL (like ``--playlist``).
Second argument:
@@ -503,6 +516,19 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
Insert the new playlist, and if nothing is currently playing, start
playback. (Always starts with the new playlist, even if the internal
playlist was not empty before running this command.)
+ <insert-at>
+ Insert the new playlist at the index given in the third argument.
+ <insert-at-play>
+ Insert the new playlist at the index given in the third argument, and if
+ nothing is currently playing, start playback. (Always starts with the
+ new playlist, even if the internal playlist was not empty before running
+ this command.)
+
+ The third argument is an insertion index, used only by the `insert-at` and
+ `insert-at-play` actions. When used with those actions, the new playlist
+ will be insert 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.
``playlist-clear``
Clear the playlist, except the currently played file.
diff --git a/common/playlist.c b/common/playlist.c
index 5ff34496c8..39c49a5230 100644
--- a/common/playlist.c
+++ b/common/playlist.c
@@ -312,8 +312,8 @@ void playlist_set_stream_flags(struct playlist *pl, int flags)
pl->entries[n]->stream_flags = flags;
}
-static int64_t playlist_transfer_entries_to(struct playlist *pl, int dst_index,
- struct playlist *source_pl)
+int64_t playlist_transfer_entries_to(struct playlist *pl, int dst_index,
+ struct playlist *source_pl)
{
assert(pl != source_pl);
struct playlist_entry *first = playlist_get_first(source_pl);
diff --git a/common/playlist.h b/common/playlist.h
index 1e01b1a5e3..853cd311da 100644
--- a/common/playlist.h
+++ b/common/playlist.h
@@ -106,6 +106,8 @@ struct playlist_entry *playlist_get_first_in_same_playlist(struct playlist_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_to(struct playlist *pl, int dst_index,
+ struct playlist *source_pl);
int64_t playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl);
int64_t playlist_append_entries(struct playlist *pl, struct playlist *source_pl);
diff --git a/player/command.c b/player/command.c
index 2c5c67e78a..d5a315290e 100644
--- a/player/command.c
+++ b/player/command.c
@@ -139,6 +139,18 @@ struct hook_handler {
bool active; // hook is currently in progress (only 1 at a time for now)
};
+enum load_action_type {
+ LOAD_TYPE_REPLACE,
+ LOAD_TYPE_INSERT_AT,
+ LOAD_TYPE_INSERT_NEXT,
+ LOAD_TYPE_APPEND,
+};
+
+struct load_action {
+ enum load_action_type type;
+ bool play;
+};
+
// U+279C HEAVY ROUND-TIPPED RIGHTWARDS ARROW
// U+00A0 NO-BREAK SPACE
#define ARROW_SP "\342\236\234\302\240"
@@ -5522,37 +5534,71 @@ static void cmd_expand_path(void *p)
};
}
+static struct load_action get_load_action(struct MPContext *mpctx, int action_flag)
+{
+ switch (action_flag) {
+ case 0: // replace
+ return (struct load_action){LOAD_TYPE_REPLACE, .play = true};
+ case 1: // append
+ return (struct load_action){LOAD_TYPE_APPEND, .play = false};
+ case 2: // append-play
+ return (struct load_action){LOAD_TYPE_APPEND, .play = true};
+ case 3: // insert-next
+ return (struct load_action){LOAD_TYPE_INSERT_NEXT, .play = false};
+ case 4: // insert-next-play
+ return (struct load_action){LOAD_TYPE_INSERT_NEXT, .play = true};
+ case 5: // insert-at
+ return (struct load_action){LOAD_TYPE_INSERT_AT, .play = false};
+ case 6: // insert-at-play
+ return (struct load_action){LOAD_TYPE_INSERT_AT, .play = true};
+ default: // default: replace
+ return (struct load_action){LOAD_TYPE_REPLACE, .play = true};
+ }
+}
+
+static struct playlist_entry *get_insert_entry(struct MPContext *mpctx, struct load_action *action,
+ int 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);
+ case LOAD_TYPE_REPLACE:
+ case LOAD_TYPE_APPEND:
+ default:
+ return NULL;
+ }
+}
+
static void cmd_loadfile(void *p)
{
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;
char *filename = cmd->args[0].v.s;
- int action = cmd->args[1].v.i;
+ int action_flag = cmd->args[1].v.i;
+ int insert_at_idx = cmd->args[2].v.i;
- bool replace = (action == 0);
- bool insert_next = (action == 3 || action == 4);
- bool play = (action == 2 || action == 4);
+ struct load_action action = get_load_action(mpctx, action_flag);
- if (replace)
+ if (action.type == LOAD_TYPE_REPLACE)
playlist_clear(mpctx->playlist);
struct playlist_entry *entry = playlist_entry_new(filename);
- if (cmd->args[2].v.str_list) {
- char **pairs = cmd->args[2].v.str_list;
+ if (cmd->args[3].v.str_list) {
+ char **pairs = cmd->args[3].v.str_list;
for (int i = 0; pairs[i] && pairs[i + 1]; i += 2)
playlist_entry_add_param(entry, bstr0(pairs[i]), bstr0(pairs[i + 1]));
}
- struct playlist_entry *at = insert_next ?
- playlist_get_next(mpctx->playlist, +1) : NULL;
-
+ struct playlist_entry *at = get_insert_entry(mpctx, &action, insert_at_idx);
playlist_insert_at(mpctx->playlist, entry, at);
struct mpv_node *res = &cmd->result;
node_init(res, MPV_FORMAT_NODE_MAP, NULL);
node_map_add_int64(res, "playlist_entry_id", entry->id);
- if (replace || (play && !mpctx->playlist->current)) {
+ if (action.type == LOAD_TYPE_REPLACE || (action.play && !mpctx->playlist->current)) {
if (mpctx->opts->position_save_on_quit) // requested in issue #1148
mp_write_watch_later_conf(mpctx);
mp_set_playlist_entry(mpctx, entry);
@@ -5566,33 +5612,37 @@ static void cmd_loadlist(void *p)
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;
char *filename = cmd->args[0].v.s;
- int flag = cmd->args[1].v.i;
+ int action_flag = cmd->args[1].v.i;
+ int insert_at_idx = cmd->args[2].v.i;
- bool replace = (flag == 0);
- bool insert_next = (flag == 3 || flag == 4);
- bool play = (flag == 2 || flag == 4);
+ struct load_action action = get_load_action(mpctx, action_flag);
struct playlist *pl = playlist_parse_file(filename, cmd->abort->cancel,
mpctx->global);
if (pl) {
prepare_playlist(mpctx, pl);
struct playlist_entry *new = pl->current;
- if (replace)
+ if (action.type == LOAD_TYPE_REPLACE)
playlist_clear(mpctx->playlist);
struct playlist_entry *first = playlist_entry_from_index(pl, 0);
int num_entries = pl->num_entries;
- if (insert_next) {
- playlist_transfer_entries(mpctx->playlist, pl);
- } else {
+
+ struct playlist_entry *at = get_insert_entry(mpctx, &action, insert_at_idx);
+ if (at == NULL) {
playlist_append_entries(mpctx->playlist, pl);
+ } else {
+ int at_index = playlist_entry_to_index(mpctx->playlist, at);
+ playlist_transfer_entries_to(mpctx->playlist, at_index, pl);
}
talloc_free(pl);
if (!new)
new = playlist_get_first(mpctx->playlist);
- if ((replace || (play && !mpctx->playlist->current)) && new)
+ if ((action.type == LOAD_TYPE_REPLACE ||
+ (action.play && !mpctx->playlist->current)) && new) {
mp_set_playlist_entry(mpctx, new);
+ }
struct mpv_node *res = &cmd->result;
node_init(res, MPV_FORMAT_NODE_MAP, NULL);
@@ -6699,8 +6749,11 @@ const struct mp_cmd_def mp_cmds[] = {
{"append", 1},
{"append-play", 2},
{"insert-next", 3},
- {"insert-next-play", 4}),
+ {"insert-next-play", 4},
+ {"insert-at", 5},
+ {"insert-at-play", 6}),
.flags = MP_CMD_OPT_ARG},
+ {"index", OPT_INT(v.i), OPTDEF_INT(-1)},
{"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG},
},
},
@@ -6712,8 +6765,11 @@ const struct mp_cmd_def mp_cmds[] = {
{"append", 1},
{"append-play", 2},
{"insert-next", 3},
- {"insert-next-play", 4}),
+ {"insert-next-play", 4},
+ {"insert-at", 5},
+ {"insert-at-play", 6}),
.flags = MP_CMD_OPT_ARG},
+ {"index", OPT_INT(v.i), OPTDEF_INT(-1)},
},
.spawn_thread = true,
.can_abort = true,