mirror of
https://github.com/familyfriendlymikey/mpv-cut
synced 2024-07-01 12:08:58 +00:00
add cancel_cut binding, add bash utils with functions make_cuts and concat, remove make_cuts
binding
This commit is contained in:
parent
26ad54b42d
commit
6849b272a4
131
README.md
131
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
|
||||
|
33
main.lua
33
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)
|
||||
|
19
utils
Normal file
19
utils
Normal file
@ -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"
|
||||
}
|
Loading…
Reference in New Issue
Block a user