mirror of
https://github.com/mpv-player/mpv
synced 2025-01-03 21:42:18 +00:00
player: normalize paths for resuming playback
Paths like foo.mkv, ./foo.mkv .//foo.mkv, ../"$(basename "$PWD")"/foo.mkv, and C:\foo.mkv and C:/foo.mkv on Windows, use different config files for resuming playback, so if you quit-watch-later and later play the same file with a different path, mpv does not resume playback. This commit normalizes the paths on Unix to fix this.
This commit is contained in:
parent
8a61929eb8
commit
1d640c9887
@ -151,10 +151,61 @@ char *mp_getcwd(void *talloc_ctx)
|
||||
|
||||
char *mp_normalize_path(void *talloc_ctx, const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
if (mp_is_url(bstr0(path)))
|
||||
return talloc_strdup(talloc_ctx, path);
|
||||
|
||||
return mp_path_join(talloc_ctx, mp_getcwd(talloc_ctx), path);
|
||||
if (!mp_path_is_absolute(bstr0(path))) {
|
||||
char *cwd = mp_getcwd(talloc_ctx);
|
||||
if (!cwd)
|
||||
return NULL;
|
||||
path = mp_path_join(talloc_ctx, cwd, path);
|
||||
}
|
||||
|
||||
#if HAVE_DOS_PATHS
|
||||
return talloc_strdup(talloc_ctx, path);
|
||||
#else
|
||||
char *result = talloc_strdup(talloc_ctx, "");
|
||||
const char *next;
|
||||
const char *end = path + strlen(path);
|
||||
|
||||
for (const char *ptr = path; ptr < end; ptr = next + 1) {
|
||||
next = memchr(ptr, '/', end - ptr);
|
||||
if (next == NULL)
|
||||
next = end;
|
||||
|
||||
switch (next - ptr) {
|
||||
case 0:
|
||||
continue;
|
||||
case 1:
|
||||
if (ptr[0] == '.')
|
||||
continue;
|
||||
break;
|
||||
case 2:
|
||||
// Normalizing symlink/.. results in a wrong path: if the
|
||||
// current working directory is /tmp/foo, and it is a symlink to
|
||||
// /usr/bin, mpv ../file.mkv opens /usr/file.mkv, so we can't
|
||||
// normalize the path to /tmp/file.mkv. Resolve symlinks to fix
|
||||
// this. Otherwise we don't use realpath so users can use
|
||||
// symlinks e.g. to hide how media files are distributed over
|
||||
// real storage and move them while still resuming playback as
|
||||
// long as the symlinked path doesn't change.
|
||||
if (ptr[0] == '.' && ptr[1] == '.') {
|
||||
char *tmp_result = realpath(path, NULL);
|
||||
result = talloc_strdup(talloc_ctx, tmp_result);
|
||||
free(tmp_result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result = talloc_strdup_append_buffer(result, "/");
|
||||
result = talloc_strndup_append_buffer(result, ptr, next - ptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mp_path_exists(const char *path)
|
||||
|
@ -209,20 +209,16 @@ static char *mp_get_playback_resume_config_filename(struct MPContext *mpctx,
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
char *res = NULL;
|
||||
void *tmp = talloc_new(NULL);
|
||||
const char *realpath = fname;
|
||||
bstr bfname = bstr0(fname);
|
||||
if (!mp_is_url(bfname)) {
|
||||
if (opts->ignore_path_in_watch_later_config) {
|
||||
realpath = mp_basename(fname);
|
||||
} else {
|
||||
char *cwd = mp_getcwd(tmp);
|
||||
if (!cwd)
|
||||
goto exit;
|
||||
realpath = mp_path_join(tmp, cwd, fname);
|
||||
}
|
||||
const char *path = NULL;
|
||||
if (opts->ignore_path_in_watch_later_config && !mp_is_url(bstr0(path))) {
|
||||
path = mp_basename(fname);
|
||||
} else {
|
||||
path = mp_normalize_path(tmp, fname);
|
||||
if (!path)
|
||||
goto exit;
|
||||
}
|
||||
uint8_t md5[16];
|
||||
av_md5_sum(md5, realpath, strlen(realpath));
|
||||
av_md5_sum(md5, path, strlen(path));
|
||||
char *conf = talloc_strdup(tmp, "");
|
||||
for (int i = 0; i < 16; i++)
|
||||
conf = talloc_asprintf_append(conf, "%02X", md5[i]);
|
||||
@ -312,6 +308,8 @@ void mp_write_watch_later_conf(struct MPContext *mpctx)
|
||||
goto exit;
|
||||
|
||||
char *path = mp_normalize_path(ctx, cur->filename);
|
||||
if (!path)
|
||||
goto exit;
|
||||
|
||||
struct demuxer *demux = mpctx->demuxer;
|
||||
|
||||
@ -391,26 +389,19 @@ exit:
|
||||
|
||||
void mp_delete_watch_later_conf(struct MPContext *mpctx, const char *file)
|
||||
{
|
||||
if (!file) {
|
||||
struct playlist_entry *cur = mpctx->playing;
|
||||
if (!cur)
|
||||
return;
|
||||
file = cur->filename;
|
||||
if (!file)
|
||||
return;
|
||||
}
|
||||
void *ctx = talloc_new(NULL);
|
||||
char *path = mp_normalize_path(ctx, file ? file : mpctx->filename);
|
||||
if (!path)
|
||||
goto exit;
|
||||
|
||||
char *fname = mp_get_playback_resume_config_filename(mpctx, file);
|
||||
char *fname = mp_get_playback_resume_config_filename(mpctx, path);
|
||||
if (fname) {
|
||||
unlink(fname);
|
||||
talloc_free(fname);
|
||||
}
|
||||
|
||||
if (mp_is_url(bstr0(file)) || mpctx->opts->ignore_path_in_watch_later_config)
|
||||
return;
|
||||
|
||||
void *ctx = talloc_new(NULL);
|
||||
char *path = mp_normalize_path(ctx, file);
|
||||
if (mp_is_url(bstr0(path)) || mpctx->opts->ignore_path_in_watch_later_config)
|
||||
goto exit;
|
||||
|
||||
bstr dir = mp_dirname(path);
|
||||
while (dir.len > 1 && dir.len < strlen(path)) {
|
||||
@ -424,6 +415,7 @@ void mp_delete_watch_later_conf(struct MPContext *mpctx, const char *file)
|
||||
dir = mp_dirname(path);
|
||||
}
|
||||
|
||||
exit:
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
|
34
test/paths.c
34
test/paths.c
@ -26,12 +26,28 @@ static void test_abs(char *file, int line, bool abs, char *a)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_normalize(char *file, int line, char *expected, char *path)
|
||||
{
|
||||
void *ctx = talloc_new(NULL);
|
||||
char *normalized = mp_normalize_path(ctx, path);
|
||||
if (strcmp(normalized, expected)) {
|
||||
printf("%s:%d: mp_normalize_path('%s') => %s, expected %s\n",
|
||||
file, line, path, normalized, expected);
|
||||
fflush(stdout);
|
||||
abort();
|
||||
}
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
#define TEST_JOIN(a, b, c) \
|
||||
test_join(__FILE__, __LINE__, a, b, c);
|
||||
|
||||
#define TEST_ABS(abs, a) \
|
||||
test_abs(__FILE__, __LINE__, abs, a)
|
||||
|
||||
#define TEST_NORMALIZE(expected, path) \
|
||||
test_normalize(__FILE__, __LINE__, expected, path)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
TEST_ABS(true, "/ab");
|
||||
@ -63,5 +79,23 @@ int main(void)
|
||||
TEST_JOIN("c:a", "b", "c:a/b");
|
||||
TEST_JOIN("c:", "b", "c:b");
|
||||
#endif
|
||||
|
||||
TEST_NORMALIZE("https://foo", "https://foo");
|
||||
TEST_NORMALIZE("/foo", "/foo");
|
||||
|
||||
void *ctx = talloc_new(NULL);
|
||||
bstr dst = bstr0(mp_getcwd(ctx));
|
||||
bstr_xappend(ctx, &dst, bstr0("/foo"));
|
||||
TEST_NORMALIZE(dst.start, "foo");
|
||||
talloc_free(ctx);
|
||||
|
||||
#if (!HAVE_DOS_PATHS)
|
||||
TEST_NORMALIZE("/foo/bar", "/foo//bar");
|
||||
TEST_NORMALIZE("/foo/bar", "/foo///bar");
|
||||
TEST_NORMALIZE("/foo/bar", "/foo/bar/");
|
||||
TEST_NORMALIZE("/foo/bar", "/foo/./bar");
|
||||
TEST_NORMALIZE("/usr", "/usr/bin/..");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user