From a9b847ab11ab8d27e5894668be7eb09e5ddd6160 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 7 Jan 2025 21:58:50 +0100 Subject: [PATCH] select.lua: select from the watch history with g-h Implement selection of the entries in the watch history. --osd-playlist-entry determines whether titles and/or filenames are shown. But unlike in show-text ${playlist} and select-playlist, "file" and "both" print full paths because history is much more likely to have files from completely different directories, so showing the directory conveys where files are located. This is particularly helpful for filenames like 1.jpg. The last entry in the selector deletes the history file, as requested by Samillion. --- DOCS/man/mpv.rst | 3 ++ DOCS/man/options.rst | 8 +++- etc/input.conf | 1 + player/lua/select.lua | 100 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 7c67cf0d96d18..ecb54f42abec9 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -328,6 +328,9 @@ g-l g-d Select an audio device. +g-h + Select a file from the watch history. Requires ``--save-watch-history``. + g-w Select a file from watch later config files (see `RESUMING PLAYBACK`_) to resume playing. Requires ``--write-filename-in-watch-later-config``. This diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index ece0e1621641b..265b12a66fbac 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1152,7 +1152,8 @@ Watch History ------------- ``--save-watch-history`` - Whether to save which files are played. + Whether to save which files are played. These can be then selected with the + default ``g-h`` key binding. .. warning:: @@ -1163,6 +1164,11 @@ Watch History The path in which to store the watch history. Default: ``~~state/watch_history.jsonl`` (see `PATHS`_). + This file contains one JSON array per line. The first field is the UNIX + timestamp when the file was opened, the second field is its normalized path, + and the third file is its title, or missing if no title was present. Any new + fields will be appended after the last one. + Video ----- diff --git a/etc/input.conf b/etc/input.conf index 2faa88c233b28..adbb824a0d838 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -187,6 +187,7 @@ #g-e script-binding select/select-edition #g-l script-binding select/select-subtitle-line #g-d script-binding select/select-audio-device +#g-h script-binding select/select-watch-history #g-w script-binding select/select-watch-later #g-b script-binding select/select-binding #g-r script-binding select/show-properties diff --git a/player/lua/select.lua b/player/lua/select.lua index 7f20602aff098..3f29bfdee9491 100644 --- a/player/lua/select.lua +++ b/player/lua/select.lua @@ -353,6 +353,106 @@ mp.add_key_binding(nil, "select-audio-device", function () }) end) +local function get_history_entry(line, seen, error_message) + local entry = utils.parse_json(line) + + if not entry then + mp.msg.warn(error_message) + return + end + + local time, path, title = unpack(entry) + + if not path then + mp.msg.warn(error_message) + return + end + + if seen[path] then + return + end + + seen[path] = true + + local status, date = pcall(os.date, "(%Y-%m-%d %H:%M) ", time) + + if not status then + mp.msg.warn(error_message) + return + end + + return { + date = date, + path = path, + title = title, + } +end + + +local function format_history_entry(entry, osd_playlist_entry) + if entry.title and osd_playlist_entry == "title" then + return entry.title + end + + if entry.title and osd_playlist_entry == "both" then + return entry.title .. " (" .. entry.path .. ")" + end + + return entry.path +end + +mp.add_key_binding(nil, "select-watch-history", function () + local history_file_path = mp.command_native({"expand-path", + mp.get_property("watch-history-path")}) + local history_file, error_message = io.open(history_file_path) + if not history_file then + show_warning(mp.get_property_native("save-watch-history") + and error_message + or "Enable --save-watch-history") + return + end + + local lines = {} + for line in history_file:lines() do + table.insert(lines, line) + end + history_file:close() + + local entries = {} + local seen = {} + local items = {} + local osd_playlist_entry = mp.get_property("osd-playlist-entry") + + for i = #lines, 1, -1 do + error_message = history_file_path .. ": Parse error at line " .. i + local entry = get_history_entry(lines[i], seen, error_message) + if entry then + entries[#entries + 1] = entry + items[#items + 1] = entry.date .. format_history_entry(entry, osd_playlist_entry) + end + end + + items[#items+1] = "Clear history" + + input.select({ + prompt = "Select a file:", + items = items, + submit = function (i) + if entries[i] then + mp.commandv("loadfile", entries[i].path) + return + end + + error_message = select(2, os.remove(history_file_path)) + if error_message then + show_error(error_message) + else + mp.osd_message("History cleared.") + end + end, + }) +end) + mp.add_key_binding(nil, "select-watch-later", function () local watch_later_dir = mp.get_property("current-watch-later-dir")