diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index a3539c156e..b4927470fa 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -40,6 +40,8 @@ Interface changes - remove `--icc-contrast` and introduce `--icc-force-contrast`. The latter defaults to the equivalent of the old `--icc-contrast=inf`, and can instead be used to specifically set the contrast to any value. + - add a `--watch-later-options` option to allow configuring which + options quit-watch-later saves --- mpv 0.33.0 --- - add `--d3d11-exclusive-fs` flag to enable D3D11 exclusive fullscreen mode when the player enters fullscreen. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index c1b0ba03af..0745eba0e9 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -851,6 +851,28 @@ Program Behavior - ``--reset-on-next-file=all`` Try to reset all settings that were changed during playback. +``--watch-later-options=option1,option2,...`` + The options that are saved in "watch later" files if they have been changed + since when mpv started. These values will be restored the next time the + files are played. The playback position is always saved as ``start``, so + adding ``start`` to this list has no effect. + + When removing options, existing watch later data won't be modified and will + still be applied fully, but new watch later data won't contain these + options. + + This is a string list option. See `List Options`_ for details. + + .. admonition:: Examples + + - ``--watch-later-options-remove=fullscreen`` + Resuming a file won't restore the fullscreen state. + - ``--watch-later-options-remove=volume,mute`` + Resuming a file won't restore the volume or mute state. + - ``--watch-later-options=`` + Resuming a file won't restore any option except the starting + position. + ``--write-filename-in-watch-later-config`` Prepend the watch later config files with the name of the file they refer to. This is simply written as comment on the top of the file. diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c index a3356c4111..4a8c583f91 100644 --- a/options/m_config_frontend.c +++ b/options/m_config_frontend.c @@ -244,6 +244,28 @@ void m_config_restore_backups(struct m_config *config) restore_backups(&config->backup_opts, config); } +bool m_config_watch_later_backup_opt_changed(struct m_config *config, + char *opt_name) +{ + struct m_config_option *co = m_config_get_co(config, bstr0(opt_name)); + if (!co) { + // --watch-later-options= makes the first list item an empty string. + if (strcmp(opt_name, "") != 0) + MP_ERR(config, "Option %s not found.\n", opt_name); + return false; + } + + for (struct m_opt_backup *bc = config->watch_later_backup_opts; bc; + bc = bc->next) { + if (strcmp(bc->co->name, co->name) == 0) { + struct m_config_option *bc_co = (struct m_config_option *)bc->backup; + return !m_option_equal(co->opt, co->data, bc_co); + } + } + + return false; +} + void m_config_backup_opt(struct m_config *config, const char *opt) { struct m_config_option *co = m_config_get_co(config, bstr0(opt)); @@ -260,6 +282,12 @@ void m_config_backup_all_opts(struct m_config *config) ensure_backup(&config->backup_opts, BACKUP_LOCAL, &config->opts[n]); } +void m_config_backup_watch_later_opts(struct m_config *config) +{ + for (int n = 0; n < config->num_opts; n++) + ensure_backup(&config->watch_later_backup_opts, BACKUP_LOCAL, + &config->opts[n]); +} struct m_config_option *m_config_get_co_raw(const struct m_config *config, struct bstr name) @@ -509,6 +537,13 @@ static void config_destroy(void *p) config->option_change_callback = NULL; m_config_restore_backups(config); + struct m_opt_backup **list = &config->watch_later_backup_opts; + while (*list) { + struct m_opt_backup *bc = *list; + *list = bc->next; + talloc_free(bc); + } + talloc_free(config->cache); talloc_free(config->shadow); } diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h index ee6b9aec46..2812033b75 100644 --- a/options/m_config_frontend.h +++ b/options/m_config_frontend.h @@ -75,6 +75,7 @@ typedef struct m_config { int profile_backup_flags; struct m_opt_backup *backup_opts; + struct m_opt_backup *watch_later_backup_opts; bool use_profiles; bool is_toplevel; @@ -134,10 +135,18 @@ void m_config_backup_opt(struct m_config *config, const char *opt); // Call m_config_backup_opt() on all options. void m_config_backup_all_opts(struct m_config *config); +// Backup options on startup so that quit-watch-later can compare the current +// values to their backups, and save them only if they have been changed. +void m_config_backup_watch_later_opts(struct m_config *config); + // Restore all options backed up with m_config_backup_opt(), and delete the // backups afterwards. void m_config_restore_backups(struct m_config *config); +// Whether opt_name is different from its initial value. +bool m_config_watch_later_backup_opt_changed(struct m_config *config, + char *opt_name); + enum { M_SETOPT_PRE_PARSE_ONLY = 1, // Silently ignore non-M_OPT_PRE_PARSE opt. M_SETOPT_CHECK_ONLY = 2, // Don't set, just check name/value diff --git a/options/m_option.c b/options/m_option.c index 4c199967b3..9b946680b7 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -3668,7 +3668,7 @@ static bool obj_settings_list_equal(const m_option_t *opt, void *pa, void *pb) struct m_obj_settings *b = VAL(pb); if (a == b || !a || !b) - return a == b; + return a == b || (!a && !b[0].name) || (!b && !a[0].name); for (int n = 0; a[n].name || b[n].name; n++) { if (!a[n].name || !b[n].name) diff --git a/options/options.c b/options/options.c index cf0eebf527..4ea23cc702 100644 --- a/options/options.c +++ b/options/options.c @@ -695,6 +695,7 @@ static const m_option_t mp_opts[] = { OPT_FLAG(ignore_path_in_watch_later_config)}, {"watch-later-directory", OPT_STRING(watch_later_directory), .flags = M_OPT_FILE}, + {"watch-later-options", OPT_STRINGLIST(watch_later_options)}, {"ordered-chapters", OPT_FLAG(ordered_chapters)}, {"ordered-chapters-files", OPT_STRING(ordered_chapters_files), @@ -1043,6 +1044,44 @@ static const struct MPOpts mp_default_opts = { }, .cuda_device = -1, + + .watch_later_options = (char **)(const char*[]){ + "osd-level", + "speed", + "edition", + "pause", + "volume", + "mute", + "audio-delay", + "fullscreen", + "ontop", + "border", + "gamma", + "brightness", + "contrast", + "saturation", + "hue", + "deinterlace", + "vf", + "af", + "panscan", + "aid", + "vid", + "sid", + "sub-delay", + "sub-speed", + "sub-pos", + "sub-visibility", + "sub-scale", + "sub-use-margins", + "sub-ass-force-margins", + "sub-ass-vsfilter-aspect-compat", + "sub-ass-override", + "ab-loop-a", + "ab-loop-b", + "video-aspect-override", + NULL + }, }; const struct m_sub_options mp_opt_root = { diff --git a/options/options.h b/options/options.h index f0de6781ee..41aa88abb9 100644 --- a/options/options.h +++ b/options/options.h @@ -252,6 +252,7 @@ typedef struct MPOpts { int write_filename_in_watch_later_config; int ignore_path_in_watch_later_config; char *watch_later_directory; + char **watch_later_options; int pause; int keep_open; int keep_open_pause; diff --git a/player/configfiles.c b/player/configfiles.c index 83aed38d27..65dd9df425 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -37,6 +37,7 @@ #include "misc/ctype.h" #include "options/path.h" #include "options/m_config.h" +#include "options/m_config_frontend.h" #include "options/parse_configfile.h" #include "common/playlist.h" #include "options/options.h" @@ -237,63 +238,6 @@ exit: return res; } -static const char *const backup_properties[] = { - "osd-level", - //"loop", - "speed", - "options/edition", - "pause", - "volume", - "mute", - "audio-delay", - //"balance", - "fullscreen", - "ontop", - "border", - "gamma", - "brightness", - "contrast", - "saturation", - "hue", - "options/deinterlace", - "vf", - "af", - "panscan", - "options/aid", - "options/vid", - "options/sid", - "sub-delay", - "sub-speed", - "sub-pos", - "sub-visibility", - "sub-scale", - "sub-use-margins", - "sub-ass-force-margins", - "sub-ass-vsfilter-aspect-compat", - "sub-ass-override", - "ab-loop-a", - "ab-loop-b", - "options/video-aspect-override", - 0 -}; - -// Used to retrieve default settings, which should not be stored in the -// resume config. Uses backup_properties[] meaning/order of values. -// This explicitly includes values set by config files and command line. -void mp_get_resume_defaults(struct MPContext *mpctx) -{ - char **list = - talloc_zero_array(mpctx, char*, MP_ARRAY_SIZE(backup_properties)); - for (int i = 0; backup_properties[i]; i++) { - const char *pname = backup_properties[i]; - char *val = NULL; - int r = mp_property_do(pname, M_PROPERTY_GET_STRING, &val, mpctx); - if (r == M_PROPERTY_OK) - list[i] = talloc_steal(list, val); - } - mpctx->resume_defaults = list; -} - // Should follow what parser-cfg.c does/needs static bool needs_config_quoting(const char *s) { @@ -368,25 +312,21 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) } else { fprintf(file, "start=%f\n", pos); } - for (int i = 0; backup_properties[i]; i++) { - const char *pname = backup_properties[i]; - char *val = NULL; - int r = mp_property_do(pname, M_PROPERTY_GET_STRING, &val, mpctx); - if (r == M_PROPERTY_OK) { - if (strncmp(pname, "options/", 8) == 0) - pname += 8; - // Only store it if it's different from the initial value. - char *prev = mpctx->resume_defaults[i]; - if (!prev || strcmp(prev, val) != 0) { - if (needs_config_quoting(val)) { - // e.g. '%6%STRING' - fprintf(file, "%s=%%%d%%%s\n", pname, (int)strlen(val), val); - } else { - fprintf(file, "%s=%s\n", pname, val); - } + char **watch_later_options = mpctx->opts->watch_later_options; + for (int i = 0; watch_later_options && watch_later_options[i]; i++) { + char *pname = watch_later_options[i]; + // Only store it if it's different from the initial value. + if (m_config_watch_later_backup_opt_changed(mpctx->mconfig, pname)) { + char *val = NULL; + mp_property_do(pname, M_PROPERTY_GET_STRING, &val, mpctx); + if (needs_config_quoting(val)) { + // e.g. '%6%STRING' + fprintf(file, "%s=%%%d%%%s\n", pname, (int)strlen(val), val); + } else { + fprintf(file, "%s=%s\n", pname, val); } + talloc_free(val); } - talloc_free(val); } fclose(file); diff --git a/player/core.h b/player/core.h index fcb513bed1..1d5b395b07 100644 --- a/player/core.h +++ b/player/core.h @@ -295,7 +295,6 @@ typedef struct MPContext { // Return code to use with PT_QUIT int quit_custom_rc; bool has_quit_custom_rc; - char **resume_defaults; // Global file statistics int files_played; // played without issues (even if stopped by user) @@ -511,7 +510,6 @@ void audio_start_ao(struct MPContext *mpctx); // configfiles.c void mp_parse_cfgfiles(struct MPContext *mpctx); void mp_load_auto_profiles(struct MPContext *mpctx); -void mp_get_resume_defaults(struct MPContext *mpctx); void mp_load_playback_resume(struct MPContext *mpctx, const char *file); void mp_write_watch_later_conf(struct MPContext *mpctx); void mp_delete_watch_later_conf(struct MPContext *mpctx, const char *file); diff --git a/player/main.c b/player/main.c index 58be00b6d8..e039f61975 100644 --- a/player/main.c +++ b/player/main.c @@ -353,7 +353,10 @@ int mp_initialize(struct MPContext *mpctx, char **options) m_config_set_profile(mpctx->mconfig, "pseudo-gui", 0); } - mp_get_resume_defaults(mpctx); + // Backup the default settings, which should not be stored in the resume + // config files. This explicitly includes values set by config files and + // the command line. + m_config_backup_watch_later_opts(mpctx->mconfig); mp_input_load_config(mpctx->input);