diff --git a/README.md b/README.md index 965271c..6ecce26 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ That's all you have to do, next time you run mpv the script will be automaticall The resulting cut will be placed in the same directory as the source file. +- You can press `C` to cancel a cut. + ### Actions You can press `a` to cycle between three default actions: @@ -80,9 +82,37 @@ the channel and `=` to increment the channel. You can configure a name for each channel as shown below. -### Making Cuts +### Utils -If you want to make all the cuts stored in a cut list, simply press `0`. +This plugin includes a `utils` script that you can source in your shell's +startup file. In my `~/.zshrc` I have this line: + +``` +source ~/.config/mpv/scripts/mpv-cut/utils +``` + +Now when you open new terminals, you'll have access to the functions inside of +the `utils` script, which are explained in this section. + +#### Making Cuts + +The `make_cuts` function takes a `.list` file and ffmpeg output options except +for an output filename. To make cuts without reencoding: + +``` +make_cuts some_video.mp4.list -c copy +``` + +#### Concatenate, Merge, Join Cuts + +The `concat` function takes a prefix and ffmpeg output options. Any file in the current directory +starting with the prefix will be included. For example, to concatenate all +files in the current directory whose filename starts with `CUT` without +reencoding: + +``` +concat CUT -c copy output.mp4 +``` ## Config @@ -94,29 +124,41 @@ You can include or omit any of the following: ```lua -- Key config KEY_CUT = "c" -KEY_CYCLE_ACTION = "a" -KEY_BOOKMARK_ADD = "i" -KEY_CHANNEL_INC = "=" -KEY_CHANNEL_DEC = "-" -KEY_MAKE_CUTS = "0" -- The list of channel names, you can choose whatever you want. CHANNEL_NAMES[1] = "FUNNY" -CHANNEL_NAMES[2] = "COOL" -- The default channel CHANNEL = 1 -- The default action -ACTION = "ENCODE" - --- The action to use when making cuts from a cut list -MAKE_CUT = ACTIONS.COPY +ACTION = "COPY" -- Delete a default action ACTIONS.LIST = nil +``` --- Specify custom actions +### Custom Actions + +In the config file you can also specify custom actions. Even if you don't know +Lua, it should be pretty straightforward to take the following example and tune +it to your needs. I think this is a very powerful abstraction. All of the +default actions are implemented the same way you'd implement custom actions. + +You can essentially define an arbitrary callback to run whenever an action is +invoked (the second time you press `c` in mpv). The callback function gets +passed a table with the following properties: + +``` +inpath, indir, infile, infile_noext, ext +channel +start_time, end_time, duration +start_time_hms, end_time_hms, duration_hms +``` + +Here is an example overwriting the default `ENCODE` action: + +```lua ACTIONS.ENCODE = function(d) local args = { "ffmpeg", @@ -136,12 +178,6 @@ ACTIONS.ENCODE = function(d) playback_only = false, }, function() print("Done") end) end - --- The table that gets passed to an action will have the following properties: --- inpath, indir, infile, infile_noext, ext --- channel --- start_time, end_time, duration --- start_time_hms, end_time_hms, duration_hms ``` ## Optimized MPV Input Config @@ -152,16 +188,18 @@ quickly editing videos. ``` RIGHT seek 2 exact LEFT seek -2 exact +UP seek 2 keyframes +DOWN seek -2 keyframes ] add speed 0.5 [ add speed -0.5 } add speed 0.25 { add speed -0.25 +\ set speed 1 -SPACE cycle pause; set speed 1 # Reset speed whenever pausing. -BS script-binding osc/visibility # Make progress bar stay visible. -UP seek 0.01 keyframes # Seek by keyframes only. -DOWN seek -0.01 keyframes # Seek by keyframes only. +BS script-binding osc/visibility + +Alt+= add video-zoom 0.1 ``` You may also want to change your key repeat delay and rate by tweaking @@ -249,53 +287,6 @@ editors. - If the video's compression isn't efficient enough to upload to a messaging platform or something, you may want to compress it more. -### How Do I Concatenate Videos Manually With ffmpeg? - -To concatenate videos with ffmpeg, you need to create a file with content like -this: - -``` -file cut_1.mp4 -file cut_2.mp4 -file cut_3.mp4 -file cut_4.mp4 -``` - -You can name the file whatever you want, here I named it `concat.txt`. - -Then run the command: - -``` -ffmpeg -f concat -safe 0 -i concat.txt -c copy out.mp4 -``` - -That's annoying though, so you can skip manually creating the file by using -bash. This command will concatenate all files in the current directory that -begin with "COPY_": - -``` -ffmpeg -f concat -safe 0 -i <(printf 'file %q\n' "$PWD"/COPY_*) -c copy lol.mp4 -``` - -- You need to escape apostrophes which is why we are using `printf %q - "$string"`. - -- Instead of actually creating a file we just use process substitution - `<(whatever)` to create a temporary file, which is why we need the `$PWD` in - there for the absolute path. - -You can also do it in vim, among other things. - -``` -ls | vim - -:%s/'/\\'/g -:%norm Ifile -:wq concat.txt -``` - -This substitution might not cover all cases, but whatever, if you're -concatenating a file named `[{}1;']["!.mp4` you can figure it out yourself. - ### Can I Make Seeking And Reverse Playback Faster? Depending on the encoding of the video file being played, the following may be diff --git a/main.lua b/main.lua index 0c19efb..bb93053 100644 --- a/main.lua +++ b/main.lua @@ -111,6 +111,7 @@ CHANNEL = 1 CHANNEL_NAMES = {} KEY_CUT = "c" +KEY_CANCEL_CUT = "C" KEY_CYCLE_ACTION = "a" KEY_BOOKMARK_ADD = "i" KEY_CHANNEL_INC = "=" @@ -187,30 +188,6 @@ local function cycle_action() print_or_update_text_overlay("ACTION: " .. ACTION) end -local function make_cuts() - print("MAKING CUTS") - if not MAKE_CUT then print("MAKE_CUT function not found.") return end - local inpath = mp.get_property("path") .. ".list" - local file = io.open(inpath, "r") - if not file then print("Error reading cut list") return end - for line in file:lines() do - if line ~= "" then - local cut = {} - for token in string.gmatch(line, "[^" .. ":" .. "]+") do - table.insert(cut, token) - end - local d = get_data() - d.channel = cut[1] - local t = get_times(tonumber(cut[2]), tonumber(cut[3])) - for k, v in pairs(t) do d[k] = v end - mp.msg.info("MAKE_CUT") - mp.msg.info(table_to_str(d)) - MAKE_CUT(d) - end - end - io.close(file) -end - local function cut(start_time, end_time) local d = get_data() local t = get_times(start_time, end_time) @@ -237,6 +214,12 @@ local function put_time() end end +local function cancel_cut() + text_overlay_off() + START_TIME = nil + print("CANCELLED CUT") +end + local function get_bookmark_file_path() local d = get_data() mp.msg.info(table_to_str(d)) @@ -289,10 +272,10 @@ local function channel_dec() end mp.add_key_binding(KEY_CUT, "cut", put_time) +mp.add_key_binding(KEY_CANCEL_CUT, "cancel_cut", cancel_cut) mp.add_key_binding(KEY_BOOKMARK_ADD, "bookmark_add", bookmark_add) mp.add_key_binding(KEY_CHANNEL_INC, "channel_inc", channel_inc) mp.add_key_binding(KEY_CHANNEL_DEC, "channel_dec", channel_dec) mp.add_key_binding(KEY_CYCLE_ACTION, "cycle_action", cycle_action) -mp.add_key_binding(KEY_MAKE_CUTS, "make_cuts", make_cuts) mp.register_event('file-loaded', bookmarks_load) diff --git a/utils b/utils new file mode 100644 index 0000000..f84eef9 --- /dev/null +++ b/utils @@ -0,0 +1,19 @@ +#! /usr/bin/env bash + +concat() { + local prefix="$1" + shift + ffmpeg -f concat -safe 0 -i <(printf 'file %q\n' "$PWD"/"$prefix"*) "$@" +} + +make_cuts() { + local list="$1" + local vid="${list%.*}" + local ext="${vid##*.}" + local vid_noext="${vid%.*}" + shift + while IFS=: read -r channel_name start_ts end_ts; do + if [[ -z "$end_ts" ]]; then continue; fi + ffmpeg -nostdin -ss "$start_ts" -to "$end_ts" -i "$vid" "$@" "CUT_${channel_name}_${vid}_${start_ts}_${end_ts}.${ext}" + done < "$list" +}