1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-30 11:02:10 +00:00

input/player: add loadfile/loadlist insert-at command

This commit is contained in:
David Vaughan 2024-02-13 13:24:58 -08:00 committed by Dudemanguy
parent da753196af
commit c678033c1d
4 changed files with 112 additions and 28 deletions

View File

@ -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 restarted if for example the new playlist entry is the same as the previous
one. 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 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 to it). Actual file loading happens independently. For example, a
``loadfile`` command that replaces the current file with a new one returns ``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. 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. 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 (Always starts with the added file, even if the playlist was not empty
before running this command.) before running this command.)
<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 a list of options and values which should be set 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,..``. 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 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 table), however the values themselves must be strings currently. These
options are set during playback, and restored to the previous value at end options are set during playback, and restored to the previous value at end
of playback (see `Per-File Options`_). of playback (see `Per-File Options`_).
``loadlist <url> [<flags>]`` ``loadlist <url> [<flags> [<index>]]``
Load the given playlist file or URL (like ``--playlist``). Load the given playlist file or URL (like ``--playlist``).
Second argument: 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 Insert the new playlist, and if nothing is currently playing, start
playback. (Always starts with the new playlist, even if the internal playback. (Always starts with the new playlist, even if the internal
playlist was not empty before running this command.) 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`` ``playlist-clear``
Clear the playlist, except the currently played file. Clear the playlist, except the currently played file.

View File

@ -312,7 +312,7 @@ void playlist_set_stream_flags(struct playlist *pl, int flags)
pl->entries[n]->stream_flags = flags; pl->entries[n]->stream_flags = flags;
} }
static int64_t playlist_transfer_entries_to(struct playlist *pl, int dst_index, int64_t playlist_transfer_entries_to(struct playlist *pl, int dst_index,
struct playlist *source_pl) struct playlist *source_pl)
{ {
assert(pl != source_pl); assert(pl != source_pl);

View File

@ -106,6 +106,8 @@ struct playlist_entry *playlist_get_first_in_same_playlist(struct playlist_entry
char *current_playlist_path); char *current_playlist_path);
void playlist_add_base_path(struct playlist *pl, bstr base_path); void playlist_add_base_path(struct playlist *pl, bstr base_path);
void playlist_set_stream_flags(struct playlist *pl, int flags); 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_transfer_entries(struct playlist *pl, struct playlist *source_pl);
int64_t playlist_append_entries(struct playlist *pl, struct playlist *source_pl); int64_t playlist_append_entries(struct playlist *pl, struct playlist *source_pl);

View File

@ -139,6 +139,18 @@ struct hook_handler {
bool active; // hook is currently in progress (only 1 at a time for now) 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+279C HEAVY ROUND-TIPPED RIGHTWARDS ARROW
// U+00A0 NO-BREAK SPACE // U+00A0 NO-BREAK SPACE
#define ARROW_SP "\342\236\234\302\240" #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) static void cmd_loadfile(void *p)
{ {
struct mp_cmd_ctx *cmd = p; struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx; struct MPContext *mpctx = cmd->mpctx;
char *filename = cmd->args[0].v.s; 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); struct load_action action = get_load_action(mpctx, action_flag);
bool insert_next = (action == 3 || action == 4);
bool play = (action == 2 || action == 4);
if (replace) if (action.type == LOAD_TYPE_REPLACE)
playlist_clear(mpctx->playlist); playlist_clear(mpctx->playlist);
struct playlist_entry *entry = playlist_entry_new(filename); struct playlist_entry *entry = playlist_entry_new(filename);
if (cmd->args[2].v.str_list) { if (cmd->args[3].v.str_list) {
char **pairs = cmd->args[2].v.str_list; char **pairs = cmd->args[3].v.str_list;
for (int i = 0; pairs[i] && pairs[i + 1]; i += 2) for (int i = 0; pairs[i] && pairs[i + 1]; i += 2)
playlist_entry_add_param(entry, bstr0(pairs[i]), bstr0(pairs[i + 1])); playlist_entry_add_param(entry, bstr0(pairs[i]), bstr0(pairs[i + 1]));
} }
struct playlist_entry *at = insert_next ? struct playlist_entry *at = get_insert_entry(mpctx, &action, insert_at_idx);
playlist_get_next(mpctx->playlist, +1) : NULL;
playlist_insert_at(mpctx->playlist, entry, at); playlist_insert_at(mpctx->playlist, entry, at);
struct mpv_node *res = &cmd->result; struct mpv_node *res = &cmd->result;
node_init(res, MPV_FORMAT_NODE_MAP, NULL); node_init(res, MPV_FORMAT_NODE_MAP, NULL);
node_map_add_int64(res, "playlist_entry_id", entry->id); 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 if (mpctx->opts->position_save_on_quit) // requested in issue #1148
mp_write_watch_later_conf(mpctx); mp_write_watch_later_conf(mpctx);
mp_set_playlist_entry(mpctx, entry); mp_set_playlist_entry(mpctx, entry);
@ -5566,33 +5612,37 @@ static void cmd_loadlist(void *p)
struct mp_cmd_ctx *cmd = p; struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx; struct MPContext *mpctx = cmd->mpctx;
char *filename = cmd->args[0].v.s; 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); struct load_action action = get_load_action(mpctx, action_flag);
bool insert_next = (flag == 3 || flag == 4);
bool play = (flag == 2 || flag == 4);
struct playlist *pl = playlist_parse_file(filename, cmd->abort->cancel, struct playlist *pl = playlist_parse_file(filename, cmd->abort->cancel,
mpctx->global); mpctx->global);
if (pl) { if (pl) {
prepare_playlist(mpctx, pl); prepare_playlist(mpctx, pl);
struct playlist_entry *new = pl->current; struct playlist_entry *new = pl->current;
if (replace) if (action.type == LOAD_TYPE_REPLACE)
playlist_clear(mpctx->playlist); playlist_clear(mpctx->playlist);
struct playlist_entry *first = playlist_entry_from_index(pl, 0); struct playlist_entry *first = playlist_entry_from_index(pl, 0);
int num_entries = pl->num_entries; int num_entries = pl->num_entries;
if (insert_next) {
playlist_transfer_entries(mpctx->playlist, pl); struct playlist_entry *at = get_insert_entry(mpctx, &action, insert_at_idx);
} else { if (at == NULL) {
playlist_append_entries(mpctx->playlist, pl); 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); talloc_free(pl);
if (!new) if (!new)
new = playlist_get_first(mpctx->playlist); 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); mp_set_playlist_entry(mpctx, new);
}
struct mpv_node *res = &cmd->result; struct mpv_node *res = &cmd->result;
node_init(res, MPV_FORMAT_NODE_MAP, NULL); node_init(res, MPV_FORMAT_NODE_MAP, NULL);
@ -6699,8 +6749,11 @@ const struct mp_cmd_def mp_cmds[] = {
{"append", 1}, {"append", 1},
{"append-play", 2}, {"append-play", 2},
{"insert-next", 3}, {"insert-next", 3},
{"insert-next-play", 4}), {"insert-next-play", 4},
{"insert-at", 5},
{"insert-at-play", 6}),
.flags = MP_CMD_OPT_ARG}, .flags = MP_CMD_OPT_ARG},
{"index", OPT_INT(v.i), OPTDEF_INT(-1)},
{"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG}, {"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", 1},
{"append-play", 2}, {"append-play", 2},
{"insert-next", 3}, {"insert-next", 3},
{"insert-next-play", 4}), {"insert-next-play", 4},
{"insert-at", 5},
{"insert-at-play", 6}),
.flags = MP_CMD_OPT_ARG}, .flags = MP_CMD_OPT_ARG},
{"index", OPT_INT(v.i), OPTDEF_INT(-1)},
}, },
.spawn_thread = true, .spawn_thread = true,
.can_abort = true, .can_abort = true,