vidply 1.2.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +974 -946
- package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-JYYLK5KB.js} +275 -19
- package/dist/dev/vidply.AudioDescriptionManager-JYYLK5KB.js.map +7 -0
- package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-47RCKQF5.js} +4 -4
- package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-VEJ4HDHO.js} +3 -3
- package/dist/dev/vidply.DASHRenderer-VEJ4HDHO.js.map +7 -0
- package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-C2UVRPZY.js} +5 -5
- package/dist/dev/vidply.FloatingPlayerManager-C2UVRPZY.js.map +7 -0
- package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZVBK2TNQ.js} +4 -4
- package/dist/dev/vidply.HLSRenderer-ZVBK2TNQ.js.map +7 -0
- package/dist/dev/vidply.HTML5Renderer-HLRQUOCU.js +12 -0
- package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-FLUCBW5H.js} +8 -8
- package/dist/dev/vidply.SignLanguageManager-FLUCBW5H.js.map +7 -0
- package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-MGMAJ7NK.js} +3 -3
- package/dist/dev/vidply.SoundCloudRenderer-MGMAJ7NK.js.map +7 -0
- package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-Y2RYXHJW.js} +10 -10
- package/dist/dev/vidply.TranscriptManager-Y2RYXHJW.js.map +7 -0
- package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-RQFQD7OE.js} +3 -3
- package/dist/dev/vidply.VimeoRenderer-RQFQD7OE.js.map +7 -0
- package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-EU2BARZF.js} +3 -3
- package/dist/dev/vidply.YouTubeRenderer-EU2BARZF.js.map +7 -0
- package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-6LYZYI5G.js} +3 -3
- package/dist/dev/vidply.chunk-6LYZYI5G.js.map +7 -0
- package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-A4ESEOQ2.js} +6 -6
- package/dist/dev/vidply.chunk-A4ESEOQ2.js.map +7 -0
- package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-CGYIED2I.js} +2 -2
- package/dist/dev/vidply.chunk-CGYIED2I.js.map +7 -0
- package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-HZ7UOKOU.js} +3 -3
- package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-I6EDRYGJ.js} +33 -6
- package/dist/dev/vidply.chunk-I6EDRYGJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-JKMQGLCJ.js} +5 -5
- package/dist/dev/vidply.chunk-JKMQGLCJ.js.map +7 -0
- package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-JZNZX32Z.js} +2 -2
- package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-P25MRJ6O.js} +2 -2
- package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-PRFNESYA.js} +2 -2
- package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-UI3RYCVF.js} +4 -3
- package/dist/dev/vidply.chunk-UI3RYCVF.js.map +7 -0
- package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-UNFGMABP.js} +2 -2
- package/dist/dev/vidply.chunk-UNFGMABP.js.map +7 -0
- package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-VAUVSQXC.js} +29 -2
- package/dist/dev/vidply.de-VAUVSQXC.js.map +7 -0
- package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-G65HFWO6.js} +29 -2
- package/dist/dev/vidply.es-G65HFWO6.js.map +7 -0
- package/dist/dev/vidply.esm.js +648 -35
- package/dist/dev/vidply.esm.js.map +3 -3
- package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-MJNOZELM.js} +29 -2
- package/dist/dev/vidply.fr-MJNOZELM.js.map +7 -0
- package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-INMDHIYJ.js} +29 -2
- package/dist/dev/vidply.ja-INMDHIYJ.js.map +7 -0
- package/dist/legacy/vidply.js +1062 -34
- package/dist/legacy/vidply.js.map +3 -3
- package/dist/legacy/vidply.min.js +2 -2
- package/dist/legacy/vidply.min.meta.json +127 -55
- package/dist/prod/vidply.AudioDescriptionManager-EKWUNOPE.min.js +6 -0
- package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-JTWSNHRQ.min.js} +2 -2
- package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-CIDAHFWM.min.js} +2 -2
- package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-VZXHPCPM.min.js} +2 -2
- package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-Q6EFYKID.min.js} +2 -2
- package/dist/prod/vidply.HTML5Renderer-XRDJUTOO.min.js +6 -0
- package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-JUOSA5AM.min.js} +2 -2
- package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-7ODD46PO.min.js} +2 -2
- package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-4B2QKYGQ.min.js} +2 -2
- package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-MR3UYLY7.min.js} +2 -2
- package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-ITRTC7NR.min.js} +2 -2
- package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-3EEDXU4T.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-5HTX5QXW.min.js} +1 -1
- package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-6OGHHIYP.min.js} +2 -2
- package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-GUPGMFUZ.min.js} +2 -2
- package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-MWEBITCP.min.js} +1 -1
- package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-PL3P3JHR.min.js} +1 -1
- package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-QQZGV7TD.min.js} +2 -2
- package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-U5IRRYG5.min.js} +1 -1
- package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-VKHV4QHA.min.js} +2 -2
- package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-XA4M574A.min.js} +1 -1
- package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-ZPTV4JEP.min.js} +2 -2
- package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-UZHFCEZU.min.js} +2 -2
- package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-BOISUV2S.min.js} +2 -2
- package/dist/prod/vidply.esm.min.js +2 -2
- package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-ICSMKPFM.min.js} +2 -2
- package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-VQ2HKGAY.min.js} +2 -2
- package/dist/vidply.css +5852 -5796
- package/dist/vidply.esm.min.meta.json +204 -149
- package/dist/vidply.min.css +1 -1
- package/package.json +11 -11
- package/src/controls/CaptionManager.ts +598 -598
- package/src/controls/ControlBar.ts +4191 -4159
- package/src/controls/KeyboardHelp.ts +326 -0
- package/src/controls/KeyboardManager.ts +387 -383
- package/src/controls/SettingsDialog.ts +488 -488
- package/src/controls/TranscriptManager.ts +2426 -2426
- package/src/core/AudioDescriptionManager.ts +863 -774
- package/src/core/DescriptionSpeechManager.ts +232 -0
- package/src/core/FloatingPlayerManager.ts +674 -674
- package/src/core/LazyInit.ts +80 -80
- package/src/core/MediaSessionManager.ts +341 -0
- package/src/core/MetadataAlertsManager.ts +514 -514
- package/src/core/Player.ts +2973 -2872
- package/src/core/PosterManager.ts +169 -169
- package/src/core/PseudoFullscreen.ts +179 -179
- package/src/core/ResponsiveManager.ts +231 -231
- package/src/core/ResumeManager.ts +236 -236
- package/src/core/SignLanguageManager.ts +1308 -1308
- package/src/core/ThemeManager.ts +157 -157
- package/src/features/PlaylistManager.ts +1838 -1827
- package/src/i18n/i18n.ts +223 -223
- package/src/i18n/languages/de.ts +244 -217
- package/src/i18n/languages/en.ts +245 -218
- package/src/i18n/languages/es.ts +241 -214
- package/src/i18n/languages/fr.ts +241 -214
- package/src/i18n/languages/ja.ts +241 -214
- package/src/icons/Icons.ts +168 -167
- package/src/index.ts +196 -193
- package/src/renderers/DASHRenderer.ts +1077 -1077
- package/src/renderers/HLSRenderer.ts +944 -944
- package/src/renderers/HTML5Renderer.ts +389 -389
- package/src/renderers/SoundCloudRenderer.ts +437 -437
- package/src/renderers/VimeoRenderer.ts +298 -298
- package/src/renderers/YouTubeRenderer.ts +290 -290
- package/src/styles/vidply.css +5852 -5796
- package/src/types/events.ts +128 -122
- package/src/types/globals.d.ts +313 -313
- package/src/types/options.ts +199 -182
- package/src/types/renderer.ts +58 -58
- package/src/utils/DOMUtils.ts +281 -281
- package/src/utils/DownloadInfo.ts +171 -171
- package/src/utils/DraggablePanel.ts +539 -539
- package/src/utils/DraggablePanelMenu.ts +195 -195
- package/src/utils/DraggableResizable.ts +997 -997
- package/src/utils/EventEmitter.ts +59 -59
- package/src/utils/FormUtils.ts +95 -95
- package/src/utils/MenuFactory.ts +483 -483
- package/src/utils/Sanitize.ts +70 -70
- package/src/utils/SettingsMenuFactory.ts +289 -289
- package/src/utils/StorageManager.ts +287 -287
- package/src/utils/TrackLabelUtils.ts +52 -52
- package/src/utils/UrlSafe.ts +69 -69
- package/src/utils/VideoFrameCapture.ts +114 -114
- package/src/utils/WindowComponents.ts +250 -250
- package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
- package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
- package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
- package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
- package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
- package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
- package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
- package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
- package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
- package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
- package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
- package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
- package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
- package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
- package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
- package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
- package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
- package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
- package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
- package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
- package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
- package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
- package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
- /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-47RCKQF5.js.map} +0 -0
- /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-HLRQUOCU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-HZ7UOKOU.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-JZNZX32Z.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-P25MRJ6O.js.map} +0 -0
- /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-PRFNESYA.js.map} +0 -0
package/dist/legacy/vidply.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* VidPly v1.2.
|
|
2
|
+
* VidPly v1.2.3 - Universal, Accessible Video Player
|
|
3
3
|
* (c) 2026 Matthias Peltzer
|
|
4
4
|
* Released under GPL-2.0-or-later License
|
|
5
5
|
*/
|
|
@@ -8,8 +8,13 @@
|
|
|
8
8
|
var __defProp = Object.defineProperty;
|
|
9
9
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
10
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
-
var __esm = (fn, res) => function __init() {
|
|
12
|
-
|
|
11
|
+
var __esm = (fn, res, err) => function __init() {
|
|
12
|
+
if (err) throw err[0];
|
|
13
|
+
try {
|
|
14
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
throw err = [e], e;
|
|
17
|
+
}
|
|
13
18
|
};
|
|
14
19
|
var __export = (target, all) => {
|
|
15
20
|
for (var name in all)
|
|
@@ -423,6 +428,33 @@
|
|
|
423
428
|
reset: "Reset to defaults",
|
|
424
429
|
close: "Close"
|
|
425
430
|
},
|
|
431
|
+
help: {
|
|
432
|
+
title: "Keyboard shortcuts",
|
|
433
|
+
button: "Keyboard shortcuts",
|
|
434
|
+
close: "Close",
|
|
435
|
+
or: "or",
|
|
436
|
+
keys: {
|
|
437
|
+
space: "Space"
|
|
438
|
+
},
|
|
439
|
+
actions: {
|
|
440
|
+
"play-pause": "Play / Pause",
|
|
441
|
+
"seek-backward": "Seek backward",
|
|
442
|
+
"seek-forward": "Seek forward",
|
|
443
|
+
"volume-up": "Volume up",
|
|
444
|
+
"volume-down": "Volume down",
|
|
445
|
+
"mute": "Mute / Unmute",
|
|
446
|
+
"captions": "Toggle captions",
|
|
447
|
+
"caption-style-menu": "Caption styling",
|
|
448
|
+
"speed-down": "Decrease speed",
|
|
449
|
+
"speed-up": "Increase speed",
|
|
450
|
+
"speed-menu": "Playback speed",
|
|
451
|
+
"quality-menu": "Quality",
|
|
452
|
+
"chapters-menu": "Chapters",
|
|
453
|
+
"transcript-toggle": "Toggle transcript",
|
|
454
|
+
"fullscreen": "Toggle fullscreen",
|
|
455
|
+
"help": "Keyboard shortcuts"
|
|
456
|
+
}
|
|
457
|
+
},
|
|
426
458
|
speeds: {
|
|
427
459
|
normal: "Normal"
|
|
428
460
|
},
|
|
@@ -647,6 +679,33 @@
|
|
|
647
679
|
reset: "Zurücksetzen",
|
|
648
680
|
close: "Schließen"
|
|
649
681
|
},
|
|
682
|
+
help: {
|
|
683
|
+
title: "Tastaturkürzel",
|
|
684
|
+
button: "Tastaturkürzel",
|
|
685
|
+
close: "Schließen",
|
|
686
|
+
or: "oder",
|
|
687
|
+
keys: {
|
|
688
|
+
space: "Leertaste"
|
|
689
|
+
},
|
|
690
|
+
actions: {
|
|
691
|
+
"play-pause": "Wiedergabe / Pause",
|
|
692
|
+
"seek-backward": "Zurückspulen",
|
|
693
|
+
"seek-forward": "Vorspulen",
|
|
694
|
+
"volume-up": "Lauter",
|
|
695
|
+
"volume-down": "Leiser",
|
|
696
|
+
"mute": "Stumm / Ton an",
|
|
697
|
+
"captions": "Untertitel umschalten",
|
|
698
|
+
"caption-style-menu": "Untertitel-Stil",
|
|
699
|
+
"speed-down": "Langsamer",
|
|
700
|
+
"speed-up": "Schneller",
|
|
701
|
+
"speed-menu": "Wiedergabegeschwindigkeit",
|
|
702
|
+
"quality-menu": "Qualität",
|
|
703
|
+
"chapters-menu": "Kapitel",
|
|
704
|
+
"transcript-toggle": "Transkript umschalten",
|
|
705
|
+
"fullscreen": "Vollbild umschalten",
|
|
706
|
+
"help": "Tastaturkürzel"
|
|
707
|
+
}
|
|
708
|
+
},
|
|
650
709
|
speeds: {
|
|
651
710
|
normal: "Normal"
|
|
652
711
|
},
|
|
@@ -868,6 +927,33 @@
|
|
|
868
927
|
reset: "Restablecer",
|
|
869
928
|
close: "Cerrar"
|
|
870
929
|
},
|
|
930
|
+
help: {
|
|
931
|
+
title: "Atajos de teclado",
|
|
932
|
+
button: "Atajos de teclado",
|
|
933
|
+
close: "Cerrar",
|
|
934
|
+
or: "o",
|
|
935
|
+
keys: {
|
|
936
|
+
space: "Espacio"
|
|
937
|
+
},
|
|
938
|
+
actions: {
|
|
939
|
+
"play-pause": "Reproducir / Pausar",
|
|
940
|
+
"seek-backward": "Retroceder",
|
|
941
|
+
"seek-forward": "Avanzar",
|
|
942
|
+
"volume-up": "Subir volumen",
|
|
943
|
+
"volume-down": "Bajar volumen",
|
|
944
|
+
"mute": "Silenciar / Activar sonido",
|
|
945
|
+
"captions": "Alternar subtítulos",
|
|
946
|
+
"caption-style-menu": "Estilo de subtítulos",
|
|
947
|
+
"speed-down": "Reducir velocidad",
|
|
948
|
+
"speed-up": "Aumentar velocidad",
|
|
949
|
+
"speed-menu": "Velocidad de reproducción",
|
|
950
|
+
"quality-menu": "Calidad",
|
|
951
|
+
"chapters-menu": "Capítulos",
|
|
952
|
+
"transcript-toggle": "Alternar transcripción",
|
|
953
|
+
"fullscreen": "Alternar pantalla completa",
|
|
954
|
+
"help": "Atajos de teclado"
|
|
955
|
+
}
|
|
956
|
+
},
|
|
871
957
|
speeds: {
|
|
872
958
|
normal: "Normal"
|
|
873
959
|
},
|
|
@@ -1089,6 +1175,33 @@
|
|
|
1089
1175
|
reset: "Réinitialiser",
|
|
1090
1176
|
close: "Fermer"
|
|
1091
1177
|
},
|
|
1178
|
+
help: {
|
|
1179
|
+
title: "Raccourcis clavier",
|
|
1180
|
+
button: "Raccourcis clavier",
|
|
1181
|
+
close: "Fermer",
|
|
1182
|
+
or: "ou",
|
|
1183
|
+
keys: {
|
|
1184
|
+
space: "Espace"
|
|
1185
|
+
},
|
|
1186
|
+
actions: {
|
|
1187
|
+
"play-pause": "Lecture / Pause",
|
|
1188
|
+
"seek-backward": "Reculer",
|
|
1189
|
+
"seek-forward": "Avancer",
|
|
1190
|
+
"volume-up": "Augmenter le volume",
|
|
1191
|
+
"volume-down": "Baisser le volume",
|
|
1192
|
+
"mute": "Couper / Activer le son",
|
|
1193
|
+
"captions": "Activer/désactiver les sous-titres",
|
|
1194
|
+
"caption-style-menu": "Style des sous-titres",
|
|
1195
|
+
"speed-down": "Ralentir",
|
|
1196
|
+
"speed-up": "Accélérer",
|
|
1197
|
+
"speed-menu": "Vitesse de lecture",
|
|
1198
|
+
"quality-menu": "Qualité",
|
|
1199
|
+
"chapters-menu": "Chapitres",
|
|
1200
|
+
"transcript-toggle": "Activer/désactiver la transcription",
|
|
1201
|
+
"fullscreen": "Activer/désactiver le plein écran",
|
|
1202
|
+
"help": "Raccourcis clavier"
|
|
1203
|
+
}
|
|
1204
|
+
},
|
|
1092
1205
|
speeds: {
|
|
1093
1206
|
normal: "Normal"
|
|
1094
1207
|
},
|
|
@@ -1310,6 +1423,33 @@
|
|
|
1310
1423
|
reset: "リセット",
|
|
1311
1424
|
close: "閉じる"
|
|
1312
1425
|
},
|
|
1426
|
+
help: {
|
|
1427
|
+
title: "キーボードショートカット",
|
|
1428
|
+
button: "キーボードショートカット",
|
|
1429
|
+
close: "閉じる",
|
|
1430
|
+
or: "または",
|
|
1431
|
+
keys: {
|
|
1432
|
+
space: "スペース"
|
|
1433
|
+
},
|
|
1434
|
+
actions: {
|
|
1435
|
+
"play-pause": "再生 / 一時停止",
|
|
1436
|
+
"seek-backward": "巻き戻し",
|
|
1437
|
+
"seek-forward": "早送り",
|
|
1438
|
+
"volume-up": "音量を上げる",
|
|
1439
|
+
"volume-down": "音量を下げる",
|
|
1440
|
+
"mute": "ミュート / ミュート解除",
|
|
1441
|
+
"captions": "字幕の切り替え",
|
|
1442
|
+
"caption-style-menu": "字幕スタイル",
|
|
1443
|
+
"speed-down": "速度を下げる",
|
|
1444
|
+
"speed-up": "速度を上げる",
|
|
1445
|
+
"speed-menu": "再生速度",
|
|
1446
|
+
"quality-menu": "画質",
|
|
1447
|
+
"chapters-menu": "チャプター",
|
|
1448
|
+
"transcript-toggle": "文字起こしの切り替え",
|
|
1449
|
+
"fullscreen": "全画面表示の切り替え",
|
|
1450
|
+
"help": "キーボードショートカット"
|
|
1451
|
+
}
|
|
1452
|
+
},
|
|
1313
1453
|
speeds: {
|
|
1314
1454
|
normal: "通常"
|
|
1315
1455
|
},
|
|
@@ -1762,7 +1902,8 @@
|
|
|
1762
1902
|
move: `<path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/>`,
|
|
1763
1903
|
resize: `<path d="M21.71 11.29l-9-9c-.39-.39-1.02-.39-1.41 0l-9 9c-.39.39-.39 1.02 0 1.41l9 9c.39.39 1.02.39 1.41 0l9-9c.39-.38.39-1.01 0-1.41zM14 14.5V12h-4v2.5L7 11l3-3.5V10h4V7.5l3 3.5-3 3.5z"/>`,
|
|
1764
1904
|
clock: `<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/>`,
|
|
1765
|
-
download: `<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"
|
|
1905
|
+
download: `<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>`,
|
|
1906
|
+
help: `<path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/>`
|
|
1766
1907
|
};
|
|
1767
1908
|
svgWrapper = (paths) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">${paths}</svg>`;
|
|
1768
1909
|
Icons = Object.fromEntries(
|
|
@@ -3153,6 +3294,194 @@
|
|
|
3153
3294
|
}
|
|
3154
3295
|
});
|
|
3155
3296
|
|
|
3297
|
+
// src/core/DescriptionSpeechManager.ts
|
|
3298
|
+
var DescriptionSpeechManager;
|
|
3299
|
+
var init_DescriptionSpeechManager = __esm({
|
|
3300
|
+
"src/core/DescriptionSpeechManager.ts"() {
|
|
3301
|
+
"use strict";
|
|
3302
|
+
DescriptionSpeechManager = class {
|
|
3303
|
+
constructor(player) {
|
|
3304
|
+
__publicField(this, "player");
|
|
3305
|
+
__publicField(this, "enabled", false);
|
|
3306
|
+
__publicField(this, "descriptionTrack", null);
|
|
3307
|
+
__publicField(this, "cueChangeHandler", null);
|
|
3308
|
+
__publicField(this, "seekedHandler", null);
|
|
3309
|
+
__publicField(this, "wasPlayingBeforeCue", false);
|
|
3310
|
+
__publicField(this, "speaking", false);
|
|
3311
|
+
__publicField(this, "lastSpokenCueKey", null);
|
|
3312
|
+
__publicField(this, "_pendingUtterance", null);
|
|
3313
|
+
this.player = player;
|
|
3314
|
+
}
|
|
3315
|
+
/**
|
|
3316
|
+
* Whether speech synthesis is available and enabled in player options.
|
|
3317
|
+
*/
|
|
3318
|
+
canUseSpeech() {
|
|
3319
|
+
if (this.player.options.audioDescriptionSpeech === false) {
|
|
3320
|
+
return false;
|
|
3321
|
+
}
|
|
3322
|
+
return typeof window !== "undefined" && "speechSynthesis" in window;
|
|
3323
|
+
}
|
|
3324
|
+
/**
|
|
3325
|
+
* Resolve the descriptions track, preferring the active caption language.
|
|
3326
|
+
*/
|
|
3327
|
+
findDescriptionTrack() {
|
|
3328
|
+
var _a, _b, _c;
|
|
3329
|
+
const textTracks = this.player.element ? Array.from(this.player.element.textTracks || []) : [];
|
|
3330
|
+
const descriptionsTracks = textTracks.filter(
|
|
3331
|
+
(track) => track.kind === "descriptions" && !track._vidplyStale
|
|
3332
|
+
);
|
|
3333
|
+
if (descriptionsTracks.length === 0) {
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
const captionLang = (_c = (_b = (_a = this.player.captionManager) == null ? void 0 : _a.currentTrack) == null ? void 0 : _b.track) == null ? void 0 : _c.language;
|
|
3337
|
+
if (captionLang) {
|
|
3338
|
+
const match = descriptionsTracks.find((track) => track.language === captionLang);
|
|
3339
|
+
if (match) {
|
|
3340
|
+
return match;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
return descriptionsTracks[0] ?? null;
|
|
3344
|
+
}
|
|
3345
|
+
/**
|
|
3346
|
+
* Enable VTT speech mode: wire cuechange/seeked listeners.
|
|
3347
|
+
*/
|
|
3348
|
+
enable() {
|
|
3349
|
+
const track = this.findDescriptionTrack();
|
|
3350
|
+
if (!track) {
|
|
3351
|
+
return false;
|
|
3352
|
+
}
|
|
3353
|
+
if (!this.canUseSpeech()) {
|
|
3354
|
+
track.mode = "showing";
|
|
3355
|
+
return true;
|
|
3356
|
+
}
|
|
3357
|
+
this.descriptionTrack = track;
|
|
3358
|
+
track.mode = "hidden";
|
|
3359
|
+
this.cueChangeHandler = () => {
|
|
3360
|
+
this.handleCueChange();
|
|
3361
|
+
};
|
|
3362
|
+
track.addEventListener("cuechange", this.cueChangeHandler);
|
|
3363
|
+
this.seekedHandler = () => {
|
|
3364
|
+
this.cancelSpeech();
|
|
3365
|
+
this.lastSpokenCueKey = null;
|
|
3366
|
+
this.handleCueChange();
|
|
3367
|
+
};
|
|
3368
|
+
this.player.on("seeked", this.seekedHandler);
|
|
3369
|
+
this.enabled = true;
|
|
3370
|
+
this.handleCueChange();
|
|
3371
|
+
return true;
|
|
3372
|
+
}
|
|
3373
|
+
/**
|
|
3374
|
+
* Disable VTT speech mode and restore track state.
|
|
3375
|
+
*/
|
|
3376
|
+
disable() {
|
|
3377
|
+
this.cancelSpeech();
|
|
3378
|
+
this.lastSpokenCueKey = null;
|
|
3379
|
+
this.enabled = false;
|
|
3380
|
+
if (this.descriptionTrack && this.cueChangeHandler) {
|
|
3381
|
+
this.descriptionTrack.removeEventListener("cuechange", this.cueChangeHandler);
|
|
3382
|
+
}
|
|
3383
|
+
if (this.seekedHandler) {
|
|
3384
|
+
this.player.off("seeked", this.seekedHandler);
|
|
3385
|
+
}
|
|
3386
|
+
if (this.descriptionTrack) {
|
|
3387
|
+
this.descriptionTrack.mode = "hidden";
|
|
3388
|
+
}
|
|
3389
|
+
this.cueChangeHandler = null;
|
|
3390
|
+
this.seekedHandler = null;
|
|
3391
|
+
this.descriptionTrack = null;
|
|
3392
|
+
this.wasPlayingBeforeCue = false;
|
|
3393
|
+
}
|
|
3394
|
+
/**
|
|
3395
|
+
* Handle active description cues on the wired track.
|
|
3396
|
+
*/
|
|
3397
|
+
handleCueChange() {
|
|
3398
|
+
var _a;
|
|
3399
|
+
if (!this.enabled || !this.descriptionTrack || !this.canUseSpeech()) {
|
|
3400
|
+
return;
|
|
3401
|
+
}
|
|
3402
|
+
const activeCues = this.descriptionTrack.activeCues;
|
|
3403
|
+
if (!activeCues || activeCues.length === 0) {
|
|
3404
|
+
return;
|
|
3405
|
+
}
|
|
3406
|
+
const cue = activeCues[0];
|
|
3407
|
+
const text = (_a = cue.text) == null ? void 0 : _a.trim();
|
|
3408
|
+
if (!text) {
|
|
3409
|
+
return;
|
|
3410
|
+
}
|
|
3411
|
+
const cueKey = `${cue.startTime}:${cue.endTime}:${text}`;
|
|
3412
|
+
if (this.speaking && this.lastSpokenCueKey === cueKey) {
|
|
3413
|
+
return;
|
|
3414
|
+
}
|
|
3415
|
+
if (this.lastSpokenCueKey === cueKey && !this.player.state.playing) {
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
this.speakCue(cue, cueKey);
|
|
3419
|
+
}
|
|
3420
|
+
/**
|
|
3421
|
+
* Pause playback and speak a description cue.
|
|
3422
|
+
*/
|
|
3423
|
+
speakCue(cue, cueKey) {
|
|
3424
|
+
var _a;
|
|
3425
|
+
if (!this.canUseSpeech()) {
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
if (this.player.state.paused && !this.speaking && !this.wasPlayingBeforeCue) {
|
|
3429
|
+
return;
|
|
3430
|
+
}
|
|
3431
|
+
this.cancelSpeech();
|
|
3432
|
+
this.wasPlayingBeforeCue = this.player.state.playing;
|
|
3433
|
+
if (this.wasPlayingBeforeCue) {
|
|
3434
|
+
this.player.pause();
|
|
3435
|
+
}
|
|
3436
|
+
this.speaking = true;
|
|
3437
|
+
this.lastSpokenCueKey = cueKey;
|
|
3438
|
+
const detail = {
|
|
3439
|
+
time: cue.startTime,
|
|
3440
|
+
endTime: cue.endTime,
|
|
3441
|
+
text: cue.text.trim(),
|
|
3442
|
+
cue
|
|
3443
|
+
};
|
|
3444
|
+
this.player.emit("audiodescriptioncuestart", detail);
|
|
3445
|
+
const utterance = new SpeechSynthesisUtterance(detail.text);
|
|
3446
|
+
const lang = ((_a = this.descriptionTrack) == null ? void 0 : _a.language) || this.player.options.language || "en";
|
|
3447
|
+
utterance.lang = lang;
|
|
3448
|
+
const finish = () => {
|
|
3449
|
+
if (this._pendingUtterance !== utterance) {
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
this._pendingUtterance = null;
|
|
3453
|
+
this.speaking = false;
|
|
3454
|
+
this.player.emit("audiodescriptioncueend", detail);
|
|
3455
|
+
const extended = this.player.options.audioDescriptionExtended !== false;
|
|
3456
|
+
const shouldResume = extended ? this.wasPlayingBeforeCue : this.wasPlayingBeforeCue && this.player.state.currentTime < cue.endTime;
|
|
3457
|
+
if (shouldResume && this.enabled) {
|
|
3458
|
+
void this.player.play();
|
|
3459
|
+
}
|
|
3460
|
+
this.wasPlayingBeforeCue = false;
|
|
3461
|
+
};
|
|
3462
|
+
utterance.onend = finish;
|
|
3463
|
+
utterance.onerror = finish;
|
|
3464
|
+
this._pendingUtterance = utterance;
|
|
3465
|
+
window.speechSynthesis.speak(utterance);
|
|
3466
|
+
}
|
|
3467
|
+
/**
|
|
3468
|
+
* Cancel any in-progress speech synthesis.
|
|
3469
|
+
*/
|
|
3470
|
+
cancelSpeech() {
|
|
3471
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
3472
|
+
window.speechSynthesis.cancel();
|
|
3473
|
+
}
|
|
3474
|
+
this._pendingUtterance = null;
|
|
3475
|
+
this.speaking = false;
|
|
3476
|
+
this.wasPlayingBeforeCue = false;
|
|
3477
|
+
}
|
|
3478
|
+
destroy() {
|
|
3479
|
+
this.disable();
|
|
3480
|
+
}
|
|
3481
|
+
};
|
|
3482
|
+
}
|
|
3483
|
+
});
|
|
3484
|
+
|
|
3156
3485
|
// src/core/AudioDescriptionManager.ts
|
|
3157
3486
|
var AudioDescriptionManager_exports = {};
|
|
3158
3487
|
__export(AudioDescriptionManager_exports, {
|
|
@@ -3163,6 +3492,7 @@
|
|
|
3163
3492
|
"src/core/AudioDescriptionManager.ts"() {
|
|
3164
3493
|
"use strict";
|
|
3165
3494
|
init_CaptionManager();
|
|
3495
|
+
init_DescriptionSpeechManager();
|
|
3166
3496
|
AudioDescriptionManager = class {
|
|
3167
3497
|
constructor(player) {
|
|
3168
3498
|
__publicField(this, "player");
|
|
@@ -3172,6 +3502,7 @@
|
|
|
3172
3502
|
__publicField(this, "originalSource");
|
|
3173
3503
|
__publicField(this, "sourceElement");
|
|
3174
3504
|
__publicField(this, "src");
|
|
3505
|
+
__publicField(this, "speechManager");
|
|
3175
3506
|
this.player = player;
|
|
3176
3507
|
this.enabled = false;
|
|
3177
3508
|
this.desiredState = false;
|
|
@@ -3179,6 +3510,49 @@
|
|
|
3179
3510
|
this.sourceElement = null;
|
|
3180
3511
|
this.originalSource = null;
|
|
3181
3512
|
this.captionTracks = [];
|
|
3513
|
+
this.speechManager = null;
|
|
3514
|
+
}
|
|
3515
|
+
/**
|
|
3516
|
+
* Whether a described video source swap is configured.
|
|
3517
|
+
*/
|
|
3518
|
+
_hasSwapSource() {
|
|
3519
|
+
const hasSourceElementsWithDesc = this.player.sourceElements.some(
|
|
3520
|
+
(el) => el.getAttribute("data-desc-src")
|
|
3521
|
+
);
|
|
3522
|
+
return Boolean(this.src || hasSourceElementsWithDesc);
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Whether a descriptions VTT track is present on the media element.
|
|
3526
|
+
*/
|
|
3527
|
+
_hasDescriptionsTrack() {
|
|
3528
|
+
return Boolean(this.player.findTextTrack("descriptions"));
|
|
3529
|
+
}
|
|
3530
|
+
/**
|
|
3531
|
+
* Resolve which audio-description delivery mode applies for the current media.
|
|
3532
|
+
*/
|
|
3533
|
+
resolveDeliveryMode() {
|
|
3534
|
+
const configured = this.player.options.audioDescriptionMode ?? "auto";
|
|
3535
|
+
const hasSwap = this._hasSwapSource();
|
|
3536
|
+
const hasDescriptions = this._hasDescriptionsTrack();
|
|
3537
|
+
if (configured === "swap") {
|
|
3538
|
+
return hasSwap ? "swap" : "none";
|
|
3539
|
+
}
|
|
3540
|
+
if (configured === "vtt_speech") {
|
|
3541
|
+
return hasDescriptions ? "vtt_speech" : "none";
|
|
3542
|
+
}
|
|
3543
|
+
if (hasSwap) {
|
|
3544
|
+
return "swap";
|
|
3545
|
+
}
|
|
3546
|
+
if (hasDescriptions) {
|
|
3547
|
+
return "vtt_speech";
|
|
3548
|
+
}
|
|
3549
|
+
return "none";
|
|
3550
|
+
}
|
|
3551
|
+
_ensureSpeechManager() {
|
|
3552
|
+
if (!this.speechManager) {
|
|
3553
|
+
this.speechManager = new DescriptionSpeechManager(this.player);
|
|
3554
|
+
}
|
|
3555
|
+
return this.speechManager;
|
|
3182
3556
|
}
|
|
3183
3557
|
/**
|
|
3184
3558
|
* Initialize audio description from source elements
|
|
@@ -3232,24 +3606,35 @@
|
|
|
3232
3606
|
* Check if audio description is available
|
|
3233
3607
|
*/
|
|
3234
3608
|
isAvailable() {
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3609
|
+
const mode = this.resolveDeliveryMode();
|
|
3610
|
+
if (mode === "swap" || mode === "vtt_speech") {
|
|
3611
|
+
return true;
|
|
3612
|
+
}
|
|
3613
|
+
return this.captionTracks.length > 0;
|
|
3239
3614
|
}
|
|
3240
3615
|
/**
|
|
3241
3616
|
* Enable audio description
|
|
3242
3617
|
*/
|
|
3243
3618
|
async enable() {
|
|
3244
|
-
const
|
|
3245
|
-
(el) => el.getAttribute("data-desc-src")
|
|
3246
|
-
);
|
|
3619
|
+
const deliveryMode = this.resolveDeliveryMode();
|
|
3247
3620
|
const hasTracksWithDesc = this.captionTracks.length > 0;
|
|
3248
|
-
if (
|
|
3249
|
-
console.warn("VidPly: No audio description source,
|
|
3621
|
+
if (deliveryMode === "none" && !hasTracksWithDesc) {
|
|
3622
|
+
console.warn("VidPly: No audio description source, descriptions track, or tracks provided");
|
|
3250
3623
|
return;
|
|
3251
3624
|
}
|
|
3252
3625
|
this.desiredState = true;
|
|
3626
|
+
if (deliveryMode === "vtt_speech") {
|
|
3627
|
+
const speechManager = this._ensureSpeechManager();
|
|
3628
|
+
const started = speechManager.enable();
|
|
3629
|
+
if (!started) {
|
|
3630
|
+
console.warn("VidPly: No descriptions track available for VTT speech mode");
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
this.enabled = true;
|
|
3634
|
+
this.player.state.audioDescriptionEnabled = true;
|
|
3635
|
+
this.player.emit("audiodescriptionenabled");
|
|
3636
|
+
return;
|
|
3637
|
+
}
|
|
3253
3638
|
const currentTime = this.player.state.currentTime;
|
|
3254
3639
|
const wasPlaying = this.player.state.playing;
|
|
3255
3640
|
const posterValue = this.player.element.poster || this.player.element.getAttribute("poster") || this.player.options.poster;
|
|
@@ -3269,7 +3654,15 @@
|
|
|
3269
3654
|
* Disable audio description
|
|
3270
3655
|
*/
|
|
3271
3656
|
async disable() {
|
|
3657
|
+
var _a;
|
|
3272
3658
|
this.desiredState = false;
|
|
3659
|
+
if ((_a = this.speechManager) == null ? void 0 : _a.enabled) {
|
|
3660
|
+
this.speechManager.disable();
|
|
3661
|
+
this.enabled = false;
|
|
3662
|
+
this.player.state.audioDescriptionEnabled = false;
|
|
3663
|
+
this.player.emit("audiodescriptiondisabled");
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3273
3666
|
const hasTracksWithDesc = this.captionTracks.length > 0;
|
|
3274
3667
|
if (!this.sourceElement && !this.src && hasTracksWithDesc) {
|
|
3275
3668
|
await this._swapCaptionTracks(false);
|
|
@@ -3295,19 +3688,30 @@
|
|
|
3295
3688
|
* Toggle audio description
|
|
3296
3689
|
*/
|
|
3297
3690
|
async toggle() {
|
|
3691
|
+
const deliveryMode = this.resolveDeliveryMode();
|
|
3298
3692
|
const descriptionTrack = this.player.findTextTrack("descriptions");
|
|
3299
|
-
const
|
|
3300
|
-
if (
|
|
3693
|
+
const hasSwapOrTracks = this._hasSwapSource() || this.captionTracks.length > 0;
|
|
3694
|
+
if (deliveryMode === "vtt_speech") {
|
|
3695
|
+
if (this.enabled) {
|
|
3696
|
+
await this.disable();
|
|
3697
|
+
} else {
|
|
3698
|
+
await this.enable();
|
|
3699
|
+
}
|
|
3700
|
+
return;
|
|
3701
|
+
}
|
|
3702
|
+
if (descriptionTrack && !hasSwapOrTracks) {
|
|
3301
3703
|
if (descriptionTrack.mode === "showing") {
|
|
3302
3704
|
descriptionTrack.mode = "hidden";
|
|
3303
3705
|
this.enabled = false;
|
|
3706
|
+
this.player.state.audioDescriptionEnabled = false;
|
|
3304
3707
|
this.player.emit("audiodescriptiondisabled");
|
|
3305
3708
|
} else {
|
|
3306
3709
|
descriptionTrack.mode = "showing";
|
|
3307
3710
|
this.enabled = true;
|
|
3711
|
+
this.player.state.audioDescriptionEnabled = true;
|
|
3308
3712
|
this.player.emit("audiodescriptionenabled");
|
|
3309
3713
|
}
|
|
3310
|
-
} else if (descriptionTrack &&
|
|
3714
|
+
} else if (descriptionTrack && hasSwapOrTracks) {
|
|
3311
3715
|
if (this.enabled) {
|
|
3312
3716
|
this.desiredState = false;
|
|
3313
3717
|
await this.disable();
|
|
@@ -3316,7 +3720,7 @@
|
|
|
3316
3720
|
this.desiredState = true;
|
|
3317
3721
|
await this.enable();
|
|
3318
3722
|
}
|
|
3319
|
-
} else if (
|
|
3723
|
+
} else if (hasSwapOrTracks) {
|
|
3320
3724
|
if (this.enabled) {
|
|
3321
3725
|
this.desiredState = false;
|
|
3322
3726
|
await this.disable();
|
|
@@ -3715,6 +4119,9 @@
|
|
|
3715
4119
|
* Update sources (called when playlist changes)
|
|
3716
4120
|
*/
|
|
3717
4121
|
updateSources(audioDescriptionSrc) {
|
|
4122
|
+
var _a;
|
|
4123
|
+
(_a = this.speechManager) == null ? void 0 : _a.destroy();
|
|
4124
|
+
this.speechManager = null;
|
|
3718
4125
|
this.src = audioDescriptionSrc || null;
|
|
3719
4126
|
this.enabled = false;
|
|
3720
4127
|
this.desiredState = false;
|
|
@@ -3733,6 +4140,9 @@
|
|
|
3733
4140
|
* Cleanup
|
|
3734
4141
|
*/
|
|
3735
4142
|
destroy() {
|
|
4143
|
+
var _a;
|
|
4144
|
+
(_a = this.speechManager) == null ? void 0 : _a.destroy();
|
|
4145
|
+
this.speechManager = null;
|
|
3736
4146
|
this.enabled = false;
|
|
3737
4147
|
this.desiredState = false;
|
|
3738
4148
|
this.captionTracks = [];
|
|
@@ -12102,6 +12512,12 @@
|
|
|
12102
12512
|
}
|
|
12103
12513
|
this.rightButtons.appendChild(btn);
|
|
12104
12514
|
}
|
|
12515
|
+
if (this.player.options.helpButton && this.player.options.keyboard) {
|
|
12516
|
+
const btn = this.createHelpButton();
|
|
12517
|
+
btn.dataset.overflowPriority = "3";
|
|
12518
|
+
btn.dataset.overflowPriorityMobile = "3";
|
|
12519
|
+
this.rightButtons.appendChild(btn);
|
|
12520
|
+
}
|
|
12105
12521
|
this.overflowMenuButton = this.createOverflowMenuButton();
|
|
12106
12522
|
this.overflowMenuButton.style.display = "none";
|
|
12107
12523
|
this.rightButtons.appendChild(this.overflowMenuButton);
|
|
@@ -13423,6 +13839,24 @@
|
|
|
13423
13839
|
const isVisible = this.player.transcriptManager && this.player.transcriptManager.isVisible;
|
|
13424
13840
|
this.controls.transcript.setAttribute("aria-expanded", isVisible ? "true" : "false");
|
|
13425
13841
|
}
|
|
13842
|
+
createHelpButton() {
|
|
13843
|
+
const ariaLabel = i18n.t("help.button");
|
|
13844
|
+
const button = DOMUtils.createElement("button", {
|
|
13845
|
+
className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-help`,
|
|
13846
|
+
attributes: {
|
|
13847
|
+
"type": "button",
|
|
13848
|
+
"aria-label": ariaLabel,
|
|
13849
|
+
"aria-haspopup": "dialog"
|
|
13850
|
+
}
|
|
13851
|
+
});
|
|
13852
|
+
button.appendChild(createIconElement("help"));
|
|
13853
|
+
DOMUtils.attachTooltip(button, ariaLabel, this.player.options.classPrefix);
|
|
13854
|
+
button.addEventListener("click", () => {
|
|
13855
|
+
this.player.toggleKeyboardHelp();
|
|
13856
|
+
});
|
|
13857
|
+
this.controls.help = button;
|
|
13858
|
+
return button;
|
|
13859
|
+
}
|
|
13426
13860
|
createAudioDescriptionButton() {
|
|
13427
13861
|
const ariaLabel = i18n.t("player.audioDescription");
|
|
13428
13862
|
const button = DOMUtils.createElement("button", {
|
|
@@ -14670,6 +15104,9 @@
|
|
|
14670
15104
|
return true;
|
|
14671
15105
|
}
|
|
14672
15106
|
return false;
|
|
15107
|
+
case "help":
|
|
15108
|
+
this.player.toggleKeyboardHelp();
|
|
15109
|
+
return true;
|
|
14673
15110
|
default:
|
|
14674
15111
|
return false;
|
|
14675
15112
|
}
|
|
@@ -14757,6 +15194,252 @@
|
|
|
14757
15194
|
}
|
|
14758
15195
|
};
|
|
14759
15196
|
|
|
15197
|
+
// src/core/MediaSessionManager.ts
|
|
15198
|
+
var POSITION_THROTTLE_MS = 1e3;
|
|
15199
|
+
var activeManager = null;
|
|
15200
|
+
var MediaSessionManager = class {
|
|
15201
|
+
constructor(player) {
|
|
15202
|
+
__publicField(this, "player");
|
|
15203
|
+
__publicField(this, "supported");
|
|
15204
|
+
__publicField(this, "handlers", {});
|
|
15205
|
+
__publicField(this, "boundActions", []);
|
|
15206
|
+
__publicField(this, "lastPositionUpdate", 0);
|
|
15207
|
+
this.player = player;
|
|
15208
|
+
this.supported = typeof navigator !== "undefined" && "mediaSession" in navigator;
|
|
15209
|
+
if (!this.supported) return;
|
|
15210
|
+
this.attachEvents();
|
|
15211
|
+
if (activeManager === null) {
|
|
15212
|
+
this.claimSession();
|
|
15213
|
+
}
|
|
15214
|
+
}
|
|
15215
|
+
/** Does this manager currently own the global media session? */
|
|
15216
|
+
isActive() {
|
|
15217
|
+
return activeManager === this;
|
|
15218
|
+
}
|
|
15219
|
+
/**
|
|
15220
|
+
* Take ownership of the global session: (re)register the action handlers so
|
|
15221
|
+
* the OS controls drive this player, and refresh metadata/state/position.
|
|
15222
|
+
*/
|
|
15223
|
+
claimSession() {
|
|
15224
|
+
if (!this.supported) return;
|
|
15225
|
+
activeManager = this;
|
|
15226
|
+
this.setupActionHandlers();
|
|
15227
|
+
this.updateMetadata();
|
|
15228
|
+
this.updatePlaybackState();
|
|
15229
|
+
this.updatePositionState(true);
|
|
15230
|
+
}
|
|
15231
|
+
get session() {
|
|
15232
|
+
return navigator.mediaSession;
|
|
15233
|
+
}
|
|
15234
|
+
setActionHandler(action, handler) {
|
|
15235
|
+
try {
|
|
15236
|
+
this.session.setActionHandler(action, handler);
|
|
15237
|
+
if (handler && !this.boundActions.includes(action)) {
|
|
15238
|
+
this.boundActions.push(action);
|
|
15239
|
+
}
|
|
15240
|
+
} catch {
|
|
15241
|
+
}
|
|
15242
|
+
}
|
|
15243
|
+
setupActionHandlers() {
|
|
15244
|
+
this.setActionHandler("play", () => this.player.play());
|
|
15245
|
+
this.setActionHandler("pause", () => this.player.pause());
|
|
15246
|
+
this.setActionHandler("stop", () => this.player.stop());
|
|
15247
|
+
this.setActionHandler("seekbackward", (details) => {
|
|
15248
|
+
this.player.seekBackward(this.offsetFrom(details));
|
|
15249
|
+
});
|
|
15250
|
+
this.setActionHandler("seekforward", (details) => {
|
|
15251
|
+
this.player.seekForward(this.offsetFrom(details));
|
|
15252
|
+
});
|
|
15253
|
+
this.setActionHandler("seekto", (details) => {
|
|
15254
|
+
if (details && typeof details.seekTime === "number") {
|
|
15255
|
+
this.player.seek(details.seekTime);
|
|
15256
|
+
}
|
|
15257
|
+
});
|
|
15258
|
+
this.updateTrackHandlers();
|
|
15259
|
+
}
|
|
15260
|
+
offsetFrom(details) {
|
|
15261
|
+
const offset = details && typeof details.seekOffset === "number" ? details.seekOffset : void 0;
|
|
15262
|
+
return typeof offset === "number" && offset > 0 ? offset : void 0;
|
|
15263
|
+
}
|
|
15264
|
+
/**
|
|
15265
|
+
* previous/next track only make sense with a multi-item playlist; bind
|
|
15266
|
+
* or clear them whenever the playlist state changes so the OS shows the
|
|
15267
|
+
* correct affordances.
|
|
15268
|
+
*/
|
|
15269
|
+
updateTrackHandlers() {
|
|
15270
|
+
const pm = this.player.playlistManager;
|
|
15271
|
+
const hasPlaylist = Boolean(pm && Array.isArray(pm.tracks) && pm.tracks.length > 1);
|
|
15272
|
+
if (hasPlaylist && pm) {
|
|
15273
|
+
this.setActionHandler("previoustrack", () => pm.previous());
|
|
15274
|
+
this.setActionHandler("nexttrack", () => pm.next());
|
|
15275
|
+
} else {
|
|
15276
|
+
this.setActionHandler("previoustrack", null);
|
|
15277
|
+
this.setActionHandler("nexttrack", null);
|
|
15278
|
+
}
|
|
15279
|
+
}
|
|
15280
|
+
attachEvents() {
|
|
15281
|
+
this.handlers = {
|
|
15282
|
+
// Starting playback makes this player the session owner, taking over
|
|
15283
|
+
// the OS controls from any other player on the page.
|
|
15284
|
+
play: () => this.claimSession(),
|
|
15285
|
+
pause: () => {
|
|
15286
|
+
if (!this.isActive()) return;
|
|
15287
|
+
this.updatePlaybackState();
|
|
15288
|
+
this.updatePositionState(true);
|
|
15289
|
+
},
|
|
15290
|
+
ended: () => {
|
|
15291
|
+
if (!this.isActive()) return;
|
|
15292
|
+
this.updatePlaybackState();
|
|
15293
|
+
},
|
|
15294
|
+
timeupdate: () => {
|
|
15295
|
+
if (!this.isActive()) return;
|
|
15296
|
+
this.updatePositionState();
|
|
15297
|
+
},
|
|
15298
|
+
durationchange: () => {
|
|
15299
|
+
if (!this.isActive()) return;
|
|
15300
|
+
this.updatePositionState(true);
|
|
15301
|
+
},
|
|
15302
|
+
ratechange: () => {
|
|
15303
|
+
if (!this.isActive()) return;
|
|
15304
|
+
this.updatePositionState(true);
|
|
15305
|
+
},
|
|
15306
|
+
loadedmetadata: () => {
|
|
15307
|
+
if (!this.isActive()) return;
|
|
15308
|
+
this.updateMetadata();
|
|
15309
|
+
this.updatePositionState(true);
|
|
15310
|
+
},
|
|
15311
|
+
playlisttrackchange: () => {
|
|
15312
|
+
if (!this.isActive()) return;
|
|
15313
|
+
this.updateMetadata();
|
|
15314
|
+
this.updateTrackHandlers();
|
|
15315
|
+
this.updatePositionState(true);
|
|
15316
|
+
}
|
|
15317
|
+
};
|
|
15318
|
+
for (const [event, handler] of Object.entries(this.handlers)) {
|
|
15319
|
+
if (handler) {
|
|
15320
|
+
this.player.on(event, handler);
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
}
|
|
15324
|
+
resolveMetadata() {
|
|
15325
|
+
const opts = this.player.options;
|
|
15326
|
+
let title = opts.title || "";
|
|
15327
|
+
let artist = opts.artist || "";
|
|
15328
|
+
const album = opts.album || "";
|
|
15329
|
+
let poster = opts.poster || null;
|
|
15330
|
+
const pm = this.player.playlistManager;
|
|
15331
|
+
if (pm && Array.isArray(pm.tracks) && pm.currentIndex >= 0) {
|
|
15332
|
+
const track = pm.tracks[pm.currentIndex];
|
|
15333
|
+
if (track) {
|
|
15334
|
+
if (track.title) title = track.title;
|
|
15335
|
+
if (track.artist) artist = track.artist;
|
|
15336
|
+
if (track.poster) poster = track.poster;
|
|
15337
|
+
}
|
|
15338
|
+
}
|
|
15339
|
+
if (!title && typeof document !== "undefined") {
|
|
15340
|
+
title = document.title || "VidPly";
|
|
15341
|
+
}
|
|
15342
|
+
return { title, artist, album, poster };
|
|
15343
|
+
}
|
|
15344
|
+
updateMetadata() {
|
|
15345
|
+
if (!this.supported || typeof window === "undefined" || typeof window.MediaMetadata === "undefined") {
|
|
15346
|
+
return;
|
|
15347
|
+
}
|
|
15348
|
+
const { title, artist, album, poster } = this.resolveMetadata();
|
|
15349
|
+
const artwork = [];
|
|
15350
|
+
if (poster) {
|
|
15351
|
+
try {
|
|
15352
|
+
const src = this.player.resolvePosterPath(poster);
|
|
15353
|
+
if (src) {
|
|
15354
|
+
artwork.push({ src });
|
|
15355
|
+
}
|
|
15356
|
+
} catch {
|
|
15357
|
+
}
|
|
15358
|
+
}
|
|
15359
|
+
try {
|
|
15360
|
+
this.session.metadata = new window.MediaMetadata({
|
|
15361
|
+
title,
|
|
15362
|
+
artist,
|
|
15363
|
+
album,
|
|
15364
|
+
artwork
|
|
15365
|
+
});
|
|
15366
|
+
} catch {
|
|
15367
|
+
}
|
|
15368
|
+
}
|
|
15369
|
+
updatePlaybackState() {
|
|
15370
|
+
if (!this.supported) return;
|
|
15371
|
+
try {
|
|
15372
|
+
this.session.playbackState = this.player.state.playing ? "playing" : "paused";
|
|
15373
|
+
} catch {
|
|
15374
|
+
}
|
|
15375
|
+
}
|
|
15376
|
+
/**
|
|
15377
|
+
* Push the current position to the OS scrubber. `timeupdate` fires
|
|
15378
|
+
* several times a second, so non-forced updates are throttled.
|
|
15379
|
+
*/
|
|
15380
|
+
updatePositionState(force = false) {
|
|
15381
|
+
if (!this.supported || typeof this.session.setPositionState !== "function") {
|
|
15382
|
+
return;
|
|
15383
|
+
}
|
|
15384
|
+
const now = Date.now();
|
|
15385
|
+
if (!force && now - this.lastPositionUpdate < POSITION_THROTTLE_MS) {
|
|
15386
|
+
return;
|
|
15387
|
+
}
|
|
15388
|
+
this.lastPositionUpdate = now;
|
|
15389
|
+
const duration = this.player.state.duration;
|
|
15390
|
+
if (!Number.isFinite(duration) || duration <= 0) {
|
|
15391
|
+
try {
|
|
15392
|
+
this.session.setPositionState();
|
|
15393
|
+
} catch {
|
|
15394
|
+
}
|
|
15395
|
+
return;
|
|
15396
|
+
}
|
|
15397
|
+
const playbackRate = this.player.state.playbackSpeed || 1;
|
|
15398
|
+
const position = Math.min(Math.max(0, this.player.state.currentTime || 0), duration);
|
|
15399
|
+
try {
|
|
15400
|
+
this.session.setPositionState({
|
|
15401
|
+
duration,
|
|
15402
|
+
playbackRate: playbackRate > 0 ? playbackRate : 1,
|
|
15403
|
+
position
|
|
15404
|
+
});
|
|
15405
|
+
} catch {
|
|
15406
|
+
}
|
|
15407
|
+
}
|
|
15408
|
+
destroy() {
|
|
15409
|
+
if (!this.supported) return;
|
|
15410
|
+
for (const [event, handler] of Object.entries(this.handlers)) {
|
|
15411
|
+
if (handler) {
|
|
15412
|
+
this.player.off(event, handler);
|
|
15413
|
+
}
|
|
15414
|
+
}
|
|
15415
|
+
this.handlers = {};
|
|
15416
|
+
if (this.isActive()) {
|
|
15417
|
+
for (const action of this.boundActions) {
|
|
15418
|
+
try {
|
|
15419
|
+
this.session.setActionHandler(action, null);
|
|
15420
|
+
} catch {
|
|
15421
|
+
}
|
|
15422
|
+
}
|
|
15423
|
+
try {
|
|
15424
|
+
this.session.metadata = null;
|
|
15425
|
+
} catch {
|
|
15426
|
+
}
|
|
15427
|
+
try {
|
|
15428
|
+
if (typeof this.session.setPositionState === "function") {
|
|
15429
|
+
this.session.setPositionState();
|
|
15430
|
+
}
|
|
15431
|
+
} catch {
|
|
15432
|
+
}
|
|
15433
|
+
try {
|
|
15434
|
+
this.session.playbackState = "none";
|
|
15435
|
+
} catch {
|
|
15436
|
+
}
|
|
15437
|
+
activeManager = null;
|
|
15438
|
+
}
|
|
15439
|
+
this.boundActions = [];
|
|
15440
|
+
}
|
|
15441
|
+
};
|
|
15442
|
+
|
|
14760
15443
|
// src/core/Player.ts
|
|
14761
15444
|
init_HTML5Renderer();
|
|
14762
15445
|
init_Icons();
|
|
@@ -15873,6 +16556,263 @@
|
|
|
15873
16556
|
}
|
|
15874
16557
|
};
|
|
15875
16558
|
|
|
16559
|
+
// src/controls/KeyboardHelp.ts
|
|
16560
|
+
init_DOMUtils();
|
|
16561
|
+
init_Icons();
|
|
16562
|
+
init_i18n();
|
|
16563
|
+
var ACTION_ORDER = [
|
|
16564
|
+
"play-pause",
|
|
16565
|
+
"seek-backward",
|
|
16566
|
+
"seek-forward",
|
|
16567
|
+
"volume-up",
|
|
16568
|
+
"volume-down",
|
|
16569
|
+
"mute",
|
|
16570
|
+
"captions",
|
|
16571
|
+
"caption-style-menu",
|
|
16572
|
+
"speed-down",
|
|
16573
|
+
"speed-up",
|
|
16574
|
+
"speed-menu",
|
|
16575
|
+
"quality-menu",
|
|
16576
|
+
"chapters-menu",
|
|
16577
|
+
"transcript-toggle",
|
|
16578
|
+
"fullscreen",
|
|
16579
|
+
"help"
|
|
16580
|
+
];
|
|
16581
|
+
var ACTION_REQUIRES_CONTROL = {
|
|
16582
|
+
captions: "captions",
|
|
16583
|
+
"caption-style-menu": "captionStyle",
|
|
16584
|
+
"speed-down": "speed",
|
|
16585
|
+
"speed-up": "speed",
|
|
16586
|
+
"speed-menu": "speed",
|
|
16587
|
+
"quality-menu": "quality",
|
|
16588
|
+
"chapters-menu": "chapters",
|
|
16589
|
+
"transcript-toggle": "transcript",
|
|
16590
|
+
fullscreen: "fullscreen"
|
|
16591
|
+
};
|
|
16592
|
+
var KeyboardHelp = class {
|
|
16593
|
+
constructor(player) {
|
|
16594
|
+
__publicField(this, "player");
|
|
16595
|
+
__publicField(this, "isOpen", false);
|
|
16596
|
+
__publicField(this, "overlay", null);
|
|
16597
|
+
__publicField(this, "_triggerElement", null);
|
|
16598
|
+
__publicField(this, "_keydownHandler", null);
|
|
16599
|
+
__publicField(this, "_content", null);
|
|
16600
|
+
this.player = player;
|
|
16601
|
+
}
|
|
16602
|
+
get prefix() {
|
|
16603
|
+
return this.player.options.classPrefix;
|
|
16604
|
+
}
|
|
16605
|
+
/**
|
|
16606
|
+
* Turn a raw KeyboardEvent.key value into a human-readable label. Arrow
|
|
16607
|
+
* keys become universally understood glyphs; the space bar and single
|
|
16608
|
+
* letters are normalised for legibility.
|
|
16609
|
+
*/
|
|
16610
|
+
formatKey(key) {
|
|
16611
|
+
switch (key) {
|
|
16612
|
+
case " ":
|
|
16613
|
+
return i18n.t("help.keys.space");
|
|
16614
|
+
case "ArrowUp":
|
|
16615
|
+
return "↑";
|
|
16616
|
+
case "ArrowDown":
|
|
16617
|
+
return "↓";
|
|
16618
|
+
case "ArrowLeft":
|
|
16619
|
+
return "←";
|
|
16620
|
+
case "ArrowRight":
|
|
16621
|
+
return "→";
|
|
16622
|
+
case "Escape":
|
|
16623
|
+
return "Esc";
|
|
16624
|
+
default:
|
|
16625
|
+
return key.length === 1 ? key.toUpperCase() : key;
|
|
16626
|
+
}
|
|
16627
|
+
}
|
|
16628
|
+
createElement() {
|
|
16629
|
+
const titleId = `${this.prefix}-help-title-${this.player.instanceId}`;
|
|
16630
|
+
const overlay = DOMUtils.createElement("div", {
|
|
16631
|
+
className: `${this.prefix}-settings-overlay ${this.prefix}-help-overlay`,
|
|
16632
|
+
attributes: {
|
|
16633
|
+
role: "dialog",
|
|
16634
|
+
"aria-modal": "true",
|
|
16635
|
+
"aria-labelledby": titleId
|
|
16636
|
+
}
|
|
16637
|
+
});
|
|
16638
|
+
overlay.style.display = "none";
|
|
16639
|
+
const dialog = DOMUtils.createElement("div", {
|
|
16640
|
+
className: `${this.prefix}-settings-dialog ${this.prefix}-help-dialog`
|
|
16641
|
+
});
|
|
16642
|
+
const header = DOMUtils.createElement("div", {
|
|
16643
|
+
className: `${this.prefix}-settings-header`
|
|
16644
|
+
});
|
|
16645
|
+
const title = DOMUtils.createElement("h2", {
|
|
16646
|
+
textContent: i18n.t("help.title"),
|
|
16647
|
+
attributes: { id: titleId }
|
|
16648
|
+
});
|
|
16649
|
+
const closeButton = DOMUtils.createElement("button", {
|
|
16650
|
+
className: `${this.prefix}-button ${this.prefix}-settings-close`,
|
|
16651
|
+
attributes: {
|
|
16652
|
+
type: "button",
|
|
16653
|
+
"aria-label": i18n.t("help.close")
|
|
16654
|
+
}
|
|
16655
|
+
});
|
|
16656
|
+
closeButton.appendChild(createIconElement("close"));
|
|
16657
|
+
closeButton.addEventListener("click", () => this.hide());
|
|
16658
|
+
header.appendChild(title);
|
|
16659
|
+
header.appendChild(closeButton);
|
|
16660
|
+
const content = DOMUtils.createElement("div", {
|
|
16661
|
+
className: `${this.prefix}-settings-content`
|
|
16662
|
+
});
|
|
16663
|
+
this._content = content;
|
|
16664
|
+
content.appendChild(this.buildShortcutList());
|
|
16665
|
+
dialog.appendChild(header);
|
|
16666
|
+
dialog.appendChild(content);
|
|
16667
|
+
overlay.appendChild(dialog);
|
|
16668
|
+
overlay.addEventListener("click", (e) => {
|
|
16669
|
+
if (e.target === overlay) {
|
|
16670
|
+
this.hide();
|
|
16671
|
+
}
|
|
16672
|
+
});
|
|
16673
|
+
this._keydownHandler = (e) => {
|
|
16674
|
+
if (!this.isOpen || !this.overlay) return;
|
|
16675
|
+
if (e.key === "Escape") {
|
|
16676
|
+
e.preventDefault();
|
|
16677
|
+
this.hide();
|
|
16678
|
+
return;
|
|
16679
|
+
}
|
|
16680
|
+
if (e.key === "Tab") {
|
|
16681
|
+
const focusable = Array.from(
|
|
16682
|
+
this.overlay.querySelectorAll(
|
|
16683
|
+
'button, [href], select, input, textarea, [tabindex]:not([tabindex="-1"])'
|
|
16684
|
+
)
|
|
16685
|
+
).filter((el) => !el.hasAttribute("disabled") && el.offsetParent !== null);
|
|
16686
|
+
if (focusable.length === 0) return;
|
|
16687
|
+
const first = focusable[0];
|
|
16688
|
+
const last = focusable[focusable.length - 1];
|
|
16689
|
+
if (!first || !last) return;
|
|
16690
|
+
const active = document.activeElement;
|
|
16691
|
+
if (e.shiftKey && (active === first || !this.overlay.contains(active))) {
|
|
16692
|
+
e.preventDefault();
|
|
16693
|
+
last.focus({ preventScroll: true });
|
|
16694
|
+
} else if (!e.shiftKey && active === last) {
|
|
16695
|
+
e.preventDefault();
|
|
16696
|
+
first.focus({ preventScroll: true });
|
|
16697
|
+
}
|
|
16698
|
+
}
|
|
16699
|
+
};
|
|
16700
|
+
const lifecycleSignal = this.player.lifecycleSignal;
|
|
16701
|
+
document.addEventListener(
|
|
16702
|
+
"keydown",
|
|
16703
|
+
this._keydownHandler,
|
|
16704
|
+
lifecycleSignal ? { signal: lifecycleSignal } : void 0
|
|
16705
|
+
);
|
|
16706
|
+
return overlay;
|
|
16707
|
+
}
|
|
16708
|
+
/**
|
|
16709
|
+
* Whether a shortcut row is worth showing for *this* player. Feature actions
|
|
16710
|
+
* are hidden when their control isn't present (e.g. no captions track, an
|
|
16711
|
+
* audio-only player with no fullscreen). Core actions are always relevant.
|
|
16712
|
+
*
|
|
16713
|
+
* When the player has no control bar we can't infer availability, so nothing
|
|
16714
|
+
* is hidden — the shortcuts still work and we'd rather over-show than mislead.
|
|
16715
|
+
*/
|
|
16716
|
+
isActionRelevant(action) {
|
|
16717
|
+
const requiredControl = ACTION_REQUIRES_CONTROL[action];
|
|
16718
|
+
if (!requiredControl) return true;
|
|
16719
|
+
const controlBar = this.player.controlBar;
|
|
16720
|
+
if (!controlBar || !controlBar.controls) return true;
|
|
16721
|
+
return Boolean(controlBar.controls[requiredControl]);
|
|
16722
|
+
}
|
|
16723
|
+
buildShortcutList() {
|
|
16724
|
+
const list = DOMUtils.createElement("dl", {
|
|
16725
|
+
className: `${this.prefix}-help-list`
|
|
16726
|
+
});
|
|
16727
|
+
const shortcuts = this.player.options.keyboardShortcuts;
|
|
16728
|
+
for (const action of ACTION_ORDER) {
|
|
16729
|
+
const keys = shortcuts[action];
|
|
16730
|
+
if (!Array.isArray(keys) || keys.length === 0) continue;
|
|
16731
|
+
if (!this.isActionRelevant(action)) continue;
|
|
16732
|
+
const term = DOMUtils.createElement("dt", {
|
|
16733
|
+
className: `${this.prefix}-help-action`,
|
|
16734
|
+
textContent: i18n.t(`help.actions.${action}`)
|
|
16735
|
+
});
|
|
16736
|
+
const desc = DOMUtils.createElement("dd", {
|
|
16737
|
+
className: `${this.prefix}-help-keys`
|
|
16738
|
+
});
|
|
16739
|
+
keys.forEach((key, index) => {
|
|
16740
|
+
if (index > 0) {
|
|
16741
|
+
desc.appendChild(
|
|
16742
|
+
DOMUtils.createElement("span", {
|
|
16743
|
+
className: `${this.prefix}-help-key-sep`,
|
|
16744
|
+
textContent: i18n.t("help.or")
|
|
16745
|
+
})
|
|
16746
|
+
);
|
|
16747
|
+
}
|
|
16748
|
+
desc.appendChild(
|
|
16749
|
+
DOMUtils.createElement("kbd", {
|
|
16750
|
+
className: `${this.prefix}-help-key`,
|
|
16751
|
+
textContent: this.formatKey(key)
|
|
16752
|
+
})
|
|
16753
|
+
);
|
|
16754
|
+
});
|
|
16755
|
+
list.appendChild(term);
|
|
16756
|
+
list.appendChild(desc);
|
|
16757
|
+
}
|
|
16758
|
+
return list;
|
|
16759
|
+
}
|
|
16760
|
+
show() {
|
|
16761
|
+
if (this.isOpen) return;
|
|
16762
|
+
if (!this.overlay) {
|
|
16763
|
+
this.overlay = this.createElement();
|
|
16764
|
+
this.player.container.appendChild(this.overlay);
|
|
16765
|
+
} else if (this._content) {
|
|
16766
|
+
this._content.replaceChildren(this.buildShortcutList());
|
|
16767
|
+
}
|
|
16768
|
+
const active = typeof document !== "undefined" ? document.activeElement : null;
|
|
16769
|
+
this._triggerElement = active && typeof active.focus === "function" ? active : null;
|
|
16770
|
+
this.overlay.style.display = "flex";
|
|
16771
|
+
this.isOpen = true;
|
|
16772
|
+
const closeButton = this.overlay.querySelector(`.${this.prefix}-settings-close`);
|
|
16773
|
+
closeButton == null ? void 0 : closeButton.focus({ preventScroll: true });
|
|
16774
|
+
this.player.emit("keyboardhelpopen");
|
|
16775
|
+
}
|
|
16776
|
+
hide() {
|
|
16777
|
+
var _a, _b;
|
|
16778
|
+
if (!this.overlay) return;
|
|
16779
|
+
this.overlay.style.display = "none";
|
|
16780
|
+
this.isOpen = false;
|
|
16781
|
+
const trigger = this._triggerElement;
|
|
16782
|
+
this._triggerElement = null;
|
|
16783
|
+
if (trigger && document.contains(trigger)) {
|
|
16784
|
+
try {
|
|
16785
|
+
trigger.focus({ preventScroll: true });
|
|
16786
|
+
} catch {
|
|
16787
|
+
(_a = this.player.container) == null ? void 0 : _a.focus();
|
|
16788
|
+
}
|
|
16789
|
+
} else {
|
|
16790
|
+
(_b = this.player.container) == null ? void 0 : _b.focus();
|
|
16791
|
+
}
|
|
16792
|
+
this.player.emit("keyboardhelpclose");
|
|
16793
|
+
}
|
|
16794
|
+
toggle() {
|
|
16795
|
+
if (this.isOpen) {
|
|
16796
|
+
this.hide();
|
|
16797
|
+
} else {
|
|
16798
|
+
this.show();
|
|
16799
|
+
}
|
|
16800
|
+
}
|
|
16801
|
+
destroy() {
|
|
16802
|
+
if (this._keydownHandler) {
|
|
16803
|
+
document.removeEventListener("keydown", this._keydownHandler);
|
|
16804
|
+
this._keydownHandler = null;
|
|
16805
|
+
}
|
|
16806
|
+
if (this.overlay && this.overlay.parentNode) {
|
|
16807
|
+
this.overlay.parentNode.removeChild(this.overlay);
|
|
16808
|
+
}
|
|
16809
|
+
this.overlay = null;
|
|
16810
|
+
this._content = null;
|
|
16811
|
+
this._triggerElement = null;
|
|
16812
|
+
this.isOpen = false;
|
|
16813
|
+
}
|
|
16814
|
+
};
|
|
16815
|
+
|
|
15876
16816
|
// src/core/Player.ts
|
|
15877
16817
|
var AudioDescriptionManagerModule = null;
|
|
15878
16818
|
var SignLanguageManagerModule = null;
|
|
@@ -15916,9 +16856,11 @@
|
|
|
15916
16856
|
__publicField(this, "controlBar", null);
|
|
15917
16857
|
__publicField(this, "captionManager", null);
|
|
15918
16858
|
__publicField(this, "keyboardManager", null);
|
|
16859
|
+
__publicField(this, "mediaSessionManager", null);
|
|
15919
16860
|
__publicField(this, "transcriptManager", null);
|
|
15920
16861
|
__publicField(this, "playlistManager", null);
|
|
15921
16862
|
__publicField(this, "settingsDialog", null);
|
|
16863
|
+
__publicField(this, "keyboardHelp", null);
|
|
15922
16864
|
__publicField(this, "audioDescriptionManager", null);
|
|
15923
16865
|
__publicField(this, "signLanguageManager", null);
|
|
15924
16866
|
__publicField(this, "floatingPlayerManager", null);
|
|
@@ -16032,6 +16974,11 @@
|
|
|
16032
16974
|
poster: null,
|
|
16033
16975
|
responsive: true,
|
|
16034
16976
|
fillContainer: false,
|
|
16977
|
+
// Media metadata + OS media controls (Media Session API)
|
|
16978
|
+
title: null,
|
|
16979
|
+
artist: null,
|
|
16980
|
+
album: null,
|
|
16981
|
+
mediaSession: true,
|
|
16035
16982
|
// Playback
|
|
16036
16983
|
autoplay: false,
|
|
16037
16984
|
loop: false,
|
|
@@ -16079,6 +17026,7 @@
|
|
|
16079
17026
|
captionsButton: true,
|
|
16080
17027
|
transcriptButton: true,
|
|
16081
17028
|
fullscreenButton: true,
|
|
17029
|
+
helpButton: true,
|
|
16082
17030
|
pipButton: false,
|
|
16083
17031
|
floating: false,
|
|
16084
17032
|
floatingPosition: "bottom-right",
|
|
@@ -16104,6 +17052,9 @@
|
|
|
16104
17052
|
audioDescriptionSrc: null,
|
|
16105
17053
|
// URL to audio-described version
|
|
16106
17054
|
audioDescriptionButton: true,
|
|
17055
|
+
audioDescriptionMode: "auto",
|
|
17056
|
+
audioDescriptionSpeech: true,
|
|
17057
|
+
audioDescriptionExtended: true,
|
|
16107
17058
|
// Sign Language
|
|
16108
17059
|
signLanguage: true,
|
|
16109
17060
|
signLanguageSrc: null,
|
|
@@ -16134,7 +17085,8 @@
|
|
|
16134
17085
|
"speed-menu": ["s"],
|
|
16135
17086
|
"quality-menu": ["q"],
|
|
16136
17087
|
"chapters-menu": ["j"],
|
|
16137
|
-
"transcript-toggle": ["t"]
|
|
17088
|
+
"transcript-toggle": ["t"],
|
|
17089
|
+
"help": ["?"]
|
|
16138
17090
|
},
|
|
16139
17091
|
// Accessibility
|
|
16140
17092
|
ariaLabels: {},
|
|
@@ -16517,6 +17469,9 @@
|
|
|
16517
17469
|
if (this.options.keyboard) {
|
|
16518
17470
|
this.keyboardManager = new KeyboardManager(this);
|
|
16519
17471
|
}
|
|
17472
|
+
if (this.options.mediaSession) {
|
|
17473
|
+
this.mediaSessionManager = new MediaSessionManager(this);
|
|
17474
|
+
}
|
|
16520
17475
|
this.setupResponsiveHandlers();
|
|
16521
17476
|
if (this.options.startTime > 0) {
|
|
16522
17477
|
this.seek(this.options.startTime);
|
|
@@ -16589,15 +17544,33 @@
|
|
|
16589
17544
|
if (this.audioDescriptionManager) {
|
|
16590
17545
|
return this.audioDescriptionManager;
|
|
16591
17546
|
}
|
|
16592
|
-
|
|
16593
|
-
const hasAudioDescButton = this.options.audioDescriptionButton;
|
|
16594
|
-
if (!hasAudioDescSrc && !hasAudioDescButton) {
|
|
17547
|
+
if (!this.hasAudioDescriptionContent()) {
|
|
16595
17548
|
return null;
|
|
16596
17549
|
}
|
|
16597
17550
|
const AudioDescManager = await loadAudioDescriptionManager();
|
|
16598
17551
|
this.audioDescriptionManager = new AudioDescManager(this);
|
|
16599
17552
|
return this.audioDescriptionManager;
|
|
16600
17553
|
}
|
|
17554
|
+
/**
|
|
17555
|
+
* True when the current media actually exposes audio-description content:
|
|
17556
|
+
* an explicit described-audio source, `<source>` elements carrying
|
|
17557
|
+
* `data-desc-src` / `data-orig-src`, or a `descriptions` text track.
|
|
17558
|
+
* Mirrors `ControlBar.hasAudioDescription()` so the chunk load and the
|
|
17559
|
+
* button visibility stay in lock-step.
|
|
17560
|
+
*/
|
|
17561
|
+
hasAudioDescriptionContent() {
|
|
17562
|
+
if (this.options.audioDescriptionSrc || this.audioDescriptionSrc) {
|
|
17563
|
+
return true;
|
|
17564
|
+
}
|
|
17565
|
+
const hasSourceElementsWithDesc = this.sourceElements.some(
|
|
17566
|
+
(el) => el.getAttribute("data-desc-src") || el.getAttribute("data-orig-src")
|
|
17567
|
+
);
|
|
17568
|
+
if (hasSourceElementsWithDesc) {
|
|
17569
|
+
return true;
|
|
17570
|
+
}
|
|
17571
|
+
const textTracks = this.element ? Array.from(this.element.textTracks || []) : [];
|
|
17572
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
17573
|
+
}
|
|
16601
17574
|
// ============================================
|
|
16602
17575
|
// Resume Playback Methods
|
|
16603
17576
|
// ============================================
|
|
@@ -16609,16 +17582,24 @@
|
|
|
16609
17582
|
if (this.signLanguageManager) {
|
|
16610
17583
|
return this.signLanguageManager;
|
|
16611
17584
|
}
|
|
16612
|
-
|
|
16613
|
-
const hasSignLangSources = this.options.signLanguageSources && Object.keys(this.options.signLanguageSources).length > 0;
|
|
16614
|
-
const hasSignLangButton = this.options.signLanguageButton;
|
|
16615
|
-
if (!hasSignLangSrc && !hasSignLangSources && !hasSignLangButton) {
|
|
17585
|
+
if (!this.hasSignLanguageContent()) {
|
|
16616
17586
|
return null;
|
|
16617
17587
|
}
|
|
16618
17588
|
const SignLangManager = await loadSignLanguageManager();
|
|
16619
17589
|
this.signLanguageManager = new SignLangManager(this);
|
|
16620
17590
|
return this.signLanguageManager;
|
|
16621
17591
|
}
|
|
17592
|
+
/**
|
|
17593
|
+
* True when a sign-language video source (single `signLanguageSrc` or a
|
|
17594
|
+
* `signLanguageSources` map) is configured. Mirrors
|
|
17595
|
+
* `ControlBar.hasSignLanguage()`.
|
|
17596
|
+
*/
|
|
17597
|
+
hasSignLanguageContent() {
|
|
17598
|
+
if (this.options.signLanguageSrc || this.signLanguageSrc) {
|
|
17599
|
+
return true;
|
|
17600
|
+
}
|
|
17601
|
+
return !!(this.options.signLanguageSources && Object.keys(this.options.signLanguageSources).length > 0);
|
|
17602
|
+
}
|
|
16622
17603
|
/**
|
|
16623
17604
|
* Lazy-load and instantiate the floating (in-page PiP) manager. Only
|
|
16624
17605
|
* created when `options.floating === true` and the media element is a
|
|
@@ -16643,13 +17624,10 @@
|
|
|
16643
17624
|
*/
|
|
16644
17625
|
async initFeatureManagers() {
|
|
16645
17626
|
const promises = [];
|
|
16646
|
-
|
|
16647
|
-
(el) => el.getAttribute("data-desc-src") || el.getAttribute("data-orig-src")
|
|
16648
|
-
);
|
|
16649
|
-
if (this.options.audioDescriptionButton || this.options.audioDescriptionSrc || this.audioDescriptionSrc || hasSourceElementsWithDesc) {
|
|
17627
|
+
if (this.hasAudioDescriptionContent()) {
|
|
16650
17628
|
promises.push(this.ensureAudioDescriptionManager());
|
|
16651
17629
|
}
|
|
16652
|
-
if (this.
|
|
17630
|
+
if (this.hasSignLanguageContent()) {
|
|
16653
17631
|
promises.push(this.ensureSignLanguageManager());
|
|
16654
17632
|
}
|
|
16655
17633
|
if (this.options.floating && this.element && this.element.tagName === "VIDEO") {
|
|
@@ -16991,6 +17969,9 @@
|
|
|
16991
17969
|
}
|
|
16992
17970
|
this.currentSource = src;
|
|
16993
17971
|
this._pendingSource = null;
|
|
17972
|
+
if (this.hasAudioDescriptionContent()) {
|
|
17973
|
+
await this.ensureAudioDescriptionManager();
|
|
17974
|
+
}
|
|
16994
17975
|
(_b = this.audioDescriptionManager) == null ? void 0 : _b.initFromSourceElements(this.sourceElements, this.trackElements);
|
|
16995
17976
|
if (!this.originalSrc) {
|
|
16996
17977
|
this.originalSrc = src;
|
|
@@ -17832,6 +18813,27 @@
|
|
|
17832
18813
|
}
|
|
17833
18814
|
hideSettings() {
|
|
17834
18815
|
}
|
|
18816
|
+
/**
|
|
18817
|
+
* Lazily build (on first use) and toggle the keyboard-shortcuts help
|
|
18818
|
+
* dialog. Reflects the live `keyboardShortcuts` bindings, including any
|
|
18819
|
+
* consumer overrides.
|
|
18820
|
+
*/
|
|
18821
|
+
toggleKeyboardHelp() {
|
|
18822
|
+
if (!this.keyboardHelp) {
|
|
18823
|
+
this.keyboardHelp = new KeyboardHelp(this);
|
|
18824
|
+
}
|
|
18825
|
+
this.keyboardHelp.toggle();
|
|
18826
|
+
}
|
|
18827
|
+
showKeyboardHelp() {
|
|
18828
|
+
if (!this.keyboardHelp) {
|
|
18829
|
+
this.keyboardHelp = new KeyboardHelp(this);
|
|
18830
|
+
}
|
|
18831
|
+
this.keyboardHelp.show();
|
|
18832
|
+
}
|
|
18833
|
+
hideKeyboardHelp() {
|
|
18834
|
+
var _a;
|
|
18835
|
+
(_a = this.keyboardHelp) == null ? void 0 : _a.hide();
|
|
18836
|
+
}
|
|
17835
18837
|
// Utility methods
|
|
17836
18838
|
getCurrentTime() {
|
|
17837
18839
|
return this.state.currentTime;
|
|
@@ -17972,6 +18974,22 @@
|
|
|
17972
18974
|
}
|
|
17973
18975
|
this.settingsDialog = null;
|
|
17974
18976
|
}
|
|
18977
|
+
if (this.keyboardHelp && typeof this.keyboardHelp.destroy === "function") {
|
|
18978
|
+
try {
|
|
18979
|
+
this.keyboardHelp.destroy();
|
|
18980
|
+
} catch (err) {
|
|
18981
|
+
this.log(`KeyboardHelp.destroy failed: ${err}`, "warn");
|
|
18982
|
+
}
|
|
18983
|
+
this.keyboardHelp = null;
|
|
18984
|
+
}
|
|
18985
|
+
if (this.mediaSessionManager && typeof this.mediaSessionManager.destroy === "function") {
|
|
18986
|
+
try {
|
|
18987
|
+
this.mediaSessionManager.destroy();
|
|
18988
|
+
} catch (err) {
|
|
18989
|
+
this.log(`MediaSessionManager.destroy failed: ${err}`, "warn");
|
|
18990
|
+
}
|
|
18991
|
+
this.mediaSessionManager = null;
|
|
18992
|
+
}
|
|
17975
18993
|
if (this.floatingPlayerManager) {
|
|
17976
18994
|
try {
|
|
17977
18995
|
this.floatingPlayerManager.destroy();
|
|
@@ -18466,7 +19484,7 @@
|
|
|
18466
19484
|
* @param {number} index - Track index
|
|
18467
19485
|
*/
|
|
18468
19486
|
selectTrack(index) {
|
|
18469
|
-
var _a, _b, _c, _d;
|
|
19487
|
+
var _a, _b, _c, _d, _e, _f;
|
|
18470
19488
|
if (index < 0 || index >= this.tracks.length) {
|
|
18471
19489
|
console.warn("VidPly Playlist: Invalid track index", index);
|
|
18472
19490
|
return;
|
|
@@ -18527,12 +19545,19 @@
|
|
|
18527
19545
|
if (typeof this.player.invalidateTrackCache === "function") {
|
|
18528
19546
|
this.player.invalidateTrackCache();
|
|
18529
19547
|
}
|
|
18530
|
-
|
|
19548
|
+
const reinitAudioDescription = (adm) => {
|
|
19549
|
+
if (!adm || typeof adm.initFromSourceElements !== "function") return;
|
|
18531
19550
|
try {
|
|
18532
|
-
|
|
18533
|
-
|
|
19551
|
+
adm.captionTracks = [];
|
|
19552
|
+
adm.initFromSourceElements(this.player.sourceElements, this.player.trackElements);
|
|
18534
19553
|
} catch {
|
|
18535
19554
|
}
|
|
19555
|
+
};
|
|
19556
|
+
if (this.player.audioDescriptionManager) {
|
|
19557
|
+
reinitAudioDescription(this.player.audioDescriptionManager);
|
|
19558
|
+
} else if ((_f = (_e = this.player).hasAudioDescriptionContent) == null ? void 0 : _f.call(_e)) {
|
|
19559
|
+
void this.player.ensureAudioDescriptionManager().then(reinitAudioDescription).catch(() => {
|
|
19560
|
+
});
|
|
18536
19561
|
}
|
|
18537
19562
|
if (this.player.captionManager && typeof this.player.captionManager.loadTracks === "function") {
|
|
18538
19563
|
try {
|
|
@@ -19397,6 +20422,9 @@
|
|
|
19397
20422
|
signLanguageDisplayMode: "signLanguageDisplayMode",
|
|
19398
20423
|
audioDescriptionSrc: "audioDescriptionSrc",
|
|
19399
20424
|
audioDescriptionButton: "audioDescriptionButton",
|
|
20425
|
+
audioDescriptionMode: "audioDescriptionMode",
|
|
20426
|
+
audioDescriptionSpeech: "audioDescriptionSpeech",
|
|
20427
|
+
audioDescriptionExtended: "audioDescriptionExtended",
|
|
19400
20428
|
autoplay: "autoplay",
|
|
19401
20429
|
loop: "loop",
|
|
19402
20430
|
muted: "muted",
|