From 7c4c9bc86f55f4d1224814fbeafdee8f1c3c3108 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Tue, 2 May 2023 19:29:27 -0500 Subject: [PATCH] player: use XDG_STATE_HOME for watch_later A pain point for some users is the fact that watch_later is stored in the ~/.config directory when it's really not configuration data. Roughly 2 years ago, XDG_STATE_DIR was added to the XDG Base Directory Specification[0] and its description, user-specific state data, actually perfectly matches what watch_later data is for. Let's go ahead and use this directory as the default for watch_later. This change only affects non-darwin unix-like systems (i.e. Linux, BSDs, etc.). The directory doesn't move for anyone else. Internally, quite a few things change with regards to the path selection. If the platform in question does not have a statedir concept, then the path selection will simply return "home" instead (old behavior). Fixes #9147. [0]: https://gitlab.freedesktop.org/xdg/xdg-specs/-/commit/4f2884e16db35f2962d9b64312917c81be5cb54b --- DOCS/interface-changes.rst | 3 +++ DOCS/man/mpv.rst | 4 +++- DOCS/man/options.rst | 5 +++-- common/global.h | 1 + options/path.c | 42 +++++++++++++++++++++++++------------- osdep/path-unix.c | 19 +++++++++++++---- osdep/path.h | 6 ++++++ player/configfiles.c | 32 ++++++++++++++--------------- player/core.h | 2 -- 9 files changed, 75 insertions(+), 39 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index e44697dbad..028759f261 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -61,6 +61,9 @@ Interface changes `--gamma` to float. - add `platform` property - add `--auto-window-resize` + - `--save-position-on-quit` and its associated commands now store state files in + the XDG_STATE_HOME directory by default. This only has an effect on linux/bsd + systems. --- mpv 0.35.0 --- - add the `--vo=gpu-next` video output driver, as well as the options `--allow-delayed-peak-detect`, `--builtin-scalers`, diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index c1314ef2c2..63042e2925 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -461,6 +461,8 @@ Name Meaning ``~~desktop/`` the path to the desktop (win32, macOS) ``~~exe_dir/`` win32 only: the path to the directory containing the exe (for config file purposes; ``$MPV_HOME`` overrides it) +``~~state/`` the path to application state data (``~/.local/state/mpv/``) + On some platforms, this will be the same as ``~~home/``. ``~~old_home/`` do not use ================ =============================================================== @@ -1584,7 +1586,7 @@ For Windows-specifics, see `FILES ON WINDOWS`_ section. See `Script location`_ for details. -``~/.config/mpv/watch_later/`` +``~/.local/state/mpv/watch_later/`` Contains temporary config files needed for resuming playback of files with the watch later feature. See for example the ``Q`` key binding, or the ``quit-watch-later`` input command. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index bf00454bd2..96b969ba11 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1015,8 +1015,9 @@ Watch Later ``--watch-later-directory=`` The directory in which to store the "watch later" temporary files. - The default is a subdirectory named "watch_later" underneath the - config directory (usually ``~/.config/mpv/``). + If this option is unset, the files will be stored in a subdirectory + named "watch_later" underneath the local state directory + (usually ``~/.local/state/mpv/``). ``--no-resume-playback`` Do not restore playback position from the ``watch_later`` configuration diff --git a/common/global.h b/common/global.h index f95cf28a4d..a7e4c4cee8 100644 --- a/common/global.h +++ b/common/global.h @@ -10,6 +10,7 @@ struct mpv_global { struct mp_client_api *client_api; char *configdir; struct stats_base *stats; + bool no_statedir; }; #endif diff --git a/options/path.c b/options/path.c index bd8adf6d81..4ea7269d01 100644 --- a/options/path.c +++ b/options/path.c @@ -65,19 +65,6 @@ static const char *const config_dirs[] = { "global", }; -void mp_init_paths(struct mpv_global *global, struct MPOpts *opts) -{ - TA_FREEP(&global->configdir); - - const char *force_configdir = getenv("MPV_HOME"); - if (opts->force_configdir && opts->force_configdir[0]) - force_configdir = opts->force_configdir; - if (!opts->load_config) - force_configdir = ""; - - global->configdir = talloc_strdup(global, force_configdir); -} - // Return a platform specific path using a path type as defined in osdep/path.h. // Keep in mind that the only way to free the return value is freeing talloc_ctx // (or its children), as this function can return a statically allocated string. @@ -87,13 +74,19 @@ static const char *mp_get_platform_path(void *talloc_ctx, { assert(talloc_ctx); - if (global->configdir) { + bool config_dir = strcmp(type, "state") != 0; + if (global->configdir && config_dir) { for (int n = 0; n < MP_ARRAY_SIZE(config_dirs); n++) { if (strcmp(config_dirs[n], type) == 0) return (n == 0 && global->configdir[0]) ? global->configdir : NULL; } } + // Return the native config path if the platform doesn't support the + // type we are trying to fetch. + if (strcmp(type, "state") == 0 && global->no_statedir) + type = "home"; + for (int n = 0; n < MP_ARRAY_SIZE(path_resolvers); n++) { const char *path = path_resolvers[n](talloc_ctx, type); if (path && path[0]) @@ -102,6 +95,27 @@ static const char *mp_get_platform_path(void *talloc_ctx, return NULL; } +void mp_init_paths(struct mpv_global *global, struct MPOpts *opts) +{ + TA_FREEP(&global->configdir); + + // Check if the platform has unique directories that differ from + // the standard config directory. + void *tmp = talloc_new(NULL); + const char *state = mp_get_platform_path(tmp, global, "state"); + if (!state) + global->no_statedir = true; + talloc_free(tmp); + + const char *force_configdir = getenv("MPV_HOME"); + if (opts->force_configdir && opts->force_configdir[0]) + force_configdir = opts->force_configdir; + if (!opts->load_config) + force_configdir = ""; + + global->configdir = talloc_strdup(global, force_configdir); +} + char *mp_find_user_file(void *talloc_ctx, struct mpv_global *global, const char *type, const char *filename) { diff --git a/osdep/path-unix.c b/osdep/path-unix.c index d9a49ab06d..34187b430e 100644 --- a/osdep/path-unix.c +++ b/osdep/path-unix.c @@ -27,14 +27,16 @@ static pthread_once_t path_init_once = PTHREAD_ONCE_INIT; static char mpv_home[512]; static char old_home[512]; +static char mpv_state[512]; static void path_init(void) { char *home = getenv("HOME"); - char *xdg_dir = getenv("XDG_CONFIG_HOME"); + char *xdg_config = getenv("XDG_CONFIG_HOME"); + char *xdg_state = getenv("XDG_STATE_HOME"); - if (xdg_dir && xdg_dir[0]) { - snprintf(mpv_home, sizeof(mpv_home), "%s/mpv", xdg_dir); + if (xdg_config && xdg_config[0]) { + snprintf(mpv_home, sizeof(mpv_home), "%s/mpv", xdg_config); } else if (home && home[0]) { snprintf(mpv_home, sizeof(mpv_home), "%s/.config/mpv", home); } @@ -43,10 +45,17 @@ static void path_init(void) if (home && home[0]) snprintf(old_home, sizeof(old_home), "%s/.mpv", home); + if (xdg_state && xdg_state[0]) { + snprintf(mpv_state, sizeof(mpv_state), "%s/mpv", xdg_state); + } else if (home && home[0]) { + snprintf(mpv_state, sizeof(mpv_state), "%s/.local/state/mpv", home); + } + // If the old ~/.mpv exists, and the XDG config dir doesn't, use the old - // config dir only. + // config dir only. Also do not use any other XDG directories. if (mp_path_exists(old_home) && !mp_path_exists(mpv_home)) { snprintf(mpv_home, sizeof(mpv_home), "%s", old_home); + snprintf(mpv_state, sizeof(mpv_state), "%s", old_home); old_home[0] = '\0'; } } @@ -58,6 +67,8 @@ const char *mp_get_platform_path_unix(void *talloc_ctx, const char *type) return mpv_home; if (strcmp(type, "old_home") == 0) return old_home; + if (strcmp(type, "state") == 0) + return mpv_state; if (strcmp(type, "global") == 0) return MPV_CONFDIR; if (strcmp(type, "desktop") == 0) diff --git a/osdep/path.h b/osdep/path.h index 43b9d63bbe..d678b12072 100644 --- a/osdep/path.h +++ b/osdep/path.h @@ -11,6 +11,12 @@ // "global" the least priority, global config file location // "desktop" path to desktop contents // +// These additional types are also defined. However, they are not necessarily +// implemented on every platform. Unlike some other type values that are +// platform specific (like "osxbundle"), the value of "home" is returned +// instead if these types are not explicitly defined. +// "state" the native mpv-specific user state dir +// // It is allowed to return a static string, so the caller must set talloc_ctx // to something other than NULL to avoid memory leaks. typedef const char *(*mp_get_platform_path_cb)(void *talloc_ctx, const char *type); diff --git a/player/configfiles.c b/player/configfiles.c index 9de7e36ec7..93079f85a9 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -192,6 +192,17 @@ static bool copy_mtime(const char *f1, const char *f2) return true; } +static char *mp_get_playback_resume_dir(struct MPContext *mpctx) +{ + char *wl_dir = mpctx->opts->watch_later_directory; + if (wl_dir && wl_dir[0]) { + wl_dir = mp_get_user_path(mpctx, mpctx->global, wl_dir); + } else { + wl_dir = mp_find_user_file(mpctx, mpctx->global, "state", MP_WATCH_LATER_CONF); + } + return wl_dir; +} + static char *mp_get_playback_resume_config_filename(struct MPContext *mpctx, const char *fname) { @@ -216,21 +227,9 @@ static char *mp_get_playback_resume_config_filename(struct MPContext *mpctx, for (int i = 0; i < 16; i++) conf = talloc_asprintf_append(conf, "%02X", md5[i]); - if (!mpctx->cached_watch_later_configdir) { - char *wl_dir = mpctx->opts->watch_later_directory; - if (wl_dir && wl_dir[0]) { - mpctx->cached_watch_later_configdir = - mp_get_user_path(mpctx, mpctx->global, wl_dir); - } - } - - if (!mpctx->cached_watch_later_configdir) { - mpctx->cached_watch_later_configdir = - mp_find_user_file(mpctx, mpctx->global, "home", MP_WATCH_LATER_CONF); - } - - if (mpctx->cached_watch_later_configdir) - res = mp_path_join(NULL, mpctx->cached_watch_later_configdir, conf); + char *wl_dir = mp_get_playback_resume_dir(mpctx); + if (wl_dir && wl_dir[0]) + res = mp_path_join(NULL, wl_dir, conf); exit: talloc_free(tmp); @@ -292,7 +291,8 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) if (!conffile) goto exit; - mp_mk_user_dir(mpctx->global, "home", mpctx->cached_watch_later_configdir); + char *wl_dir = mp_get_playback_resume_dir(mpctx); + mp_mk_user_dir(mpctx->global, "state", wl_dir); MP_INFO(mpctx, "Saving state.\n"); diff --git a/player/core.h b/player/core.h index dc37b7c399..1427f340c7 100644 --- a/player/core.h +++ b/player/core.h @@ -424,8 +424,6 @@ typedef struct MPContext { struct mp_recorder *recorder; - char *cached_watch_later_configdir; - struct screenshot_ctx *screenshot_ctx; struct command_ctx *command_ctx; struct encode_lavc_context *encode_lavc_ctx;