192 lines
5.3 KiB
Lua
192 lines
5.3 KiB
Lua
-- Source: https://github.com/dexeonify/mpv-config/blob/main/scripts/seek-to.lua
|
|
-- with modifications
|
|
|
|
local assdraw = require 'mp.assdraw'
|
|
local utils = require 'mp.utils'
|
|
local msg = require 'mp.msg'
|
|
local active = false
|
|
local cursor_position = 1
|
|
local time_scale = {60*60*10, 60*60, 60*10, 60, 10, 1, 0.1, 0.01, 0.001}
|
|
|
|
local ass_begin = mp.get_property("osd-ass-cc/0")
|
|
local ass_end = mp.get_property("osd-ass-cc/1")
|
|
|
|
local history = { {} }
|
|
for i = 1, 9 do
|
|
history[1][i] = 0
|
|
end
|
|
local history_position = 1
|
|
|
|
-- timer to redraw periodically the message
|
|
-- to avoid leaving bindings when the seeker disappears for whatever reason
|
|
-- pretty hacky tbh
|
|
local timer = nil
|
|
local timer_duration = 3
|
|
|
|
function show_seeker()
|
|
local prepend_char = {'','',':','',':','','.','',''}
|
|
local str = ''
|
|
for i = 1, 9 do
|
|
str = str .. prepend_char[i]
|
|
if i == cursor_position then
|
|
str = str .. '{\\b1}' .. history[history_position][i] .. '{\\r}'
|
|
else
|
|
str = str .. history[history_position][i]
|
|
end
|
|
end
|
|
mp.osd_message("Seek to: " .. ass_begin .. str .. ass_end, timer_duration)
|
|
end
|
|
|
|
function copy_history_to_last()
|
|
if history_position ~= #history then
|
|
for i = 1, 9 do
|
|
history[#history][i] = history[history_position][i]
|
|
end
|
|
history_position = #history
|
|
end
|
|
end
|
|
|
|
function change_number(i)
|
|
-- can't set above 60 minutes or seconds
|
|
if (cursor_position == 3 or cursor_position == 5) and i >= 6 then
|
|
return
|
|
end
|
|
if history[history_position][cursor_position] ~= i then
|
|
copy_history_to_last()
|
|
history[#history][cursor_position] = i
|
|
end
|
|
shift_cursor(false)
|
|
end
|
|
|
|
function shift_cursor(left)
|
|
if left then
|
|
cursor_position = math.max(1, cursor_position - 1)
|
|
else
|
|
cursor_position = math.min(cursor_position + 1, 9)
|
|
end
|
|
end
|
|
|
|
function current_time_as_sec(time)
|
|
local sec = 0
|
|
for i = 1, 9 do
|
|
sec = sec + time_scale[i] * time[i]
|
|
end
|
|
return sec
|
|
end
|
|
|
|
function time_equal(lhs, rhs)
|
|
for i = 1, 9 do
|
|
if lhs[i] ~= rhs[i] then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
function seek_to()
|
|
copy_history_to_last()
|
|
mp.commandv("osd-bar", "seek", current_time_as_sec(history[history_position]), "absolute")
|
|
--deduplicate consecutive timestamps
|
|
if #history == 1 or not time_equal(history[history_position], history[#history - 1]) then
|
|
history[#history + 1] = {}
|
|
history_position = #history
|
|
end
|
|
for i = 1, 9 do
|
|
history[#history][i] = 0
|
|
end
|
|
end
|
|
|
|
function backspace()
|
|
if history[history_position][cursor_position] ~= 0 then
|
|
copy_history_to_last()
|
|
history[#history][cursor_position] = 0
|
|
end
|
|
shift_cursor(true)
|
|
end
|
|
|
|
function history_move(up)
|
|
if up then
|
|
history_position = math.max(1, history_position - 1)
|
|
else
|
|
history_position = math.min(history_position + 1, #history)
|
|
end
|
|
end
|
|
|
|
local key_mappings = {
|
|
LEFT = function() shift_cursor(true) show_seeker() end,
|
|
RIGHT = function() shift_cursor(false) show_seeker() end,
|
|
UP = function() history_move(true) show_seeker() end,
|
|
DOWN = function() history_move(false) show_seeker() end,
|
|
BS = function() backspace() show_seeker() end,
|
|
ESC = function() set_inactive() end,
|
|
ENTER = function() seek_to() set_inactive() end
|
|
}
|
|
for i = 0, 9 do
|
|
local func = function() change_number(i) show_seeker() end
|
|
key_mappings[string.format("KP%d", i)] = func
|
|
key_mappings[string.format("%d", i)] = func
|
|
end
|
|
|
|
function set_active()
|
|
if not mp.get_property("seekable") then return end
|
|
-- find duration of the video and set cursor position accordingly
|
|
local duration = mp.get_property_number("duration")
|
|
if duration ~= nil then
|
|
for i = 1, 9 do
|
|
if duration > time_scale[i] then
|
|
cursor_position = i
|
|
break
|
|
end
|
|
end
|
|
end
|
|
for key, func in pairs(key_mappings) do
|
|
mp.add_forced_key_binding(key, "seek-to-"..key, func)
|
|
end
|
|
show_seeker()
|
|
timer = mp.add_periodic_timer(timer_duration, show_seeker)
|
|
active = true
|
|
end
|
|
|
|
function set_inactive()
|
|
mp.osd_message("")
|
|
for key, _ in pairs(key_mappings) do
|
|
mp.remove_key_binding("seek-to-"..key)
|
|
end
|
|
timer:kill()
|
|
active = false
|
|
end
|
|
|
|
function paste_timestamp()
|
|
-- get clipboard data
|
|
local clipboard = utils.subprocess({
|
|
args = { "powershell", "-Command", "Get-Clipboard", "-Raw" },
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
capture_stderr = true
|
|
})
|
|
|
|
-- error handling
|
|
if not clipboard.error then
|
|
timestamp = clipboard.stdout
|
|
else
|
|
msg.error("Error getting data from clipboard:")
|
|
msg.error(" stderr: " .. clipboard.stderr)
|
|
msg.error(" stdout: " .. clipboard.stdout)
|
|
return
|
|
end
|
|
|
|
-- find timestamp from clipboard
|
|
match = timestamp:match("%d?%d?:?%d%d:%d%d%.?%d*")
|
|
|
|
-- paste and seek to timestamp
|
|
if match ~= nil then
|
|
mp.osd_message("Timestamp pasted: " .. match)
|
|
mp.commandv("osd-bar", "seek", match, "absolute")
|
|
else
|
|
msg.warn("No pastable timestamp found!")
|
|
end
|
|
end
|
|
|
|
-- keybindings are set in input.conf
|
|
mp.add_key_binding(nil, "toggle-seeker", function() if active then set_inactive() else set_active() end end)
|
|
mp.add_key_binding(nil, "paste-timestamp", paste_timestamp)
|