From 859354ddc4a8e2bb06d03949ecf279452f125025 Mon Sep 17 00:00:00 2001 From: InigoGutierrez Date: Thu, 25 Aug 2022 17:19:50 +0200 Subject: Updated mpv-splice to work on online videos. --- stow/mpv/.config/mpv/scripts-opts/mpv-splice.conf | 54 ++++ stow/mpv/.config/mpv/scripts/mpv-splice.lua | 349 +++++++++++----------- 2 files changed, 232 insertions(+), 171 deletions(-) create mode 100755 stow/mpv/.config/mpv/scripts-opts/mpv-splice.conf mode change 100644 => 100755 stow/mpv/.config/mpv/scripts/mpv-splice.lua diff --git a/stow/mpv/.config/mpv/scripts-opts/mpv-splice.conf b/stow/mpv/.config/mpv/scripts-opts/mpv-splice.conf new file mode 100755 index 0000000..519d09b --- /dev/null +++ b/stow/mpv/.config/mpv/scripts-opts/mpv-splice.conf @@ -0,0 +1,54 @@ +# Location of temporary files +# tmp_location = "~/tmpXXX" + +# KEY BINDS +# +bind_put_time=Alt+t +bind_show_times=Alt+p +bind_process_video=Alt+c +bind_reset_current_slice=Alt+r +bind_delete_slice=Alt+d +bind_toggle_do_encode=Alt+e +bind_toggle_do_upload=Alt+u + +# Default togglable variable values +# +# setting do_encode to "yes" will make the process of cutting the video +# onto pieces hundreds of times slower, but will make the cuts +# frame-perfect (with "no" there might be extra frames before each starting timestamp). +do_encode=no +do_upload=no + +# Locations where resulting video is stored +# +output_location=~/Videos/cut + +# Output video format +# +output_format=mp4 + +# UPLOADING THE VIDEO +# this script can upload the resulting video to a video hosting and automatically copy the link to it into your clipboard using online_pattern +# I haven't tasted it with anything other than streamable and not sure if these variables are enough. + +# URL that is used to upload the video, if "" - script won't try to upload +# +online_upload_url=https://api.streamable.com/upload + +# Your credentials used to access the website +# +online_secret=email:password + +# If "yes" the script will copy the resulting video url into clipboard +# +online_do_copy_to_clipboard=yes + +# URL that points to the uploaded video. %s will be substituted with the string that is found by jq under online_pattern (on the html page downloaded by curl) +# (double % is needed to excape lua's string format's %s) +# +online_resulting_url=https://streamable.com/%%s + +# Pattern in the downloaded html page after downloading the video that is used to determine resulting video link +# This parameter is passed to jq -r +# +online_pattern=.shortcode diff --git a/stow/mpv/.config/mpv/scripts/mpv-splice.lua b/stow/mpv/.config/mpv/scripts/mpv-splice.lua old mode 100644 new mode 100755 index b121dc4..cd03222 --- a/stow/mpv/.config/mpv/scripts/mpv-splice.lua +++ b/stow/mpv/.config/mpv/scripts/mpv-splice.lua @@ -1,113 +1,9 @@ -- ----------------------------------------------------------------------------- -- -- MPV Splice --- URL: https://github.com/pvpscript/mpv-video-splice --- --- Requires: ffmpeg --- --- Description: --- --- This script provides the hability to create video slices by grabbing two --- timestamps, which generate a slice from timestamp A[i] to timestamp B[i], --- e.g.: --- -> Slice 1: 00:10:34.25 -> 00:15:00.00. --- -> Slice 2: 00:23:00.84 -> 00:24:10.00. --- ... --- -> Slice n: 01:44:22.47 -> 01:56:00.00. --- --- Then, all the slices from 1 to n are joined together, creating a new --- video. --- --- The output file will appear at the directory that the mpv command was ran, --- or in the environment variable set for it (see Environment variables below) --- --- Note: This script prevents the mpv player from closing when the video ends, --- so that the slices don't get lost. Keep this in mind if there's the option --- 'keep-open=no' in the current config file. --- --- Note: This script will also silence the terminal, so the script messages --- can be seen more clearly. --- --- ----------------------------------------------------------------------------- --- --- --- Usage: --- --- In the video screen, press Alt + T to grab the first timestamp and then --- press Alt + T again to get the second timestamp. This process will generate --- a time range, which represents a video slice. Repeat this process to create --- more slices. --- --- To see all the slices made, press Alt + P. All of the slices will appear --- in the terminal in order of creation, with their corresponding timestamps. --- Incomplete slices will show up as 'Slice N in progress', where N is the --- slice number. --- --- To reset an incomplete slice, press Alt + R. If the first part of a slice --- was created at the wrong time, this will reset the current slice. --- --- To delete a whole slice, start the slice deletion mode by pressing Alt + D. --- When in this mode, it's possible to press Alt + NUM, where NUM is any --- number between 0 inclusive and 9 inclusive. For each Alt + NUM pressed, a --- number will be concatenated to make the final number referring to the slice --- to be removed, then press Alt + D again to stop the slicing deletion mode --- and delete the slice corresponding to the formed number. --- --- Example 1: Deleting slice number 3 --- -> Alt + D # Start slice deletion mode --- -> Alt + 3 # Concatenate number 3 --- -> Alt + D # Exit slice deletion mode --- --- Example 2> Deleting slice number 76 --- -> Alt + D # Start slice deletion mode --- -> Alt + 7 # Concatenate number 7 --- -> Alt + 6 # Concatenate number 6 --- -> Alt + D # Exit slice deletion mode --- --- To fire up ffmpeg, which will slice up the video and concatenate the slices --- together, press Alt + C. It's important that there are at least one --- slice, otherwise no video will be created. --- --- Note: No cut will be made unless the user presses Alt + C. --- Also, the original video file won't be affected by the cutting. +-- URL: https://github.com/teawhydee/mpv-yt-splice -- --- --- ----------------------------------------------------------------------------- --- --- --- Log level: --- --- Everytime a timestamp is grabbed, a text will appear on the screen showing --- the selected time. --- When Alt + P is pressed, besides showing the slices in the terminal, --- it will also show on the screen the total number of cuts (or slices) --- that were made. --- When the actual cutting and joining process begins, a message will be shown --- on the screen and the terminal telling that it began. When the process ends, --- a message will appear on the screen and the terminal displaying the full path --- of the generated video. It will also appear a message in the terminal telling --- that the process ended. --- --- Note: Every message that appears on the terminal has the log level of 'info'. --- --- --- ----------------------------------------------------------------------------- --- --- --- Environment Variables: --- --- This script uses environment variables to allow the user to --- set the temporary location of the video cuts and for setting the location for --- the resulting video. --- --- To set the temporary directory, set the variable MPV_SPLICE_TEMP; --- e.g.: export MPV_SPLICE_TEMP="$HOME/temporary_location" --- --- To set the video output directory, set the variable MPV_SPLICE_OUTPUT; --- e.g.: export MPV_SPLICE_OUTPUT="$HOME/output_location" --- --- Make sure the directories set in the variables really exist, or else the --- script might fail. +-- Read README.md for usage -- -- ----------------------------------------------------------------------------- @@ -116,26 +12,43 @@ local mp = require 'mp' local msg = require 'mp.msg' +local opt = require 'mp.options' -------------------------------------------------------------------------------- -- Default variables -local default_tmp_location = "/tmp" +local SCRIPT_NAME = "mpv-splice" +local default_tmp_location = "~/tmpXXX" local default_output_location = mp.get_property("working-directory") +local do_encode = "no" -------------------------------------------------------------------------------- -local concat_name = "concat.txt" +local splice_options = { + bind_put_time = 'Alt+t', + bind_show_times = 'Alt+p', + bind_process_video = 'Alt+c', + bind_reset_current_slice = 'Alt+r', + bind_delete_slice = 'Alt+d', + bind_toggle_do_encode = 'Alt+e', + bind_toggle_do_upload = 'Alt+u', + + tmp_location = os.getenv("MPV_SPLICE_TEMP") and os.getenv("MPV_SPLICE_TEMP") or default_tmp_location, + output_location = os.getenv("MPV_SPLICE_OUTPUT") and os.getenv("MPV_SPLICE_OUTPUT") or default_output_location, + output_format = "mp4", + do_encode = "no", + do_upload = "no", + + online_upload_url = "", + online_resulting_url = "", + online_secret = "", + online_pattern = "", + online_do_copy_to_clipboard = "no", +} +opt.read_options(splice_options, SCRIPT_NAME) local ffmpeg = "ffmpeg -hide_banner -loglevel warning" -local tmp_location = os.getenv("MPV_SPLICE_TEMP") - and os.getenv("MPV_SPLICE_TEMP") - or default_tmp_location -local output_location = os.getenv("MPV_SPLICE_OUTPUT") - and os.getenv("MPV_SPLICE_OUTPUT") - or default_output_location - local times = {} local start_time = nil local remove_val = "" @@ -144,7 +57,7 @@ local exit_time = 0 -------------------------------------------------------------------------------- -function notify(duration, ...) +local function notify_without_stdout(duration, ...) local args = {...} local text = "" @@ -152,9 +65,14 @@ function notify(duration, ...) text = text .. tostring(v) end - msg.info(text) mp.command(string.format("show-text \"%s\" %d 1", - text, duration)) + text, duration)) + return text +end + +local function notify(duration, ...) + local text = notify_without_stdout(duration, ...) + msg.info(text) end local function get_time() @@ -169,7 +87,8 @@ local function get_time() return fmt_time end -function put_time() +local function put_time() + print(splice_options.output_location) local time = get_time() local message = "" @@ -190,18 +109,63 @@ function put_time() notify(2000, message, ": ", time) end -function show_times() - notify(2000, "Total cuts: ", #times) +local function toggle_do_encode() + if (do_encode == "yes") then + do_encode = "no" + notify(500, "Reencode: False") + else + do_encode = "yes" + notify(500, "Reencode: True") + end +end + +local function toggle_do_upload() + if (do_upload == "yes") then + do_upload = "no" + notify(500, "Upload: False") + else + do_upload = "yes" + notify(500, "Upload: True") + end +end + +local function show_times() + local notify_text = "Reencode: " + if (do_encode == "yes") then + notify_text = notify_text .. "True" + else + notify_text = notify_text .. "False" + end + notify_text = notify_text .. "; Upload: " + if (do_upload == "yes") then + notify_text = notify_text .. "True\n" + else + notify_text = notify_text .. "False\n" + end + notify_text = notify_text .. "Total cuts: " .. #times .. "\n" + local print_limit = 10 for i, obj in ipairs(times) do - msg.info("Slice", i, ": ", obj.t_start, " -> ", obj.t_end) + local temp = i .. ": " .. obj.t_start .. " -> " .. obj.t_end + msg.info(temp) + if i < print_limit then + notify_text = notify_text .. temp .. "\n" + end end + if start_time then - notify(2000, "Slice ", #times+1, " in progress.") + local temp = "" .. #times+1 .. ": " .. start_time .. " -> in progress..." + msg.info(temp) + notify_text = notify_text .. temp .. "\n" + end + + if #times >= print_limit then + notify_text = notify_text .. "see rest in stdout.." end + notify_without_stdout(4000, notify_text) end -function reset_current_slice() +local function reset_current_slice() if start_time then notify(2000, "Slice ", #times+1, " reseted.") @@ -209,18 +173,17 @@ function reset_current_slice() end end -function delete_slice() +local function delete_slice() if remove_val == "" then notify(2000, "Entered slice deletion mode.") -- Add shortcut keys to the interval {0..9}. for i=0,9,1 do mp.add_key_binding("Alt+" .. i, "num_key_" .. i, - function() - remove_val = remove_val .. i - notify(1000, "Slice to remove: " - .. remove_val) - end + function() + remove_val = remove_val .. i + notify(1000, "Slice to remove: " .. remove_val) + end ) end else @@ -229,10 +192,12 @@ function delete_slice() mp.remove_key_binding("num_key_" .. i) end - remove_num = tonumber(remove_val) + local remove_num = tonumber(remove_val) if #times >= remove_num and remove_num > 0 then table.remove(times, remove_num) notify(2000, "Removed slice ", remove_num) + else + notify(2000, "Specified slice doesn't exist") end remove_val = "" @@ -241,7 +206,7 @@ function delete_slice() end end -function prevent_quit(name) +local function prevent_quit(name) if start_time then if os.time() - exit_time <= 2 then mp.command(name) @@ -254,63 +219,101 @@ function prevent_quit(name) end end -function process_video() +local function process_video() local alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" local rnd_size = 10 - local pieces = {} - -- Better seed randomization math.randomseed(os.time()) math.random(); math.random(); math.random() - if times[#times] then - local tmp_dir = io.popen(string.format("mktemp -d -p %s", - tmp_location)):read("*l") - local input_file = mp.get_property("path") - local ext = string.gmatch(input_file, ".*%.(.*)$")() - - local rnd_str = "" - for i=1,rnd_size,1 do - local rnd_index = math.floor(math.random() * #alphabet + 0.5) - rnd_str = rnd_str .. alphabet:sub(rnd_index, rnd_index) - end + if not times[#times] then + return + end + local tmp_dir = io.popen(string.format("mktemp -d %s", + splice_options.tmp_location)):read("*l") + local input_file = mp.get_property("path") + -- local ext = string.gmatch(input_file, ".*%.(.*)$")() + + local rnd_str = "" + for i=1,rnd_size,1 do + local rnd_index = math.floor(math.random() * #alphabet + 0.5) + rnd_str = rnd_str .. alphabet:sub(rnd_index, rnd_index) + end - local output_file = string.format("%s/%s_%s_cut.%s", - output_location, - mp.get_property("filename/no-ext"), - rnd_str, ext) + local output_title = mp.get_property("filename/no-ext") - local cat_file_name = string.format("%s/%s", tmp_dir, "concat.txt") - local cat_file_ptr = io.open(cat_file_name, "w") + local cat_file_name = string.format("%s/%s", tmp_dir, "concat.txt") + local cat_file_ptr = io.open(cat_file_name, "w") - notify(2000, "Process started!") + notify(2000, "Process started!") - for i, obj in ipairs(times) do - local path = string.format("%s/%s_%d.%s", - tmp_dir, rnd_str, i, ext) + -- Getting the individual clips before concating them. + for i, obj in ipairs(times) do + local path = string.format("%s/%s_%d.%s", + tmp_dir, rnd_str, i, splice_options.output_format) + if (string.find(input_file, "https://")) then + print ("ONLINE VIDEO DETECTED") + path = string.format("%s/%s_%d." .. splice_options.output_format, + tmp_dir, rnd_str, i) + output_title = mp.get_property("media-title") + local youtubedl = "youtube-dl --external-downloader ffmpeg --external-downloader-args " + cat_file_ptr:write(string.format("file '%s'\n", path)) + os.execute(string.format("%s \"-ss %s -to %s\" -f best \"%s\" -o %s", + youtubedl, obj.t_start, obj.t_end, input_file, path)) + else cat_file_ptr:write(string.format("file '%s'\n", path)) - os.execute(string.format("%s -ss %s -i \"%s\" -to %s " .. + if (do_encode == "yes") then + os.execute(string.format("%s -ss %s -to %s -i \"%s\" \"%s\"", + ffmpeg, obj.t_start, obj.t_end, input_file, path)) + else + os.execute(string.format("%s -ss %s -i \"%s\" -to %s " .. "-c copy -copyts -avoid_negative_ts make_zero \"%s\"", - ffmpeg, obj.t_start, input_file, obj.t_end, - path)) + ffmpeg, obj.t_start, input_file, obj.t_end, path)) + end + notify( 2000, "Download complete" ) end cat_file_ptr:close() - cmd = string.format("%s -f concat -safe 0 -i \"%s\" " .. - "-c copy \"%s\"", - ffmpeg, cat_file_name, output_file) + output_title = output_title:gsub("[/|$()* ]", "_") + local output_file = string.format("%s/%s_%s_cut." .. splice_options.output_format, + splice_options.output_location, output_title, rnd_str) + output_file = output_file:gsub("\"", "\\\"") + output_file = output_file:gsub(" ", "\\ ") + local cmd = string.format("%s -f concat -safe 0 -i \"%s\" " .. "-c copy %s", ffmpeg, cat_file_name, output_file ) + print(cmd) os.execute(cmd) - - notify(10000, "File saved as: ", output_file) - msg.info("Process ended!") + if (do_upload ~= "yes") then + notify(10000, "Local file saved as: ", output_file) + else + notify(10000, "Local file saved as: ", output_file .. "\nUploading video...") + print("Uploading video...") + local cmd_online = "%s" + if (splice_options.online_do_copy_to_clipboard) then + cmd_online = "printf \"" .. splice_options.online_resulting_url .. "\" $(%s\" | jq -r \" " .. + splice_options.online_pattern .. "\") | xclip -selection clipboard" + end + cmd_online = string.format(cmd_online, "curl --progress-bar -u \"" .. + splice_options.online_secret .. "\" -F \"file=@" .. output_file .. + "\" \"" .. splice_options.online_upload_url) + print("Command to execute: " .. cmd_online) + os.execute(cmd_online); + if (splice_options.online_do_copy_to_clipboard == "yes") then + notify(10000, "Upload complete, link copied to clipboard") + else + notify(10000, "Upload complete") + end + end os.execute(string.format("rm -rf %s", tmp_dir)) - msg.info("Temporary directory removed!") + -- msg.info("Temporary directory removed!") end end +do_upload = splice_options.do_upload +do_encode = splice_options.do_encode + mp.set_property("keep-open", "yes") -- Prevent mpv from exiting when the video ends mp.set_property("quiet", "yes") -- Silence terminal. @@ -321,8 +324,12 @@ mp.add_key_binding('Shift+q', "quit-watch-later", function() prevent_quit("quit-watch-later") end) -mp.add_key_binding('Alt+t', "put_time", put_time) -mp.add_key_binding('Alt+p', "show_times", show_times) -mp.add_key_binding('Alt+c', "process_video", process_video) -mp.add_key_binding('Alt+r', "reset_current_slice", reset_current_slice) -mp.add_key_binding('Alt+d', "delete_slice", delete_slice) +mp.add_key_binding(splice_options.bind_toggle_do_encode, "toggle_do_encode", toggle_do_encode) +mp.add_key_binding(splice_options.bind_toggle_do_upload, "toggle_do_upload", toggle_do_upload) +mp.add_key_binding(splice_options.bind_put_time, "put_time", put_time) +mp.add_key_binding(splice_options.bind_show_times, "show_times", show_times) +mp.add_key_binding(splice_options.bind_process_video, "process_video", process_video) +mp.add_key_binding(splice_options.bind_reset_current_slice, "reset_current_slice", reset_current_slice) +mp.add_key_binding(splice_options.bind_delete_slice, "delete_slice", delete_slice) + +-- vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab : -- cgit v1.2.1