diff options
-rw-r--r-- | common/playlist.c | 12 | ||||
-rw-r--r-- | common/playlist.h | 6 | ||||
-rw-r--r-- | options/path.c | 15 | ||||
-rw-r--r-- | options/path.h | 2 | ||||
-rw-r--r-- | player/configfiles.c | 70 | ||||
-rw-r--r-- | player/loadfile.c | 2 |
6 files changed, 98 insertions, 9 deletions
diff --git a/common/playlist.c b/common/playlist.c index 9fd087be67..fe197a8ded 100644 --- a/common/playlist.c +++ b/common/playlist.c @@ -206,6 +206,18 @@ void playlist_add_base_path(struct playlist *pl, bstr base_path) } } +// Add redirected_from as new redirect entry to each item in pl. +void playlist_add_redirect(struct playlist *pl, const char *redirected_from) +{ + for (struct playlist_entry *e = pl->first; e; e = e->next) { + if (e->num_redirects >= 10) // arbitrary limit for sanity + break; + char *s = talloc_strdup(e, redirected_from); + if (s) + MP_TARRAY_APPEND(e, e->redirects, e->num_redirects, s); + } +} + // Move all entries from source_pl to pl, appending them after the current entry // of pl. source_pl will be empty, and all entries have changed ownership to pl. void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl) diff --git a/common/playlist.h b/common/playlist.h index be9fd991e2..b2861b5230 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -36,6 +36,11 @@ struct playlist_entry { char *title; + // If the user plays a playlist, then the playlist's URL will be appended + // as redirect to each entry. (Same for directories etc.) + char **redirects; + int num_redirects; + // 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 @@ -88,6 +93,7 @@ void playlist_add_file(struct playlist *pl, const char *filename); void playlist_shuffle(struct playlist *pl); struct playlist_entry *playlist_get_next(struct playlist *pl, int direction); void playlist_add_base_path(struct playlist *pl, bstr base_path); +void playlist_add_redirect(struct playlist *pl, const char *redirected_from); void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl); void playlist_append_entries(struct playlist *pl, struct playlist *source_pl); diff --git a/options/path.c b/options/path.c index 5072e7312c..adfd2ded3e 100644 --- a/options/path.c +++ b/options/path.c @@ -213,6 +213,21 @@ struct bstr mp_dirname(const char *path) return ret; } + +#if HAVE_DOS_PATHS +static const char mp_path_separators[] = "\\/"; +#else +static const char mp_path_separators[] = "/"; +#endif + +// Mutates path and removes a trailing '/' (or '\' on Windows) +void mp_path_strip_trailing_separator(char *path) +{ + size_t len = strlen(path); + if (len > 0 && strchr(mp_path_separators, path[len - 1])) + path[len - 1] = '\0'; +} + char *mp_splitext(const char *path, bstr *root) { assert(path); diff --git a/options/path.h b/options/path.h index 763a8dda54..203651a931 100644 --- a/options/path.h +++ b/options/path.h @@ -65,6 +65,8 @@ char *mp_splitext(const char *path, bstr *root); */ struct bstr mp_dirname(const char *path); +void mp_path_strip_trailing_separator(char *path); + /* Join two path components and return a newly allocated string * for the result. '/' is inserted between the components if needed. * If p2 is an absolute path then the value of p1 is ignored. diff --git a/player/configfiles.c b/player/configfiles.c index db19685c0f..678d60ddc0 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -273,11 +273,35 @@ static bool needs_config_quoting(const char *s) return false; } +static void write_filename(struct MPContext *mpctx, FILE *file, char *filename) +{ + if (mpctx->opts->write_filename_in_watch_later_config) { + char write_name[1024] = {0}; + for (int n = 0; filename[n] && n < sizeof(write_name) - 1; n++) + write_name[n] = (unsigned char)filename[n] < 32 ? '_' : filename[n]; + fprintf(file, "# %s\n", write_name); + } +} + +static void write_redirect(struct MPContext *mpctx, char *path) +{ + char *conffile = mp_get_playback_resume_config_filename(mpctx, path); + if (conffile) { + FILE *file = fopen(conffile, "wb"); + if (file) { + fprintf(file, "# redirect entry\n"); + write_filename(mpctx, file, path); + fclose(file); + } + talloc_free(conffile); + } +} + void mp_write_watch_later_conf(struct MPContext *mpctx) { - char *filename = mpctx->filename; + struct playlist_entry *cur = mpctx->playing; char *conffile = NULL; - if (!filename) + if (!cur) goto exit; struct demuxer *demux = mpctx->demuxer; @@ -288,7 +312,7 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) mp_mk_config_dir(mpctx->global, MP_WATCH_LATER_CONF); - conffile = mp_get_playback_resume_config_filename(mpctx, filename); + conffile = mp_get_playback_resume_config_filename(mpctx, cur->filename); if (!conffile) goto exit; @@ -297,12 +321,9 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) FILE *file = fopen(conffile, "wb"); if (!file) goto exit; - if (mpctx->opts->write_filename_in_watch_later_config) { - char write_name[1024] = {0}; - for (int n = 0; filename[n] && n < sizeof(write_name) - 1; n++) - write_name[n] = (unsigned char)filename[n] < 32 ? '_' : filename[n]; - fprintf(file, "# %s\n", write_name); - } + + write_filename(mpctx, file, cur->filename); + double pos = get_current_time(mpctx); if (pos != MP_NOPTS_VALUE) fprintf(file, "start=%f\n", pos); @@ -328,6 +349,37 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) } fclose(file); + // This allows us to recursively resume directories etc., whose entries are + // expanded the first time it's "played". For example, if "/a/b/c.mkv" is + // the current entry, then we want to resume this file if the user does + // "mpv /a". This would expand to the directory entries in "/a", and if + // "/a/a.mkv" is not the first entry, this would be played. + // Here, we write resume entries for "/a" and "/a/b". + // (Unfortunately, this will leave stray resume files on resume, because + // obviously it resumes only from one of those paths.) + for (int n = 0; n < cur->num_redirects; n++) + write_redirect(mpctx, cur->redirects[n]); + // And at last, for local directories, we write an entry for each path + // prefix, so the user can resume from an arbitrary directory. This starts + // with the first redirect (all other redirects are further prefixes). + if (cur->num_redirects) { + char *path = cur->redirects[0]; + char tmp[4096]; + if (!mp_is_url(bstr0(path)) && strlen(path) < sizeof(tmp)) { + snprintf(tmp, sizeof(tmp), "%s", path); + for (;;) { + bstr dir = mp_dirname(tmp); + if (dir.len == strlen(tmp) || !dir.len || bstr_equals0(dir, ".")) + break; + + tmp[dir.len] = '\0'; + if (strlen(tmp) >= 2) // keep "/" + mp_path_strip_trailing_separator(tmp); + write_redirect(mpctx, tmp); + } + } + } + exit: talloc_free(conffile); } diff --git a/player/loadfile.c b/player/loadfile.c index 4a7a71f421..ec4d19d3c5 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -836,6 +836,8 @@ static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl) if (pl->first) { prepare_playlist(mpctx, pl); struct playlist_entry *new = pl->current; + if (mpctx->playlist->current) + playlist_add_redirect(pl, mpctx->playlist->current->filename); playlist_transfer_entries(mpctx->playlist, pl); // current entry is replaced if (mpctx->playlist->current) |