options: add watch-later-options

This allows configuring which options are saved by quit-watch-later.

Fixes #4126, #4641 and #5567.

Toggling a video or audio filter twice would treat the option as changed
because the backup value is NULL, and the current value of vf/af is a
list with one empty item, so obj_settings_list_equal had to be changed.
This commit is contained in:
Guido Cella 2021-07-21 11:06:41 +02:00 committed by Dudemanguy
parent ccb87ad637
commit 1d1d1fbff9
10 changed files with 127 additions and 78 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = {

View File

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

View File

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

View File

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

View File

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