1
0
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:
Guido Cella 2024-05-05 18:11:00 +02:00 committed by Kacper Michajłow
parent 8a61929eb8
commit 1d640c9887
3 changed files with 104 additions and 27 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
}