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:
parent
da753196af
commit
c678033c1d
@ -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.
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
100
player/command.c
100
player/command.c
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user