diff options
author | Chris Down <chris@chrisdown.name> | 2019-11-09 18:24:16 +0000 |
---|---|---|
committer | wm4 <1387750+wm4@users.noreply.github.com> | 2019-11-20 15:11:33 +0100 |
commit | e143966a76a259e4e83fce1b816c8adf86898ab0 (patch) | |
tree | d8261a5c7c0c5be7f91d7be9bd3a3d962dfc3ac4 | |
parent | 1649ba15ab60a99db4ee6bd914d614848d8ed044 (diff) | |
download | mpv-e143966a76a259e4e83fce1b816c8adf86898ab0.tar.bz2 mpv-e143966a76a259e4e83fce1b816c8adf86898ab0.tar.xz |
player: Optionally validate st_mtime when restoring playback state
I often watch sporting events. On many occasions I get files with the
same filename for each session. For example, for F1 I might have the
following directory structure:
F1/
FP1.mkv
FP2.mkv
FP3.mkv
Qualification.mkv
Race.mkv
Since usually one simply watches one race after the other, I usually
just rsync the new event's files over the old ones, so, for example,
Race.mkv will be replaced from the file for the last event with the file
from the new event.
One problem with this is that I like to use --resume-playback for other
kinds of media, so I have it on by default. That works great for, say, a
movie, but doesn't work so well with this scheme, because you can
trivially forget to pass --no-resume-playback on the command line and
end up 2 hours in, watching spoilers as the race results scroll down the
screen :-)
This patch adds a new option, --resume-playback-check-mtime, which
validates that the file's mtime hasn't changed since the watch_later
configuration was saved. It does this by setting the watch_later
configuration to have the same mtime as the file after it is saved.
Switching back and forth between checking mtime and not checking mtime
works fine, as we only choose whether to compare based on it, but we
update the watch_later configuration mtime regardless of its value.
-rw-r--r-- | DOCS/interface-changes.rst | 2 | ||||
-rw-r--r-- | DOCS/man/options.rst | 7 | ||||
-rw-r--r-- | options/options.c | 1 | ||||
-rw-r--r-- | options/options.h | 1 | ||||
-rw-r--r-- | osdep/io.h | 3 | ||||
-rw-r--r-- | player/configfiles.c | 44 |
6 files changed, 58 insertions, 0 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 26337e9713..3a399fb265 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -25,6 +25,8 @@ Interface changes :: --- mpv 0.31.0 --- + - add `--resume-playback-check-mtime` to check consistent mtime when + restoring playback state. - add `--d3d11-output-csp` to enable explicit selection of a D3D11 swap chain color space. - the --sws- options and similar now affect vo_image and screenshot diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 3c52acec00..b2ba69ff26 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -714,6 +714,13 @@ Program Behavior subdirectory (usually ``~/.config/mpv/watch_later/``). See ``quit-watch-later`` input command. +``--resume-playback-check-mtime`` + Only restore the playback position from the ``watch_later`` configuration + subdirectory (usually ``~/.config/mpv/watch_later/``) if the file's + modification time is the same as at the time of saving. This may prevent + skipping forward in files with the same name which have different content. + (Default: ``no``) + ``--profile=<profile1,profile2,...>`` Use the given profile(s), ``--profile=help`` displays a list of the defined profiles. diff --git a/options/options.c b/options/options.c index 480186a908..1f0c9b1ef3 100644 --- a/options/options.c +++ b/options/options.c @@ -631,6 +631,7 @@ const m_option_t mp_opts[] = { OPT_ALIAS("loop", "loop-file"), OPT_FLAG("resume-playback", position_resume, 0), + OPT_FLAG("resume-playback-check-mtime", position_check_mtime, 0), OPT_FLAG("save-position-on-quit", position_save_on_quit, 0), OPT_FLAG("write-filename-in-watch-later-config", write_filename_in_watch_later_config, 0), OPT_FLAG("ignore-path-in-watch-later-config", ignore_path_in_watch_later_config, 0), diff --git a/options/options.h b/options/options.h index 2f7e368446..126e4cb59a 100644 --- a/options/options.h +++ b/options/options.h @@ -232,6 +232,7 @@ typedef struct MPOpts { double ab_loop[2]; double step_sec; int position_resume; + int position_check_mtime; int position_save_on_quit; int write_filename_in_watch_later_config; int ignore_path_in_watch_later_config; diff --git a/osdep/io.h b/osdep/io.h index 8699fb3e4a..12907e5cc9 100644 --- a/osdep/io.h +++ b/osdep/io.h @@ -172,6 +172,9 @@ void mp_globfree(mp_glob_t *pglob); #undef fstat #define fstat(...) mp_fstat(__VA_ARGS__) +#define utime(...) _utime(__VA_ARGS__) +#define utimbuf _utimbuf + void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length); int msync(void *addr, size_t length, int flags); diff --git a/player/configfiles.c b/player/configfiles.c index 668b34c542..d9a1e7d9f1 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -15,12 +15,14 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> #include <stddef.h> #include <stdbool.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> +#include <utime.h> #include <libavutil/md5.h> @@ -155,6 +157,32 @@ void mp_load_auto_profiles(struct MPContext *mpctx) #define MP_WATCH_LATER_CONF "watch_later" +static bool check_mtime(const char *f1, const char *f2) +{ + struct stat st1, st2; + if (stat(f1, &st1) != 0 || stat(f2, &st2) != 0) + return false; + return st1.st_mtime == st2.st_mtime; +} + +static bool copy_mtime(const char *f1, const char *f2) +{ + struct stat st1, st2; + + if (stat(f1, &st1) != 0 || stat(f2, &st2) != 0) + return false; + + struct utimbuf ut = { + .actime = st2.st_atime, // we want to pass this through intact + .modtime = st1.st_mtime, + }; + + if (!utime(f2, &ut)) + return false; + + return true; +} + static char *mp_get_playback_resume_config_filename(struct MPContext *mpctx, const char *fname) { @@ -290,6 +318,10 @@ static void write_redirect(struct MPContext *mpctx, char *path) write_filename(mpctx, file, path); fclose(file); } + + if (mpctx->opts->position_check_mtime && !copy_mtime(path, conffile)) + MP_WARN(mpctx, "Can't copy mtime from %s to %s\n", path, conffile); + talloc_free(conffile); } } @@ -346,6 +378,13 @@ void mp_write_watch_later_conf(struct MPContext *mpctx) } fclose(file); + if (mpctx->opts->position_check_mtime && + !copy_mtime(cur->filename, conffile)) + { + MP_WARN(mpctx, "Can't copy mtime from %s to %s\n", cur->filename, + conffile); + } + // This allows us to recursively resume directories etc., whose entries are // expanded the first time it's "played". For example, if "/a/b/c.mkv" is // the current entry, then we want to resume this file if the user does @@ -387,6 +426,11 @@ void mp_load_playback_resume(struct MPContext *mpctx, const char *file) return; char *fname = mp_get_playback_resume_config_filename(mpctx, file); if (fname && mp_path_exists(fname)) { + if (mpctx->opts->position_check_mtime && !check_mtime(file, fname)) { + talloc_free(fname); + return; + } + // Never apply the saved start position to following files m_config_backup_opt(mpctx->mconfig, "start"); MP_INFO(mpctx, "Resuming playback. This behavior can " |