-
Notifications
You must be signed in to change notification settings - Fork 12
/
osc_tethys.lua
5545 lines (4704 loc) · 195 KB
/
osc_tethys.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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
-- Windows: C:\Users\USER\AppData\Roaming\mpv\script-opts\tethys.conf
-- Linux: ~/config/mpv/script-opts/tethys.conf
local tethys = {
-- Config
showPictureInPictureButton = true,
showSpeedButton = true,
showShortcutTooltip = true, -- Show name and shortcut of buttons on hover
showChapterTooltip = true, -- Show chapter above timestamp in seekbar tooltip
skipBy = 5, -- skipback/skipfrwd amount in seconds
skipByMore = 30, -- RightClick skipback/skipfrwd amount in seconds
skipMode = "exact", -- "exact" (mordenx default) or "relative+keyframes" (mpv default)
pipGeometry = "33%+-10+-10", -- PictureInPicture 33% screen width, 10px from bottom right
pipAllWorkspaces = true, -- PictureInPicture will show video on all virtual desktops
-- Sizes
thumbnailSize = 256, -- 16:9 = 256x144
seekbarHeight = 20,
controlsHeight = 64,
smallButtonSize = 42, -- controlsHeight * 2/3
trackButtonSize = 36, -- controlsHeight / 2
buttonTooltipSize = 20,
windowBarHeight = 44,
windowButtonSize = 44,
windowTitleSize = 24,
cacheTextSize = 20,
timecodeSize = 27,
seekbarTimestampSize = 30,
seekbarTimestampOutline = 1,
chapterTickSize = 6,
windowTitleOutline = 1,
-- Misc
osdSymbolFont = "mpv-osd-symbols", -- Seems to be hardcoded and unchangeable
-- Colors (uses GGBBRR for some reason)
-- Alpha ranges 0 (opaque) .. 255 (transparent)
textColor = "FFFFFF",
buttonColor = "CCCCCC",
buttonHoveredColor = "FFFFFF",
buttonHoveredRectColor = "000000",
buttonHoveredRectAlpha = 255, -- Easily debug button geometry by setting to 80
tooltipColor = "CCCCCC",
windowBarColor = "000000",
windowBarAlpha = 255, -- (80 is mpv default) (255 morden default)
windowButtonColor = "CCCCCC",
closeButtonHoveredColor = "1111DD", -- #DD1111
seekbarHandleColor = "FFFFFF",
seekbarFgColor = "483DD7", -- #d73d48
seekbarBgColor = "929292",
seekbarCacheColor = "000000",
seekbarCacheAlpha = 128,
chapterTickColor = "CCCCCC",
}
read_options(tethys, "tethys")
local function parseColor(color)
if string.find(color, "#") then
local colorU = string.upper(color)
local r = string.sub(colorU, 2, 3)
local g = string.sub(colorU, 4, 5)
local b = string.sub(colorU, 6, 7)
return b..g..r
else
return color
end
end
local function parseConfig(configTable)
for k,v in pairs(configTable) do
if string.find(k, "Color") then
configTable[k] = parseColor(v)
end
end
end
parseConfig(tethys)
tethys.bottomBarHeight = tethys.seekbarHeight + tethys.controlsHeight
tethys.buttonW = tethys.controlsHeight
tethys.buttonH = tethys.controlsHeight
tethys.smallButtonSize = math.min(tethys.controlsHeight, tethys.smallButtonSize)
tethys.trackButtonSize = math.min(tethys.controlsHeight, tethys.trackButtonSize)
tethys.windowButtonSize = math.min(tethys.windowBarHeight, tethys.windowButtonSize)
tethys.windowControlsRect = {
w = tethys.windowButtonSize * 3,
h = tethys.windowBarHeight,
}
tethys.trackTextScale = 105
-- [1] Foreground, [2] Karaoki Foreground, [3] Border, [4] Shadow
-- https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index22h3
tethys.windowBarAlphaTable = {[1] = tethys.windowBarAlpha, [2] = 255, [3] = 255, [4] = 255}
tethys.seekbarCacheAlphaTable = {[1] = tethys.seekbarCacheAlpha, [2] = 255, [3] = 255, [4] = 255}
tethys.tooltipAlphaTable = {[1] = 0, [2] = 255, [3] = 88, [4] = 255} -- Opache Text, 65% opacity outlines
tethys.showButtonHoveredRect = tethys.buttonHoveredRectAlpha < 255 -- Note: 255=transparent
tethys.isPictureInPicture = false
tethys.pipWasFullscreen = false
tethys.pipWasMaximized = false
tethys.pipWasOnTop = false
tethys.pipHadBorders = false
tethys.userdataAvail = (function()
local list = mp.get_property_native("property-list")
for k,v in ipairs(list) do
if (v == "user-data") then
return true
end
end
return false
end)()
-- https://github.com/libass/libass/wiki/ASSv5-Override-Tags#color-and-alpha---c-o
function genColorStyle(color)
return "{\\c&H"..color.."&}" -- Not sure why &H...& is used in santa_hat_lines
-- return "{\\c("..color..")}" -- Works
-- return "{\\c(#"..color..")}" -- Only works for paths, and breaks other stuff.
end
---- mpv's stats.lua has some ASS formatting
-- https://aegi.vmoe.info/docs/3.0/ASS_Tags/
-- https://github.com/libass/libass/wiki/ASSv5-Override-Tags
-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L62
-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L176
-- "{\\r}{\\an7}{\\fs%d}{\\fn%s}{\\bord%f}{\\3c&H%s&}{\\1c&H%s&}{\\alpha&H%s&}{\\xshad%f}{\\yshad%f}{\\4c&H%s&}"
-- {\\bord%f} = border size
-- {\\3c&H%s&} = border color
-- {\\1c&H%s&} = font color
-- {\\alpha&H%s&} = alpha
-- {\\xshad%f}{\\yshad%f} = shadow x,y offset
-- {\\4c&H%s&} = shadow color
-- {\\b(400)} = font weight, 400=normal, 700=bold
---- \\q2 in windowTitle is unknown
---- Not sure why \1c is rect fill color. Here's docs for \3c:
-- https://github.com/libass/libass/wiki/Libass'-ASS-Extensions#borderstyle4
-- "{\\1c&H"..color.."}"
local tethysStyle = {
button = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.buttonH, tethys.osdSymbolFont),
buttonHovered = genColorStyle(tethys.buttonHoveredColor),
buttonHoveredRect = ("{\\rDefault\\blur0\\bord0\\1c&H%s\\1a&H%X&}"):format(tethys.buttonHoveredRectColor, tethys.buttonHoveredRectAlpha),
smallButton = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.smallButtonSize, tethys.osdSymbolFont),
trackButton = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.trackButtonSize, tethys.osdSymbolFont),
trackText = ("{\\fscx%s\\fscy%s\\fn(%s)}"):format(tethys.trackTextScale, tethys.trackTextScale, mp.get_property("options/osd-font")),
windowBar = ("{\\1c&H%s}"):format(tethys.windowBarColor),
windowButton = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)\\fn(%s)}"):format(tethys.windowTitleOutline, tethys.windowButtonColor, tethys.windowButtonSize, tethys.osdSymbolFont),
closeButtonHovered = genColorStyle(tethys.closeButtonHoveredColor),
windowTitle = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.windowTitleOutline, tethys.textColor, tethys.windowTitleSize),
buttonTooltip = ("{\\blur0\\bord(1)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.tooltipColor, tethys.buttonTooltipSize),
buttonKeybindFormat = ("{\\bord(3)\\b(700)} %s {\\bord(1)\\b(400)}"), -- Spaces around the key to accound for thick outlines
timecode = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.textColor, tethys.timecodeSize),
cacheText = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.textColor, tethys.cacheTextSize, tethys.osdSymbolFont),
seekbar = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.seekbarFgColor, tethys.seekbarHeight),
seekbarTimestamp = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.seekbarTimestampOutline, tethys.textColor, tethys.seekbarTimestampSize),
text = genColorStyle(tethys.textColor),
seekbarHandle = genColorStyle(tethys.seekbarHandleColor),
seekbarFg = genColorStyle(tethys.seekbarFgColor),
seekbarBg = genColorStyle(tethys.seekbarBgColor),
seekbarCache = genColorStyle(tethys.seekbarCacheColor),
chapterTick = genColorStyle(tethys.chapterTickColor),
}
---- Icons
-- 44x44
local tethysIcon_play = "{\\p1}m 0 0 m 44 44 m 37.236218 17.599999 b 41.584084 20.610064 41.584084 21.923269 37.236218 24.933333 b 22.516553 35.123867 9.369549 44 6.436216 44 b 3.502883 44 3.502883 39.6 3.502883 21.266665 b 3.502883 4.4 3.502883 0 6.436216 0 b 9.369549 0 22.516553 7.409462 37.236218 17.599999{\\p0}"
local tethysIcon_pause = "{\\p1}m 0 0 m 44 44 m 17.5 40.2064 b 17.5 45.263808 4.5 45.263808 4.5 40.2107 l 4.5 3.793057 b 4.5 -1.264352 17.5 -1.264352 17.5 3.793057 m 39.5 40.2064 b 39.5 45.263808 26.5 45.263808 26.5 40.2107 l 26.5 3.793057 b 26.5 -1.264352 39.5 -1.264352 39.5 3.793057{\\p0}"
local mpvOsdIcon_close = "{\\p1}m 0 0 m 44 44 m 34 34 l 30.571428 34 l 22 25.535715 l 13.535714 34 l 10 34 l 10 30.571428 l 18.464286 22 l 10 13.535714 l 10 10 l 13.535714 10 l 22 18.464286 l 30.571428 10 l 34 10 l 34 13.535714 l 25.535715 22 l 34 30.464285{\\p0}"
local mpvOsdIcon_maximize = "{\\p1}m 0 0 m 44 44 m 34 33 l 10 33 l 10 11 l 34 11 m 32 31 l 32 15 l 12 15 l 12 31{\\p0}"
local mpvOsdIcon_minimize = "{\\p1}m 0 0 m 44 44 m 34 25 l 10 25 l 10 19 l 34 19{\\p0}"
local mpvOsdIcon_restore = "{\\p1}m 0 0 m 44 44 m 34 25 l 27.999999 25 l 27.999999 33 l 10 33 l 10 18.999999 l 16 18.999999 l 16 11 l 34 11 m 32 23.000001 l 32 15 l 18 15 l 18 18.999999 l 27.999999 18.999999 l 27.999999 23.000001 m 26 31 l 26 23.000001 l 12 23.000001 l 12 31{\\p0}"
-- 32x28
local mpvOsdIcon_fs_enter = "{\\p1}m 0 0 m 32 28 m 0 23.454546 l 0 4.545454 b 0 3.454545 1.090909 2.363636 2.181818 2.363636 l 29.818182 2.363636 b 30.90909 2.363636 32 3.454545 32 4.545454 l 32 23.454546 b 32 24.545456 30.90909 25.636364 29.818182 25.636364 l 2.181818 25.636364 b 1.090909 25.636364 0 24.545456 0 23.454546 m 2.181818 23.454546 l 29.818182 23.454546 l 29.818182 4.545454 l 2.181818 4.545454 m 21.090909 6.727272 l 27.636363 6.727272 l 27.636363 13.272728 m 22.036363 11.09091 l 22.036363 16.872726 l 9.963636 16.872726 l 9.963636 11.09091 m 10.909091 21.272728 l 4.363636 21.272728 l 4.363636 14.727272{\\p0}"
local mpvOsdIcon_fs_exit = "{\\p1}m 0 0 m 32 28 m 0 23.454546 l 0 4.545454 b 0 3.454545 1.090909 2.363636 2.181818 2.363636 l 29.818182 2.363636 b 30.909091 2.363636 32 3.454545 32 4.545454 l 32 23.454546 b 32 24.545454 30.909091 25.636364 29.818182 25.636364 l 2.181818 25.636364 b 1.090909 25.636364 0 24.545454 0 23.454546 m 2.181818 23.454546 l 29.818182 23.454546 l 29.818182 4.545454 l 2.181818 4.545454 m 8.254546 14.000001 l 4.363636 18 l 4.363636 10 m 27.636364 18 l 23.745455 14.000001 l 27.636364 10 m 21.636364 10.181818 l 21.636364 17.781818 l 10.363636 17.781818 l 10.363636 10.181818{\\p0}"
-- 28x28
local tethysIcon_ch_prev = "{\\p1}m 0 0 m 28 28 m 15.555834 12.5 b 14.073607 13.526159 14.073607 13.973842 15.555834 15.000001 b 20.573903 18.474048 25.055836 21.5 26.055836 21.5 b 27.055835 21.5 27.055835 20.000001 27.055835 13.75 b 27.055835 8.000001 27.055835 6.5 26.055836 6.5 b 25.055836 6.5 20.573903 9.025952 15.555834 12.5 m 2.055835 12.5 b 0.573608 13.526159 0.573608 13.973842 2.055835 15.000001 b 7.073904 18.474048 11.555837 21.5 12.555836 21.5 b 13.555836 21.5 13.555836 20.000001 13.555836 13.75 b 13.555836 8.000001 13.555836 6.5 12.555836 6.5 b 11.555837 6.5 7.073904 9.025952 2.055835 12.5{\\p0}"
local tethysIcon_ch_next = "{\\p1}m 0 0 m 28 28 m 12.444166 12.5 b 13.926393 13.526159 13.926393 13.973842 12.444166 15.000001 b 7.426097 18.474048 2.944164 21.5 1.944165 21.5 b 0.944165 21.5 0.944165 20.000001 0.944165 13.75 b 0.944165 8.000001 0.944165 6.5 1.944165 6.5 b 2.944164 6.5 7.426097 9.025952 12.444166 12.5 m 25.944165 12.5 b 27.426392 13.526159 27.426392 13.973842 25.944165 15.000001 b 20.926096 18.474048 16.444163 21.5 15.444164 21.5 b 14.444164 21.5 14.444164 20.000001 14.444164 13.75 b 14.444164 8.000001 14.444164 6.5 15.444164 6.5 b 16.444163 6.5 20.926096 9.025952 25.944165 12.5{\\p0}"
local tethysIcon_pip_enter = "{\\p1}m 0 0 m 28 28 m 14 16 l 22 16 l 22 21 l 14 21 m 2 5 b 2 5 2 22 2 23 b 2 24 3 25 4 25 b 5 25 24 25 24 25 b 25 25 26 24 26 23 l 26 5 b 26 4 25 3 24 3 l 4 3 b 3 3 2 4 2 5 m 4 5 l 24 5 l 24 23 l 4 23{\\p0}"
local tethysIcon_pip_exit = "{\\p1}m 0 0 m 28 28 m 14 3 l 14 5 l 24 5 l 24 23 l 4 23 l 4 16 l 2 16 l 2 23 b 2 24 3 25 4 25 l 24 25 b 25 25 26 24 26 23 l 26 5 b 26 4 25 3 24 3 m 2 3 l 2 12 l 4 12 l 4 7 l 18 20 l 20 18 l 6 5 l 11 5 l 11 3{\\p0}"
local tethysIcon_pl_prev = "{\\p1}m 0 0 m 28 28 m 10.133332 11.8 b 7.959399 13.305034 7.959399 13.961635 10.133332 15.466668 b 17.493166 20.561937 24.066668 25 25.533334 25 b 27 25 27 22.800002 27 13.633333 b 27 5.200001 27 3 25.533334 3 b 24.066668 3 17.493166 6.70473 10.133332 11.8 m 1 23.103196 b 1 25.631901 7.574631 25.631901 7.574631 23.105396 l 7.574631 4.896528 b 7.574631 2.367824 1 2.367824 1 4.896528{\\p0}"
local tethysIcon_pl_next = "{\\p1}m 0 0 m 28 28 m 17.866668 11.8 b 20.040601 13.305034 20.040601 13.961635 17.866668 15.466668 b 10.506834 20.561937 3.933332 25 2.466666 25 b 1 25 1 22.800002 1 13.633333 b 1 5.200001 1 3 2.466666 3 b 3.933332 3 10.506834 6.70473 17.866668 11.8 m 27 23.103196 b 27 25.631901 20.425369 25.631901 20.425369 23.105396 l 20.425369 4.896528 b 20.425369 2.367824 27 2.367824 27 4.896528{\\p0}"
local tethysIcon_skipback = "{\\p1}m 0 0 m 28 28 m 2.511898 -0 l 2.511898 9.57764 l 12.089539 9.57764 l 12.089539 6.385093 l 8.163287 6.385093 b 11.540598 3.999689 16.093522 3.879191 19.632345 6.243757 b 23.661324 8.935835 25.219633 14.07368 23.365296 18.550442 b 21.510961 23.027205 16.775533 25.558703 12.023026 24.613371 b 7.27052 23.668038 3.864989 19.515531 3.864989 14.669918 l 0.672442 14.669918 b 0.672442 21.018992 5.172403 26.50492 11.399482 27.743563 b 17.626561 28.982206 23.884976 25.638369 26.314661 19.772589 b 28.744346 13.906809 26.684352 7.114815 21.40529 3.587458 b 18.765759 1.82378 15.680838 1.117147 12.694376 1.411288 b 10.187051 1.658238 7.750413 2.61433 5.704444 4.242179 l 5.704444 -0{\\p0}"
local tethysIcon_skipfrwd = "{\\p1}m 0 0 m 28 28 m 25.488102 -0 l 25.488102 9.57764 l 15.910461 9.57764 l 15.910461 6.385093 l 19.836712 6.385093 b 16.459402 3.999689 11.906478 3.879191 8.367655 6.243757 b 4.338676 8.935835 2.780367 14.07368 4.634704 18.550442 b 6.489039 23.027205 11.224467 25.558703 15.976974 24.613371 b 20.729479 23.668038 24.135011 19.515531 24.135011 14.669918 l 27.327558 14.669918 b 27.327558 21.018992 22.827597 26.50492 16.600518 27.743563 b 10.373439 28.982206 4.115024 25.638369 1.685339 19.772589 b -0.744346 13.906809 1.315648 7.114815 6.59471 3.587458 b 9.234241 1.82378 12.319162 1.117147 15.305624 1.411288 b 17.812949 1.658238 20.249586 2.61433 22.295555 4.242179 l 22.295555 -0{\\p0}"
local tethysIcon_speed = "{\\p1}m 0 0 m 28 28 m 14 2.053711 b 10.414212 2.053711 6.827634 3.417483 4.099609 6.145508 b -1.35644 11.601557 -1.35644 20.490239 4.099609 25.946289 l 6.017578 24.02832 b 1.597151 19.607893 1.597151 12.483903 6.017578 8.063476 b 10.438006 3.64305 17.561994 3.64305 21.982422 8.063476 b 26.402849 12.483903 26.402849 19.607893 21.982422 24.02832 l 23.900391 25.946289 b 29.35644 20.490239 29.35644 11.601557 23.900391 6.145508 b 21.172366 3.417483 17.585788 2.053711 14 2.053711 m 17.886719 10.034179 l 14.351562 13.571289 b 14.235118 13.554564 14.117639 13.54608 14 13.545898 b 13.336959 13.545898 12.701074 13.80929 12.232233 14.278131 b 11.763392 14.746972 11.5 15.382857 11.5 16.045898 b 11.5 17.42661 12.619288 18.545898 14 18.545898 b 14.663041 18.545898 15.298926 18.282506 15.767767 17.813665 b 16.236608 17.344824 16.5 16.708939 16.5 16.045898 b 16.499911 15.927607 16.491426 15.809472 16.47461 15.692382 l 20.009767 12.155273{\\p0}"
local tethysIcon_vol_033 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}"
local tethysIcon_vol_066 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}"
local tethysIcon_vol_100 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 23.532835 3.779296 l 21.294544 6.017587 b 22.97216 7.695202 24.35259 10.812999 24.344937 13.990067 b 24.337337 17.167135 22.938039 20.301821 21.257445 21.982413 l 23.499858 24.220704 b 26.040275 21.680287 27.501508 17.812486 27.510697 13.99831 b 27.519997 10.184133 26.076229 6.322689 23.532835 3.779296 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}"
local tethysIcon_vol_101 = "{\\p1}m 0 0 m 28 28 m 26.774083 5.201582 l 25.69218 18.248063 b 25.66035 18.693555 25.533063 18.916303 25.31033 18.916303 b 25.08759 18.916303 24.960302 18.693563 24.928482 18.248063 l 23.878399 5.201582 l 23.878399 5.074292 b 23.878399 4.660623 24.005689 4.342418 24.292068 4.119669 b 24.578454 3.865105 24.928482 3.737822 25.31033 3.737822 b 25.724 3.737822 26.042205 3.865111 26.328594 4.119669 b 26.614979 4.342409 26.774083 4.660623 26.774083 5.074292 m 26.774083 22.734783 b 26.774083 23.180275 26.614991 23.530301 26.360414 23.816689 b 26.074028 24.134895 25.724 24.262178 25.31033 24.262178 b 24.928482 24.262178 24.578454 24.134888 24.292068 23.816689 b 24.005682 23.530301 23.878399 23.180275 23.878399 22.734783 b 23.878399 22.321115 24.005689 21.971087 24.292068 21.684702 b 24.578454 21.366494 24.928482 21.239213 25.31033 21.239213 b 25.724 21.239213 26.074028 21.366487 26.360414 21.684702 b 26.614979 21.971087 26.774083 22.321115 26.774083 22.734783 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}"
local tethysIcon_vol_mute = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 26.699268 7.480125 b 26.905593 7.480125 27.111919 7.52139 27.276978 7.68645 b 27.607099 8.01657 27.607099 8.51175 27.276978 8.841871 l 22.077583 14.041265 l 27.276978 19.240659 b 27.565833 19.529515 27.565833 19.98343 27.276978 20.31355 b 26.988123 20.602406 26.492943 20.602406 26.204087 20.31355 l 21.004692 15.114157 l 15.805297 20.31355 b 15.516442 20.602406 14.979997 20.602406 14.691142 20.31355 b 14.361021 19.98343 14.361021 19.48825 14.691142 19.158129 l 19.849271 13.958735 l 14.649877 8.759341 b 14.361021 8.470485 14.361021 8.01657 14.649877 7.68645 b 14.979997 7.397594 15.433912 7.397594 15.764033 7.68645 l 20.963428 12.885844 l 26.162823 7.68645 b 26.286617 7.52139 26.492943 7.480125 26.699268 7.480125{\\p0}"
function scaleIcon(iconStr, iconScale)
-- Match space before number to ignore {\p1} and {\p0}
return iconStr:gsub(" ([%d%.]+)", function(numStr)
local num = tonumber(numStr)
num = num * iconScale
return " " .. tostring(num)
end)
end
local iconScale = tethys.controlsHeight / 64
if iconScale ~= 1 then
tethysIcon_play = scaleIcon(tethysIcon_play, iconScale)
tethysIcon_pause = scaleIcon(tethysIcon_pause, iconScale)
end
iconScale = tethys.windowButtonSize / 44
if iconScale ~= 1 then
mpvOsdIcon_close = scaleIcon(mpvOsdIcon_close, iconScale)
mpvOsdIcon_maximize = scaleIcon(mpvOsdIcon_maximize, iconScale)
mpvOsdIcon_minimize = scaleIcon(mpvOsdIcon_minimize, iconScale)
mpvOsdIcon_restore = scaleIcon(mpvOsdIcon_restore, iconScale)
end
iconScale = tethys.smallButtonSize / 42
if iconScale ~= 1 then
mpvOsdIcon_fs_enter = scaleIcon(mpvOsdIcon_fs_enter, iconScale)
mpvOsdIcon_fs_exit = scaleIcon(mpvOsdIcon_fs_exit, iconScale)
tethysIcon_ch_prev = scaleIcon(tethysIcon_ch_prev, iconScale)
tethysIcon_ch_next = scaleIcon(tethysIcon_ch_next, iconScale)
tethysIcon_pip_enter = scaleIcon(tethysIcon_pip_enter, iconScale)
tethysIcon_pip_exit = scaleIcon(tethysIcon_pip_exit, iconScale)
tethysIcon_pl_prev = scaleIcon(tethysIcon_pl_prev, iconScale)
tethysIcon_pl_next = scaleIcon(tethysIcon_pl_next, iconScale)
tethysIcon_skipback = scaleIcon(tethysIcon_skipback, iconScale)
tethysIcon_skipfrwd = scaleIcon(tethysIcon_skipfrwd, iconScale)
tethysIcon_speed = scaleIcon(tethysIcon_speed, iconScale)
tethysIcon_vol_033 = scaleIcon(tethysIcon_vol_033, iconScale)
tethysIcon_vol_066 = scaleIcon(tethysIcon_vol_066, iconScale)
tethysIcon_vol_100 = scaleIcon(tethysIcon_vol_100, iconScale)
tethysIcon_vol_101 = scaleIcon(tethysIcon_vol_101, iconScale)
tethysIcon_vol_mute = scaleIcon(tethysIcon_vol_mute, iconScale)
end
--
-- Parameters
--
-- default user option values
-- do not touch, change them in osc.conf
local user_opts = {
showwindowed = true, -- show OSC when windowed?
showfullscreen = true, -- show OSC when fullscreen?
idlescreen = true, -- show mpv logo on idle
scalewindowed = 1, -- scaling of the controller when windowed
scalefullscreen = 1, -- scaling of the controller when fullscreen
scaleforcedwindow = 2, -- scaling when rendered on a forced window
vidscale = true, -- scale the controller with the video?
valign = 0.8, -- vertical alignment, -1 (top) to 1 (bottom)
halign = 0, -- horizontal alignment, -1 (left) to 1 (right)
barmargin = 0, -- vertical margin of top/bottombar
boxalpha = 80, -- alpha of the background box,
-- 0 (opaque) to 255 (fully transparent)
hidetimeout = 500, -- duration in ms until the OSC hides if no
-- mouse movement. enforced non-negative for the
-- user, but internally negative is "always-on".
fadeduration = 200, -- duration of fade out in ms, 0 = no fade
deadzonesize = 0.5, -- size of deadzone
minmousemove = 0, -- minimum amount of pixels the mouse has to
-- move between ticks to make the OSC show up
iamaprogrammer = false, -- use native mpv values and disable OSC
-- internal track list management (and some
-- functions that depend on it)
-- layout = "bottombar",
layout = "tethys",
seekbarstyle = "bar", -- bar, diamond or knob
seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle
seekrangestyle = "inverted",-- bar, line, slider, inverted or none
seekrangeseparate = true, -- whether the seekranges overlay on the bar-style seekbar
seekrangealpha = 200, -- transparency of seekranges
seekbarkeyframes = true, -- use keyframes when dragging the seekbar
title = "${media-title}", -- string compatible with property-expansion
-- to be shown as OSC title
tooltipborder = 1, -- border of tooltip in bottom/topbar
timetotal = false, -- display total time instead of remaining time?
timems = false, -- display timecodes with milliseconds?
tcspace = 100, -- timecode spacing (compensate font size estimation)
visibility = "auto", -- only used at init to set visibility_mode(...)
-- visibility = "always", -- only used at init to set visibility_mode(...)
boxmaxchars = 80, -- title crop threshold for box layout
boxvideo = false, -- apply osc_param.video_margins to video
windowcontrols = "auto", -- whether to show window controls
windowcontrols_alignment = "right", -- which side to show window controls on
greenandgrumpy = false, -- disable santa hat
livemarkers = true, -- update seekbar chapter markers on duration change
chapters_osd = true, -- whether to show chapters OSD on next/prev
playlist_osd = true, -- whether to show playlist OSD on next/prev
chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable
unicodeminus = false, -- whether to use the Unicode minus sign character
}
-- read options from config and command-line
opt.read_options(user_opts, "osc", function(list) update_options(list) end)
local osc_param = { -- calculated by osc_init()
playresy = 0, -- canvas size Y
playresx = 0, -- canvas size X
display_aspect = 1,
unscaled_y = 0,
areas = {},
video_margins = {
l = 0, r = 0, t = 0, b = 0, -- left/right/top/bottom
},
}
local osc_styles = {
bigButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}",
smallButtonsL = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}",
smallButtonsLlabel = "{\\fscx105\\fscy105\\fn" .. mp.get_property("options/osd-font") .. "}",
smallButtonsR = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}",
topButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}",
elementDown = "{\\1c&H999999}",
timecodes = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs20}",
vidtitle = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\q2}",
box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}",
topButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}",
smallButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}",
timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}",
timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}",
vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}",
wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}",
wcTitle = "{\\1c&HFFFFFF\\fs24\\q2}",
wcBar = "{\\1c&H000000}",
}
---- Tooltip Utils
-- See MPV's stats.lua for a full example (Shortcut: I + 4)
-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L433
local bindings = mp.get_property_native("input-bindings", {})
local active = {} -- map: key-name -> bind-info
for _, bind in pairs(bindings) do
if bind.priority >= 0 and (
not active[bind.key] or
(active[bind.key].is_weak and not bind.is_weak) or
(bind.is_weak == active[bind.key].is_weak and
bind.priority > active[bind.key].priority)
) and not bind.cmd:find("script-binding stats/__forced_", 1, true)
then
active[bind.key] = bind
end
end
local ordered = {}
for _, bind in pairs(active) do
table.insert(ordered, bind)
_,_, bind.mods = bind.key:find("(.*)%+.")
_, bind.mods_count = bind.key:gsub("%+.", "")
end
table.sort(ordered, function(a, b)
if a.subject ~= b.subject then
return a.subject < b.subject
elseif a.mods_count ~= b.mods_count then
return a.mods_count < b.mods_count
elseif a.mods ~= b.mods then
return a.mods < b.mods
elseif a.key:len() ~= b.key:len() then
return a.key:len() < b.key:len()
elseif a.key:lower() ~= b.key:lower() then
return a.key:lower() < b.key:lower()
else
return a.key > b.key -- only case differs, lowercase first
end
end)
-- for _, bind in pairs(ordered) do
-- jsonstr, err = utils.format_json(bind)
-- print(jsonstr)
-- end
function isIgnored(bind, ignoredKeys)
for _, ignoredKey in pairs(ignoredKeys) do
if bind.key == ignoredKey then
return true
end
end
return false
end
function grepBindByCmd(pattern, ignoredKeys)
ignoredKeys = ignoredKeys or {}
local cmdBinds = {}
for _, bind in pairs(ordered) do
local ignored = isIgnored(bind, ignoredKeys)
if not ignored and bind.cmd:find(pattern) then
-- print(bind.key, bind.cmd)
cmdBinds[#cmdBinds+1] = bind
end
end
return cmdBinds
end
function grepSeekBinds(ignoredKeys)
ignoredKeys = ignoredKeys or {}
local backBinds = {}
local frwdBinds = {}
for _, bind in pairs(ordered) do
if isIgnored(bind, ignoredKeys) then
-- skip
elseif bind.cmd:find("^seek(%s+)(%-[%d%.]+)") then
backBinds[#backBinds+1] = bind
elseif bind.cmd:find("^no%-osd(%s+)seek(%s+)(%-[%d%.]+)") then
backBinds[#backBinds+1] = bind
elseif bind.cmd:find("^seek(%s+)(%+?[%d%.]+)") then
frwdBinds[#frwdBinds+1] = bind
elseif bind.cmd:find("^no%-osd(%s+)seek(%s+)(%+?[%d%.]+)") then
frwdBinds[#frwdBinds+1] = bind
end
end
return backBinds, frwdBinds
end
function grepSpeedBinds(ignoredKeys)
ignoredKeys = ignoredKeys or {}
local downBinds = {}
local upBinds = {}
for _, bind in pairs(ordered) do
if isIgnored(bind, ignoredKeys) then
-- skip
elseif bind.cmd:find("^add(%s+)speed(%s+)(%+?[%d%.]+)$") then
upBinds[#upBinds+1] = bind
elseif bind.cmd:find("^add(%s+)speed(%s+)(%-[%d%.]+)$") then
downBinds[#downBinds+1] = bind
elseif bind.cmd:find("^multiply(%s+)speed(%s+)([%d%.]+)/([%d%.]+)$") then
local num, den = bind.cmd:match("^multiply%s+speed%s+([%d%.]+)/([%d%.]+)$")
num = tonumber(num) -- numerator
den = tonumber(den) -- denominator
if num < den then
downBinds[#downBinds+1] = bind
else
upBinds[#upBinds+1] = bind
end
elseif bind.cmd:find("^multiply(%s+)speed(%s+)([%d%.]+)$") then
local x = bind.cmd:match("^multiply%s+speed%s+([%d%.]+)$")
x = tonumber(x)
if x < 1 then
downBinds[#downBinds+1] = bind
else
upBinds[#upBinds+1] = bind
end
end
end
return downBinds, upBinds
end
function humanBindKey(key)
if key == 'PGUP' then return 'PgUp'
elseif key == 'PGDWN' then return 'PgDn'
elseif key == 'UP' then return '⇧'
elseif key == 'DOWN' then return '⇩'
elseif key == 'LEFT' then return '⇦'
elseif key == 'RIGHT' then return '⇨'
elseif key == 'Shift+UP' then return 'Shift ⇧'
elseif key == 'Shift+DOWN' then return 'Shift ⇩'
elseif key == 'Shift+LEFT' then return 'Shift ⇦'
elseif key == 'Shift+RIGHT' then return 'Shift ⇨'
elseif key == 'WHEEL_UP' then return 'Scroll Up'
elseif key == 'WHEEL_DOWN' then return 'Scroll Down'
elseif key == 'SHARP' then return '#'
elseif key == 'BS' then return 'Backspace'
elseif key == '{' then return '\\{'
elseif key == '}' then return '\\}'
else return key
end
end
function formatBindKey(key)
return tethysStyle.buttonKeybindFormat:format(humanBindKey(key))
end
function formatBinds(binds)
local str = ""
for i, bind in pairs(binds) do
if i ~= 1 then -- lua arrays start at 1
str = str .. " or "
end
str = str .. formatBindKey(bind.key)
end
return str
end
function formatSeekBind(bind)
local seekBy
if bind.cmd:match("^no%-osd%s+seek") then
seekBy = bind.cmd:match("^no%-osd%s+seek%s+([%+%-]?[%d%.]+)")
else
seekBy = bind.cmd:match("^seek%s+([%+%-]?[%d%.]+)")
end
seekBy = tonumber(seekBy) -- Note: +0.1 is parsed okay
local label
if seekBy < 0 then
return ("Back %ss %s"):format(-seekBy, formatBindKey(bind.key))
else
return ("Forward %ss %s"):format(seekBy, formatBindKey(bind.key))
end
end
function formatSeekBinds(binds)
local list = {}
for i, bind in pairs(binds) do
table.insert(list, formatSeekBind(bind))
end
return list
end
---- Filter bindings by commands using regex
---- Keys passed into grepBindByCmd() are ignored.
-- %s+ = One or more spaces
-- %- = A literal dash '-'
-- %-? = May or may not contain a dash
-- %d+ = One or more digits from 0 to 9
-- (%-?%d+) = Positive or negative integer
local pauseBinds = grepBindByCmd("^cycle(%s+)pause", {"p", "PLAYPAUSE", "MBTN_RIGHT", "PLAY", "PAUSE"})
local seekBackBinds, seekFrwdBinds = grepSeekBinds({"REWIND", "Shift+PGDWN", "FORWARD", "Shift+PGUP"})
local muteBinds = grepBindByCmd("^cycle(%s+)mute", {"MUTE"})
local volDnBinds = grepBindByCmd("^add(%s+)volume(%s+)(%-%d+)", {"VOLUME_DOWN", "WHEEL_LEFT"})
local volUpBinds = grepBindByCmd("^add(%s+)volume(%s+)(%d+)", {"VOLUME_UP", "WHEEL_RIGHT"})
local plPrevBinds = grepBindByCmd("^playlist%-prev", {"PREV", "MBTN_BACK"})
local plNextBinds = grepBindByCmd("^playlist%-next", {"NEXT", "MBTN_FORWARD"})
local chPrevBinds = grepBindByCmd("^add chapter (%-%d+)", {})
local chNextBinds = grepBindByCmd("^add chapter (%d+)", {})
local audioBinds = grepBindByCmd("^cycle(%s+)audio", {})
local subBinds = grepBindByCmd("^cycle(%s+)sub$", {})
local speedResetBinds = grepBindByCmd("^set(%s+)speed(%s+)1", {})
local speedDnBinds, speedUpBinds = grepSpeedBinds()
local fullscreenBinds = grepBindByCmd("^cycle(%s+)fullscreen", {"MBTN_LEFT_DBL"})
---- Generate tooltips
local pauseTooltip = ("Play %s"):format(formatBinds(pauseBinds))
local seekBackTooltip = formatSeekBinds(seekBackBinds)
local seekFrwdTooltip = formatSeekBinds(seekFrwdBinds)
local muteTooltip = formatBinds(muteBinds)
local volDnTooltip = formatBinds(volDnBinds)
local volUpTooltip = formatBinds(volUpBinds)
local volTooltip = ("Mute %s\\NVolume Up %s\\NVolume Down %s"):format(muteTooltip, volUpTooltip, volDnTooltip)
local plPrevTooltip = ("Previous %s"):format(formatBinds(plPrevBinds))
local plNextTooltip = ("Next %s"):format(formatBinds(plNextBinds))
local chPrevTooltip = ("Prev Chapter %s"):format(formatBinds(chPrevBinds))
local chNextTooltip = ("Next Chapter %s"):format(formatBinds(chNextBinds))
local audioTooltip = ("Audio Track %s"):format(formatBinds(audioBinds))
local subTooltip = ("Subtitle Track %s"):format(formatBinds(subBinds))
local speedResetTooltip = formatBinds(speedResetBinds)
local speedDnTooltip = formatBinds(speedDnBinds)
local speedUpTooltip = formatBinds(speedUpBinds)
local speedTooltip = ("Reset %s\\NFaster %s\\NSlower %s"):format(speedResetTooltip, speedUpTooltip, speedDnTooltip)
local pipTooltip = "Picture In Picture"
local fullscreenTooltip = ("Fullscreen %s"):format(formatBinds(fullscreenBinds))
-- print("pauseTooltip", pauseTooltip)
-- print("seekBackTooltip", utils.format_json(seekBackTooltip))
-- print("seekFrwdTooltip", utils.format_json(seekFrwdTooltip))
-- print("muteTooltip", muteTooltip)
-- print("volDnTooltip", volDnTooltip)
-- print("volUpTooltip", volUpTooltip)
-- print("volTooltip", utils.format_json(volTooltip))
-- print("plPrevTooltip", plPrevTooltip)
-- print("plNextTooltip", plNextTooltip)
-- print("chPrevTooltip", chPrevTooltip)
-- print("chNextTooltip", chNextTooltip)
-- print("audioTooltip", audioTooltip)
-- print("subTooltip", subTooltip)
-- print("speedResetTooltip", speedResetTooltip)
-- print("speedDnTooltip", speedDnTooltip)
-- print("speedUpTooltip", speedUpTooltip)
-- print("speedTooltip", utils.format_json(speedTooltip))
-- print("pipTooltip", pipTooltip)
-- print("fullscreenTooltip", fullscreenTooltip)
---- Playlist / Chapter Utils
function getDeltaListItem(listKey, curKey, delta, clamp)
local pos = mp.get_property_number(curKey, 0) + 1
local count, limlist = limited_list(listKey, pos)
if count == 0 then
return nil
end
local curIndex = -1
for i, v in ipairs(limlist) do
if v.current then
curIndex = i
break
end
end
local deltaIndex = curIndex + delta
if curIndex == -1 then
return nil
elseif deltaIndex < 1 then
if clamp then
deltaIndex = 1
else
return nil
end
elseif deltaIndex > count then
if clamp then
deltaIndex = count
else
return nil
end
end
local deltaItem = limlist[deltaIndex]
return deltaIndex, deltaItem
end
function getDeltaChapter(delta)
local deltaIndex, deltaChapter = getDeltaListItem('chapter-list', 'chapter', delta, true)
if deltaChapter == nil then -- Video Done
return nil
end
deltaChapter = {
index = deltaIndex,
time = deltaChapter.time,
title = deltaChapter.title,
label = nil,
}
local label = deltaChapter.title
if label == nil then
label = string.format('Chapter %02d', deltaChapter.index)
end
-- local time = mp.format_time(deltaChapter.time)
-- deltaChapter.label = string.format('[%s] %s', time, label)
deltaChapter.label = label
return deltaChapter
end
function getDeltaPlaylistItem(delta)
local deltaIndex, deltaItem = getDeltaListItem('playlist', 'playlist-pos', delta, false)
if deltaItem == nil then
return nil
end
deltaItem = {
index = deltaIndex,
filename = deltaItem.filename,
title = deltaItem.title,
label = nil,
}
local label = deltaItem.title
if label == nil then
local _, filename = utils.split_path(deltaItem.filename)
label = filename
end
deltaItem.label = label
return deltaItem
end
---- Thumbnailer (https://github.com/TheAMM/mpv_thumbnail_script)
-- mpv_thumbnail_script/lib/helpers.lua
-- (partial file) Only copied the needed functions
function clear_table(target)
for key, value in pairs(target) do
target[key] = nil
end
end
ON_WINDOWS = (package.config:sub(1,1) ~= '/')
function is_absolute_path( path )
local tmp, is_win = path:gsub("^[A-Z]:\\", "")
local tmp, is_unix = path:gsub("^/", "")
return (is_win > 0) or (is_unix > 0)
end
function join_paths(...)
local sep = ON_WINDOWS and "\\" or "/"
local result = "";
for i, p in pairs({...}) do
if p ~= "" then
if is_absolute_path(p) then
result = p
else
result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p
end
end
end
return result:gsub("[\\"..sep.."]*$", "")
end
function create_directories(path)
local cmd
if ON_WINDOWS then
cmd = { args = {"cmd", "/c", "mkdir", path} }
else
cmd = { args = {"mkdir", "-p", path} }
end
utils.subprocess(cmd)
end
function file_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
local ok, err, code = f:read(1)
io.close(f)
return code == nil
else
return false
end
end
-- Find an executable in PATH or CWD with the given name
function find_executable(name)
local delim = ON_WINDOWS and ";" or ":"
local pwd = os.getenv("PWD") or utils.getcwd()
local path = os.getenv("PATH")
local env_path = pwd .. delim .. path -- Check CWD first
local result, filename
for path_dir in env_path:gmatch("[^"..delim.."]+") do
filename = join_paths(path_dir, name)
if file_exists(filename) then
result = filename
break
end
end
return result
end
-- Searches for an executable and caches the result if any
local ExecutableFinder = { path_cache = {} }
function ExecutableFinder:get_executable_path(name, raw_name)
name = ON_WINDOWS and not raw_name and (name .. ".exe") or name
if self.path_cache[name] == nil then
self.path_cache[name] = find_executable(name) or false
end
return self.path_cache[name]
end
-- mpv_thumbnail_script/lib/sha1.lua
-- $Revision: 1.5 $
-- $Date: 2014-09-10 16:54:25 $
-- This module was originally taken from http://cube3d.de/uploads/Main/sha1.txt.
-------------------------------------------------------------------------------
-- SHA-1 secure hash computation, and HMAC-SHA1 signature computation,
-- in pure Lua (tested on Lua 5.1)
-- License: MIT
--
-- Usage:
-- local hashAsHex = sha1.hex(message) -- returns a hex string
-- local hashAsData = sha1.bin(message) -- returns raw bytes
--
-- local hmacAsHex = sha1.hmacHex(key, message) -- hex string
-- local hmacAsData = sha1.hmacBin(key, message) -- raw bytes
--
--
-- Pass sha1.hex() a string, and it returns a hash as a 40-character hex string.
-- For example, the call
--
-- local hash = sha1.hex("iNTERFACEWARE")
--
-- puts the 40-character string
--
-- "e76705ffb88a291a0d2f9710a5471936791b4819"
--
-- into the variable 'hash'
--
-- Pass sha1.hmacHex() a key and a message, and it returns the signature as a
-- 40-byte hex string.
--
--
-- The two "bin" versions do the same, but return the 20-byte string of raw
-- data that the 40-byte hex strings represent.
--
-------------------------------------------------------------------------------
--
-- Description
-- Due to the lack of bitwise operations in 5.1, this version uses numbers to
-- represents the 32bit words that we combine with binary operations. The basic
-- operations of byte based "xor", "or", "and" are all cached in a combination
-- table (several 64k large tables are built on startup, which
-- consumes some memory and time). The caching can be switched off through
-- setting the local cfg_caching variable to false.
-- For all binary operations, the 32 bit numbers are split into 8 bit values
-- that are combined and then merged again.
--
-- Algorithm: http://www.itl.nist.gov/fipspubs/fip180-1.htm
--
-------------------------------------------------------------------------------
local sha1 = (function()
local sha1 = {}
-- set this to false if you don't want to build several 64k sized tables when
-- loading this file (takes a while but grants a boost of factor 13)
local cfg_caching = false
-- local storing of global functions (minor speedup)
local floor,modf = math.floor,math.modf
local char,format,rep = string.char,string.format,string.rep
-- merge 4 bytes to an 32 bit word
local function bytes_to_w32 (a,b,c,d) return a*0x1000000+b*0x10000+c*0x100+d end
-- split a 32 bit word into four 8 bit numbers
local function w32_to_bytes (i)
return floor(i/0x1000000)%0x100,floor(i/0x10000)%0x100,floor(i/0x100)%0x100,i%0x100
end
-- shift the bits of a 32 bit word. Don't use negative values for "bits"
local function w32_rot (bits,a)
local b2 = 2^(32-bits)
local a,b = modf(a/b2)
return a+b*b2*(2^(bits))
end
-- caching function for functions that accept 2 arguments, both of values between
-- 0 and 255. The function to be cached is passed, all values are calculated
-- during loading and a function is returned that returns the cached values (only)
local function cache2arg (fn)
if not cfg_caching then return fn end
local lut = {}
for i=0,0xffff do
local a,b = floor(i/0x100),i%0x100
lut[i] = fn(a,b)
end
return function (a,b)
return lut[a*0x100+b]
end
end
-- splits an 8-bit number into 8 bits, returning all 8 bits as booleans
local function byte_to_bits (b)
local b = function (n)
local b = floor(b/n)
return b%2==1
end
return b(1),b(2),b(4),b(8),b(16),b(32),b(64),b(128)
end
-- builds an 8bit number from 8 booleans
local function bits_to_byte (a,b,c,d,e,f,g,h)
local function n(b,x) return b and x or 0 end
return n(a,1)+n(b,2)+n(c,4)+n(d,8)+n(e,16)+n(f,32)+n(g,64)+n(h,128)
end
-- debug function for visualizing bits in a string
local function bits_to_string (a,b,c,d,e,f,g,h)
local function x(b) return b and "1" or "0" end
return ("%s%s%s%s %s%s%s%s"):format(x(a),x(b),x(c),x(d),x(e),x(f),x(g),x(h))
end
-- debug function for converting a 8-bit number as bit string
local function byte_to_bit_string (b)
return bits_to_string(byte_to_bits(b))
end
-- debug function for converting a 32 bit number as bit string
local function w32_to_bit_string(a)
if type(a) == "string" then return a end
local aa,ab,ac,ad = w32_to_bytes(a)
local s = byte_to_bit_string
return ("%s %s %s %s"):format(s(aa):reverse(),s(ab):reverse(),s(ac):reverse(),s(ad):reverse()):reverse()
end
-- bitwise "and" function for 2 8bit number
local band = cache2arg (function(a,b)
local A,B,C,D,E,F,G,H = byte_to_bits(b)
local a,b,c,d,e,f,g,h = byte_to_bits(a)
return bits_to_byte(
A and a, B and b, C and c, D and d,
E and e, F and f, G and g, H and h)
end)
-- bitwise "or" function for 2 8bit numbers
local bor = cache2arg(function(a,b)
local A,B,C,D,E,F,G,H = byte_to_bits(b)
local a,b,c,d,e,f,g,h = byte_to_bits(a)
return bits_to_byte(
A or a, B or b, C or c, D or d,
E or e, F or f, G or g, H or h)
end)
-- bitwise "xor" function for 2 8bit numbers
local bxor = cache2arg(function(a,b)
local A,B,C,D,E,F,G,H = byte_to_bits(b)
local a,b,c,d,e,f,g,h = byte_to_bits(a)
return bits_to_byte(
A ~= a, B ~= b, C ~= c, D ~= d,
E ~= e, F ~= f, G ~= g, H ~= h)
end)
-- bitwise complement for one 8bit number
local function bnot (x)
return 255-(x % 256)
end
-- creates a function to combine to 32bit numbers using an 8bit combination function
local function w32_comb(fn)
return function (a,b)
local aa,ab,ac,ad = w32_to_bytes(a)
local ba,bb,bc,bd = w32_to_bytes(b)
return bytes_to_w32(fn(aa,ba),fn(ab,bb),fn(ac,bc),fn(ad,bd))
end
end
-- create functions for and, xor and or, all for 2 32bit numbers
local w32_and = w32_comb(band)
local w32_xor = w32_comb(bxor)
local w32_or = w32_comb(bor)
-- xor function that may receive a variable number of arguments
local function w32_xor_n (a,...)
local aa,ab,ac,ad = w32_to_bytes(a)
for i=1,select('#',...) do
local ba,bb,bc,bd = w32_to_bytes(select(i,...))
aa,ab,ac,ad = bxor(aa,ba),bxor(ab,bb),bxor(ac,bc),bxor(ad,bd)
end
return bytes_to_w32(aa,ab,ac,ad)
end
-- combining 3 32bit numbers through binary "or" operation
local function w32_or3 (a,b,c)
local aa,ab,ac,ad = w32_to_bytes(a)
local ba,bb,bc,bd = w32_to_bytes(b)
local ca,cb,cc,cd = w32_to_bytes(c)
return bytes_to_w32(
bor(aa,bor(ba,ca)), bor(ab,bor(bb,cb)), bor(ac,bor(bc,cc)), bor(ad,bor(bd,cd))
)
end
-- binary complement for 32bit numbers
local function w32_not (a)
return 4294967295-(a % 4294967296)
end
-- adding 2 32bit numbers, cutting off the remainder on 33th bit
local function w32_add (a,b) return (a+b) % 4294967296 end
-- adding n 32bit numbers, cutting off the remainder (again)
local function w32_add_n (a,...)
for i=1,select('#',...) do
a = (a+select(i,...)) % 4294967296
end
return a
end
-- converting the number to a hexadecimal string
local function w32_to_hexstring (w) return format("%08x",w) end
-- calculating the SHA1 for some text
function sha1.hex(msg)
local H0,H1,H2,H3,H4 = 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0
local msg_len_in_bits = #msg * 8
local first_append = char(0x80) -- append a '1' bit plus seven '0' bits