From 5a261507173d28c762ba4f605d7983d928d4bf24 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 28 Dec 2019 21:32:03 +0100 Subject: command: add a playlist-unshuffle command Has a number of restrictions. See: #2491, #7294 --- DOCS/man/input.rst | 6 ++++++ common/playlist.c | 22 ++++++++++++++++++++++ common/playlist.h | 4 ++++ player/command.c | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 1d66dc47bc..d6430581a8 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -426,6 +426,12 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_). Shuffle the playlist. This is similar to what is done on start if the ``--shuffle`` option is used. +``playlist-unshuffle`` + Attempt to revert the previous ``playlist-shuffle`` command. This works + only once (multiple successive ``playlist-unshuffle`` commands do nothing). + May not work correctly if new recursive playlists have been opened since + a ``playlist-shuffle`` command. + ``run [ [ [...]]]`` Run the given command. Unlike in MPlayer/mplayer2 and earlier versions of mpv (0.2.x and older), this doesn't call the shell. Instead, the command diff --git a/common/playlist.c b/common/playlist.c index 300fc48bf9..1fd202b98f 100644 --- a/common/playlist.c +++ b/common/playlist.c @@ -33,6 +33,7 @@ struct playlist_entry *playlist_entry_new(const char *filename) char *local_filename = mp_file_url_to_filename(e, bstr0(filename)); e->filename = local_filename ? local_filename : talloc_strdup(e, filename); e->stream_flags = STREAM_ORIGIN_DIRECT; + e->original_index = -1; return e; } @@ -141,6 +142,8 @@ void playlist_add_file(struct playlist *pl, const char *filename) void playlist_shuffle(struct playlist *pl) { + for (int n = 0; n < pl->num_entries; n++) + pl->entries[n]->original_index = n; for (int n = 0; n < pl->num_entries - 1; n++) { int j = (int)((double)(pl->num_entries - n) * rand() / (RAND_MAX + 1.0)); MPSWAP(struct playlist_entry *, pl->entries[n], pl->entries[n + j]); @@ -148,6 +151,25 @@ void playlist_shuffle(struct playlist *pl) playlist_update_indexes(pl, 0, -1); } +#define CMP_INT(a, b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1)) + +static int cmp_unshuffle(const void *a, const void *b) +{ + struct playlist_entry *ea = *(struct playlist_entry **)a; + struct playlist_entry *eb = *(struct playlist_entry **)b; + + if (ea->original_index >= 0 && ea->original_index != eb->original_index) + return CMP_INT(ea->original_index, eb->original_index); + return CMP_INT(ea->pl_index, eb->pl_index); +} + +void playlist_unshuffle(struct playlist *pl) +{ + if (pl->num_entries) + qsort(pl->entries, pl->num_entries, sizeof(pl->entries[0]), cmp_unshuffle); + playlist_update_indexes(pl, 0, -1); +} + // (Explicitly ignores current_was_replaced.) struct playlist_entry *playlist_get_first(struct playlist *pl) { diff --git a/common/playlist.h b/common/playlist.h index d0f17e315f..8b014e864d 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -42,6 +42,9 @@ struct playlist_entry { char **redirects; int num_redirects; + // Used for unshuffling: the pl_index before it was shuffled. -1 => unknown. + int original_index; + // Set to true if playback didn't seem to work, or if the file could be // played only for a very short time. This is used to make playlist // navigation just work in case the user has unplayable files in the @@ -87,6 +90,7 @@ void playlist_move(struct playlist *pl, struct playlist_entry *entry, void playlist_add_file(struct playlist *pl, const char *filename); void playlist_shuffle(struct playlist *pl); +void playlist_unshuffle(struct playlist *pl); struct playlist_entry *playlist_get_first(struct playlist *pl); struct playlist_entry *playlist_get_last(struct playlist *pl); struct playlist_entry *playlist_get_next(struct playlist *pl, int direction); diff --git a/player/command.c b/player/command.c index 084fd0fc4e..0a17a1def4 100644 --- a/player/command.c +++ b/player/command.c @@ -4916,6 +4916,15 @@ static void cmd_playlist_shuffle(void *p) mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL); } +static void cmd_playlist_unshuffle(void *p) +{ + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + + playlist_unshuffle(mpctx->playlist); + mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL); +} + static void cmd_stop(void *p) { struct mp_cmd_ctx *cmd = p; @@ -5629,6 +5638,7 @@ const struct mp_cmd_def mp_cmds[] = { .priv = &(const int){-1}, }, { "playlist-shuffle", cmd_playlist_shuffle, }, + { "playlist-unshuffle", cmd_playlist_unshuffle, }, { "sub-step", cmd_sub_step_seek, { OPT_INT("skip", v.i, 0) }, .allow_auto_repeat = true, .priv = &(const bool){true} }, { "sub-seek", cmd_sub_step_seek, { OPT_INT("skip", v.i, 0) }, -- cgit v1.2.3