-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathevafast.lua
313 lines (279 loc) · 11 KB
/
evafast.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
-- evafast.lua
--
-- Much speed.
--
-- Jumps forwards when right arrow is pressed, speeds up when it's held.
-- Inspired by bilibili.com's player. Allows you to have both seeking and fast-forwarding on the same key.
-- Also supports toggling fastforward mode with a keypress.
-- Adjust --input-ar-delay to define when to start fastforwarding.
-- Define --hr-seek if you want accurate seeking.
-- If you just want a nicer fastforward.lua without hybrid key behavior, set seek_distance to 0.
local options = {
-- How far to jump on press, set to 0 to disable seeking and force fastforward
seek_distance = 5,
-- Playback speed modifier, applied once every speed_interval until cap is reached
speed_increase = 0.1,
speed_decrease = 0.1,
-- At what interval to apply speed modifiers
speed_interval = 0.05,
-- Playback speed cap
speed_cap = 2,
-- Playback speed cap when subtitles are displayed, 'no' for same as speed_cap
subs_speed_cap = 1.6,
-- Multiply current speed by modifier before adjustment (exponential speedup)
-- Use much lower values than default e.g. speed_increase=0.05, speed_decrease=0.025
multiply_modifier = false,
-- Show current speed on the osd (or flash speed if using uosc)
show_speed = true,
-- Show current speed on the osd when toggled (or flash speed if using uosc)
show_speed_toggled = true,
-- Show current speed on the osd when speeding up towards a target time (or flash speed if using uosc)
show_speed_target = false,
-- Show seek actions on the osd (or flash timeline if using uosc)
show_seek = true,
-- Look ahead for smoother transition when subs_speed_cap is set
lookahead = false
}
mp.options = require "mp.options"
mp.options.read_options(options, "evafast")
local uosc_available = false
local repeated = false
local speed_timer = nil
local speedup = true
local no_speedup = false
local jumps_reset_speed = true
local toggle_display = false
local toggle_state = false
local freeze = false
local forced_speed_cap = nil
local use_forced_speed_cap = false
local speedup_target = nil
local function speed_transition(test_speed, target)
local time_for_correction = 0
if not freeze then
while test_speed ~= target do
time_for_correction = time_for_correction + options.speed_interval
if test_speed <= target then
if options.multiply_modifier then
test_speed = math.min(test_speed + (test_speed * options.speed_increase), target)
else
test_speed = math.min(test_speed + options.speed_increase, target)
end
else
if options.multiply_modifier then
test_speed = math.max(test_speed - (test_speed * options.speed_decrease), 1)
else
test_speed = math.max(test_speed - options.speed_decrease, 1)
end
end
if test_speed == 1 then break end
end
end
return time_for_correction
end
local function adjust_speed()
local no_sub_speed = not options.subs_speed_cap or mp.get_property("sub-start") == nil
local effective_speed_cap = no_sub_speed and options.speed_cap or options.subs_speed_cap
local speed = mp.get_property_number("speed", 1)
local old_speed = speed
if options.lookahead and options.subs_speed_cap and no_sub_speed and not use_forced_speed_cap then
local sub_delay = mp.get_property_native("sub-delay")
local sub_visible = mp.get_property_bool("sub-visibility")
if sub_visible then
mp.set_property_bool("sub-visibility", false)
end
mp.command("no-osd sub-step 1")
local sub_next_delay = mp.get_property_native("sub-delay")
local sub_next = sub_delay - sub_next_delay
mp.set_property("sub-delay", sub_delay)
if sub_visible then
mp.set_property_bool("sub-visibility", sub_visible)
end
-- calculate how long it takes to get from current speed to target speed, and use that as threshold for sub_next
local time_for_correction = speed_transition(speed, options.subs_speed_cap)
if sub_next ~= 0 and sub_next <= (time_for_correction * speed) then
effective_speed_cap = options.subs_speed_cap
use_forced_speed_cap = true
forced_speed_cap = effective_speed_cap
end
end
if speedup_target ~= nil then
local current_time = mp.get_property_number("time-pos", 0)
if current_time >= speedup_target then
jumps_reset_speed = true
no_speedup = true
repeated = false
freeze = false
else
local time_for_correction = speed_transition(speed, math.max(math.min(options.speed_cap, options.subs_speed_cap and options.subs_speed_cap or options.speed_cap), 1.1)) -- not effective_speed_cap because it may lead to huge fluctuations in transition speed
if (time_for_correction * speed + current_time) > speedup_target then
effective_speed_cap = 1.1 -- >1 so we don't get stuck trying to catch the target
use_forced_speed_cap = true
forced_speed_cap = effective_speed_cap
else
forced_speed_cap = nil
use_forced_speed_cap = false
end
end
end
if not freeze then
if forced_speed_cap ~= nil then
if speed ~= forced_speed_cap or mp.get_property_bool("pause") then
use_forced_speed_cap = true
end
effective_speed_cap = forced_speed_cap
end
if speedup and not no_speedup and speed <= effective_speed_cap then
if options.multiply_modifier then
speed = math.min(speed + (speed * options.speed_increase), effective_speed_cap)
else
speed = math.min(speed + options.speed_increase, effective_speed_cap)
end
else
if options.multiply_modifier then
speed = math.max(speed - (speed * options.speed_decrease), 1)
else
speed = math.max(speed - options.speed_decrease, 1)
end
end
if forced_speed_cap ~= nil and not use_forced_speed_cap then
forced_speed_cap = nil
end
if speed == options.subs_speed_cap then
if use_forced_speed_cap then
use_forced_speed_cap = false
end
end
end
if speed ~= old_speed then
mp.set_property("speed", speed)
if (options.show_speed and not toggle_display) or (options.show_speed_toggled and toggle_display and speedup_target == nil) or (options.show_speed_target and speedup_target ~= nil) then
if uosc_available then
mp.command("script-binding uosc/flash-speed")
else
mp.osd_message(("▶▶ x%.1f"):format(speed))
end
end
end
if speed == 1 and effective_speed_cap ~= 1 then
if speed_timer ~= nil and not toggle_state then
speed_timer:kill()
speed_timer = nil
end
repeated = false
jumps_reset_speed = true
toggle_display = false
toggle_state = false
speedup_target = nil
elseif speed_timer == nil then
speed_timer = mp.add_periodic_timer(options.speed_interval, adjust_speed)
end
end
local function evafast(keypress)
if jumps_reset_speed and not toggle_state and (keypress["event"] == "up" or keypress["event"] == "press") then
speedup = false
speedup_target = nil
end
if options.seek_distance == 0 then
if keypress["event"] == "up" or keypress["event"] == "press" then
speedup = false
no_speedup = true
repeated = false
speedup_target = nil
end
if keypress["event"] == "down" then
keypress["event"] = "repeat"
end
end
if keypress["event"] == "up" or keypress["event"] == "press" then
toggle_display = toggle_state
if toggle_state and jumps_reset_speed then
speedup = false
speedup_target = nil
end
if speed_timer ~= nil and not toggle_state and mp.get_property_number("speed") == 1 and ((not options.subs_speed_cap or mp.get_property("sub-start") == nil) and options.speed_cap or options.subs_speed_cap) ~= 1 then
speed_timer:kill()
speed_timer = nil
jumps_reset_speed = true
toggle_display = false
toggle_state = false
speedup_target = nil
end
freeze = false
end
if keypress["event"] == "down" then
repeated = false
speedup = true
freeze = true
toggle_display = false
if options.show_seek and not repeated and not uosc_available then
mp.osd_message("▶▶")
end
elseif (keypress["event"] == "up" and (not repeated or speedup_target)) or keypress["event"] == "press" then
if options.seek_distance ~= 0 then
mp.commandv("seek", options.seek_distance)
if options.show_seek and uosc_available then
mp.command("script-binding uosc/flash-timeline")
end
end
repeated = false
if jumps_reset_speed and not toggle_state then
no_speedup = true
end
elseif keypress["event"] == "repeat" then
freeze = false
speedup = true
no_speedup = false
if not repeated then
adjust_speed()
end
repeated = true
end
end
local function evafast_speedup()
no_speedup = false
speedup = true
jumps_reset_speed = false
toggle_display = true
toggle_state = true
evafast({event = "repeat"})
end
local function evafast_slowdown()
jumps_reset_speed = true
no_speedup = true
repeated = false
freeze = false
speedup_target = nil
end
local function evafast_toggle()
if (repeated or not jumps_reset_speed) and speedup then
evafast_slowdown()
else
evafast_speedup()
end
end
mp.register_script_message("uosc-version", function(version)
uosc_available = true
end)
mp.register_script_message("speedup-target", function(time)
time = tonumber(time) or 0
if mp.get_property_number("time-pos", 0) >= time then
if speedup_target ~= nil then
use_forced_speed_cap = false
forced_speed_cap = nil
speedup_target = nil
evafast_slowdown()
end
return
end
speedup_target = time
evafast_speedup()
end)
mp.register_script_message("get-version", function(script)
mp.commandv("script-message-to", script, "evafast-version", "1.0")
end)
mp.add_key_binding("RIGHT", "evafast", evafast, {repeatable = true, complex = true})
mp.add_key_binding(nil, "speedup", evafast_speedup)
mp.add_key_binding(nil, "slowdown", evafast_slowdown)
mp.add_key_binding(nil, "toggle", evafast_toggle)
mp.commandv("script-message-to", "uosc", "get-version", mp.get_script_name())