-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtrack-list.lua
347 lines (305 loc) · 11.3 KB
/
track-list.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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
--[[
* track-list.lua v.2024-11-11
*
* AUTHORS: dyphire
* License: MIT
* link: https://github.com/dyphire/mpv-scripts
This script implements an interractive track list
Usage: add bindings to input.conf
-- key script-message-to track_list toggle-vidtrack-browser
-- key script-message-to track_list toggle-audtrack-browser
-- key script-message-to track_list toggle-subtrack-browser
-- key script-message-to track_list toggle-secondary-subtrack-browser
This script needs to be used with scroll-list.lua
https://github.com/CogentRedTester/mpv-scroll-list
]]
local mp = require 'mp'
local opts = require("mp.options")
local propNative = mp.get_property_native
local o = {
-- header of the list
-- %cursor% and %total% to be used to display the cursor position and the total number of lists
header = "Track List [%cursor%/%total%]\\N ------------------------------------",
--list ass style overrides inside curly brackets
--these styles will be used for the whole list. so you need to reset them for every line
--read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags
global_style = [[]],
header_style = [[{\q2\fs30\c&00ccff&}]],
list_style = [[{\q2\fs20\c&Hffffff&}]],
wrapper_style = [[{\c&00ccff&\fs16}]],
cursor_style = [[{\c&00ccff&}]],
selected_style = [[{\c&Hfce788&}]],
active_style = [[{\c&H33ff66&}]],
cursor = [[➤\h]],
indent = [[\h\h\h]],
--amount of entries to show before slicing. Optimal value depends on font/video size etc.
num_entries = 16,
--slice long filenames, and how many chars to show
max_title_length = 100,
-- wrap the cursor around the top and bottom of the list
wrap = true,
-- set dynamic keybinds to bind when the list is open
key_move_begin = "HOME",
key_move_end = "END",
key_move_pageup = "PGUP",
key_move_pagedown = "PGDWN",
key_scroll_down = "DOWN WHEEL_DOWN",
key_scroll_up = "UP WHEEL_UP",
key_select_track = "ENTER MBTN_LEFT",
key_reload_track = "F5 MBTN_MID",
key_remove_track = "DEL BS",
key_close_browser = "ESC MBTN_RIGHT",
}
opts.read_options(o)
--adding the source directory to the package path and loading the module
package.path = mp.command_native({"expand-path", "~~/script-modules/?.lua;"}) .. package.path
local list = require "scroll-list"
local list_type = nil
--modifying the list settings
local original_open = list.open
list.header = o.header
list.cursor = o.cursor
list.indent = o.indent
list.wrap = o.wrap
list.num_entries = o.num_entries
list.global_style = o.global_style
list.header_style = o.header_style
list.list_style = o.list_style
list.wrapper_style = o.wrapper_style
list.cursor_style = o.cursor_style
list.selected_style = o.selected_style
--escape header specifies the format
--display the cursor position and the total number of lists in the header
function list:format_header_string(str)
if #list.list > 1 then
str = str:gsub("%%(%a+)%%", { cursor = list.selected - 1, total = #list.list - 1 })
else str = str:gsub("%[.*%]", "") end
return str
end
-- from http://lua-users.org/wiki/LuaUnicode
local UTF8_PATTERN = '[%z\1-\127\194-\244][\128-\191]*'
-- return a substring based on utf8 characters
-- like string.sub, but negative index is not supported
local function utf8_sub(s, i, j)
if i > j then
return s
end
local t = {}
local idx = 1
for char in s:gmatch(UTF8_PATTERN) do
if i <= idx and idx <= j then
local width = #char > 2 and 2 or 1
idx = idx + width
t[#t + 1] = char
end
end
return table.concat(t)
end
local function escape_codec(str)
if not str or str == '' then return '' end
local codec_map = {
mpeg2 = "mpeg2",
dvvideo = "dv",
pcm = "pcm",
pgs = "pgs",
subrip = "srt",
vtt = "vtt",
dvd_sub = "vob",
dvb_sub = "dvb",
dvb_tele = "teletext",
arib = "arib"
}
for key, value in pairs(codec_map) do
if str:find(key) then
return value
end
end
return str
end
local function isTrackSelected(index, type)
local selectedId = propNative("current-tracks/" .. type .. "/id")
return selectedId == index
end
local function isTrackDisabled(index, type)
return (type == "sub2" and isTrackSelected(index, "sub"))
or (type == "sub" and isTrackSelected(index, "sub2"))
end
local function get_track_title(track, type, filename)
local title = track.title or ''
local codec = escape_codec(track.codec)
if track.external and title ~= '' then
local extension = title:match('%.([^%.]+)$')
if filename ~= '' and extension then
title = title:gsub(filename .. '%.?', ''):gsub('%.?([^%.]+)$', '')
end
if track.lang and title:lower() == track.lang:lower() then
title = ''
end
end
local title_clip = utf8_sub(title, 1, o.max_title_length)
if title ~= title_clip then
title = title_clip .. "..."
end
if title == '' then
local name = type:sub(1, 1):upper() .. type:sub(2, #type)
title = string.format('%s %02.f', name, track.id)
end
local hints = {}
local function h(value) hints[#hints + 1] = value end
if codec ~= '' then h(codec) end
if track['demux-h'] then
h(track['demux-w'] and (track['demux-w'] .. 'x' .. track['demux-h'] or track['demux-h'] .. 'p'))
end
if track['demux-fps'] then h(string.format('%.5g fps', track['demux-fps'])) end
if track['audio-channels'] then h(track['audio-channels'] .. ' ch') end
if track['demux-samplerate'] then h(string.format('%.3g kHz', track['demux-samplerate'] / 1000)) end
if track['demux-bitrate'] then h(string.format('%.0f kbps', track['demux-bitrate'] / 1000)) end
if track.lang then title = string.format('%s, %s', title, track.lang) end
if #hints > 0 then title = string.format('%s\t[%s]', title, table.concat(hints, ', ')) end
if track.forced then title = title .. ' Forced' end
if track.external then title = title .. ' External' end
if track.default then title = title .. ' (Default)' end
return list.ass_escape(title)
end
local function updateTrackList(title, type, prop)
list.header = title .. ": " .. o.header
local filename = propNative('filename/no-ext', ''):gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0")
local track_type = type == 'sub2' and 'sub' or type
mp.observe_property("track-list", "native", function(_, track_list)
mp.observe_property(prop, "native", function()
list.list = {}
list.list = {
{
id = nil,
index = nil,
disabled = false,
ass = "○ None"
}
}
if isTrackSelected(nil, type) then
list.selected = 1
list[1].ass = "● None"
list[1].style = o.active_style
end
if not track_list then return end
for _, track in ipairs(track_list) do
if track.type == track_type then
local title = get_track_title(track, type, filename)
local isDisabled = isTrackDisabled(track.id, type)
local listItem = {
id = track.id,
disabled = isDisabled
}
if isTrackSelected(track.id, type) then
list.selected = track.id + 1
listItem.style = o.active_style
listItem.ass = "● " .. title
elseif isDisabled then
listItem.style = [[{\c&Hff6666&}]]
listItem.ass = "○ " .. title
else
listItem.ass = "○ " .. title
end
table.insert(list.list, listItem)
end
end
list:update()
end)
end)
end
local function selectTrack()
local selected = list.list[list.selected]
if selected then
if selected.disabled then return end
if selected.id == nil then selected.id = "no" end
mp.commandv('set', list_prop, selected.id)
end
end
local function reloadTrack()
local selected = list.list[list.selected]
local track_type = list_type == 'sub2' and 'sub' or list_type
if selected then
if selected.id == nil then return end
mp.commandv(track_type .. "-reload", selected.id)
end
end
local function removeTrack()
local selected = list.list[list.selected]
local track_type = list_type == 'sub2' and 'sub' or list_type
if selected then
if selected.id == nil then return end
mp.commandv(track_type .. "-remove", selected.id)
end
end
--dynamic keybinds to bind when the list is open
list.keybinds = {}
local function add_keys(keys, name, fn, flags)
local i = 1
for key in keys:gmatch("%S+") do
table.insert(list.keybinds, { key, name .. i, fn, flags })
i = i + 1
end
end
add_keys(o.key_scroll_down, 'scroll_down', function() list:scroll_down() end, { repeatable = true })
add_keys(o.key_scroll_up, 'scroll_up', function() list:scroll_up() end, { repeatable = true })
add_keys(o.key_move_pageup, 'move_pageup', function() list:move_pageup() end, {})
add_keys(o.key_move_pagedown, 'move_pagedown', function() list:move_pagedown() end, {})
add_keys(o.key_move_begin, 'move_begin', function() list:move_begin() end, {})
add_keys(o.key_move_end, 'move_end', function() list:move_end() end, {})
add_keys(o.key_select_track, 'select_track', selectTrack, {})
add_keys(o.key_reload_track, 'reload_track', reloadTrack, {})
add_keys(o.key_remove_track, 'remove_track', removeTrack, {})
add_keys(o.key_close_browser, 'close_browser', function() list:close() end, {})
function list:open()
video_menu = (list_type == "video")
audio_menu = (list_type == "audio")
sub_menu = (list_type == "sub")
sub2_menu = (list_type == "sub2")
original_open(self)
end
local function toggleListDelayed()
mp.add_timeout(0.1, function()
list:toggle()
end)
end
local function toggleList(type, prop)
list_type = type
list_prop = prop
local function toggleMenu(menu)
if _G[menu] then
_G[menu] = false
else
toggleListDelayed()
end
end
if type == "video" then
toggleMenu("video_menu")
elseif type == "audio" then
toggleMenu("audio_menu")
elseif type == "sub" then
toggleMenu("sub_menu")
elseif type == "sub2" then
toggleMenu("sub2_menu")
end
end
local function openTrackList(title, type, prop)
list:close()
updateTrackList(title, type, prop)
toggleList(type, prop)
end
mp.register_script_message("toggle-vidtrack-browser", function()
openTrackList("Video", "video", "vid")
end)
mp.register_script_message("toggle-audtrack-browser", function()
openTrackList("Audio", "audio", "aid")
end)
mp.register_script_message("toggle-subtrack-browser", function()
openTrackList("Subtitle", "sub", "sid")
end)
mp.register_script_message("toggle-secondary-subtrack-browser", function()
openTrackList("Secondary Subtitle", "sub2", "secondary-sid")
end)
mp.register_event('end-file', function()
list:close()
mp.unobserve_property(updateTrackList)
end)