summary refs log tree commit diff
path: root/dot_config/mpv/scripts/seek-to.lua
blob: e57c200c0c42668c2c9af2f6c7f22ffceaec83a2 (plain)
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
local assdraw = require 'mp.assdraw'
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

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)
    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")
    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 cursor_position ~= 9 or current_time[9] == 0 then
        shift_cursor(true)
    end
    if history[history_position][cursor_position] ~= 0 then
        copy_history_to_last()
        history[#history][cursor_position] = 0
    end
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
    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

mp.add_key_binding(nil, "toggle-seeker", function() if active then set_inactive() else set_active() end end)