diff options
| author | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-01-25 14:04:30 +0100 | 
|---|---|---|
| committer | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-01-25 14:04:30 +0100 | 
| commit | db3eebea90e2a547c7892c060b56326df81c5d18 (patch) | |
| tree | 186e8bd2a67e90d7cceb8b6122875bcbe332acb2 /config/common/mpv/scripts/mpv-cut | |
| parent | 06c3f38bb0d1b77902617bfa5757561262873124 (diff) | |
Add mpv-cut and bindings
*Also added custom gitignore for mpv
Diffstat (limited to 'config/common/mpv/scripts/mpv-cut')
| -rw-r--r-- | config/common/mpv/scripts/mpv-cut/README.org | 20 | ||||
| -rw-r--r-- | config/common/mpv/scripts/mpv-cut/config.lua | 19 | ||||
| -rw-r--r-- | config/common/mpv/scripts/mpv-cut/main.lua | 278 | ||||
| -rw-r--r-- | config/common/mpv/scripts/mpv-cut/utils | 44 | 
4 files changed, 361 insertions, 0 deletions
diff --git a/config/common/mpv/scripts/mpv-cut/README.org b/config/common/mpv/scripts/mpv-cut/README.org new file mode 100644 index 0000000..02540b0 --- /dev/null +++ b/config/common/mpv/scripts/mpv-cut/README.org @@ -0,0 +1,20 @@ +[[https://github.com/familyfriendlymikey/mpv-cut][mpv-cut]] + +* Files +|------------+---------------| +| file       | what          | +|------------+---------------| +| ~config.lua~ | configuration | +| ~.book~      | bookmarks     | +| ~.list~      | backup        | +|------------+---------------| + +* Actions +|---+--------------------------------------------| +| ~c~ | START/END cut                              | +| ~C~ | cancel cut                                 | +| ~a~ | cycle actions                              | +| ~i~ | bookmark timestamp to ~.list~ (+add chapter) | +| ~-~ | decrement channel +| ~=~ | increment channel                          | + diff --git a/config/common/mpv/scripts/mpv-cut/config.lua b/config/common/mpv/scripts/mpv-cut/config.lua new file mode 100644 index 0000000..4639cb7 --- /dev/null +++ b/config/common/mpv/scripts/mpv-cut/config.lua @@ -0,0 +1,19 @@ +-- Key config +KEY_CUT = "c" +KEY_CANCEL_CUT = "C" +KEY_CYCLE_ACTION = "a" +KEY_BOOKMARK_ADD = "i" +KEY_CHANNEL_INC = "=" +KEY_CHANNEL_DEC = "-" + +-- The list of channel names, you can choose whatever you want. +CHANNEL_NAMES[1] = "FUNNY" + +-- The default channel +CHANNEL = 1 + +-- The default action +ACTION = "COPY" + +-- Delete a default action +ACTIONS.LIST = nil
\ No newline at end of file diff --git a/config/common/mpv/scripts/mpv-cut/main.lua b/config/common/mpv/scripts/mpv-cut/main.lua new file mode 100644 index 0000000..7db65aa --- /dev/null +++ b/config/common/mpv/scripts/mpv-cut/main.lua @@ -0,0 +1,278 @@ +mp.msg.info("MPV-CUT LOADED") + +utils = require "mp.utils" + +local function print(s) +	mp.msg.info(s) +	mp.osd_message(s) +end + +local function table_to_str(o) +	if type(o) == 'table' then +		local s = '' +		for k,v in pairs(o) do +			if type(k) ~= 'number' then k = '"'..k..'"' end +			s = s .. '['..k..'] = ' .. table_to_str(v) .. '\n' +		end +		return s +	else +		return tostring(o) +	end +end + +local function to_hms(seconds) +	local ms = math.floor((seconds - math.floor(seconds)) * 1000) +	local secs = math.floor(seconds) +	local mins = math.floor(secs / 60) +	secs = secs % 60 +	local hours = math.floor(mins / 60) +	mins = mins % 60 +	return string.format("%02d-%02d-%02d-%03d", hours, mins, secs, ms) +end + +local function next_table_key(t, current) +	local keys = {} +	for k in pairs(t) do +		keys[#keys + 1] = k +	end +	table.sort(keys) +	for i = 1, #keys do +		if keys[i] == current then +			return keys[(i % #keys) + 1] +		end +	end +	return keys[1] +end + +ACTIONS = {} + +ACTIONS.COPY = function(d) +	local args = { +		"ffmpeg", +		"-nostdin", "-y", +		"-loglevel", "error", +		"-ss", d.start_time, +		"-t", d.duration, +		"-i", d.inpath, +		"-c", "copy", +		"-map", "0", +		"-dn", +		"-avoid_negative_ts", "make_zero", +		utils.join_path(d.indir, "COPY_" .. d.channel .. "_" .. d.infile_noext .. "_FROM_" .. d.start_time_hms .. "_TO_" .. d.end_time_hms .. d.ext) +	} +	mp.command_native_async({ +		name = "subprocess", +		args = args, +		playback_only = false, +	}, function() print("Done") end) +end + +ACTIONS.ENCODE = function(d) +	local args = { +		"ffmpeg", +		"-nostdin", "-y", +		"-loglevel", "error", +		"-ss", d.start_time, +		"-t", d.duration, +		"-i", d.inpath, +		"-pix_fmt", "yuv420p", +		"-crf", "16", +		"-preset", "superfast", +		utils.join_path(d.indir, "ENCODE_" .. d.channel .. "_" .. d.infile_noext .. "_FROM_" .. d.start_time_hms .. "_TO_" .. d.end_time_hms .. d.ext) +	} +	mp.command_native_async({ +		name = "subprocess", +		args = args, +		playback_only = false, +	}, function() print("Done") end) +end + +ACTIONS.LIST = function(d) +	local inpath = mp.get_property("path") +	local outpath = inpath .. ".list" +	local file = io.open(outpath, "a") +	if not file then print("Error writing to cut list") return end +	local filesize = file:seek("end") +	local s = "\n" .. d.channel +		.. ":" .. d.start_time +		.. ":" .. d.end_time +	file:write(s) +	local delta = file:seek("end") - filesize +	io.close(file) +	print("Δ " .. delta) +end + +ACTION = "COPY" + +CHANNEL = 1 + +CHANNEL_NAMES = {} + +KEY_CUT = "c" +KEY_CANCEL_CUT = "C" +KEY_CYCLE_ACTION = "a" +KEY_BOOKMARK_ADD = "i" +KEY_CHANNEL_INC = "=" +KEY_CHANNEL_DEC = "-" + +home_config = mp.command_native({"expand-path", "~/.config/mpv-cut/config.lua"}) +if pcall(require, "config") then +    mp.msg.info("Loaded config file from script dir") +elseif pcall(dofile, home_config) then +    mp.msg.info("Loaded config file from " .. home_config) +else +    mp.msg.info("No config loaded") +end + +for i, v in ipairs(CHANNEL_NAMES) do +    CHANNEL_NAMES[i] = string.gsub(v, ":", "-") +end + +if not ACTIONS[ACTION] then ACTION = next_table_key(ACTIONS, nil) end + +START_TIME = nil + +local function get_current_channel_name() +	return CHANNEL_NAMES[CHANNEL] or tostring(CHANNEL) +end + +local function get_data() +	local d = {} +	d.inpath = mp.get_property("path") +	d.indir = utils.split_path(d.inpath) +	d.infile = mp.get_property("filename") +	d.infile_noext = mp.get_property("filename/no-ext") +	d.ext = mp.get_property("filename"):match("^.+(%..+)$") or ".mp4" +	d.channel = get_current_channel_name() +	return d +end + +local function get_times(start_time, end_time) +	local d = {} +	d.start_time = tostring(start_time) +	d.end_time = tostring(end_time) +	d.duration = tostring(end_time - start_time) +	d.start_time_hms = tostring(to_hms(start_time)) +	d.end_time_hms = tostring(to_hms(end_time)) +	d.duration_hms = tostring(to_hms(end_time - start_time)) +	return d +end + +text_overlay = mp.create_osd_overlay("ass-events") +text_overlay.hidden = true +text_overlay:update() + +local function text_overlay_off() +	-- https://github.com/mpv-player/mpv/issues/10227 +	text_overlay:update() +	text_overlay.hidden = true +	text_overlay:update() +end + +local function text_overlay_on() +	local channel = get_current_channel_name() +	text_overlay.data = string.format("%s in %s from %s", ACTION, channel, START_TIME) +	text_overlay.hidden = false +	text_overlay:update() +end + +local function print_or_update_text_overlay(content) +	if START_TIME then text_overlay_on() else print(content) end +end + +local function cycle_action() +	ACTION = next_table_key(ACTIONS, ACTION) +	print_or_update_text_overlay("ACTION: " .. ACTION) +end + +local function cut(start_time, end_time) +	local d = get_data() +	local t = get_times(start_time, end_time) +	for k, v in pairs(t) do d[k] = v end +	mp.msg.info(ACTION) +	mp.msg.info(table_to_str(d)) +	ACTIONS[ACTION](d) +end + +local function put_time() +	local time = mp.get_property_number("time-pos") +	if not START_TIME then +		START_TIME = time +		text_overlay_on() +		return +	end +	text_overlay_off() +	if time > START_TIME then +		cut(START_TIME, time) +		START_TIME = nil +	else +		print("INVALID") +		START_TIME = nil +	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)) +	local outfile = string.format("%s_%s.book", d.channel, d.infile) +	return utils.join_path(d.indir, outfile) +end + +local function bookmarks_load() +	local inpath = get_bookmark_file_path() +	local file = io.open(inpath, "r") +	if not file then return end +	local arr = {} +	for line in file:lines() do +		if tonumber(line) then +			table.insert(arr, { +				time = tonumber(line), +				title = "chapter_" .. line +			}) +		end +	end +	file:close() +	table.sort(arr, function(a, b) return a.time < b.time end) +	mp.set_property_native("chapter-list", arr) +end + +local function bookmark_add() +	local d = get_data() +	local outpath = get_bookmark_file_path() +	local file = io.open(outpath, "a") +	if not file then print("Failed to open bookmark file for writing") return end +	local out_string = mp.get_property_number("time-pos") .. "\n" +	local filesize = file:seek("end") +	file:write(out_string) +	local delta = file:seek("end") - filesize +	io.close(file) +	bookmarks_load() +	print(string.format("Δ %s, %s", delta, d.channel)) +end + +local function channel_inc() +	CHANNEL = CHANNEL + 1 +	bookmarks_load() +	print_or_update_text_overlay(get_current_channel_name()) +end + +local function channel_dec() +	if CHANNEL >= 2 then CHANNEL = CHANNEL - 1 end +	bookmarks_load() +	print_or_update_text_overlay(get_current_channel_name()) +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.register_event('file-loaded', bookmarks_load) diff --git a/config/common/mpv/scripts/mpv-cut/utils b/config/common/mpv/scripts/mpv-cut/utils new file mode 100644 index 0000000..b64ca8e --- /dev/null +++ b/config/common/mpv/scripts/mpv-cut/utils @@ -0,0 +1,44 @@ +#! /usr/bin/env bash + +mcc() { +	local list=( *.list ) +	if [[ ${#list[@]} -ne 1 ]]; then +		echo "Number of .list files in cwd must be exactly 1, exiting." +		return 1 +	fi +	make_cuts "$list" "$@" +	concat CUT -c copy "CONCAT_${list%.*}" +} + +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%.*}" +	local start_ts_hms +	local end_ts_hms +	shift +	while IFS=: read -r channel_name start_ts end_ts || [[ -n "$channel_name" ]]; do +		if [[ -z "$end_ts" ]]; then continue; fi +		start_ts_hms="$(_mpv_cut_to_hms "$start_ts")" +		end_ts_hms="$(_mpv_cut_to_hms "$end_ts")" +		echo "$channel_name" "$start_ts" "$end_ts" +		ffmpeg -nostdin -ss "$start_ts" -to "$end_ts" -i "$vid" "$@" "CUT_${channel_name}_${vid_noext}_${start_ts_hms}_${end_ts_hms}.${ext}" +	done < "$list" +} + +_mpv_cut_to_hms() { +	local total_seconds="$1" +	local hours=$(( ${total_seconds%.*} / 3600 )) +	local minutes=$(( (${total_seconds%.*} % 3600) / 60 )) +	local seconds=$(( ${total_seconds%.*} % 60 )) +	local ms +	ms=$(printf "%.0f" "$(echo "($total_seconds - ${total_seconds%.*}) * 1000" | bc)") +	printf "%02d-%02d-%02d-%03d\n" $hours $minutes $seconds "$ms" +}  | 
