summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/playlist.c12
-rw-r--r--common/playlist.h6
-rw-r--r--options/path.c15
-rw-r--r--options/path.h2
-rw-r--r--player/configfiles.c70
-rw-r--r--player/loadfile.c2
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)