-
Notifications
You must be signed in to change notification settings - Fork 6
/
seek-to.lua
192 lines (171 loc) · 5.39 KB
/
seek-to.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
-- Original script from https://github.com/occivink/mpv-scripts/blob/master/scripts/seek-to.lua
-- prerequisite: xclip (clipboard CLI interface) installed
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 = { "xclip", "-selection", "clipboard", "-o" },
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)