From 62964016e4601234cb16b8856edcb96f6ec26d89 Mon Sep 17 00:00:00 2001 From: ksyasuda Date: Wed, 4 Sep 2024 11:44:02 -0700 Subject: [PATCH 1/9] Add history db - Sends video data to backend server on configured port and inserts into a mysql database --- mpv-youtube-queue.conf | 2 ++ mpv-youtube-queue.lua | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mpv-youtube-queue.conf b/mpv-youtube-queue.conf index 18fb9b4..d7e56cb 100644 --- a/mpv-youtube-queue.conf +++ b/mpv-youtube-queue.conf @@ -26,3 +26,5 @@ menu_timeout=5 show_errors=yes ytdlp_file_format=mp4 ytdlp_output_template=%(uploader)s/%(title)s.%(ext)s +backend_host=http://localhost +backend_port=42069 diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index c2ea9cf..421baad 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -58,7 +58,9 @@ local options = { menu_timeout = 5, show_errors = true, ytdlp_file_format = "mp4", - ytdlp_output_template = "%(uploader)s/%(title)s.%(ext)s" + ytdlp_output_template = "%(uploader)s/%(title)s.%(ext)s", + backend_host = "http://localhost", + backend_port = "42069" } mp.options.read_options(options, "mpv-youtube-queue") @@ -206,6 +208,30 @@ local function _split_command(cmd) return components end +function YouTubeQueue._add_to_history(video) + local url = options.backend_host .. ":" .. options.backend_port .. + "/add_video" + local current_date = os.date("%Y-%m-%d") -- Get the current date in YYYY-MM-DD format + local command = { + "curl", "-X", "POST", url, "-H", "Content-Type: application/json", "-d", + string.format( + '{"video_url": "%s", "video_name": "%s", "channel_url": "%s", "channel_name": "%s", "watch_date": "%s"}', + video.video_url, video.video_name, video.channel_url, + video.channel_name, current_date) + } + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + args = command + }, function(success, result, err) + if not success then + print_osd_message("Failed to send video data to backend: " .. err, + MSG_DURATION, style.error) + end + end) +end + -- }}} -- QUEUE GETTERS AND SETTERS {{{ @@ -486,7 +512,7 @@ function YouTubeQueue.play_video(direction) mp.set_property_number("playlist-pos", index - 1) end YouTubeQueue.print_current_video() - sleep(MSG_DURATION) + YouTubeQueue._add_to_history(current_video) end -- add the video to the queue from the clipboard or call from script-message From e484aa506814c49f97c89f3f2ed915e75c7b5045 Mon Sep 17 00:00:00 2001 From: ksyasuda Date: Wed, 4 Sep 2024 11:47:40 -0700 Subject: [PATCH 2/9] add option to disable history db function --- mpv-youtube-queue.conf | 1 + mpv-youtube-queue.lua | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mpv-youtube-queue.conf b/mpv-youtube-queue.conf index d7e56cb..0d11465 100644 --- a/mpv-youtube-queue.conf +++ b/mpv-youtube-queue.conf @@ -26,5 +26,6 @@ menu_timeout=5 show_errors=yes ytdlp_file_format=mp4 ytdlp_output_template=%(uploader)s/%(title)s.%(ext)s +use_history_db=yes backend_host=http://localhost backend_port=42069 diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index 421baad..e86b207 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -59,6 +59,7 @@ local options = { show_errors = true, ytdlp_file_format = "mp4", ytdlp_output_template = "%(uploader)s/%(title)s.%(ext)s", + use_history_db = true, backend_host = "http://localhost", backend_port = "42069" } @@ -208,7 +209,7 @@ local function _split_command(cmd) return components end -function YouTubeQueue._add_to_history(video) +function YouTubeQueue._add_to_history_db(video) local url = options.backend_host .. ":" .. options.backend_port .. "/add_video" local current_date = os.date("%Y-%m-%d") -- Get the current date in YYYY-MM-DD format @@ -512,7 +513,9 @@ function YouTubeQueue.play_video(direction) mp.set_property_number("playlist-pos", index - 1) end YouTubeQueue.print_current_video() - YouTubeQueue._add_to_history(current_video) + if options.use_history_db then + YouTubeQueue._add_to_history_db(current_video) + end end -- add the video to the queue from the clipboard or call from script-message From ed3d280cdad512859f51bcefa4b23ef79bcc5fc2 Mon Sep 17 00:00:00 2001 From: ksyasuda Date: Thu, 5 Sep 2024 04:12:27 -0700 Subject: [PATCH 3/9] Squash bugs - update strip command to remove newline characters - add history db function call to playback restart listener to catch first video --- mpv-youtube-queue.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index e86b207..c0be5c0 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -114,7 +114,7 @@ local function surround_with_quotes(s) end end -local function remove_quotes(s) return string.gsub(s, "'", "") end +local function strip(s) return string.gsub(s, "['\n\r]", "") end -- run sleep shell command for n seconds local function sleep(n) os.execute("sleep " .. tonumber(n)) end @@ -209,16 +209,15 @@ local function _split_command(cmd) return components end -function YouTubeQueue._add_to_history_db(video) +function YouTubeQueue._add_to_history_db(v) + if not options.use_history_db then return end local url = options.backend_host .. ":" .. options.backend_port .. "/add_video" - local current_date = os.date("%Y-%m-%d") -- Get the current date in YYYY-MM-DD format local command = { "curl", "-X", "POST", url, "-H", "Content-Type: application/json", "-d", string.format( - '{"video_url": "%s", "video_name": "%s", "channel_url": "%s", "channel_name": "%s", "watch_date": "%s"}', - video.video_url, video.video_name, video.channel_url, - video.channel_name, current_date) + '{"video_url": "%s", "video_name": "%s", "channel_url": "%s", "channel_name": "%s"}', + v.video_url, v.video_name, v.channel_url, v.channel_name) } mp.command_native_async({ name = "subprocess", @@ -229,8 +228,10 @@ function YouTubeQueue._add_to_history_db(video) if not success then print_osd_message("Failed to send video data to backend: " .. err, MSG_DURATION, style.error) + return false end end) + return true end -- }}} @@ -513,9 +514,7 @@ function YouTubeQueue.play_video(direction) mp.set_property_number("playlist-pos", index - 1) end YouTubeQueue.print_current_video() - if options.use_history_db then - YouTubeQueue._add_to_history_db(current_video) - end + -- YouTubeQueue._add_to_history_db(current_video) end -- add the video to the queue from the clipboard or call from script-message @@ -538,7 +537,7 @@ function YouTubeQueue.add_to_queue(url, update_internal_playlist) local video, channel_url, channel_name, video_name if not is_file(url) then channel_url, channel_name, video_name = YouTubeQueue.get_video_info(url) - url = remove_quotes(url) + url = strip(url) if (channel_url == nil or channel_name == nil or video_name == nil) or (channel_url == "" or channel_name == "" or video_name == "") then print_osd_message("Error getting video info.", MSG_DURATION, @@ -637,10 +636,13 @@ end -- LISTENERS {{{ -- Function to be called when the end-file event is triggered +-- This function is called when the current file ends or when moving to the +-- next or previous item in the internal playlist local function on_end_file(event) if event.reason == "eof" then -- The file ended normally YouTubeQueue.update_current_index() end + YouTubeQueue._add_to_history_db(current_video) end -- Function to be called when the track-changed event is triggered @@ -654,6 +656,7 @@ local function on_playback_restart() elseif current_video == nil then local url = mp.get_property("path") YouTubeQueue.add_to_queue(url) + YouTubeQueue._add_to_history_db(current_video) end end From 2f7756d1fbab52b574e30b267f650c917563a4fa Mon Sep 17 00:00:00 2001 From: sudacode Date: Thu, 5 Sep 2024 23:11:05 -0700 Subject: [PATCH 4/9] squash more bugs - add debug - fix history db for repeated calls and first play - fix is file - change print current video to use full file path if showing a file - remove unused functions - fix video title when selecting video from list --- mpv-youtube-queue.lua | 46 ++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index c0be5c0..d582e40 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -29,6 +29,7 @@ local marked_index = nil local current_video = nil local destroyer = nil local timeout +local debug = false local options = { add_to_queue = "ctrl+a", @@ -105,20 +106,18 @@ local style = { -- }}} -- HELPERS {{{ + -- surround string with single quotes if it does not already have them local function surround_with_quotes(s) - if string.sub(s, 0, 1) == "'" and string.sub(s, -1) == "'" then - return s + if string.sub(s, 0, 1) == '"' and string.sub(s, -1) == '"' then + return else - return "'" .. s .. "'" + return '"' .. s .. '"' end end local function strip(s) return string.gsub(s, "['\n\r]", "") end --- run sleep shell command for n seconds -local function sleep(n) os.execute("sleep " .. tonumber(n)) end - local function print_osd_message(message, duration, s) if s == style.error and not options.show_errors then return end destroy() @@ -131,8 +130,11 @@ end -- returns true if the provided path exists and is a file local function is_file(filepath) local result = utils.file_info(filepath) - if result == nil then return false end - return result.is_file + if debug and type(result) == "table" then + print("IS_FILE() check: " .. tostring(result.is_file)) + end + if result == nil or type(result) ~= "table" then return false end + return true end -- returns the filename given a path (e.g. /home/user/file.txt -> file.txt) @@ -210,7 +212,6 @@ local function _split_command(cmd) end function YouTubeQueue._add_to_history_db(v) - if not options.use_history_db then return end local url = options.backend_host .. ":" .. options.backend_port .. "/add_video" local command = { @@ -294,8 +295,8 @@ end function YouTubeQueue.print_current_video() destroy() local current = current_video - if current and current.vidro_url and is_file(current.video_url) then - print_osd_message("Playing: " .. current.video_name, 3) + if current and current.vidro_url ~= "" and is_file(current.video_url) then + print_osd_message("Playing: " .. current.video_url, 3) else if current and current.video_url then print_osd_message("Playing: " .. current.video_name .. ' by ' .. @@ -338,14 +339,19 @@ function YouTubeQueue.is_in_queue(url) end -- Function to find the index of the currently playing video -function YouTubeQueue.update_current_index() +function YouTubeQueue.update_current_index(update_history) + if debug then print("Updating current index") end if #video_queue == 0 then return end + if update_history == nil then update_history = false end local current_url = mp.get_property("path") for i, v in ipairs(video_queue) do if v.video_url == current_url then index = i selected_index = index current_video = YouTubeQueue.get_video_at(index) + if update_history then + YouTubeQueue._add_to_history_db(current_video) + end return end end @@ -485,6 +491,7 @@ function YouTubeQueue.play_video_at(idx) end index = idx selected_index = idx + current_video = video_queue[index] mp.set_property_number("playlist-pos", index - 1) -- zero-based index YouTubeQueue.print_current_video() return current_video @@ -514,7 +521,6 @@ function YouTubeQueue.play_video(direction) mp.set_property_number("playlist-pos", index - 1) end YouTubeQueue.print_current_video() - -- YouTubeQueue._add_to_history_db(current_video) end -- add the video to the queue from the clipboard or call from script-message @@ -535,9 +541,9 @@ function YouTubeQueue.add_to_queue(url, update_internal_playlist) end local video, channel_url, channel_name, video_name + url = strip(url) if not is_file(url) then channel_url, channel_name, video_name = YouTubeQueue.get_video_info(url) - url = strip(url) if (channel_url == nil or channel_name == nil or video_name == nil) or (channel_url == "" or channel_name == "" or video_name == "") then print_osd_message("Error getting video info.", MSG_DURATION, @@ -639,20 +645,24 @@ end -- This function is called when the current file ends or when moving to the -- next or previous item in the internal playlist local function on_end_file(event) + if debug then print("End file event triggered: " .. event.reason) end if event.reason == "eof" then -- The file ended normally - YouTubeQueue.update_current_index() + YouTubeQueue.update_current_index(true) end - YouTubeQueue._add_to_history_db(current_video) end -- Function to be called when the track-changed event is triggered -local function on_track_changed() YouTubeQueue.update_current_index() end +local function on_track_changed() + if debug then print("Track changed event triggered.") end + YouTubeQueue.update_current_index() +end -- Function to be called when the playback-restart event is triggered local function on_playback_restart() + if debug then print("Playback restart event triggered.") end local playlist_size = mp.get_property_number("playlist-count", 0) if current_video ~= nil and playlist_size > 1 then - YouTubeQueue.update_current_index() + YouTubeQueue.update_current_index(true) elseif current_video == nil then local url = mp.get_property("path") YouTubeQueue.add_to_queue(url) From 0bcc7334cbd8ae73cafd089fdefa9ab366679f23 Mon Sep 17 00:00:00 2001 From: sudacode Date: Thu, 5 Sep 2024 23:17:03 -0700 Subject: [PATCH 5/9] disable history db by default - change default config - add back line to prevent from running when disabled --- mpv-youtube-queue.conf | 2 +- mpv-youtube-queue.lua | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mpv-youtube-queue.conf b/mpv-youtube-queue.conf index 0d11465..92223f7 100644 --- a/mpv-youtube-queue.conf +++ b/mpv-youtube-queue.conf @@ -26,6 +26,6 @@ menu_timeout=5 show_errors=yes ytdlp_file_format=mp4 ytdlp_output_template=%(uploader)s/%(title)s.%(ext)s -use_history_db=yes +use_history_db=no backend_host=http://localhost backend_port=42069 diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index d582e40..4fda47d 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -60,7 +60,7 @@ local options = { show_errors = true, ytdlp_file_format = "mp4", ytdlp_output_template = "%(uploader)s/%(title)s.%(ext)s", - use_history_db = true, + use_history_db = false, backend_host = "http://localhost", backend_port = "42069" } @@ -212,6 +212,7 @@ local function _split_command(cmd) end function YouTubeQueue._add_to_history_db(v) + if not options.use_history_db then return false end local url = options.backend_host .. ":" .. options.backend_port .. "/add_video" local command = { From b544ca8d6f3c9e4ffb34dd033bb45ba0ed0edb17 Mon Sep 17 00:00:00 2001 From: sudacode Date: Thu, 5 Sep 2024 23:25:24 -0700 Subject: [PATCH 6/9] appease the linter --- mpv-youtube-queue.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index 4fda47d..18985dd 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -226,7 +226,7 @@ function YouTubeQueue._add_to_history_db(v) playback_only = false, capture_stdout = true, args = command - }, function(success, result, err) + }, function(success, _, err) if not success then print_osd_message("Failed to send video data to backend: " .. err, MSG_DURATION, style.error) From 7916e3a1bc3e8418726e82333d55bbd54c21e732 Mon Sep 17 00:00:00 2001 From: sudacode Date: Thu, 5 Sep 2024 23:30:17 -0700 Subject: [PATCH 7/9] update readme --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 64f49ae..42013a9 100644 --- a/README.md +++ b/README.md @@ -63,21 +63,20 @@ This script requires the following software to be installed on the system - `clipboard_command - xclip -o`: The command to use to get the contents of the clipboard - `cursor_icon - ➤`: The icon to use for the cursor - `display_limit - 10`: The maximum amount of videos to show on the OSD at once -- `download_directory - ~/videos/YouTube`: The directory to use when - downloading a video +- `download_directory - ~/videos/YouTube`: The directory to use when downloading a video - `download_quality 720p`: The maximum download quality - `downloader - curl`: The name of the program to use to download the video - `font_name - JetBrains Mono`: The name of the font to use - `font_size - 12`: Size of the font -- `marked_icon - ⇅`: The icon to use to mark a video as ready to be moved in - the queue +- `marked_icon - ⇅`: The icon to use to mark a video as ready to be moved in the queue - `menu_timeout - 5`: The number of seconds until the menu times out - `show_errors - yes`: Show error messages on the OSD - `ytdlp_file_format - mp4`: The preferred file format for downloaded videos -- `ytdlp_output_template - %(uploader)s/%(title)s.%(ext)s`: The [yt-dlp output - template string](https://github.com/yt-dlp/yt-dlp#output-template) - - Full path with the default `download_directory` - is: `~/videos/YouTube//.<ext>` +- `ytdlp_output_template - %(uploader)s/%(title)s.%(ext)s`: The [yt-dlp output template string](https://github.com/yt-dlp/yt-dlp#output-template) + - Full path with the default `download_directory` is: `~/videos/YouTube/<uploader>/<title>.<ext>` +- `use_history_db - no`: Enable watch history tracking through integration with [mpv-youtube-queue-server](https://gitea.suda.codes/sudacode/mpv-youtube-queue-server) +- `backend_host`: ip or hostname of the backend server +- `backend_port`: port to connect to for the backend server ## License From 89cf199a879239553370542cf2d087c56c20c27c Mon Sep 17 00:00:00 2001 From: ksyasuda <ksyasuda@umich.edu> Date: Fri, 6 Sep 2024 02:43:09 -0700 Subject: [PATCH 8/9] add load-file even listener for adding to history db --- mpv-youtube-queue.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index 18985dd..9e109e4 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -29,7 +29,7 @@ local marked_index = nil local current_video = nil local destroyer = nil local timeout -local debug = false +local debug = true local options = { add_to_queue = "ctrl+a", @@ -658,13 +658,18 @@ local function on_track_changed() YouTubeQueue.update_current_index() end +local function on_file_loaded() + if debug then print("Load file event triggered.") end + YouTubeQueue.update_current_index(true) +end + -- Function to be called when the playback-restart event is triggered local function on_playback_restart() if debug then print("Playback restart event triggered.") end local playlist_size = mp.get_property_number("playlist-count", 0) - if current_video ~= nil and playlist_size > 1 then - YouTubeQueue.update_current_index(true) - elseif current_video == nil then + -- if current_video ~= nil and playlist_size > 1 then + -- YouTubeQueue.update_current_index() + if current_video == nil then local url = mp.get_property("path") YouTubeQueue.add_to_queue(url) YouTubeQueue._add_to_history_db(current_video) @@ -707,6 +712,7 @@ mp.add_key_binding(options.remove_from_queue, "delete_video", mp.register_event("end-file", on_end_file) mp.register_event("track-changed", on_track_changed) mp.register_event("playback-restart", on_playback_restart) +mp.register_event("file-loaded", on_file_loaded) -- keep for backwards compatibility mp.register_script_message("add_to_queue", YouTubeQueue.add_to_queue) From 827eb80d6e92fa241f905483bf32f7c54152fbe8 Mon Sep 17 00:00:00 2001 From: sudacode <suda@sudacode.com> Date: Sun, 8 Sep 2024 01:40:04 -0700 Subject: [PATCH 9/9] add save/load queue functions --- mpv-youtube-queue.lua | 88 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/mpv-youtube-queue.lua b/mpv-youtube-queue.lua index 9e109e4..c5ce052 100644 --- a/mpv-youtube-queue.lua +++ b/mpv-youtube-queue.lua @@ -62,7 +62,9 @@ local options = { ytdlp_output_template = "%(uploader)s/%(title)s.%(ext)s", use_history_db = false, backend_host = "http://localhost", - backend_port = "42069" + backend_port = "42069", + save_queue = "ctrl+s", + load_queue = "ctrl+l" } mp.options.read_options(options, "mpv-youtube-queue") @@ -236,6 +238,88 @@ function YouTubeQueue._add_to_history_db(v) return true end +-- Returns a list of URLs in the queue from index + 1 to the end +function YouTubeQueue._get_urls(start_index) + if start_index < 0 or start_index + 1 >= #video_queue then return nil end + local urls = {} + for i = start_index + 1, #video_queue do + table.insert(urls, video_queue[i].video_url) + end + return urls +end + +-- Converts to json +function YouTubeQueue._convert_to_json(key, val) + if val == nil then return end + if type(val) ~= "table" then return "{" .. key .. ":" .. val .. "}" end + local json = string.format('{"%s": [', key) + for i, v in ipairs(val) do + json = json .. '"' .. v .. '"' + if i < #val then json = json .. ", " end + end + json = json .. "]}" + return json +end + +-- Saves the remainder of the videos in the queue (all videos after the currently playing +-- video) to the history database +function YouTubeQueue.save_queue() + if not options.use_history_db then return false end + local url = options.backend_host .. ":" .. options.backend_port .. + "/save_queue" + local data = YouTubeQueue._convert_to_json("urls", + YouTubeQueue._get_urls(index)) + if data == nil then + print_osd_message("Failed to save queue: No videos remaining in queue", + MSG_DURATION, style.error) + return false + end + if debug then print("Data: " .. data) end + local command = { + "curl", "-X", "POST", url, "-H", "Content-Type: application/json", "-d", + data + } + if debug then + print("Saving queue to history") + print("Command: " .. table.concat(command, " ")) + end + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + args = command + }, function(success, _, err) + if not success then + print_osd_message("Failed to save queue: " .. err, MSG_DURATION, + style.error) + return false + end + end) +end + +-- loads the queue from the backend +function YouTubeQueue.load_queue() + if not options.use_history_db then return false end + local url = options.backend_host .. ":" .. options.backend_port .. + "/load_queue" + local command = { "curl", "-X", "GET", url } + + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + args = command + }, function(success, result, err) + if not success then + print_osd_message("Failed to load queue: " .. err, MSG_DURATION, + style.error) + return false + else + for i in result do YouTubeQueue.add_to_queue(i) end + end + end) +end + -- }}} -- QUEUE GETTERS AND SETTERS {{{ @@ -708,6 +792,8 @@ mp.add_key_binding(options.move_video, "move_video", YouTubeQueue.mark_and_move_video) mp.add_key_binding(options.remove_from_queue, "delete_video", YouTubeQueue.remove_from_queue) +mp.add_key_binding(options.save_queue, "save_queue", YouTubeQueue.save_queue) +mp.add_key_binding(options.load_queue, "load_queue", YouTubeQueue.load_queue) mp.register_event("end-file", on_end_file) mp.register_event("track-changed", on_track_changed)