vidply 1.0.6 → 1.0.8
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 +19 -4
- package/dist/vidply.css +640 -25
- package/dist/vidply.esm.js +2208 -177
- package/dist/vidply.esm.js.map +4 -4
- package/dist/vidply.esm.min.js +6 -6
- package/dist/vidply.esm.min.meta.json +38 -15
- package/dist/vidply.js +2208 -177
- package/dist/vidply.js.map +4 -4
- package/dist/vidply.min.css +1 -1
- package/dist/vidply.min.js +6 -6
- package/dist/vidply.min.meta.json +38 -15
- package/package.json +2 -2
- package/src/controls/CaptionManager.js +30 -0
- package/src/controls/ControlBar.js +11 -4
- package/src/controls/SettingsDialog.js +3 -3
- package/src/controls/TranscriptManager.js +1147 -72
- package/src/core/Player.js +1435 -26
- package/src/i18n/translations.js +70 -15
- package/src/icons/Icons.js +8 -4
- package/src/styles/vidply.css +640 -25
- package/src/utils/StorageManager.js +156 -0
package/dist/vidply.js
CHANGED
|
@@ -468,7 +468,11 @@ var VidPly = (() => {
|
|
|
468
468
|
noCaptions: "No captions available",
|
|
469
469
|
auto: "Auto",
|
|
470
470
|
autoQuality: "Auto (no quality selection available)",
|
|
471
|
-
noQuality: "Quality selection not available"
|
|
471
|
+
noQuality: "Quality selection not available",
|
|
472
|
+
signLanguageDragResize: "Sign Language Video - Press D to drag with keyboard, R to resize",
|
|
473
|
+
signLanguageDragActive: "Sign Language Video - Drag mode active. Use arrow keys to move, Escape to exit.",
|
|
474
|
+
signLanguageResizeActive: "Sign Language Video - Resize mode active. Use left/right arrow keys to resize, Escape to exit.",
|
|
475
|
+
resizeHandle: "Resize {direction} corner"
|
|
472
476
|
},
|
|
473
477
|
captions: {
|
|
474
478
|
off: "Off",
|
|
@@ -481,7 +485,7 @@ var VidPly = (() => {
|
|
|
481
485
|
},
|
|
482
486
|
fontSizes: {
|
|
483
487
|
small: "Small",
|
|
484
|
-
|
|
488
|
+
normal: "Normal",
|
|
485
489
|
large: "Large",
|
|
486
490
|
xlarge: "X-Large"
|
|
487
491
|
},
|
|
@@ -509,7 +513,14 @@ var VidPly = (() => {
|
|
|
509
513
|
title: "Transcript",
|
|
510
514
|
close: "Close transcript",
|
|
511
515
|
loading: "Loading transcript...",
|
|
512
|
-
noTranscript: "No transcript available for this video."
|
|
516
|
+
noTranscript: "No transcript available for this video.",
|
|
517
|
+
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
518
|
+
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
519
|
+
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
520
|
+
resizeWindow: "Resize Window",
|
|
521
|
+
styleTranscript: "Open transcript style settings",
|
|
522
|
+
closeMenu: "Close Menu",
|
|
523
|
+
styleTitle: "Transcript Style"
|
|
513
524
|
},
|
|
514
525
|
settings: {
|
|
515
526
|
title: "Settings",
|
|
@@ -578,7 +589,11 @@ var VidPly = (() => {
|
|
|
578
589
|
noCaptions: "Keine Untertitel verf\xFCgbar",
|
|
579
590
|
auto: "Automatisch",
|
|
580
591
|
autoQuality: "Automatisch (keine Qualit\xE4tsauswahl verf\xFCgbar)",
|
|
581
|
-
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar"
|
|
592
|
+
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar",
|
|
593
|
+
signLanguageDragResize: "Geb\xE4rdensprache-Video - Dr\xFCcken Sie D zum Verschieben per Tastatur, R zum \xC4ndern der Gr\xF6\xDFe",
|
|
594
|
+
signLanguageDragActive: "Geb\xE4rdensprache-Video - Verschiebemodus aktiv. Pfeiltasten zum Bewegen, Escape zum Beenden.",
|
|
595
|
+
signLanguageResizeActive: "Geb\xE4rdensprache-Video - Gr\xF6\xDFen\xE4nderungsmodus aktiv. Links-/Rechts-Pfeiltasten zum \xC4ndern der Gr\xF6\xDFe, Escape zum Beenden.",
|
|
596
|
+
resizeHandle: "Gr\xF6\xDFen\xE4nderung {direction}-Ecke"
|
|
582
597
|
},
|
|
583
598
|
captions: {
|
|
584
599
|
off: "Aus",
|
|
@@ -591,7 +606,7 @@ var VidPly = (() => {
|
|
|
591
606
|
},
|
|
592
607
|
fontSizes: {
|
|
593
608
|
small: "Klein",
|
|
594
|
-
|
|
609
|
+
normal: "Normal",
|
|
595
610
|
large: "Gro\xDF",
|
|
596
611
|
xlarge: "Sehr gro\xDF"
|
|
597
612
|
},
|
|
@@ -619,7 +634,14 @@ var VidPly = (() => {
|
|
|
619
634
|
title: "Transkript",
|
|
620
635
|
close: "Transkript schlie\xDFen",
|
|
621
636
|
loading: "Transkript wird geladen...",
|
|
622
|
-
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar."
|
|
637
|
+
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar.",
|
|
638
|
+
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
639
|
+
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
640
|
+
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
641
|
+
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
642
|
+
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
643
|
+
closeMenu: "Men\xFC schlie\xDFen",
|
|
644
|
+
styleTitle: "Transkript-Stil"
|
|
623
645
|
},
|
|
624
646
|
settings: {
|
|
625
647
|
title: "Einstellungen",
|
|
@@ -688,7 +710,11 @@ var VidPly = (() => {
|
|
|
688
710
|
noCaptions: "No hay subt\xEDtulos disponibles",
|
|
689
711
|
auto: "Autom\xE1tico",
|
|
690
712
|
autoQuality: "Autom\xE1tico (selecci\xF3n de calidad no disponible)",
|
|
691
|
-
noQuality: "Selecci\xF3n de calidad no disponible"
|
|
713
|
+
noQuality: "Selecci\xF3n de calidad no disponible",
|
|
714
|
+
signLanguageDragResize: "Video en Lengua de Se\xF1as - Presione D para arrastrar con el teclado, R para cambiar el tama\xF1o",
|
|
715
|
+
signLanguageDragActive: "Video en Lengua de Se\xF1as - Modo de arrastre activo. Use las teclas de flecha para mover, Escape para salir.",
|
|
716
|
+
signLanguageResizeActive: "Video en Lengua de Se\xF1as - Modo de cambio de tama\xF1o activo. Use las teclas de flecha izquierda/derecha para cambiar el tama\xF1o, Escape para salir.",
|
|
717
|
+
resizeHandle: "Cambiar tama\xF1o esquina {direction}"
|
|
692
718
|
},
|
|
693
719
|
captions: {
|
|
694
720
|
off: "Desactivado",
|
|
@@ -701,7 +727,7 @@ var VidPly = (() => {
|
|
|
701
727
|
},
|
|
702
728
|
fontSizes: {
|
|
703
729
|
small: "Peque\xF1o",
|
|
704
|
-
|
|
730
|
+
normal: "Normal",
|
|
705
731
|
large: "Grande",
|
|
706
732
|
xlarge: "Muy grande"
|
|
707
733
|
},
|
|
@@ -729,7 +755,14 @@ var VidPly = (() => {
|
|
|
729
755
|
title: "Transcripci\xF3n",
|
|
730
756
|
close: "Cerrar transcripci\xF3n",
|
|
731
757
|
loading: "Cargando transcripci\xF3n...",
|
|
732
|
-
noTranscript: "No hay transcripci\xF3n disponible para este video."
|
|
758
|
+
noTranscript: "No hay transcripci\xF3n disponible para este video.",
|
|
759
|
+
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
760
|
+
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
761
|
+
keyboardDragActive: "\u2328\uFE0F Modo de Arrastre con Teclado Activo (Teclas de flecha para mover, May\xFAs+Flechas para pasos grandes, D o ESC para salir)",
|
|
762
|
+
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
763
|
+
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
764
|
+
closeMenu: "Cerrar men\xFA",
|
|
765
|
+
styleTitle: "Estilo de Transcripci\xF3n"
|
|
733
766
|
},
|
|
734
767
|
settings: {
|
|
735
768
|
title: "Configuraci\xF3n",
|
|
@@ -798,7 +831,11 @@ var VidPly = (() => {
|
|
|
798
831
|
noCaptions: "Aucun sous-titre disponible",
|
|
799
832
|
auto: "Automatique",
|
|
800
833
|
autoQuality: "Automatique (s\xE9lection de qualit\xE9 non disponible)",
|
|
801
|
-
noQuality: "S\xE9lection de qualit\xE9 non disponible"
|
|
834
|
+
noQuality: "S\xE9lection de qualit\xE9 non disponible",
|
|
835
|
+
signLanguageDragResize: "Vid\xE9o en Langue des Signes - Appuyez sur D pour d\xE9placer avec le clavier, R pour redimensionner",
|
|
836
|
+
signLanguageDragActive: "Vid\xE9o en Langue des Signes - Mode glissement actif. Utilisez les touches fl\xE9ch\xE9es pour d\xE9placer, \xC9chap pour quitter.",
|
|
837
|
+
signLanguageResizeActive: "Vid\xE9o en Langue des Signes - Mode redimensionnement actif. Utilisez les touches fl\xE9ch\xE9es gauche/droite pour redimensionner, \xC9chap pour quitter.",
|
|
838
|
+
resizeHandle: "Redimensionner coin {direction}"
|
|
802
839
|
},
|
|
803
840
|
captions: {
|
|
804
841
|
off: "D\xE9sactiv\xE9",
|
|
@@ -811,7 +848,7 @@ var VidPly = (() => {
|
|
|
811
848
|
},
|
|
812
849
|
fontSizes: {
|
|
813
850
|
small: "Petit",
|
|
814
|
-
|
|
851
|
+
normal: "Normal",
|
|
815
852
|
large: "Grand",
|
|
816
853
|
xlarge: "Tr\xE8s grand"
|
|
817
854
|
},
|
|
@@ -839,7 +876,14 @@ var VidPly = (() => {
|
|
|
839
876
|
title: "Transcription",
|
|
840
877
|
close: "Fermer la transcription",
|
|
841
878
|
loading: "Chargement de la transcription...",
|
|
842
|
-
noTranscript: "Aucune transcription disponible pour cette vid\xE9o."
|
|
879
|
+
noTranscript: "Aucune transcription disponible pour cette vid\xE9o.",
|
|
880
|
+
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
881
|
+
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
882
|
+
keyboardDragActive: "\u2328\uFE0F Mode Glissement Clavier Actif (Touches fl\xE9ch\xE9es pour d\xE9placer, Maj+Fl\xE9ch\xE9es pour grands pas, D ou \xC9chap pour quitter)",
|
|
883
|
+
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
884
|
+
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
885
|
+
closeMenu: "Fermer le menu",
|
|
886
|
+
styleTitle: "Style de Transcription"
|
|
843
887
|
},
|
|
844
888
|
settings: {
|
|
845
889
|
title: "Param\xE8tres",
|
|
@@ -908,7 +952,11 @@ var VidPly = (() => {
|
|
|
908
952
|
noCaptions: "\u5B57\u5E55\u304C\u3042\u308A\u307E\u305B\u3093",
|
|
909
953
|
auto: "\u81EA\u52D5",
|
|
910
954
|
autoQuality: "\u81EA\u52D5\uFF08\u753B\u8CEA\u9078\u629E\u4E0D\u53EF\uFF09",
|
|
911
|
-
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF"
|
|
955
|
+
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF",
|
|
956
|
+
signLanguageDragResize: "\u624B\u8A71\u52D5\u753B - \u30AD\u30FC\u30DC\u30FC\u30C9\u3067\u30C9\u30E9\u30C3\u30B0\u3059\u308B\u306B\u306FD\u30AD\u30FC\u3092\u3001\u30B5\u30A4\u30BA\u5909\u66F4\u3059\u308B\u306B\u306FR\u30AD\u30FC\u3092\u62BC\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
957
|
+
signLanguageDragActive: "\u624B\u8A71\u52D5\u753B - \u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u304C\u6709\u52B9\u3067\u3059\u3002\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Escape\u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
958
|
+
signLanguageResizeActive: "\u624B\u8A71\u52D5\u753B - \u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u304C\u6709\u52B9\u3067\u3059\u3002\u5DE6\u53F3\u306E\u77E2\u5370\u30AD\u30FC\u3067\u30B5\u30A4\u30BA\u5909\u66F4\u3001Escape\u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
959
|
+
resizeHandle: "{direction}\u30B3\u30FC\u30CA\u30FC\u306E\u30B5\u30A4\u30BA\u5909\u66F4"
|
|
912
960
|
},
|
|
913
961
|
captions: {
|
|
914
962
|
off: "\u30AA\u30D5",
|
|
@@ -921,7 +969,7 @@ var VidPly = (() => {
|
|
|
921
969
|
},
|
|
922
970
|
fontSizes: {
|
|
923
971
|
small: "\u5C0F",
|
|
924
|
-
|
|
972
|
+
normal: "\u6A19\u6E96",
|
|
925
973
|
large: "\u5927",
|
|
926
974
|
xlarge: "\u7279\u5927"
|
|
927
975
|
},
|
|
@@ -949,7 +997,14 @@ var VidPly = (() => {
|
|
|
949
997
|
title: "\u6587\u5B57\u8D77\u3053\u3057",
|
|
950
998
|
close: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u9589\u3058\u308B",
|
|
951
999
|
loading: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D...",
|
|
952
|
-
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002"
|
|
1000
|
+
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
1001
|
+
settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
|
|
1002
|
+
keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
|
|
1003
|
+
keyboardDragActive: "\u2328\uFE0F \u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u6709\u52B9\uFF08\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3001D\u307E\u305F\u306FESC\u3067\u7D42\u4E86\uFF09",
|
|
1004
|
+
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
1005
|
+
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
1006
|
+
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
1007
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
953
1008
|
},
|
|
954
1009
|
settings: {
|
|
955
1010
|
title: "\u8A2D\u5B9A",
|
|
@@ -1128,14 +1183,16 @@ var VidPly = (() => {
|
|
|
1128
1183
|
language: `<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 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/>`,
|
|
1129
1184
|
hd: `<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/>`,
|
|
1130
1185
|
transcript: `<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>`,
|
|
1131
|
-
audioDescription: `<
|
|
1132
|
-
audioDescriptionOn: `<
|
|
1186
|
+
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="currentColor">AD</text>`,
|
|
1187
|
+
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="#1a1a1a" stroke="#1a1a1a" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="#ffffff">AD</text>`,
|
|
1133
1188
|
signLanguage: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1134
1189
|
signLanguageOn: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1135
1190
|
speaker: `<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/>`,
|
|
1136
1191
|
music: `<path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7zm-1.5 16c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>`,
|
|
1137
1192
|
moreVertical: `<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
1138
|
-
moreHorizontal: `<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
|
1193
|
+
moreHorizontal: `<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
1194
|
+
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"/>`,
|
|
1195
|
+
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"/>`
|
|
1139
1196
|
};
|
|
1140
1197
|
var svgWrapper = (paths) => `<svg viewBox="0 0 24 24" fill="currentColor">${paths}</svg>`;
|
|
1141
1198
|
var Icons = Object.fromEntries(
|
|
@@ -1431,7 +1488,11 @@ var VidPly = (() => {
|
|
|
1431
1488
|
return false;
|
|
1432
1489
|
}
|
|
1433
1490
|
hasAudioDescription() {
|
|
1434
|
-
|
|
1491
|
+
if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {
|
|
1492
|
+
return true;
|
|
1493
|
+
}
|
|
1494
|
+
const textTracks = Array.from(this.player.element.textTracks || []);
|
|
1495
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
1435
1496
|
}
|
|
1436
1497
|
hasSignLanguage() {
|
|
1437
1498
|
return this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;
|
|
@@ -2042,9 +2103,9 @@ var VidPly = (() => {
|
|
|
2042
2103
|
i18n.t("styleLabels.fontSize"),
|
|
2043
2104
|
"captionsFontSize",
|
|
2044
2105
|
[
|
|
2045
|
-
{ label: i18n.t("fontSizes.small"), value: "
|
|
2046
|
-
{ label: i18n.t("fontSizes.
|
|
2047
|
-
{ label: i18n.t("fontSizes.large"), value: "
|
|
2106
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
2107
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
2108
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
2048
2109
|
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
2049
2110
|
]
|
|
2050
2111
|
);
|
|
@@ -2733,6 +2794,141 @@ var VidPly = (() => {
|
|
|
2733
2794
|
}
|
|
2734
2795
|
};
|
|
2735
2796
|
|
|
2797
|
+
// src/utils/StorageManager.js
|
|
2798
|
+
var StorageManager = class {
|
|
2799
|
+
constructor(namespace = "vidply") {
|
|
2800
|
+
this.namespace = namespace;
|
|
2801
|
+
this.storage = this.isStorageAvailable() ? localStorage : null;
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Check if localStorage is available
|
|
2805
|
+
*/
|
|
2806
|
+
isStorageAvailable() {
|
|
2807
|
+
try {
|
|
2808
|
+
const test = "__storage_test__";
|
|
2809
|
+
localStorage.setItem(test, test);
|
|
2810
|
+
localStorage.removeItem(test);
|
|
2811
|
+
return true;
|
|
2812
|
+
} catch (e) {
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* Get a namespaced key
|
|
2818
|
+
*/
|
|
2819
|
+
getKey(key) {
|
|
2820
|
+
return `${this.namespace}_${key}`;
|
|
2821
|
+
}
|
|
2822
|
+
/**
|
|
2823
|
+
* Save a value to storage
|
|
2824
|
+
*/
|
|
2825
|
+
set(key, value) {
|
|
2826
|
+
if (!this.storage) return false;
|
|
2827
|
+
try {
|
|
2828
|
+
const namespacedKey = this.getKey(key);
|
|
2829
|
+
this.storage.setItem(namespacedKey, JSON.stringify(value));
|
|
2830
|
+
return true;
|
|
2831
|
+
} catch (e) {
|
|
2832
|
+
console.warn("Failed to save to localStorage:", e);
|
|
2833
|
+
return false;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* Get a value from storage
|
|
2838
|
+
*/
|
|
2839
|
+
get(key, defaultValue = null) {
|
|
2840
|
+
if (!this.storage) return defaultValue;
|
|
2841
|
+
try {
|
|
2842
|
+
const namespacedKey = this.getKey(key);
|
|
2843
|
+
const value = this.storage.getItem(namespacedKey);
|
|
2844
|
+
return value ? JSON.parse(value) : defaultValue;
|
|
2845
|
+
} catch (e) {
|
|
2846
|
+
console.warn("Failed to read from localStorage:", e);
|
|
2847
|
+
return defaultValue;
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Remove a value from storage
|
|
2852
|
+
*/
|
|
2853
|
+
remove(key) {
|
|
2854
|
+
if (!this.storage) return false;
|
|
2855
|
+
try {
|
|
2856
|
+
const namespacedKey = this.getKey(key);
|
|
2857
|
+
this.storage.removeItem(namespacedKey);
|
|
2858
|
+
return true;
|
|
2859
|
+
} catch (e) {
|
|
2860
|
+
console.warn("Failed to remove from localStorage:", e);
|
|
2861
|
+
return false;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Clear all namespaced values
|
|
2866
|
+
*/
|
|
2867
|
+
clear() {
|
|
2868
|
+
if (!this.storage) return false;
|
|
2869
|
+
try {
|
|
2870
|
+
const keys = Object.keys(this.storage);
|
|
2871
|
+
keys.forEach((key) => {
|
|
2872
|
+
if (key.startsWith(this.namespace)) {
|
|
2873
|
+
this.storage.removeItem(key);
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
return true;
|
|
2877
|
+
} catch (e) {
|
|
2878
|
+
console.warn("Failed to clear localStorage:", e);
|
|
2879
|
+
return false;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Save transcript preferences
|
|
2884
|
+
*/
|
|
2885
|
+
saveTranscriptPreferences(preferences) {
|
|
2886
|
+
return this.set("transcript_preferences", preferences);
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Get transcript preferences
|
|
2890
|
+
*/
|
|
2891
|
+
getTranscriptPreferences() {
|
|
2892
|
+
return this.get("transcript_preferences", null);
|
|
2893
|
+
}
|
|
2894
|
+
/**
|
|
2895
|
+
* Save caption preferences
|
|
2896
|
+
*/
|
|
2897
|
+
saveCaptionPreferences(preferences) {
|
|
2898
|
+
return this.set("caption_preferences", preferences);
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Get caption preferences
|
|
2902
|
+
*/
|
|
2903
|
+
getCaptionPreferences() {
|
|
2904
|
+
return this.get("caption_preferences", null);
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* Save player preferences (volume, speed, etc.)
|
|
2908
|
+
*/
|
|
2909
|
+
savePlayerPreferences(preferences) {
|
|
2910
|
+
return this.set("player_preferences", preferences);
|
|
2911
|
+
}
|
|
2912
|
+
/**
|
|
2913
|
+
* Get player preferences
|
|
2914
|
+
*/
|
|
2915
|
+
getPlayerPreferences() {
|
|
2916
|
+
return this.get("player_preferences", null);
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Save sign language preferences (position and size)
|
|
2920
|
+
*/
|
|
2921
|
+
saveSignLanguagePreferences(preferences) {
|
|
2922
|
+
return this.set("sign_language_preferences", preferences);
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* Get sign language preferences
|
|
2926
|
+
*/
|
|
2927
|
+
getSignLanguagePreferences() {
|
|
2928
|
+
return this.get("sign_language_preferences", null);
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
|
|
2736
2932
|
// src/controls/CaptionManager.js
|
|
2737
2933
|
var CaptionManager = class {
|
|
2738
2934
|
constructor(player) {
|
|
@@ -2741,8 +2937,29 @@ var VidPly = (() => {
|
|
|
2741
2937
|
this.tracks = [];
|
|
2742
2938
|
this.currentTrack = null;
|
|
2743
2939
|
this.currentCue = null;
|
|
2940
|
+
this.storage = new StorageManager("vidply");
|
|
2941
|
+
this.loadSavedPreferences();
|
|
2744
2942
|
this.init();
|
|
2745
2943
|
}
|
|
2944
|
+
loadSavedPreferences() {
|
|
2945
|
+
const saved = this.storage.getCaptionPreferences();
|
|
2946
|
+
if (saved) {
|
|
2947
|
+
if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;
|
|
2948
|
+
if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;
|
|
2949
|
+
if (saved.color) this.player.options.captionsColor = saved.color;
|
|
2950
|
+
if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;
|
|
2951
|
+
if (saved.opacity !== void 0) this.player.options.captionsOpacity = saved.opacity;
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
saveCaptionPreferences() {
|
|
2955
|
+
this.storage.saveCaptionPreferences({
|
|
2956
|
+
fontSize: this.player.options.captionsFontSize,
|
|
2957
|
+
fontFamily: this.player.options.captionsFontFamily,
|
|
2958
|
+
color: this.player.options.captionsColor,
|
|
2959
|
+
backgroundColor: this.player.options.captionsBackgroundColor,
|
|
2960
|
+
opacity: this.player.options.captionsOpacity
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2746
2963
|
init() {
|
|
2747
2964
|
this.createElement();
|
|
2748
2965
|
this.loadTracks();
|
|
@@ -2891,6 +3108,7 @@ var VidPly = (() => {
|
|
|
2891
3108
|
break;
|
|
2892
3109
|
}
|
|
2893
3110
|
this.updateStyles();
|
|
3111
|
+
this.saveCaptionPreferences();
|
|
2894
3112
|
this.player.emit("captionschange");
|
|
2895
3113
|
}
|
|
2896
3114
|
getAvailableTracks() {
|
|
@@ -3101,11 +3319,36 @@ var VidPly = (() => {
|
|
|
3101
3319
|
this.player = player;
|
|
3102
3320
|
this.transcriptWindow = null;
|
|
3103
3321
|
this.transcriptEntries = [];
|
|
3322
|
+
this.metadataCues = [];
|
|
3104
3323
|
this.currentActiveEntry = null;
|
|
3105
3324
|
this.isVisible = false;
|
|
3325
|
+
this.storage = new StorageManager("vidply");
|
|
3106
3326
|
this.isDragging = false;
|
|
3107
3327
|
this.dragOffsetX = 0;
|
|
3108
3328
|
this.dragOffsetY = 0;
|
|
3329
|
+
this.isResizing = false;
|
|
3330
|
+
this.resizeDirection = null;
|
|
3331
|
+
this.resizeStartX = 0;
|
|
3332
|
+
this.resizeStartY = 0;
|
|
3333
|
+
this.resizeStartWidth = 0;
|
|
3334
|
+
this.resizeStartHeight = 0;
|
|
3335
|
+
this.resizeEnabled = false;
|
|
3336
|
+
this.settingsMenuVisible = false;
|
|
3337
|
+
this.settingsMenu = null;
|
|
3338
|
+
this.settingsButton = null;
|
|
3339
|
+
this.settingsMenuJustOpened = false;
|
|
3340
|
+
this.keyboardDragMode = false;
|
|
3341
|
+
this.styleDialog = null;
|
|
3342
|
+
this.styleDialogVisible = false;
|
|
3343
|
+
this.styleDialogJustOpened = false;
|
|
3344
|
+
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3345
|
+
this.transcriptStyle = {
|
|
3346
|
+
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3347
|
+
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
3348
|
+
color: (savedPreferences == null ? void 0 : savedPreferences.color) || this.player.options.transcriptColor || "#ffffff",
|
|
3349
|
+
backgroundColor: (savedPreferences == null ? void 0 : savedPreferences.backgroundColor) || this.player.options.transcriptBackgroundColor || "#1e1e1e",
|
|
3350
|
+
opacity: (savedPreferences == null ? void 0 : savedPreferences.opacity) ?? this.player.options.transcriptOpacity ?? 0.98
|
|
3351
|
+
};
|
|
3109
3352
|
this.handlers = {
|
|
3110
3353
|
timeupdate: () => this.updateActiveEntry(),
|
|
3111
3354
|
resize: null,
|
|
@@ -3115,7 +3358,11 @@ var VidPly = (() => {
|
|
|
3115
3358
|
touchend: null,
|
|
3116
3359
|
mousedown: null,
|
|
3117
3360
|
touchstart: null,
|
|
3118
|
-
keydown: null
|
|
3361
|
+
keydown: null,
|
|
3362
|
+
settingsClick: null,
|
|
3363
|
+
settingsKeydown: null,
|
|
3364
|
+
documentClick: null,
|
|
3365
|
+
styleDialogKeydown: null
|
|
3119
3366
|
};
|
|
3120
3367
|
this.init();
|
|
3121
3368
|
}
|
|
@@ -3144,6 +3391,11 @@ var VidPly = (() => {
|
|
|
3144
3391
|
if (this.transcriptWindow) {
|
|
3145
3392
|
this.transcriptWindow.style.display = "flex";
|
|
3146
3393
|
this.isVisible = true;
|
|
3394
|
+
setTimeout(() => {
|
|
3395
|
+
if (this.settingsButton) {
|
|
3396
|
+
this.settingsButton.focus();
|
|
3397
|
+
}
|
|
3398
|
+
}, 150);
|
|
3147
3399
|
return;
|
|
3148
3400
|
}
|
|
3149
3401
|
this.createTranscriptWindow();
|
|
@@ -3151,6 +3403,11 @@ var VidPly = (() => {
|
|
|
3151
3403
|
if (this.transcriptWindow) {
|
|
3152
3404
|
this.transcriptWindow.style.display = "flex";
|
|
3153
3405
|
setTimeout(() => this.positionTranscript(), 0);
|
|
3406
|
+
setTimeout(() => {
|
|
3407
|
+
if (this.settingsButton) {
|
|
3408
|
+
this.settingsButton.focus();
|
|
3409
|
+
}
|
|
3410
|
+
}, 150);
|
|
3154
3411
|
}
|
|
3155
3412
|
this.isVisible = true;
|
|
3156
3413
|
}
|
|
@@ -3182,9 +3439,49 @@ var VidPly = (() => {
|
|
|
3182
3439
|
"tabindex": "0"
|
|
3183
3440
|
}
|
|
3184
3441
|
});
|
|
3442
|
+
this.headerLeft = DOMUtils.createElement("div", {
|
|
3443
|
+
className: `${this.player.options.classPrefix}-transcript-header-left`
|
|
3444
|
+
});
|
|
3445
|
+
this.settingsButton = DOMUtils.createElement("button", {
|
|
3446
|
+
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3447
|
+
attributes: {
|
|
3448
|
+
"type": "button",
|
|
3449
|
+
"aria-label": i18n.t("transcript.settings"),
|
|
3450
|
+
"aria-expanded": "false"
|
|
3451
|
+
}
|
|
3452
|
+
});
|
|
3453
|
+
this.settingsButton.appendChild(createIconElement("settings"));
|
|
3454
|
+
this.handlers.settingsClick = (e) => {
|
|
3455
|
+
e.preventDefault();
|
|
3456
|
+
e.stopPropagation();
|
|
3457
|
+
if (this.settingsMenuVisible) {
|
|
3458
|
+
this.hideSettingsMenu();
|
|
3459
|
+
} else {
|
|
3460
|
+
this.showSettingsMenu();
|
|
3461
|
+
}
|
|
3462
|
+
};
|
|
3463
|
+
this.settingsButton.addEventListener("click", this.handlers.settingsClick);
|
|
3464
|
+
this.handlers.settingsKeydown = (e) => {
|
|
3465
|
+
if (e.key === "d" || e.key === "D") {
|
|
3466
|
+
e.preventDefault();
|
|
3467
|
+
e.stopPropagation();
|
|
3468
|
+
this.toggleKeyboardDragMode();
|
|
3469
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
3470
|
+
e.preventDefault();
|
|
3471
|
+
e.stopPropagation();
|
|
3472
|
+
this.toggleResizeMode();
|
|
3473
|
+
} else if (e.key === "Escape" && this.settingsMenuVisible) {
|
|
3474
|
+
e.preventDefault();
|
|
3475
|
+
e.stopPropagation();
|
|
3476
|
+
this.hideSettingsMenu();
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3185
3480
|
const title = DOMUtils.createElement("h3", {
|
|
3186
3481
|
textContent: i18n.t("transcript.title")
|
|
3187
3482
|
});
|
|
3483
|
+
this.headerLeft.appendChild(this.settingsButton);
|
|
3484
|
+
this.headerLeft.appendChild(title);
|
|
3188
3485
|
const closeButton = DOMUtils.createElement("button", {
|
|
3189
3486
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3190
3487
|
attributes: {
|
|
@@ -3194,7 +3491,7 @@ var VidPly = (() => {
|
|
|
3194
3491
|
});
|
|
3195
3492
|
closeButton.appendChild(createIconElement("close"));
|
|
3196
3493
|
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
3197
|
-
this.transcriptHeader.appendChild(
|
|
3494
|
+
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3198
3495
|
this.transcriptHeader.appendChild(closeButton);
|
|
3199
3496
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
3200
3497
|
className: `${this.player.options.classPrefix}-transcript-content`
|
|
@@ -3204,6 +3501,27 @@ var VidPly = (() => {
|
|
|
3204
3501
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3205
3502
|
this.positionTranscript();
|
|
3206
3503
|
this.setupDragAndDrop();
|
|
3504
|
+
this.handlers.documentClick = (e) => {
|
|
3505
|
+
if (this.settingsMenuJustOpened) {
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3508
|
+
if (this.styleDialogJustOpened) {
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3511
|
+
if (this.settingsButton && this.settingsButton.contains(e.target)) {
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
if (this.settingsMenu && this.settingsMenu.contains(e.target)) {
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
if (this.settingsMenuVisible) {
|
|
3518
|
+
this.hideSettingsMenu();
|
|
3519
|
+
}
|
|
3520
|
+
if (this.styleDialogVisible && this.styleDialog && !this.styleDialog.contains(e.target)) {
|
|
3521
|
+
this.hideStyleDialog();
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
this.documentClickHandlerAdded = false;
|
|
3207
3525
|
let resizeTimeout;
|
|
3208
3526
|
this.handlers.resize = () => {
|
|
3209
3527
|
clearTimeout(resizeTimeout);
|
|
@@ -3284,54 +3602,133 @@ var VidPly = (() => {
|
|
|
3284
3602
|
this.transcriptEntries = [];
|
|
3285
3603
|
this.transcriptContent.innerHTML = "";
|
|
3286
3604
|
const textTracks = Array.from(this.player.element.textTracks);
|
|
3287
|
-
const
|
|
3605
|
+
const captionTrack = textTracks.find(
|
|
3288
3606
|
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
3289
3607
|
);
|
|
3290
|
-
|
|
3608
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3609
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3610
|
+
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3291
3611
|
this.showNoTranscriptMessage();
|
|
3292
3612
|
return;
|
|
3293
3613
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3614
|
+
const tracksToLoad = [captionTrack, descriptionTrack, metadataTrack].filter(Boolean);
|
|
3615
|
+
tracksToLoad.forEach((track) => {
|
|
3616
|
+
if (track.mode === "disabled") {
|
|
3617
|
+
track.mode = "hidden";
|
|
3618
|
+
}
|
|
3619
|
+
});
|
|
3620
|
+
const needsLoading = tracksToLoad.some((track) => !track.cues || track.cues.length === 0);
|
|
3621
|
+
if (needsLoading) {
|
|
3298
3622
|
const loadingMessage = DOMUtils.createElement("div", {
|
|
3299
3623
|
className: `${this.player.options.classPrefix}-transcript-loading`,
|
|
3300
3624
|
textContent: i18n.t("transcript.loading")
|
|
3301
3625
|
});
|
|
3302
3626
|
this.transcriptContent.appendChild(loadingMessage);
|
|
3627
|
+
let loaded = 0;
|
|
3303
3628
|
const onLoad = () => {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
transcriptTrack.addEventListener("load", onLoad, { once: true });
|
|
3307
|
-
setTimeout(() => {
|
|
3308
|
-
if (transcriptTrack.cues && transcriptTrack.cues.length > 0) {
|
|
3629
|
+
loaded++;
|
|
3630
|
+
if (loaded >= tracksToLoad.length) {
|
|
3309
3631
|
this.loadTranscriptData();
|
|
3310
3632
|
}
|
|
3633
|
+
};
|
|
3634
|
+
tracksToLoad.forEach((track) => {
|
|
3635
|
+
track.addEventListener("load", onLoad, { once: true });
|
|
3636
|
+
});
|
|
3637
|
+
setTimeout(() => {
|
|
3638
|
+
this.loadTranscriptData();
|
|
3311
3639
|
}, 500);
|
|
3312
3640
|
return;
|
|
3313
3641
|
}
|
|
3314
|
-
const
|
|
3315
|
-
|
|
3316
|
-
|
|
3642
|
+
const allCues = [];
|
|
3643
|
+
if (captionTrack && captionTrack.cues) {
|
|
3644
|
+
Array.from(captionTrack.cues).forEach((cue) => {
|
|
3645
|
+
allCues.push({ cue, type: "caption" });
|
|
3646
|
+
});
|
|
3647
|
+
}
|
|
3648
|
+
if (descriptionTrack && descriptionTrack.cues) {
|
|
3649
|
+
Array.from(descriptionTrack.cues).forEach((cue) => {
|
|
3650
|
+
allCues.push({ cue, type: "description" });
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
if (metadataTrack && metadataTrack.cues) {
|
|
3654
|
+
this.metadataCues = Array.from(metadataTrack.cues);
|
|
3655
|
+
this.setupMetadataHandling();
|
|
3656
|
+
}
|
|
3657
|
+
allCues.sort((a, b) => a.cue.startTime - b.cue.startTime);
|
|
3658
|
+
allCues.forEach((item, index) => {
|
|
3659
|
+
const entry = this.createTranscriptEntry(item.cue, index, item.type);
|
|
3317
3660
|
this.transcriptEntries.push({
|
|
3318
3661
|
element: entry,
|
|
3319
|
-
cue,
|
|
3320
|
-
|
|
3321
|
-
|
|
3662
|
+
cue: item.cue,
|
|
3663
|
+
type: item.type,
|
|
3664
|
+
startTime: item.cue.startTime,
|
|
3665
|
+
endTime: item.cue.endTime
|
|
3322
3666
|
});
|
|
3323
3667
|
this.transcriptContent.appendChild(entry);
|
|
3324
3668
|
});
|
|
3669
|
+
this.applyTranscriptStyles();
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Setup metadata handling
|
|
3673
|
+
* Metadata cues are not displayed but can be used programmatically
|
|
3674
|
+
*/
|
|
3675
|
+
setupMetadataHandling() {
|
|
3676
|
+
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3677
|
+
return;
|
|
3678
|
+
}
|
|
3679
|
+
const textTracks = Array.from(this.player.element.textTracks);
|
|
3680
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3681
|
+
if (metadataTrack) {
|
|
3682
|
+
metadataTrack.addEventListener("cuechange", () => {
|
|
3683
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3684
|
+
activeCues.forEach((cue) => {
|
|
3685
|
+
this.handleMetadataCue(cue);
|
|
3686
|
+
});
|
|
3687
|
+
});
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
/**
|
|
3691
|
+
* Handle individual metadata cues
|
|
3692
|
+
* Parses metadata text and emits events or triggers actions
|
|
3693
|
+
*/
|
|
3694
|
+
handleMetadataCue(cue) {
|
|
3695
|
+
const text = cue.text.trim();
|
|
3696
|
+
this.player.emit("metadata", {
|
|
3697
|
+
time: cue.startTime,
|
|
3698
|
+
endTime: cue.endTime,
|
|
3699
|
+
text,
|
|
3700
|
+
cue
|
|
3701
|
+
});
|
|
3702
|
+
if (text.includes("PAUSE")) {
|
|
3703
|
+
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3704
|
+
}
|
|
3705
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3706
|
+
if (focusMatch) {
|
|
3707
|
+
this.player.emit("metadata:focus", {
|
|
3708
|
+
time: cue.startTime,
|
|
3709
|
+
target: focusMatch[1],
|
|
3710
|
+
text
|
|
3711
|
+
});
|
|
3712
|
+
}
|
|
3713
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
3714
|
+
if (hashtags) {
|
|
3715
|
+
this.player.emit("metadata:hashtags", {
|
|
3716
|
+
time: cue.startTime,
|
|
3717
|
+
hashtags,
|
|
3718
|
+
text
|
|
3719
|
+
});
|
|
3720
|
+
}
|
|
3325
3721
|
}
|
|
3326
3722
|
/**
|
|
3327
3723
|
* Create a single transcript entry element
|
|
3328
3724
|
*/
|
|
3329
|
-
createTranscriptEntry(cue, index) {
|
|
3725
|
+
createTranscriptEntry(cue, index, type = "caption") {
|
|
3330
3726
|
const entry = DOMUtils.createElement("div", {
|
|
3331
|
-
className: `${this.player.options.classPrefix}-transcript-entry`,
|
|
3727
|
+
className: `${this.player.options.classPrefix}-transcript-entry ${this.player.options.classPrefix}-transcript-${type}`,
|
|
3332
3728
|
attributes: {
|
|
3333
3729
|
"data-start": String(cue.startTime),
|
|
3334
3730
|
"data-end": String(cue.endTime),
|
|
3731
|
+
"data-type": type,
|
|
3335
3732
|
"role": "button",
|
|
3336
3733
|
"tabindex": "0"
|
|
3337
3734
|
}
|
|
@@ -3428,6 +3825,15 @@ var VidPly = (() => {
|
|
|
3428
3825
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3429
3826
|
return;
|
|
3430
3827
|
}
|
|
3828
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3835
|
+
return;
|
|
3836
|
+
}
|
|
3431
3837
|
this.startDragging(e.clientX, e.clientY);
|
|
3432
3838
|
e.preventDefault();
|
|
3433
3839
|
};
|
|
@@ -3445,6 +3851,15 @@ var VidPly = (() => {
|
|
|
3445
3851
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3446
3852
|
return;
|
|
3447
3853
|
}
|
|
3854
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3855
|
+
return;
|
|
3856
|
+
}
|
|
3857
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3858
|
+
return;
|
|
3859
|
+
}
|
|
3860
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3861
|
+
return;
|
|
3862
|
+
}
|
|
3448
3863
|
const isMobile = window.innerWidth < 640;
|
|
3449
3864
|
const isFullscreen = this.player.state.fullscreen;
|
|
3450
3865
|
const touch = e.touches[0];
|
|
@@ -3471,49 +3886,64 @@ var VidPly = (() => {
|
|
|
3471
3886
|
}
|
|
3472
3887
|
};
|
|
3473
3888
|
this.handlers.keydown = (e) => {
|
|
3474
|
-
if (
|
|
3889
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3890
|
+
if (!this.keyboardDragMode) {
|
|
3891
|
+
return;
|
|
3892
|
+
}
|
|
3893
|
+
e.preventDefault();
|
|
3894
|
+
e.stopPropagation();
|
|
3895
|
+
const step = e.shiftKey ? 50 : 10;
|
|
3896
|
+
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3897
|
+
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3898
|
+
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3899
|
+
if (computedStyle.transform !== "none") {
|
|
3900
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3901
|
+
currentLeft = rect.left;
|
|
3902
|
+
currentTop = rect.top;
|
|
3903
|
+
this.transcriptWindow.style.transform = "none";
|
|
3904
|
+
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3905
|
+
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3906
|
+
}
|
|
3907
|
+
let newX = currentLeft;
|
|
3908
|
+
let newY = currentTop;
|
|
3909
|
+
switch (e.key) {
|
|
3910
|
+
case "ArrowLeft":
|
|
3911
|
+
newX -= step;
|
|
3912
|
+
break;
|
|
3913
|
+
case "ArrowRight":
|
|
3914
|
+
newX += step;
|
|
3915
|
+
break;
|
|
3916
|
+
case "ArrowUp":
|
|
3917
|
+
newY -= step;
|
|
3918
|
+
break;
|
|
3919
|
+
case "ArrowDown":
|
|
3920
|
+
newY += step;
|
|
3921
|
+
break;
|
|
3922
|
+
}
|
|
3923
|
+
this.transcriptWindow.style.left = `${newX}px`;
|
|
3924
|
+
this.transcriptWindow.style.top = `${newY}px`;
|
|
3475
3925
|
return;
|
|
3476
3926
|
}
|
|
3477
|
-
e.preventDefault();
|
|
3478
|
-
e.stopPropagation();
|
|
3479
3927
|
if (e.key === "Home") {
|
|
3928
|
+
e.preventDefault();
|
|
3929
|
+
e.stopPropagation();
|
|
3480
3930
|
this.resetPosition();
|
|
3481
3931
|
return;
|
|
3482
3932
|
}
|
|
3483
3933
|
if (e.key === "Escape") {
|
|
3484
|
-
|
|
3934
|
+
e.preventDefault();
|
|
3935
|
+
e.stopPropagation();
|
|
3936
|
+
if (this.styleDialogVisible) {
|
|
3937
|
+
this.hideStyleDialog();
|
|
3938
|
+
} else if (this.keyboardDragMode) {
|
|
3939
|
+
this.disableKeyboardDragMode();
|
|
3940
|
+
} else if (this.settingsMenuVisible) {
|
|
3941
|
+
this.hideSettingsMenu();
|
|
3942
|
+
} else {
|
|
3943
|
+
this.hideTranscript();
|
|
3944
|
+
}
|
|
3485
3945
|
return;
|
|
3486
3946
|
}
|
|
3487
|
-
const step = e.shiftKey ? 50 : 10;
|
|
3488
|
-
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3489
|
-
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3490
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3491
|
-
if (computedStyle.transform !== "none") {
|
|
3492
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3493
|
-
currentLeft = rect.left;
|
|
3494
|
-
currentTop = rect.top;
|
|
3495
|
-
this.transcriptWindow.style.transform = "none";
|
|
3496
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3497
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3498
|
-
}
|
|
3499
|
-
let newX = currentLeft;
|
|
3500
|
-
let newY = currentTop;
|
|
3501
|
-
switch (e.key) {
|
|
3502
|
-
case "ArrowLeft":
|
|
3503
|
-
newX -= step;
|
|
3504
|
-
break;
|
|
3505
|
-
case "ArrowRight":
|
|
3506
|
-
newX += step;
|
|
3507
|
-
break;
|
|
3508
|
-
case "ArrowUp":
|
|
3509
|
-
newY -= step;
|
|
3510
|
-
break;
|
|
3511
|
-
case "ArrowDown":
|
|
3512
|
-
newY += step;
|
|
3513
|
-
break;
|
|
3514
|
-
}
|
|
3515
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3516
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3517
3947
|
};
|
|
3518
3948
|
this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
|
|
3519
3949
|
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
@@ -3593,99 +4023,707 @@ var VidPly = (() => {
|
|
|
3593
4023
|
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
3594
4024
|
}
|
|
3595
4025
|
/**
|
|
3596
|
-
*
|
|
4026
|
+
* Toggle keyboard drag mode
|
|
3597
4027
|
*/
|
|
3598
|
-
|
|
3599
|
-
if (this.
|
|
3600
|
-
this.
|
|
3601
|
-
}
|
|
3602
|
-
|
|
3603
|
-
if (this.handlers.mousedown) {
|
|
3604
|
-
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
3605
|
-
}
|
|
3606
|
-
if (this.handlers.touchstart) {
|
|
3607
|
-
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
3608
|
-
}
|
|
3609
|
-
if (this.handlers.keydown) {
|
|
3610
|
-
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
3611
|
-
}
|
|
3612
|
-
}
|
|
3613
|
-
if (this.handlers.mousemove) {
|
|
3614
|
-
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4028
|
+
toggleKeyboardDragMode() {
|
|
4029
|
+
if (this.keyboardDragMode) {
|
|
4030
|
+
this.disableKeyboardDragMode();
|
|
4031
|
+
} else {
|
|
4032
|
+
this.enableKeyboardDragMode();
|
|
3615
4033
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
4034
|
+
}
|
|
4035
|
+
/**
|
|
4036
|
+
* Enable keyboard drag mode
|
|
4037
|
+
*/
|
|
4038
|
+
enableKeyboardDragMode() {
|
|
4039
|
+
this.keyboardDragMode = true;
|
|
4040
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4041
|
+
if (this.settingsButton) {
|
|
4042
|
+
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
3618
4043
|
}
|
|
3619
|
-
|
|
3620
|
-
|
|
4044
|
+
const indicator = DOMUtils.createElement("div", {
|
|
4045
|
+
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4046
|
+
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4047
|
+
});
|
|
4048
|
+
this.transcriptHeader.appendChild(indicator);
|
|
4049
|
+
if (this.settingsMenuVisible) {
|
|
4050
|
+
this.hideSettingsMenu();
|
|
3621
4051
|
}
|
|
3622
|
-
|
|
3623
|
-
|
|
4052
|
+
this.transcriptHeader.focus();
|
|
4053
|
+
}
|
|
4054
|
+
/**
|
|
4055
|
+
* Disable keyboard drag mode
|
|
4056
|
+
*/
|
|
4057
|
+
disableKeyboardDragMode() {
|
|
4058
|
+
this.keyboardDragMode = false;
|
|
4059
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4060
|
+
if (this.settingsButton) {
|
|
4061
|
+
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
3624
4062
|
}
|
|
3625
|
-
|
|
3626
|
-
|
|
4063
|
+
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4064
|
+
if (indicator) {
|
|
4065
|
+
indicator.remove();
|
|
3627
4066
|
}
|
|
3628
|
-
this.
|
|
3629
|
-
|
|
3630
|
-
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
4067
|
+
if (this.settingsButton) {
|
|
4068
|
+
this.settingsButton.focus();
|
|
3631
4069
|
}
|
|
3632
|
-
this.transcriptWindow = null;
|
|
3633
|
-
this.transcriptHeader = null;
|
|
3634
|
-
this.transcriptContent = null;
|
|
3635
|
-
this.transcriptEntries = [];
|
|
3636
|
-
}
|
|
3637
|
-
};
|
|
3638
|
-
|
|
3639
|
-
// src/core/Player.js
|
|
3640
|
-
init_HTML5Renderer();
|
|
3641
|
-
|
|
3642
|
-
// src/renderers/YouTubeRenderer.js
|
|
3643
|
-
var YouTubeRenderer = class {
|
|
3644
|
-
constructor(player) {
|
|
3645
|
-
this.player = player;
|
|
3646
|
-
this.youtube = null;
|
|
3647
|
-
this.videoId = null;
|
|
3648
|
-
this.isReady = false;
|
|
3649
|
-
this.iframe = null;
|
|
3650
4070
|
}
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
4071
|
+
/**
|
|
4072
|
+
* Toggle settings menu visibility
|
|
4073
|
+
*/
|
|
4074
|
+
toggleSettingsMenu() {
|
|
4075
|
+
if (this.settingsMenuVisible) {
|
|
4076
|
+
this.hideSettingsMenu();
|
|
4077
|
+
} else {
|
|
4078
|
+
this.showSettingsMenu();
|
|
3655
4079
|
}
|
|
3656
|
-
await this.loadYouTubeAPI();
|
|
3657
|
-
this.createIframe();
|
|
3658
|
-
await this.initializePlayer();
|
|
3659
4080
|
}
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
4081
|
+
/**
|
|
4082
|
+
* Show settings menu
|
|
4083
|
+
*/
|
|
4084
|
+
showSettingsMenu() {
|
|
4085
|
+
this.settingsMenuJustOpened = true;
|
|
4086
|
+
setTimeout(() => {
|
|
4087
|
+
this.settingsMenuJustOpened = false;
|
|
4088
|
+
}, 350);
|
|
4089
|
+
if (!this.documentClickHandlerAdded) {
|
|
4090
|
+
setTimeout(() => {
|
|
4091
|
+
document.addEventListener("click", this.handlers.documentClick);
|
|
4092
|
+
this.documentClickHandlerAdded = true;
|
|
4093
|
+
}, 300);
|
|
3670
4094
|
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
return Promise.resolve();
|
|
4095
|
+
if (this.settingsMenu) {
|
|
4096
|
+
this.settingsMenu.style.display = "block";
|
|
4097
|
+
this.settingsMenuVisible = true;
|
|
4098
|
+
return;
|
|
3676
4099
|
}
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
4100
|
+
this.settingsMenu = DOMUtils.createElement("div", {
|
|
4101
|
+
className: `${this.player.options.classPrefix}-transcript-settings-menu`
|
|
4102
|
+
});
|
|
4103
|
+
const keyboardDragOption = DOMUtils.createElement("button", {
|
|
4104
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4105
|
+
attributes: {
|
|
4106
|
+
"type": "button",
|
|
4107
|
+
"aria-label": i18n.t("transcript.keyboardDragMode")
|
|
3685
4108
|
}
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
4109
|
+
});
|
|
4110
|
+
const keyboardIcon = createIconElement("move");
|
|
4111
|
+
const keyboardText = DOMUtils.createElement("span", {
|
|
4112
|
+
textContent: i18n.t("transcript.keyboardDragMode")
|
|
4113
|
+
});
|
|
4114
|
+
keyboardDragOption.appendChild(keyboardIcon);
|
|
4115
|
+
keyboardDragOption.appendChild(keyboardText);
|
|
4116
|
+
keyboardDragOption.addEventListener("click", () => {
|
|
4117
|
+
this.toggleKeyboardDragMode();
|
|
4118
|
+
this.hideSettingsMenu();
|
|
4119
|
+
});
|
|
4120
|
+
const styleOption = DOMUtils.createElement("button", {
|
|
4121
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4122
|
+
attributes: {
|
|
4123
|
+
"type": "button",
|
|
4124
|
+
"aria-label": i18n.t("transcript.styleTranscript")
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
const styleIcon = createIconElement("settings");
|
|
4128
|
+
const styleText = DOMUtils.createElement("span", {
|
|
4129
|
+
textContent: i18n.t("transcript.styleTranscript")
|
|
4130
|
+
});
|
|
4131
|
+
styleOption.appendChild(styleIcon);
|
|
4132
|
+
styleOption.appendChild(styleText);
|
|
4133
|
+
styleOption.addEventListener("click", (e) => {
|
|
4134
|
+
e.preventDefault();
|
|
4135
|
+
e.stopPropagation();
|
|
4136
|
+
this.hideSettingsMenu();
|
|
4137
|
+
setTimeout(() => {
|
|
4138
|
+
this.showStyleDialog();
|
|
4139
|
+
}, 50);
|
|
4140
|
+
});
|
|
4141
|
+
const resizeOption = DOMUtils.createElement("button", {
|
|
4142
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4143
|
+
attributes: {
|
|
4144
|
+
"type": "button",
|
|
4145
|
+
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4146
|
+
}
|
|
4147
|
+
});
|
|
4148
|
+
const resizeIcon = createIconElement("resize");
|
|
4149
|
+
const resizeText = DOMUtils.createElement("span", {
|
|
4150
|
+
textContent: i18n.t("transcript.resizeWindow")
|
|
4151
|
+
});
|
|
4152
|
+
resizeOption.appendChild(resizeIcon);
|
|
4153
|
+
resizeOption.appendChild(resizeText);
|
|
4154
|
+
resizeOption.addEventListener("click", () => {
|
|
4155
|
+
this.toggleResizeMode();
|
|
4156
|
+
this.hideSettingsMenu();
|
|
4157
|
+
});
|
|
4158
|
+
const closeOption = DOMUtils.createElement("button", {
|
|
4159
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4160
|
+
attributes: {
|
|
4161
|
+
"type": "button",
|
|
4162
|
+
"aria-label": i18n.t("transcript.closeMenu")
|
|
4163
|
+
}
|
|
4164
|
+
});
|
|
4165
|
+
const closeIcon = createIconElement("close");
|
|
4166
|
+
const closeText = DOMUtils.createElement("span", {
|
|
4167
|
+
textContent: i18n.t("transcript.closeMenu")
|
|
4168
|
+
});
|
|
4169
|
+
closeOption.appendChild(closeIcon);
|
|
4170
|
+
closeOption.appendChild(closeText);
|
|
4171
|
+
closeOption.addEventListener("click", () => {
|
|
4172
|
+
this.hideSettingsMenu();
|
|
4173
|
+
});
|
|
4174
|
+
this.settingsMenu.appendChild(keyboardDragOption);
|
|
4175
|
+
this.settingsMenu.appendChild(resizeOption);
|
|
4176
|
+
this.settingsMenu.appendChild(styleOption);
|
|
4177
|
+
this.settingsMenu.appendChild(closeOption);
|
|
4178
|
+
if (this.headerLeft) {
|
|
4179
|
+
this.headerLeft.appendChild(this.settingsMenu);
|
|
4180
|
+
} else {
|
|
4181
|
+
this.transcriptHeader.appendChild(this.settingsMenu);
|
|
4182
|
+
}
|
|
4183
|
+
this.settingsMenuVisible = true;
|
|
4184
|
+
this.settingsMenu.style.display = "block";
|
|
4185
|
+
if (this.settingsButton) {
|
|
4186
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4187
|
+
}
|
|
4188
|
+
setTimeout(() => {
|
|
4189
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4190
|
+
if (firstItem) {
|
|
4191
|
+
firstItem.focus();
|
|
4192
|
+
}
|
|
4193
|
+
}, 0);
|
|
4194
|
+
}
|
|
4195
|
+
/**
|
|
4196
|
+
* Hide settings menu
|
|
4197
|
+
*/
|
|
4198
|
+
hideSettingsMenu() {
|
|
4199
|
+
if (this.settingsMenu) {
|
|
4200
|
+
this.settingsMenu.style.display = "none";
|
|
4201
|
+
this.settingsMenuVisible = false;
|
|
4202
|
+
this.settingsMenuJustOpened = false;
|
|
4203
|
+
if (this.settingsButton) {
|
|
4204
|
+
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4205
|
+
this.settingsButton.focus();
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
/**
|
|
4210
|
+
* Enable move mode (gives visual feedback)
|
|
4211
|
+
*/
|
|
4212
|
+
enableMoveMode() {
|
|
4213
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4214
|
+
const tooltip = DOMUtils.createElement("div", {
|
|
4215
|
+
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
4216
|
+
textContent: "Drag with mouse or press D for keyboard drag mode"
|
|
4217
|
+
});
|
|
4218
|
+
this.transcriptHeader.appendChild(tooltip);
|
|
4219
|
+
setTimeout(() => {
|
|
4220
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4221
|
+
if (tooltip.parentNode) {
|
|
4222
|
+
tooltip.remove();
|
|
4223
|
+
}
|
|
4224
|
+
}, 2e3);
|
|
4225
|
+
}
|
|
4226
|
+
/**
|
|
4227
|
+
* Toggle resize mode
|
|
4228
|
+
*/
|
|
4229
|
+
toggleResizeMode() {
|
|
4230
|
+
this.resizeEnabled = !this.resizeEnabled;
|
|
4231
|
+
if (this.resizeEnabled) {
|
|
4232
|
+
this.enableResizeHandles();
|
|
4233
|
+
} else {
|
|
4234
|
+
this.disableResizeHandles();
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
/**
|
|
4238
|
+
* Enable resize handles
|
|
4239
|
+
*/
|
|
4240
|
+
enableResizeHandles() {
|
|
4241
|
+
if (!this.transcriptWindow) return;
|
|
4242
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4243
|
+
directions.forEach((direction) => {
|
|
4244
|
+
const handle = DOMUtils.createElement("div", {
|
|
4245
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4246
|
+
attributes: {
|
|
4247
|
+
"data-direction": direction
|
|
4248
|
+
}
|
|
4249
|
+
});
|
|
4250
|
+
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4251
|
+
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4252
|
+
this.transcriptWindow.appendChild(handle);
|
|
4253
|
+
});
|
|
4254
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4255
|
+
this.handlers.resizeMove = (e) => {
|
|
4256
|
+
if (this.isResizing) {
|
|
4257
|
+
this.performResize(e.clientX, e.clientY);
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4260
|
+
this.handlers.resizeEnd = () => {
|
|
4261
|
+
if (this.isResizing) {
|
|
4262
|
+
this.stopResize();
|
|
4263
|
+
}
|
|
4264
|
+
};
|
|
4265
|
+
this.handlers.resizeTouchMove = (e) => {
|
|
4266
|
+
if (this.isResizing) {
|
|
4267
|
+
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4268
|
+
e.preventDefault();
|
|
4269
|
+
}
|
|
4270
|
+
};
|
|
4271
|
+
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4272
|
+
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4273
|
+
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4274
|
+
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4275
|
+
}
|
|
4276
|
+
/**
|
|
4277
|
+
* Disable resize handles
|
|
4278
|
+
*/
|
|
4279
|
+
disableResizeHandles() {
|
|
4280
|
+
if (!this.transcriptWindow) return;
|
|
4281
|
+
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4282
|
+
handles.forEach((handle) => handle.remove());
|
|
4283
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4284
|
+
if (this.handlers.resizeMove) {
|
|
4285
|
+
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
4286
|
+
}
|
|
4287
|
+
if (this.handlers.resizeEnd) {
|
|
4288
|
+
document.removeEventListener("mouseup", this.handlers.resizeEnd);
|
|
4289
|
+
}
|
|
4290
|
+
if (this.handlers.resizeTouchMove) {
|
|
4291
|
+
document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4292
|
+
}
|
|
4293
|
+
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4294
|
+
}
|
|
4295
|
+
/**
|
|
4296
|
+
* Start resizing
|
|
4297
|
+
*/
|
|
4298
|
+
startResize(e, direction) {
|
|
4299
|
+
e.stopPropagation();
|
|
4300
|
+
e.preventDefault();
|
|
4301
|
+
this.isResizing = true;
|
|
4302
|
+
this.resizeDirection = direction;
|
|
4303
|
+
this.resizeStartX = e.clientX;
|
|
4304
|
+
this.resizeStartY = e.clientY;
|
|
4305
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4306
|
+
this.resizeStartWidth = rect.width;
|
|
4307
|
+
this.resizeStartHeight = rect.height;
|
|
4308
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4309
|
+
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4310
|
+
document.body.style.userSelect = "none";
|
|
4311
|
+
}
|
|
4312
|
+
/**
|
|
4313
|
+
* Perform resize
|
|
4314
|
+
*/
|
|
4315
|
+
performResize(clientX, clientY) {
|
|
4316
|
+
if (!this.isResizing) return;
|
|
4317
|
+
const deltaX = clientX - this.resizeStartX;
|
|
4318
|
+
const deltaY = clientY - this.resizeStartY;
|
|
4319
|
+
let newWidth = this.resizeStartWidth;
|
|
4320
|
+
let newHeight = this.resizeStartHeight;
|
|
4321
|
+
const direction = this.resizeDirection;
|
|
4322
|
+
if (direction.includes("e")) {
|
|
4323
|
+
newWidth = this.resizeStartWidth + deltaX;
|
|
4324
|
+
}
|
|
4325
|
+
if (direction.includes("w")) {
|
|
4326
|
+
newWidth = this.resizeStartWidth - deltaX;
|
|
4327
|
+
}
|
|
4328
|
+
if (direction.includes("s")) {
|
|
4329
|
+
newHeight = this.resizeStartHeight + deltaY;
|
|
4330
|
+
}
|
|
4331
|
+
if (direction.includes("n")) {
|
|
4332
|
+
newHeight = this.resizeStartHeight - deltaY;
|
|
4333
|
+
}
|
|
4334
|
+
const minWidth = 300;
|
|
4335
|
+
const minHeight = 200;
|
|
4336
|
+
const maxWidth = window.innerWidth - 40;
|
|
4337
|
+
const maxHeight = window.innerHeight - 40;
|
|
4338
|
+
newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
|
|
4339
|
+
newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
|
|
4340
|
+
this.transcriptWindow.style.width = `${newWidth}px`;
|
|
4341
|
+
this.transcriptWindow.style.height = `${newHeight}px`;
|
|
4342
|
+
this.transcriptWindow.style.maxWidth = `${newWidth}px`;
|
|
4343
|
+
this.transcriptWindow.style.maxHeight = `${newHeight}px`;
|
|
4344
|
+
if (direction.includes("w")) {
|
|
4345
|
+
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4346
|
+
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4347
|
+
}
|
|
4348
|
+
if (direction.includes("n")) {
|
|
4349
|
+
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4350
|
+
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
/**
|
|
4354
|
+
* Stop resizing
|
|
4355
|
+
*/
|
|
4356
|
+
stopResize() {
|
|
4357
|
+
this.isResizing = false;
|
|
4358
|
+
this.resizeDirection = null;
|
|
4359
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4360
|
+
document.body.style.cursor = "";
|
|
4361
|
+
document.body.style.userSelect = "";
|
|
4362
|
+
}
|
|
4363
|
+
/**
|
|
4364
|
+
* Get cursor style for resize direction
|
|
4365
|
+
*/
|
|
4366
|
+
getResizeCursor(direction) {
|
|
4367
|
+
const cursors = {
|
|
4368
|
+
"n": "ns-resize",
|
|
4369
|
+
"s": "ns-resize",
|
|
4370
|
+
"e": "ew-resize",
|
|
4371
|
+
"w": "ew-resize",
|
|
4372
|
+
"ne": "nesw-resize",
|
|
4373
|
+
"nw": "nwse-resize",
|
|
4374
|
+
"se": "nwse-resize",
|
|
4375
|
+
"sw": "nesw-resize"
|
|
4376
|
+
};
|
|
4377
|
+
return cursors[direction] || "default";
|
|
4378
|
+
}
|
|
4379
|
+
/**
|
|
4380
|
+
* Show style dialog
|
|
4381
|
+
*/
|
|
4382
|
+
showStyleDialog() {
|
|
4383
|
+
if (this.styleDialog) {
|
|
4384
|
+
this.styleDialog.style.display = "block";
|
|
4385
|
+
this.styleDialogVisible = true;
|
|
4386
|
+
this.styleDialogJustOpened = true;
|
|
4387
|
+
setTimeout(() => {
|
|
4388
|
+
this.styleDialogJustOpened = false;
|
|
4389
|
+
}, 350);
|
|
4390
|
+
setTimeout(() => {
|
|
4391
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4392
|
+
if (firstSelect) {
|
|
4393
|
+
firstSelect.focus();
|
|
4394
|
+
}
|
|
4395
|
+
}, 0);
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
this.styleDialog = DOMUtils.createElement("div", {
|
|
4399
|
+
className: `${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4400
|
+
});
|
|
4401
|
+
const title = DOMUtils.createElement("h4", {
|
|
4402
|
+
textContent: i18n.t("transcript.styleTitle"),
|
|
4403
|
+
className: `${this.player.options.classPrefix}-transcript-style-title`
|
|
4404
|
+
});
|
|
4405
|
+
this.styleDialog.appendChild(title);
|
|
4406
|
+
const fontSizeControl = this.createStyleSelectControl(
|
|
4407
|
+
i18n.t("captions.fontSize"),
|
|
4408
|
+
"fontSize",
|
|
4409
|
+
[
|
|
4410
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
4411
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
4412
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
4413
|
+
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
4414
|
+
]
|
|
4415
|
+
);
|
|
4416
|
+
this.styleDialog.appendChild(fontSizeControl);
|
|
4417
|
+
const fontFamilyControl = this.createStyleSelectControl(
|
|
4418
|
+
i18n.t("captions.fontFamily"),
|
|
4419
|
+
"fontFamily",
|
|
4420
|
+
[
|
|
4421
|
+
{ label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
|
|
4422
|
+
{ label: i18n.t("fontFamilies.serif"), value: "serif" },
|
|
4423
|
+
{ label: i18n.t("fontFamilies.monospace"), value: "monospace" }
|
|
4424
|
+
]
|
|
4425
|
+
);
|
|
4426
|
+
this.styleDialog.appendChild(fontFamilyControl);
|
|
4427
|
+
const colorControl = this.createStyleColorControl(i18n.t("captions.color"), "color");
|
|
4428
|
+
this.styleDialog.appendChild(colorControl);
|
|
4429
|
+
const bgColorControl = this.createStyleColorControl(i18n.t("captions.backgroundColor"), "backgroundColor");
|
|
4430
|
+
this.styleDialog.appendChild(bgColorControl);
|
|
4431
|
+
const opacityControl = this.createStyleOpacityControl(i18n.t("captions.opacity"), "opacity");
|
|
4432
|
+
this.styleDialog.appendChild(opacityControl);
|
|
4433
|
+
const closeBtn = DOMUtils.createElement("button", {
|
|
4434
|
+
className: `${this.player.options.classPrefix}-transcript-style-close`,
|
|
4435
|
+
textContent: i18n.t("settings.close"),
|
|
4436
|
+
attributes: {
|
|
4437
|
+
"type": "button"
|
|
4438
|
+
}
|
|
4439
|
+
});
|
|
4440
|
+
closeBtn.addEventListener("click", () => this.hideStyleDialog());
|
|
4441
|
+
this.styleDialog.appendChild(closeBtn);
|
|
4442
|
+
this.handlers.styleDialogKeydown = (e) => {
|
|
4443
|
+
if (e.key === "Escape") {
|
|
4444
|
+
e.preventDefault();
|
|
4445
|
+
e.stopPropagation();
|
|
4446
|
+
this.hideStyleDialog();
|
|
4447
|
+
}
|
|
4448
|
+
};
|
|
4449
|
+
this.styleDialog.addEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4450
|
+
if (this.headerLeft) {
|
|
4451
|
+
this.headerLeft.appendChild(this.styleDialog);
|
|
4452
|
+
} else {
|
|
4453
|
+
this.transcriptHeader.appendChild(this.styleDialog);
|
|
4454
|
+
}
|
|
4455
|
+
this.applyTranscriptStyles();
|
|
4456
|
+
this.styleDialogVisible = true;
|
|
4457
|
+
this.styleDialog.style.display = "block";
|
|
4458
|
+
this.styleDialogJustOpened = true;
|
|
4459
|
+
setTimeout(() => {
|
|
4460
|
+
this.styleDialogJustOpened = false;
|
|
4461
|
+
}, 350);
|
|
4462
|
+
setTimeout(() => {
|
|
4463
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4464
|
+
if (firstSelect) {
|
|
4465
|
+
firstSelect.focus();
|
|
4466
|
+
}
|
|
4467
|
+
}, 0);
|
|
4468
|
+
}
|
|
4469
|
+
/**
|
|
4470
|
+
* Hide style dialog
|
|
4471
|
+
*/
|
|
4472
|
+
hideStyleDialog() {
|
|
4473
|
+
if (this.styleDialog) {
|
|
4474
|
+
this.styleDialog.style.display = "none";
|
|
4475
|
+
this.styleDialogVisible = false;
|
|
4476
|
+
if (this.settingsButton) {
|
|
4477
|
+
this.settingsButton.focus();
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
/**
|
|
4482
|
+
* Create style select control
|
|
4483
|
+
*/
|
|
4484
|
+
createStyleSelectControl(label, property, options) {
|
|
4485
|
+
const group = DOMUtils.createElement("div", {
|
|
4486
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4487
|
+
});
|
|
4488
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4489
|
+
textContent: label
|
|
4490
|
+
});
|
|
4491
|
+
group.appendChild(labelEl);
|
|
4492
|
+
const select = DOMUtils.createElement("select", {
|
|
4493
|
+
className: `${this.player.options.classPrefix}-transcript-style-select`
|
|
4494
|
+
});
|
|
4495
|
+
options.forEach((opt) => {
|
|
4496
|
+
const option = DOMUtils.createElement("option", {
|
|
4497
|
+
textContent: opt.label,
|
|
4498
|
+
attributes: {
|
|
4499
|
+
"value": opt.value
|
|
4500
|
+
}
|
|
4501
|
+
});
|
|
4502
|
+
if (this.transcriptStyle[property] === opt.value) {
|
|
4503
|
+
option.selected = true;
|
|
4504
|
+
}
|
|
4505
|
+
select.appendChild(option);
|
|
4506
|
+
});
|
|
4507
|
+
select.addEventListener("change", (e) => {
|
|
4508
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4509
|
+
this.applyTranscriptStyles();
|
|
4510
|
+
this.savePreferences();
|
|
4511
|
+
});
|
|
4512
|
+
group.appendChild(select);
|
|
4513
|
+
return group;
|
|
4514
|
+
}
|
|
4515
|
+
/**
|
|
4516
|
+
* Create style color control
|
|
4517
|
+
*/
|
|
4518
|
+
createStyleColorControl(label, property) {
|
|
4519
|
+
const group = DOMUtils.createElement("div", {
|
|
4520
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4521
|
+
});
|
|
4522
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4523
|
+
textContent: label
|
|
4524
|
+
});
|
|
4525
|
+
group.appendChild(labelEl);
|
|
4526
|
+
const input = DOMUtils.createElement("input", {
|
|
4527
|
+
attributes: {
|
|
4528
|
+
"type": "color",
|
|
4529
|
+
"value": this.transcriptStyle[property]
|
|
4530
|
+
},
|
|
4531
|
+
className: `${this.player.options.classPrefix}-transcript-style-color`
|
|
4532
|
+
});
|
|
4533
|
+
input.addEventListener("input", (e) => {
|
|
4534
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4535
|
+
this.applyTranscriptStyles();
|
|
4536
|
+
this.savePreferences();
|
|
4537
|
+
});
|
|
4538
|
+
group.appendChild(input);
|
|
4539
|
+
return group;
|
|
4540
|
+
}
|
|
4541
|
+
/**
|
|
4542
|
+
* Create style opacity control
|
|
4543
|
+
*/
|
|
4544
|
+
createStyleOpacityControl(label, property) {
|
|
4545
|
+
const group = DOMUtils.createElement("div", {
|
|
4546
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4547
|
+
});
|
|
4548
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4549
|
+
textContent: label
|
|
4550
|
+
});
|
|
4551
|
+
group.appendChild(labelEl);
|
|
4552
|
+
const valueDisplay = DOMUtils.createElement("span", {
|
|
4553
|
+
textContent: Math.round(this.transcriptStyle[property] * 100) + "%",
|
|
4554
|
+
className: `${this.player.options.classPrefix}-transcript-style-value`
|
|
4555
|
+
});
|
|
4556
|
+
const input = DOMUtils.createElement("input", {
|
|
4557
|
+
attributes: {
|
|
4558
|
+
"type": "range",
|
|
4559
|
+
"min": "0",
|
|
4560
|
+
"max": "1",
|
|
4561
|
+
"step": "0.1",
|
|
4562
|
+
"value": String(this.transcriptStyle[property])
|
|
4563
|
+
},
|
|
4564
|
+
className: `${this.player.options.classPrefix}-transcript-style-range`
|
|
4565
|
+
});
|
|
4566
|
+
input.addEventListener("input", (e) => {
|
|
4567
|
+
const value = parseFloat(e.target.value);
|
|
4568
|
+
this.transcriptStyle[property] = value;
|
|
4569
|
+
valueDisplay.textContent = Math.round(value * 100) + "%";
|
|
4570
|
+
this.applyTranscriptStyles();
|
|
4571
|
+
this.savePreferences();
|
|
4572
|
+
});
|
|
4573
|
+
const inputContainer = DOMUtils.createElement("div", {
|
|
4574
|
+
className: `${this.player.options.classPrefix}-transcript-style-range-container`
|
|
4575
|
+
});
|
|
4576
|
+
inputContainer.appendChild(input);
|
|
4577
|
+
inputContainer.appendChild(valueDisplay);
|
|
4578
|
+
group.appendChild(labelEl);
|
|
4579
|
+
group.appendChild(inputContainer);
|
|
4580
|
+
return group;
|
|
4581
|
+
}
|
|
4582
|
+
/**
|
|
4583
|
+
* Save transcript preferences to localStorage
|
|
4584
|
+
*/
|
|
4585
|
+
savePreferences() {
|
|
4586
|
+
this.storage.saveTranscriptPreferences(this.transcriptStyle);
|
|
4587
|
+
}
|
|
4588
|
+
/**
|
|
4589
|
+
* Apply transcript styles
|
|
4590
|
+
*/
|
|
4591
|
+
applyTranscriptStyles() {
|
|
4592
|
+
if (!this.transcriptWindow) return;
|
|
4593
|
+
this.transcriptWindow.style.backgroundColor = this.transcriptStyle.backgroundColor;
|
|
4594
|
+
this.transcriptWindow.style.opacity = String(this.transcriptStyle.opacity);
|
|
4595
|
+
if (this.transcriptContent) {
|
|
4596
|
+
this.transcriptContent.style.fontSize = this.transcriptStyle.fontSize;
|
|
4597
|
+
this.transcriptContent.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4598
|
+
this.transcriptContent.style.color = this.transcriptStyle.color;
|
|
4599
|
+
}
|
|
4600
|
+
const textEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-text`);
|
|
4601
|
+
textEntries.forEach((entry) => {
|
|
4602
|
+
entry.style.fontSize = this.transcriptStyle.fontSize;
|
|
4603
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4604
|
+
entry.style.color = this.transcriptStyle.color;
|
|
4605
|
+
});
|
|
4606
|
+
const timeEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-time`);
|
|
4607
|
+
timeEntries.forEach((entry) => {
|
|
4608
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4609
|
+
});
|
|
4610
|
+
}
|
|
4611
|
+
/**
|
|
4612
|
+
* Cleanup
|
|
4613
|
+
*/
|
|
4614
|
+
destroy() {
|
|
4615
|
+
if (this.resizeEnabled) {
|
|
4616
|
+
this.disableResizeHandles();
|
|
4617
|
+
}
|
|
4618
|
+
if (this.keyboardDragMode) {
|
|
4619
|
+
this.disableKeyboardDragMode();
|
|
4620
|
+
}
|
|
4621
|
+
if (this.handlers.timeupdate) {
|
|
4622
|
+
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
4623
|
+
}
|
|
4624
|
+
if (this.transcriptHeader) {
|
|
4625
|
+
if (this.handlers.mousedown) {
|
|
4626
|
+
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
4627
|
+
}
|
|
4628
|
+
if (this.handlers.touchstart) {
|
|
4629
|
+
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
4630
|
+
}
|
|
4631
|
+
if (this.handlers.keydown) {
|
|
4632
|
+
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
4633
|
+
}
|
|
4634
|
+
}
|
|
4635
|
+
if (this.settingsButton) {
|
|
4636
|
+
if (this.handlers.settingsClick) {
|
|
4637
|
+
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
4638
|
+
}
|
|
4639
|
+
if (this.handlers.settingsKeydown) {
|
|
4640
|
+
this.settingsButton.removeEventListener("keydown", this.handlers.settingsKeydown);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4644
|
+
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4645
|
+
}
|
|
4646
|
+
if (this.handlers.mousemove) {
|
|
4647
|
+
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4648
|
+
}
|
|
4649
|
+
if (this.handlers.mouseup) {
|
|
4650
|
+
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
4651
|
+
}
|
|
4652
|
+
if (this.handlers.touchmove) {
|
|
4653
|
+
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
4654
|
+
}
|
|
4655
|
+
if (this.handlers.touchend) {
|
|
4656
|
+
document.removeEventListener("touchend", this.handlers.touchend);
|
|
4657
|
+
}
|
|
4658
|
+
if (this.handlers.documentClick) {
|
|
4659
|
+
document.removeEventListener("click", this.handlers.documentClick);
|
|
4660
|
+
}
|
|
4661
|
+
if (this.handlers.resize) {
|
|
4662
|
+
window.removeEventListener("resize", this.handlers.resize);
|
|
4663
|
+
}
|
|
4664
|
+
this.handlers = null;
|
|
4665
|
+
if (this.transcriptWindow && this.transcriptWindow.parentNode) {
|
|
4666
|
+
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
4667
|
+
}
|
|
4668
|
+
this.transcriptWindow = null;
|
|
4669
|
+
this.transcriptHeader = null;
|
|
4670
|
+
this.transcriptContent = null;
|
|
4671
|
+
this.transcriptEntries = [];
|
|
4672
|
+
this.settingsMenu = null;
|
|
4673
|
+
this.styleDialog = null;
|
|
4674
|
+
}
|
|
4675
|
+
};
|
|
4676
|
+
|
|
4677
|
+
// src/core/Player.js
|
|
4678
|
+
init_HTML5Renderer();
|
|
4679
|
+
|
|
4680
|
+
// src/renderers/YouTubeRenderer.js
|
|
4681
|
+
var YouTubeRenderer = class {
|
|
4682
|
+
constructor(player) {
|
|
4683
|
+
this.player = player;
|
|
4684
|
+
this.youtube = null;
|
|
4685
|
+
this.videoId = null;
|
|
4686
|
+
this.isReady = false;
|
|
4687
|
+
this.iframe = null;
|
|
4688
|
+
}
|
|
4689
|
+
async init() {
|
|
4690
|
+
this.videoId = this.extractVideoId(this.player.element.src);
|
|
4691
|
+
if (!this.videoId) {
|
|
4692
|
+
throw new Error("Invalid YouTube URL");
|
|
4693
|
+
}
|
|
4694
|
+
await this.loadYouTubeAPI();
|
|
4695
|
+
this.createIframe();
|
|
4696
|
+
await this.initializePlayer();
|
|
4697
|
+
}
|
|
4698
|
+
extractVideoId(url) {
|
|
4699
|
+
const patterns = [
|
|
4700
|
+
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\s]+)/,
|
|
4701
|
+
/youtube\.com\/embed\/([^&\s]+)/
|
|
4702
|
+
];
|
|
4703
|
+
for (const pattern of patterns) {
|
|
4704
|
+
const match = url.match(pattern);
|
|
4705
|
+
if (match && match[1]) {
|
|
4706
|
+
return match[1];
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
return null;
|
|
4710
|
+
}
|
|
4711
|
+
async loadYouTubeAPI() {
|
|
4712
|
+
if (window.YT && window.YT.Player) {
|
|
4713
|
+
return Promise.resolve();
|
|
4714
|
+
}
|
|
4715
|
+
return new Promise((resolve, reject) => {
|
|
4716
|
+
if (window.onYouTubeIframeAPIReady) {
|
|
4717
|
+
const originalCallback = window.onYouTubeIframeAPIReady;
|
|
4718
|
+
window.onYouTubeIframeAPIReady = () => {
|
|
4719
|
+
originalCallback();
|
|
4720
|
+
resolve();
|
|
4721
|
+
};
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
const tag = document.createElement("script");
|
|
4725
|
+
tag.src = "https://www.youtube.com/iframe_api";
|
|
4726
|
+
window.onYouTubeIframeAPIReady = () => {
|
|
3689
4727
|
resolve();
|
|
3690
4728
|
};
|
|
3691
4729
|
tag.onerror = () => reject(new Error("Failed to load YouTube API"));
|
|
@@ -4350,7 +5388,7 @@ var VidPly = (() => {
|
|
|
4350
5388
|
captionsButton: true,
|
|
4351
5389
|
transcriptButton: true,
|
|
4352
5390
|
fullscreenButton: true,
|
|
4353
|
-
pipButton:
|
|
5391
|
+
pipButton: false,
|
|
4354
5392
|
// Seeking
|
|
4355
5393
|
seekInterval: 10,
|
|
4356
5394
|
seekIntervalLarge: 30,
|
|
@@ -4420,6 +5458,13 @@ var VidPly = (() => {
|
|
|
4420
5458
|
onError: null,
|
|
4421
5459
|
...options
|
|
4422
5460
|
};
|
|
5461
|
+
this.storage = new StorageManager("vidply");
|
|
5462
|
+
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5463
|
+
if (savedPrefs) {
|
|
5464
|
+
if (savedPrefs.volume !== void 0) this.options.volume = savedPrefs.volume;
|
|
5465
|
+
if (savedPrefs.playbackSpeed !== void 0) this.options.playbackSpeed = savedPrefs.playbackSpeed;
|
|
5466
|
+
if (savedPrefs.muted !== void 0) this.options.muted = savedPrefs.muted;
|
|
5467
|
+
}
|
|
4423
5468
|
this.state = {
|
|
4424
5469
|
ready: false,
|
|
4425
5470
|
playing: false,
|
|
@@ -4444,6 +5489,9 @@ var VidPly = (() => {
|
|
|
4444
5489
|
this.audioDescriptionSrc = this.options.audioDescriptionSrc;
|
|
4445
5490
|
this.signLanguageSrc = this.options.signLanguageSrc;
|
|
4446
5491
|
this.signLanguageVideo = null;
|
|
5492
|
+
this.audioDescriptionSourceElement = null;
|
|
5493
|
+
this.originalAudioDescriptionSource = null;
|
|
5494
|
+
this.audioDescriptionCaptionTracks = [];
|
|
4447
5495
|
this.container = null;
|
|
4448
5496
|
this.renderer = null;
|
|
4449
5497
|
this.controlBar = null;
|
|
@@ -4598,6 +5646,53 @@ var VidPly = (() => {
|
|
|
4598
5646
|
if (!src) {
|
|
4599
5647
|
throw new Error("No media source found");
|
|
4600
5648
|
}
|
|
5649
|
+
const sourceElements = this.element.querySelectorAll("source");
|
|
5650
|
+
for (const sourceEl of sourceElements) {
|
|
5651
|
+
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
5652
|
+
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
5653
|
+
if (descSrc || origSrc) {
|
|
5654
|
+
if (!this.audioDescriptionSourceElement) {
|
|
5655
|
+
this.audioDescriptionSourceElement = sourceEl;
|
|
5656
|
+
}
|
|
5657
|
+
if (origSrc) {
|
|
5658
|
+
if (!this.originalAudioDescriptionSource) {
|
|
5659
|
+
this.originalAudioDescriptionSource = origSrc;
|
|
5660
|
+
}
|
|
5661
|
+
if (!this.originalSrc) {
|
|
5662
|
+
this.originalSrc = origSrc;
|
|
5663
|
+
}
|
|
5664
|
+
} else {
|
|
5665
|
+
const currentSrcAttr = sourceEl.getAttribute("src");
|
|
5666
|
+
if (!this.originalAudioDescriptionSource && currentSrcAttr) {
|
|
5667
|
+
this.originalAudioDescriptionSource = currentSrcAttr;
|
|
5668
|
+
}
|
|
5669
|
+
if (!this.originalSrc && currentSrcAttr) {
|
|
5670
|
+
this.originalSrc = currentSrcAttr;
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
if (descSrc && !this.audioDescriptionSrc) {
|
|
5674
|
+
this.audioDescriptionSrc = descSrc;
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
}
|
|
5678
|
+
const trackElements = this.element.querySelectorAll("track");
|
|
5679
|
+
trackElements.forEach((trackEl) => {
|
|
5680
|
+
const trackKind = trackEl.getAttribute("kind");
|
|
5681
|
+
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
5682
|
+
if (trackKind === "captions" || trackKind === "subtitles" || trackKind === "chapters") {
|
|
5683
|
+
if (trackDescSrc) {
|
|
5684
|
+
this.audioDescriptionCaptionTracks.push({
|
|
5685
|
+
trackElement: trackEl,
|
|
5686
|
+
originalSrc: trackEl.getAttribute("src"),
|
|
5687
|
+
describedSrc: trackDescSrc,
|
|
5688
|
+
originalTrackSrc: trackEl.getAttribute("data-orig-src") || trackEl.getAttribute("src"),
|
|
5689
|
+
explicit: true
|
|
5690
|
+
// Explicitly defined, so we should validate it
|
|
5691
|
+
});
|
|
5692
|
+
this.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute("src")} -> ${trackDescSrc}`);
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
});
|
|
4601
5696
|
if (!this.originalSrc) {
|
|
4602
5697
|
this.originalSrc = src;
|
|
4603
5698
|
}
|
|
@@ -4754,6 +5849,7 @@ var VidPly = (() => {
|
|
|
4754
5849
|
if (newVolume > 0 && this.state.muted) {
|
|
4755
5850
|
this.state.muted = false;
|
|
4756
5851
|
}
|
|
5852
|
+
this.savePlayerPreferences();
|
|
4757
5853
|
}
|
|
4758
5854
|
getVolume() {
|
|
4759
5855
|
return this.state.volume;
|
|
@@ -4763,6 +5859,7 @@ var VidPly = (() => {
|
|
|
4763
5859
|
this.renderer.setMuted(true);
|
|
4764
5860
|
}
|
|
4765
5861
|
this.state.muted = true;
|
|
5862
|
+
this.savePlayerPreferences();
|
|
4766
5863
|
this.emit("volumechange");
|
|
4767
5864
|
}
|
|
4768
5865
|
unmute() {
|
|
@@ -4770,6 +5867,7 @@ var VidPly = (() => {
|
|
|
4770
5867
|
this.renderer.setMuted(false);
|
|
4771
5868
|
}
|
|
4772
5869
|
this.state.muted = false;
|
|
5870
|
+
this.savePlayerPreferences();
|
|
4773
5871
|
this.emit("volumechange");
|
|
4774
5872
|
}
|
|
4775
5873
|
toggleMute() {
|
|
@@ -4786,11 +5884,20 @@ var VidPly = (() => {
|
|
|
4786
5884
|
this.renderer.setPlaybackSpeed(newSpeed);
|
|
4787
5885
|
}
|
|
4788
5886
|
this.state.playbackSpeed = newSpeed;
|
|
5887
|
+
this.savePlayerPreferences();
|
|
4789
5888
|
this.emit("playbackspeedchange", newSpeed);
|
|
4790
5889
|
}
|
|
4791
5890
|
getPlaybackSpeed() {
|
|
4792
5891
|
return this.state.playbackSpeed;
|
|
4793
5892
|
}
|
|
5893
|
+
// Save player preferences to localStorage
|
|
5894
|
+
savePlayerPreferences() {
|
|
5895
|
+
this.storage.savePlayerPreferences({
|
|
5896
|
+
volume: this.state.volume,
|
|
5897
|
+
muted: this.state.muted,
|
|
5898
|
+
playbackSpeed: this.state.playbackSpeed
|
|
5899
|
+
});
|
|
5900
|
+
}
|
|
4794
5901
|
// Fullscreen
|
|
4795
5902
|
enterFullscreen() {
|
|
4796
5903
|
const elem = this.container;
|
|
@@ -4870,15 +5977,396 @@ var VidPly = (() => {
|
|
|
4870
5977
|
this.enableCaptions();
|
|
4871
5978
|
}
|
|
4872
5979
|
}
|
|
5980
|
+
/**
|
|
5981
|
+
* Check if a track file exists
|
|
5982
|
+
* @param {string} url - Track file URL
|
|
5983
|
+
* @returns {Promise<boolean>} - True if file exists
|
|
5984
|
+
*/
|
|
5985
|
+
async validateTrackExists(url) {
|
|
5986
|
+
try {
|
|
5987
|
+
const response = await fetch(url, { method: "HEAD", cache: "no-cache" });
|
|
5988
|
+
return response.ok;
|
|
5989
|
+
} catch (error) {
|
|
5990
|
+
return false;
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
4873
5993
|
// Audio Description
|
|
4874
5994
|
async enableAudioDescription() {
|
|
4875
|
-
|
|
4876
|
-
|
|
5995
|
+
const hasSourceElementsWithDesc = Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
5996
|
+
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
5997
|
+
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
5998
|
+
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
4877
5999
|
return;
|
|
4878
6000
|
}
|
|
4879
6001
|
const currentTime = this.state.currentTime;
|
|
4880
6002
|
const wasPlaying = this.state.playing;
|
|
4881
|
-
|
|
6003
|
+
let swappedTracksForTranscript = [];
|
|
6004
|
+
if (this.audioDescriptionSourceElement) {
|
|
6005
|
+
const currentSrc = this.element.currentSrc || this.element.src;
|
|
6006
|
+
const sourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6007
|
+
let sourceElementToUpdate = null;
|
|
6008
|
+
let descSrc = this.audioDescriptionSrc;
|
|
6009
|
+
for (const sourceEl of sourceElements) {
|
|
6010
|
+
const sourceSrc = sourceEl.getAttribute("src");
|
|
6011
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6012
|
+
const sourceFilename = sourceSrc ? sourceSrc.split("/").pop() : "";
|
|
6013
|
+
const currentFilename = currentSrc ? currentSrc.split("/").pop() : "";
|
|
6014
|
+
if (currentSrc && (currentSrc === sourceSrc || currentSrc.includes(sourceSrc) || currentSrc.includes(sourceFilename) || sourceFilename && currentFilename === sourceFilename)) {
|
|
6015
|
+
sourceElementToUpdate = sourceEl;
|
|
6016
|
+
if (descSrcAttr) {
|
|
6017
|
+
descSrc = descSrcAttr;
|
|
6018
|
+
} else if (sourceSrc) {
|
|
6019
|
+
descSrc = this.audioDescriptionSrc || descSrc;
|
|
6020
|
+
}
|
|
6021
|
+
break;
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
if (!sourceElementToUpdate) {
|
|
6025
|
+
sourceElementToUpdate = this.audioDescriptionSourceElement;
|
|
6026
|
+
const storedDescSrc = sourceElementToUpdate.getAttribute("data-desc-src");
|
|
6027
|
+
if (storedDescSrc) {
|
|
6028
|
+
descSrc = storedDescSrc;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6032
|
+
const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
|
|
6033
|
+
if (trackInfo.trackElement && trackInfo.describedSrc) {
|
|
6034
|
+
if (trackInfo.explicit === true) {
|
|
6035
|
+
try {
|
|
6036
|
+
const exists = await this.validateTrackExists(trackInfo.describedSrc);
|
|
6037
|
+
return { trackInfo, exists };
|
|
6038
|
+
} catch (error) {
|
|
6039
|
+
return { trackInfo, exists: false };
|
|
6040
|
+
}
|
|
6041
|
+
} else {
|
|
6042
|
+
return { trackInfo, exists: false };
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
return { trackInfo, exists: false };
|
|
6046
|
+
});
|
|
6047
|
+
const validationResults = await Promise.all(validationPromises);
|
|
6048
|
+
const tracksToSwap = validationResults.filter((result) => result.exists);
|
|
6049
|
+
if (tracksToSwap.length > 0) {
|
|
6050
|
+
const trackModes = /* @__PURE__ */ new Map();
|
|
6051
|
+
tracksToSwap.forEach(({ trackInfo }) => {
|
|
6052
|
+
const textTrack = trackInfo.trackElement.track;
|
|
6053
|
+
if (textTrack) {
|
|
6054
|
+
trackModes.set(trackInfo, {
|
|
6055
|
+
wasShowing: textTrack.mode === "showing",
|
|
6056
|
+
wasHidden: textTrack.mode === "hidden"
|
|
6057
|
+
});
|
|
6058
|
+
} else {
|
|
6059
|
+
trackModes.set(trackInfo, {
|
|
6060
|
+
wasShowing: false,
|
|
6061
|
+
wasHidden: false
|
|
6062
|
+
});
|
|
6063
|
+
}
|
|
6064
|
+
});
|
|
6065
|
+
const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
|
|
6066
|
+
const oldSrc = trackInfo.trackElement.getAttribute("src");
|
|
6067
|
+
const parent = trackInfo.trackElement.parentNode;
|
|
6068
|
+
const nextSibling = trackInfo.trackElement.nextSibling;
|
|
6069
|
+
const attributes = {};
|
|
6070
|
+
Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
|
|
6071
|
+
attributes[attr.name] = attr.value;
|
|
6072
|
+
});
|
|
6073
|
+
return {
|
|
6074
|
+
trackInfo,
|
|
6075
|
+
oldSrc,
|
|
6076
|
+
parent,
|
|
6077
|
+
nextSibling,
|
|
6078
|
+
attributes
|
|
6079
|
+
};
|
|
6080
|
+
});
|
|
6081
|
+
tracksToReadd.forEach(({ trackInfo }) => {
|
|
6082
|
+
trackInfo.trackElement.remove();
|
|
6083
|
+
});
|
|
6084
|
+
this.element.load();
|
|
6085
|
+
setTimeout(() => {
|
|
6086
|
+
tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
|
|
6087
|
+
swappedTracksForTranscript.push(trackInfo);
|
|
6088
|
+
const newTrackElement = document.createElement("track");
|
|
6089
|
+
newTrackElement.setAttribute("src", trackInfo.describedSrc);
|
|
6090
|
+
Object.keys(attributes).forEach((attrName) => {
|
|
6091
|
+
if (attrName !== "src" && attrName !== "data-desc-src") {
|
|
6092
|
+
newTrackElement.setAttribute(attrName, attributes[attrName]);
|
|
6093
|
+
}
|
|
6094
|
+
});
|
|
6095
|
+
if (nextSibling && nextSibling.parentNode) {
|
|
6096
|
+
parent.insertBefore(newTrackElement, nextSibling);
|
|
6097
|
+
} else {
|
|
6098
|
+
parent.appendChild(newTrackElement);
|
|
6099
|
+
}
|
|
6100
|
+
trackInfo.trackElement = newTrackElement;
|
|
6101
|
+
});
|
|
6102
|
+
this.element.load();
|
|
6103
|
+
const setupNewTracks = () => {
|
|
6104
|
+
setTimeout(() => {
|
|
6105
|
+
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6106
|
+
const trackElement = trackInfo.trackElement;
|
|
6107
|
+
const newTextTrack = trackElement.track;
|
|
6108
|
+
if (newTextTrack) {
|
|
6109
|
+
const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
|
|
6110
|
+
newTextTrack.mode = "hidden";
|
|
6111
|
+
const restoreMode = () => {
|
|
6112
|
+
if (modeInfo.wasShowing) {
|
|
6113
|
+
newTextTrack.mode = "hidden";
|
|
6114
|
+
} else if (modeInfo.wasHidden) {
|
|
6115
|
+
newTextTrack.mode = "hidden";
|
|
6116
|
+
} else {
|
|
6117
|
+
newTextTrack.mode = "disabled";
|
|
6118
|
+
}
|
|
6119
|
+
};
|
|
6120
|
+
if (newTextTrack.readyState >= 2) {
|
|
6121
|
+
restoreMode();
|
|
6122
|
+
} else {
|
|
6123
|
+
newTextTrack.addEventListener("load", restoreMode, { once: true });
|
|
6124
|
+
newTextTrack.addEventListener("error", restoreMode, { once: true });
|
|
6125
|
+
}
|
|
6126
|
+
}
|
|
6127
|
+
});
|
|
6128
|
+
}, 300);
|
|
6129
|
+
};
|
|
6130
|
+
if (this.element.readyState >= 1) {
|
|
6131
|
+
setTimeout(setupNewTracks, 200);
|
|
6132
|
+
} else {
|
|
6133
|
+
this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
|
|
6134
|
+
setTimeout(setupNewTracks, 2e3);
|
|
6135
|
+
}
|
|
6136
|
+
}, 100);
|
|
6137
|
+
const skippedCount = validationResults.length - tracksToSwap.length;
|
|
6138
|
+
}
|
|
6139
|
+
}
|
|
6140
|
+
const allSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6141
|
+
const sourcesToUpdate = [];
|
|
6142
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6143
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6144
|
+
const currentSrc2 = sourceEl.getAttribute("src");
|
|
6145
|
+
if (descSrcAttr) {
|
|
6146
|
+
const type = sourceEl.getAttribute("type");
|
|
6147
|
+
let origSrc = sourceEl.getAttribute("data-orig-src");
|
|
6148
|
+
if (!origSrc) {
|
|
6149
|
+
origSrc = currentSrc2;
|
|
6150
|
+
}
|
|
6151
|
+
sourcesToUpdate.push({
|
|
6152
|
+
src: descSrcAttr,
|
|
6153
|
+
// Use described version
|
|
6154
|
+
type,
|
|
6155
|
+
origSrc,
|
|
6156
|
+
descSrc: descSrcAttr
|
|
6157
|
+
});
|
|
6158
|
+
} else {
|
|
6159
|
+
const type = sourceEl.getAttribute("type");
|
|
6160
|
+
const src = sourceEl.getAttribute("src");
|
|
6161
|
+
sourcesToUpdate.push({
|
|
6162
|
+
src,
|
|
6163
|
+
type,
|
|
6164
|
+
origSrc: null,
|
|
6165
|
+
descSrc: null
|
|
6166
|
+
});
|
|
6167
|
+
}
|
|
6168
|
+
});
|
|
6169
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6170
|
+
sourceEl.remove();
|
|
6171
|
+
});
|
|
6172
|
+
sourcesToUpdate.forEach((sourceInfo) => {
|
|
6173
|
+
const newSource = document.createElement("source");
|
|
6174
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6175
|
+
if (sourceInfo.type) {
|
|
6176
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6177
|
+
}
|
|
6178
|
+
if (sourceInfo.origSrc) {
|
|
6179
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6180
|
+
}
|
|
6181
|
+
if (sourceInfo.descSrc) {
|
|
6182
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6183
|
+
}
|
|
6184
|
+
this.element.appendChild(newSource);
|
|
6185
|
+
});
|
|
6186
|
+
this.element.load();
|
|
6187
|
+
await new Promise((resolve) => {
|
|
6188
|
+
const onLoadedMetadata = () => {
|
|
6189
|
+
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
6190
|
+
resolve();
|
|
6191
|
+
};
|
|
6192
|
+
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
6193
|
+
});
|
|
6194
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
6195
|
+
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6196
|
+
if (this.element.readyState >= 1) {
|
|
6197
|
+
this.element.currentTime = 1e-3;
|
|
6198
|
+
setTimeout(() => {
|
|
6199
|
+
this.element.currentTime = 0;
|
|
6200
|
+
}, 10);
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6203
|
+
this.seek(currentTime);
|
|
6204
|
+
if (wasPlaying) {
|
|
6205
|
+
this.play();
|
|
6206
|
+
}
|
|
6207
|
+
this.state.audioDescriptionEnabled = true;
|
|
6208
|
+
this.emit("audiodescriptionenabled");
|
|
6209
|
+
} else {
|
|
6210
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6211
|
+
const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
|
|
6212
|
+
if (trackInfo.trackElement && trackInfo.describedSrc) {
|
|
6213
|
+
if (trackInfo.explicit === true) {
|
|
6214
|
+
try {
|
|
6215
|
+
const exists = await this.validateTrackExists(trackInfo.describedSrc);
|
|
6216
|
+
return { trackInfo, exists };
|
|
6217
|
+
} catch (error) {
|
|
6218
|
+
return { trackInfo, exists: false };
|
|
6219
|
+
}
|
|
6220
|
+
} else {
|
|
6221
|
+
return { trackInfo, exists: false };
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
6224
|
+
return { trackInfo, exists: false };
|
|
6225
|
+
});
|
|
6226
|
+
const validationResults = await Promise.all(validationPromises);
|
|
6227
|
+
const tracksToSwap = validationResults.filter((result) => result.exists);
|
|
6228
|
+
if (tracksToSwap.length > 0) {
|
|
6229
|
+
const trackModes = /* @__PURE__ */ new Map();
|
|
6230
|
+
tracksToSwap.forEach(({ trackInfo }) => {
|
|
6231
|
+
const textTrack = trackInfo.trackElement.track;
|
|
6232
|
+
if (textTrack) {
|
|
6233
|
+
trackModes.set(trackInfo, {
|
|
6234
|
+
wasShowing: textTrack.mode === "showing",
|
|
6235
|
+
wasHidden: textTrack.mode === "hidden"
|
|
6236
|
+
});
|
|
6237
|
+
} else {
|
|
6238
|
+
trackModes.set(trackInfo, {
|
|
6239
|
+
wasShowing: false,
|
|
6240
|
+
wasHidden: false
|
|
6241
|
+
});
|
|
6242
|
+
}
|
|
6243
|
+
});
|
|
6244
|
+
const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
|
|
6245
|
+
const oldSrc = trackInfo.trackElement.getAttribute("src");
|
|
6246
|
+
const parent = trackInfo.trackElement.parentNode;
|
|
6247
|
+
const nextSibling = trackInfo.trackElement.nextSibling;
|
|
6248
|
+
const attributes = {};
|
|
6249
|
+
Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
|
|
6250
|
+
attributes[attr.name] = attr.value;
|
|
6251
|
+
});
|
|
6252
|
+
return {
|
|
6253
|
+
trackInfo,
|
|
6254
|
+
oldSrc,
|
|
6255
|
+
parent,
|
|
6256
|
+
nextSibling,
|
|
6257
|
+
attributes
|
|
6258
|
+
};
|
|
6259
|
+
});
|
|
6260
|
+
tracksToReadd.forEach(({ trackInfo }) => {
|
|
6261
|
+
trackInfo.trackElement.remove();
|
|
6262
|
+
});
|
|
6263
|
+
this.element.load();
|
|
6264
|
+
setTimeout(() => {
|
|
6265
|
+
tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
|
|
6266
|
+
swappedTracksForTranscript.push(trackInfo);
|
|
6267
|
+
const newTrackElement = document.createElement("track");
|
|
6268
|
+
newTrackElement.setAttribute("src", trackInfo.describedSrc);
|
|
6269
|
+
Object.keys(attributes).forEach((attrName) => {
|
|
6270
|
+
if (attrName !== "src" && attrName !== "data-desc-src") {
|
|
6271
|
+
newTrackElement.setAttribute(attrName, attributes[attrName]);
|
|
6272
|
+
}
|
|
6273
|
+
});
|
|
6274
|
+
if (nextSibling && nextSibling.parentNode) {
|
|
6275
|
+
parent.insertBefore(newTrackElement, nextSibling);
|
|
6276
|
+
} else {
|
|
6277
|
+
parent.appendChild(newTrackElement);
|
|
6278
|
+
}
|
|
6279
|
+
trackInfo.trackElement = newTrackElement;
|
|
6280
|
+
});
|
|
6281
|
+
this.element.load();
|
|
6282
|
+
const setupNewTracks = () => {
|
|
6283
|
+
setTimeout(() => {
|
|
6284
|
+
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6285
|
+
const trackElement = trackInfo.trackElement;
|
|
6286
|
+
const newTextTrack = trackElement.track;
|
|
6287
|
+
if (newTextTrack) {
|
|
6288
|
+
const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
|
|
6289
|
+
newTextTrack.mode = "hidden";
|
|
6290
|
+
const restoreMode = () => {
|
|
6291
|
+
if (modeInfo.wasShowing) {
|
|
6292
|
+
newTextTrack.mode = "hidden";
|
|
6293
|
+
} else if (modeInfo.wasHidden) {
|
|
6294
|
+
newTextTrack.mode = "hidden";
|
|
6295
|
+
} else {
|
|
6296
|
+
newTextTrack.mode = "disabled";
|
|
6297
|
+
}
|
|
6298
|
+
};
|
|
6299
|
+
if (newTextTrack.readyState >= 2) {
|
|
6300
|
+
restoreMode();
|
|
6301
|
+
} else {
|
|
6302
|
+
newTextTrack.addEventListener("load", restoreMode, { once: true });
|
|
6303
|
+
newTextTrack.addEventListener("error", restoreMode, { once: true });
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6306
|
+
});
|
|
6307
|
+
}, 300);
|
|
6308
|
+
};
|
|
6309
|
+
if (this.element.readyState >= 1) {
|
|
6310
|
+
setTimeout(setupNewTracks, 200);
|
|
6311
|
+
} else {
|
|
6312
|
+
this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
|
|
6313
|
+
setTimeout(setupNewTracks, 2e3);
|
|
6314
|
+
}
|
|
6315
|
+
}, 100);
|
|
6316
|
+
}
|
|
6317
|
+
}
|
|
6318
|
+
const fallbackSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6319
|
+
const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6320
|
+
if (hasSourceElementsWithDesc2) {
|
|
6321
|
+
const fallbackSourcesToUpdate = [];
|
|
6322
|
+
fallbackSourceElements.forEach((sourceEl) => {
|
|
6323
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6324
|
+
const currentSrc = sourceEl.getAttribute("src");
|
|
6325
|
+
if (descSrcAttr) {
|
|
6326
|
+
const type = sourceEl.getAttribute("type");
|
|
6327
|
+
let origSrc = sourceEl.getAttribute("data-orig-src");
|
|
6328
|
+
if (!origSrc) {
|
|
6329
|
+
origSrc = currentSrc;
|
|
6330
|
+
}
|
|
6331
|
+
fallbackSourcesToUpdate.push({
|
|
6332
|
+
src: descSrcAttr,
|
|
6333
|
+
type,
|
|
6334
|
+
origSrc,
|
|
6335
|
+
descSrc: descSrcAttr
|
|
6336
|
+
});
|
|
6337
|
+
} else {
|
|
6338
|
+
const type = sourceEl.getAttribute("type");
|
|
6339
|
+
const src = sourceEl.getAttribute("src");
|
|
6340
|
+
fallbackSourcesToUpdate.push({
|
|
6341
|
+
src,
|
|
6342
|
+
type,
|
|
6343
|
+
origSrc: null,
|
|
6344
|
+
descSrc: null
|
|
6345
|
+
});
|
|
6346
|
+
}
|
|
6347
|
+
});
|
|
6348
|
+
fallbackSourceElements.forEach((sourceEl) => {
|
|
6349
|
+
sourceEl.remove();
|
|
6350
|
+
});
|
|
6351
|
+
fallbackSourcesToUpdate.forEach((sourceInfo) => {
|
|
6352
|
+
const newSource = document.createElement("source");
|
|
6353
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6354
|
+
if (sourceInfo.type) {
|
|
6355
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6356
|
+
}
|
|
6357
|
+
if (sourceInfo.origSrc) {
|
|
6358
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6359
|
+
}
|
|
6360
|
+
if (sourceInfo.descSrc) {
|
|
6361
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6362
|
+
}
|
|
6363
|
+
this.element.appendChild(newSource);
|
|
6364
|
+
});
|
|
6365
|
+
this.element.load();
|
|
6366
|
+
} else {
|
|
6367
|
+
this.element.src = this.audioDescriptionSrc;
|
|
6368
|
+
}
|
|
6369
|
+
}
|
|
4882
6370
|
await new Promise((resolve) => {
|
|
4883
6371
|
const onLoadedMetadata = () => {
|
|
4884
6372
|
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
@@ -4886,10 +6374,183 @@ var VidPly = (() => {
|
|
|
4886
6374
|
};
|
|
4887
6375
|
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
4888
6376
|
});
|
|
6377
|
+
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6378
|
+
if (this.element.readyState >= 1) {
|
|
6379
|
+
this.element.currentTime = 1e-3;
|
|
6380
|
+
setTimeout(() => {
|
|
6381
|
+
this.element.currentTime = 0;
|
|
6382
|
+
}, 10);
|
|
6383
|
+
}
|
|
6384
|
+
}
|
|
4889
6385
|
this.seek(currentTime);
|
|
4890
6386
|
if (wasPlaying) {
|
|
4891
6387
|
this.play();
|
|
4892
6388
|
}
|
|
6389
|
+
if (swappedTracksForTranscript.length > 0 && this.captionManager) {
|
|
6390
|
+
const wasCaptionsEnabled = this.state.captionsEnabled;
|
|
6391
|
+
let currentTrackInfo = null;
|
|
6392
|
+
if (this.captionManager.currentTrack) {
|
|
6393
|
+
const currentTrackIndex = this.captionManager.tracks.findIndex((t) => t.track === this.captionManager.currentTrack.track);
|
|
6394
|
+
if (currentTrackIndex >= 0) {
|
|
6395
|
+
currentTrackInfo = {
|
|
6396
|
+
language: this.captionManager.tracks[currentTrackIndex].language,
|
|
6397
|
+
kind: this.captionManager.tracks[currentTrackIndex].kind
|
|
6398
|
+
};
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
setTimeout(() => {
|
|
6402
|
+
this.captionManager.tracks = [];
|
|
6403
|
+
this.captionManager.loadTracks();
|
|
6404
|
+
if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {
|
|
6405
|
+
const matchingTrackIndex = this.captionManager.tracks.findIndex(
|
|
6406
|
+
(t) => t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind
|
|
6407
|
+
);
|
|
6408
|
+
if (matchingTrackIndex >= 0) {
|
|
6409
|
+
this.captionManager.enable(matchingTrackIndex);
|
|
6410
|
+
} else if (this.captionManager.tracks.length > 0) {
|
|
6411
|
+
this.captionManager.enable(0);
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
}, 600);
|
|
6415
|
+
}
|
|
6416
|
+
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6417
|
+
const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
|
|
6418
|
+
if (swappedTracks.length > 0) {
|
|
6419
|
+
const onMetadataLoaded = () => {
|
|
6420
|
+
const allTextTracks = Array.from(this.element.textTracks);
|
|
6421
|
+
const freshTracks = swappedTracks.map((trackInfo) => {
|
|
6422
|
+
const trackEl = trackInfo.trackElement;
|
|
6423
|
+
const expectedSrc = trackEl.getAttribute("src");
|
|
6424
|
+
const srclang = trackEl.getAttribute("srclang");
|
|
6425
|
+
const kind = trackEl.getAttribute("kind");
|
|
6426
|
+
let foundTrack = allTextTracks.find((track) => trackEl.track === track);
|
|
6427
|
+
if (!foundTrack) {
|
|
6428
|
+
foundTrack = allTextTracks.find((track) => {
|
|
6429
|
+
if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
|
|
6430
|
+
const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
|
|
6431
|
+
(el) => el.track === track
|
|
6432
|
+
);
|
|
6433
|
+
if (trackElementForTrack) {
|
|
6434
|
+
const actualSrc = trackElementForTrack.getAttribute("src");
|
|
6435
|
+
if (actualSrc === expectedSrc) {
|
|
6436
|
+
return true;
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
}
|
|
6440
|
+
return false;
|
|
6441
|
+
});
|
|
6442
|
+
}
|
|
6443
|
+
if (foundTrack) {
|
|
6444
|
+
const trackElement = Array.from(this.element.querySelectorAll("track")).find(
|
|
6445
|
+
(el) => el.track === foundTrack
|
|
6446
|
+
);
|
|
6447
|
+
if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
|
|
6448
|
+
return null;
|
|
6449
|
+
}
|
|
6450
|
+
}
|
|
6451
|
+
return foundTrack;
|
|
6452
|
+
}).filter(Boolean);
|
|
6453
|
+
if (freshTracks.length === 0) {
|
|
6454
|
+
setTimeout(() => {
|
|
6455
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6456
|
+
this.transcriptManager.loadTranscriptData();
|
|
6457
|
+
}
|
|
6458
|
+
}, 1e3);
|
|
6459
|
+
return;
|
|
6460
|
+
}
|
|
6461
|
+
freshTracks.forEach((track) => {
|
|
6462
|
+
if (track.mode === "disabled") {
|
|
6463
|
+
track.mode = "hidden";
|
|
6464
|
+
}
|
|
6465
|
+
});
|
|
6466
|
+
let loadedCount = 0;
|
|
6467
|
+
const checkLoaded = () => {
|
|
6468
|
+
loadedCount++;
|
|
6469
|
+
if (loadedCount >= freshTracks.length) {
|
|
6470
|
+
setTimeout(() => {
|
|
6471
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6472
|
+
const allTextTracks2 = Array.from(this.element.textTracks);
|
|
6473
|
+
const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
|
|
6474
|
+
const hasCorrectTracks = freshTracks.some((track) => {
|
|
6475
|
+
const trackEl = Array.from(this.element.querySelectorAll("track")).find(
|
|
6476
|
+
(el) => el.track === track
|
|
6477
|
+
);
|
|
6478
|
+
return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
|
|
6479
|
+
});
|
|
6480
|
+
if (hasCorrectTracks || freshTracks.length > 0) {
|
|
6481
|
+
this.transcriptManager.loadTranscriptData();
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
}, 800);
|
|
6485
|
+
}
|
|
6486
|
+
};
|
|
6487
|
+
freshTracks.forEach((track) => {
|
|
6488
|
+
if (track.mode === "disabled") {
|
|
6489
|
+
track.mode = "hidden";
|
|
6490
|
+
}
|
|
6491
|
+
const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
|
|
6492
|
+
(el) => el.track === track
|
|
6493
|
+
);
|
|
6494
|
+
const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
|
|
6495
|
+
const expectedTrackInfo = swappedTracks.find((t) => {
|
|
6496
|
+
const tEl = t.trackElement;
|
|
6497
|
+
return tEl && (tEl.track === track || tEl.getAttribute("srclang") === track.language && tEl.getAttribute("kind") === track.kind);
|
|
6498
|
+
});
|
|
6499
|
+
const expectedSrc = expectedTrackInfo ? expectedTrackInfo.describedSrc : null;
|
|
6500
|
+
if (expectedSrc && actualSrc && actualSrc !== expectedSrc) {
|
|
6501
|
+
checkLoaded();
|
|
6502
|
+
return;
|
|
6503
|
+
}
|
|
6504
|
+
if (track.readyState >= 2 && track.cues && track.cues.length > 0) {
|
|
6505
|
+
checkLoaded();
|
|
6506
|
+
} else {
|
|
6507
|
+
if (track.mode === "disabled") {
|
|
6508
|
+
track.mode = "hidden";
|
|
6509
|
+
}
|
|
6510
|
+
const onTrackLoad = () => {
|
|
6511
|
+
setTimeout(checkLoaded, 300);
|
|
6512
|
+
};
|
|
6513
|
+
if (track.readyState >= 2) {
|
|
6514
|
+
setTimeout(() => {
|
|
6515
|
+
if (track.cues && track.cues.length > 0) {
|
|
6516
|
+
checkLoaded();
|
|
6517
|
+
} else {
|
|
6518
|
+
track.addEventListener("load", onTrackLoad, { once: true });
|
|
6519
|
+
}
|
|
6520
|
+
}, 100);
|
|
6521
|
+
} else {
|
|
6522
|
+
track.addEventListener("load", onTrackLoad, { once: true });
|
|
6523
|
+
track.addEventListener("error", () => {
|
|
6524
|
+
checkLoaded();
|
|
6525
|
+
}, { once: true });
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
});
|
|
6529
|
+
};
|
|
6530
|
+
const waitForTracks = () => {
|
|
6531
|
+
setTimeout(() => {
|
|
6532
|
+
if (this.element.readyState >= 1) {
|
|
6533
|
+
onMetadataLoaded();
|
|
6534
|
+
} else {
|
|
6535
|
+
this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
|
|
6536
|
+
setTimeout(onMetadataLoaded, 2e3);
|
|
6537
|
+
}
|
|
6538
|
+
}, 500);
|
|
6539
|
+
};
|
|
6540
|
+
waitForTracks();
|
|
6541
|
+
setTimeout(() => {
|
|
6542
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6543
|
+
this.transcriptManager.loadTranscriptData();
|
|
6544
|
+
}
|
|
6545
|
+
}, 5e3);
|
|
6546
|
+
} else {
|
|
6547
|
+
setTimeout(() => {
|
|
6548
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6549
|
+
this.transcriptManager.loadTranscriptData();
|
|
6550
|
+
}
|
|
6551
|
+
}, 800);
|
|
6552
|
+
}
|
|
6553
|
+
}
|
|
4893
6554
|
this.state.audioDescriptionEnabled = true;
|
|
4894
6555
|
this.emit("audiodescriptionenabled");
|
|
4895
6556
|
}
|
|
@@ -4899,7 +6560,64 @@ var VidPly = (() => {
|
|
|
4899
6560
|
}
|
|
4900
6561
|
const currentTime = this.state.currentTime;
|
|
4901
6562
|
const wasPlaying = this.state.playing;
|
|
4902
|
-
this.
|
|
6563
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6564
|
+
this.audioDescriptionCaptionTracks.forEach((trackInfo) => {
|
|
6565
|
+
if (trackInfo.trackElement && trackInfo.originalTrackSrc) {
|
|
6566
|
+
trackInfo.trackElement.setAttribute("src", trackInfo.originalTrackSrc);
|
|
6567
|
+
}
|
|
6568
|
+
});
|
|
6569
|
+
}
|
|
6570
|
+
const allSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6571
|
+
const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
|
|
6572
|
+
if (hasSourceElementsToSwap) {
|
|
6573
|
+
const sourcesToRestore = [];
|
|
6574
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6575
|
+
const origSrcAttr = sourceEl.getAttribute("data-orig-src");
|
|
6576
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6577
|
+
if (origSrcAttr) {
|
|
6578
|
+
const type = sourceEl.getAttribute("type");
|
|
6579
|
+
sourcesToRestore.push({
|
|
6580
|
+
src: origSrcAttr,
|
|
6581
|
+
// Use original version
|
|
6582
|
+
type,
|
|
6583
|
+
origSrc: origSrcAttr,
|
|
6584
|
+
descSrc: descSrcAttr
|
|
6585
|
+
// Keep data-desc-src for future swaps
|
|
6586
|
+
});
|
|
6587
|
+
} else {
|
|
6588
|
+
const type = sourceEl.getAttribute("type");
|
|
6589
|
+
const src = sourceEl.getAttribute("src");
|
|
6590
|
+
sourcesToRestore.push({
|
|
6591
|
+
src,
|
|
6592
|
+
type,
|
|
6593
|
+
origSrc: null,
|
|
6594
|
+
descSrc: descSrcAttr
|
|
6595
|
+
});
|
|
6596
|
+
}
|
|
6597
|
+
});
|
|
6598
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6599
|
+
sourceEl.remove();
|
|
6600
|
+
});
|
|
6601
|
+
sourcesToRestore.forEach((sourceInfo) => {
|
|
6602
|
+
const newSource = document.createElement("source");
|
|
6603
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6604
|
+
if (sourceInfo.type) {
|
|
6605
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6606
|
+
}
|
|
6607
|
+
if (sourceInfo.origSrc) {
|
|
6608
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6609
|
+
}
|
|
6610
|
+
if (sourceInfo.descSrc) {
|
|
6611
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6612
|
+
}
|
|
6613
|
+
this.element.appendChild(newSource);
|
|
6614
|
+
});
|
|
6615
|
+
this.element.load();
|
|
6616
|
+
} else {
|
|
6617
|
+
const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
|
|
6618
|
+
this.element.src = originalSrcToUse;
|
|
6619
|
+
this.element.load();
|
|
6620
|
+
}
|
|
4903
6621
|
await new Promise((resolve) => {
|
|
4904
6622
|
const onLoadedMetadata = () => {
|
|
4905
6623
|
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
@@ -4911,14 +6629,44 @@ var VidPly = (() => {
|
|
|
4911
6629
|
if (wasPlaying) {
|
|
4912
6630
|
this.play();
|
|
4913
6631
|
}
|
|
6632
|
+
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6633
|
+
setTimeout(() => {
|
|
6634
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6635
|
+
this.transcriptManager.loadTranscriptData();
|
|
6636
|
+
}
|
|
6637
|
+
}, 500);
|
|
6638
|
+
}
|
|
4914
6639
|
this.state.audioDescriptionEnabled = false;
|
|
4915
6640
|
this.emit("audiodescriptiondisabled");
|
|
4916
6641
|
}
|
|
4917
6642
|
async toggleAudioDescription() {
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
6643
|
+
const textTracks = Array.from(this.element.textTracks || []);
|
|
6644
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
6645
|
+
const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
6646
|
+
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
6647
|
+
if (this.state.audioDescriptionEnabled) {
|
|
6648
|
+
descriptionTrack.mode = "hidden";
|
|
6649
|
+
await this.disableAudioDescription();
|
|
6650
|
+
} else {
|
|
6651
|
+
await this.enableAudioDescription();
|
|
6652
|
+
descriptionTrack.mode = "showing";
|
|
6653
|
+
}
|
|
6654
|
+
} else if (descriptionTrack) {
|
|
6655
|
+
if (descriptionTrack.mode === "showing") {
|
|
6656
|
+
descriptionTrack.mode = "hidden";
|
|
6657
|
+
this.state.audioDescriptionEnabled = false;
|
|
6658
|
+
this.emit("audiodescriptiondisabled");
|
|
6659
|
+
} else {
|
|
6660
|
+
descriptionTrack.mode = "showing";
|
|
6661
|
+
this.state.audioDescriptionEnabled = true;
|
|
6662
|
+
this.emit("audiodescriptionenabled");
|
|
6663
|
+
}
|
|
6664
|
+
} else if (hasAudioDescriptionSrc) {
|
|
6665
|
+
if (this.state.audioDescriptionEnabled) {
|
|
6666
|
+
await this.disableAudioDescription();
|
|
6667
|
+
} else {
|
|
6668
|
+
await this.enableAudioDescription();
|
|
6669
|
+
}
|
|
4922
6670
|
}
|
|
4923
6671
|
}
|
|
4924
6672
|
// Sign Language
|
|
@@ -4927,24 +6675,47 @@ var VidPly = (() => {
|
|
|
4927
6675
|
console.warn("No sign language video source provided");
|
|
4928
6676
|
return;
|
|
4929
6677
|
}
|
|
4930
|
-
if (this.
|
|
4931
|
-
this.
|
|
6678
|
+
if (this.signLanguageWrapper) {
|
|
6679
|
+
this.signLanguageWrapper.style.display = "block";
|
|
4932
6680
|
this.state.signLanguageEnabled = true;
|
|
4933
6681
|
this.emit("signlanguageenabled");
|
|
4934
6682
|
return;
|
|
4935
6683
|
}
|
|
6684
|
+
this.signLanguageWrapper = document.createElement("div");
|
|
6685
|
+
this.signLanguageWrapper.className = "vidply-sign-language-wrapper";
|
|
6686
|
+
this.signLanguageWrapper.setAttribute("tabindex", "0");
|
|
6687
|
+
this.signLanguageWrapper.setAttribute("aria-label", "Sign Language Video - Press D to drag with keyboard, R to resize");
|
|
4936
6688
|
this.signLanguageVideo = document.createElement("video");
|
|
4937
6689
|
this.signLanguageVideo.className = "vidply-sign-language-video";
|
|
4938
6690
|
this.signLanguageVideo.src = this.signLanguageSrc;
|
|
4939
6691
|
this.signLanguageVideo.setAttribute("aria-label", i18n.t("player.signLanguage"));
|
|
4940
|
-
const position = this.options.signLanguagePosition || "bottom-right";
|
|
4941
|
-
this.signLanguageVideo.classList.add(`vidply-sign-position-${position}`);
|
|
4942
6692
|
this.signLanguageVideo.muted = true;
|
|
6693
|
+
const resizeHandles = ["nw", "ne", "sw", "se"].map((dir) => {
|
|
6694
|
+
const handle = document.createElement("div");
|
|
6695
|
+
handle.className = `vidply-sign-resize-handle vidply-sign-resize-${dir}`;
|
|
6696
|
+
handle.setAttribute("data-direction", dir);
|
|
6697
|
+
handle.setAttribute("aria-label", `Resize ${dir.toUpperCase()}`);
|
|
6698
|
+
return handle;
|
|
6699
|
+
});
|
|
6700
|
+
this.signLanguageWrapper.appendChild(this.signLanguageVideo);
|
|
6701
|
+
resizeHandles.forEach((handle) => this.signLanguageWrapper.appendChild(handle));
|
|
6702
|
+
const saved = this.storage.getSignLanguagePreferences();
|
|
6703
|
+
if (saved && saved.size && saved.size.width) {
|
|
6704
|
+
this.signLanguageWrapper.style.width = saved.size.width;
|
|
6705
|
+
} else {
|
|
6706
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6707
|
+
}
|
|
6708
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6709
|
+
this.signLanguageDesiredPosition = this.options.signLanguagePosition || "bottom-right";
|
|
6710
|
+
this.container.appendChild(this.signLanguageWrapper);
|
|
6711
|
+
requestAnimationFrame(() => {
|
|
6712
|
+
this.constrainSignLanguagePosition();
|
|
6713
|
+
});
|
|
4943
6714
|
this.signLanguageVideo.currentTime = this.state.currentTime;
|
|
4944
6715
|
if (!this.state.paused) {
|
|
4945
6716
|
this.signLanguageVideo.play();
|
|
4946
6717
|
}
|
|
4947
|
-
this.
|
|
6718
|
+
this.setupSignLanguageInteraction();
|
|
4948
6719
|
this.signLanguageHandlers = {
|
|
4949
6720
|
play: () => {
|
|
4950
6721
|
if (this.signLanguageVideo) {
|
|
@@ -4975,8 +6746,8 @@ var VidPly = (() => {
|
|
|
4975
6746
|
this.emit("signlanguageenabled");
|
|
4976
6747
|
}
|
|
4977
6748
|
disableSignLanguage() {
|
|
4978
|
-
if (this.
|
|
4979
|
-
this.
|
|
6749
|
+
if (this.signLanguageWrapper) {
|
|
6750
|
+
this.signLanguageWrapper.style.display = "none";
|
|
4980
6751
|
}
|
|
4981
6752
|
this.state.signLanguageEnabled = false;
|
|
4982
6753
|
this.emit("signlanguagedisabled");
|
|
@@ -4988,6 +6759,237 @@ var VidPly = (() => {
|
|
|
4988
6759
|
this.enableSignLanguage();
|
|
4989
6760
|
}
|
|
4990
6761
|
}
|
|
6762
|
+
setupSignLanguageInteraction() {
|
|
6763
|
+
if (!this.signLanguageWrapper) return;
|
|
6764
|
+
let isDragging = false;
|
|
6765
|
+
let isResizing = false;
|
|
6766
|
+
let resizeDirection = null;
|
|
6767
|
+
let startX = 0;
|
|
6768
|
+
let startY = 0;
|
|
6769
|
+
let startLeft = 0;
|
|
6770
|
+
let startTop = 0;
|
|
6771
|
+
let startWidth = 0;
|
|
6772
|
+
let startHeight = 0;
|
|
6773
|
+
let dragMode = false;
|
|
6774
|
+
let resizeMode = false;
|
|
6775
|
+
const onMouseDownVideo = (e) => {
|
|
6776
|
+
if (e.target !== this.signLanguageVideo) return;
|
|
6777
|
+
e.preventDefault();
|
|
6778
|
+
isDragging = true;
|
|
6779
|
+
startX = e.clientX;
|
|
6780
|
+
startY = e.clientY;
|
|
6781
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6782
|
+
startLeft = rect.left;
|
|
6783
|
+
startTop = rect.top;
|
|
6784
|
+
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6785
|
+
};
|
|
6786
|
+
const onMouseDownHandle = (e) => {
|
|
6787
|
+
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6788
|
+
e.preventDefault();
|
|
6789
|
+
e.stopPropagation();
|
|
6790
|
+
isResizing = true;
|
|
6791
|
+
resizeDirection = e.target.getAttribute("data-direction");
|
|
6792
|
+
startX = e.clientX;
|
|
6793
|
+
startY = e.clientY;
|
|
6794
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6795
|
+
startLeft = rect.left;
|
|
6796
|
+
startTop = rect.top;
|
|
6797
|
+
startWidth = rect.width;
|
|
6798
|
+
startHeight = rect.height;
|
|
6799
|
+
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6800
|
+
};
|
|
6801
|
+
const onMouseMove = (e) => {
|
|
6802
|
+
if (isDragging) {
|
|
6803
|
+
const deltaX = e.clientX - startX;
|
|
6804
|
+
const deltaY = e.clientY - startY;
|
|
6805
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6806
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6807
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6808
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6809
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6810
|
+
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6811
|
+
let newTop = startTop + deltaY - containerRect.top;
|
|
6812
|
+
const controlsHeight = 95;
|
|
6813
|
+
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6814
|
+
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6815
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6816
|
+
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6817
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6818
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6819
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6820
|
+
} else if (isResizing) {
|
|
6821
|
+
const deltaX = e.clientX - startX;
|
|
6822
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6823
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6824
|
+
let newWidth = startWidth;
|
|
6825
|
+
let newLeft = startLeft - containerRect.left;
|
|
6826
|
+
if (resizeDirection.includes("e")) {
|
|
6827
|
+
newWidth = Math.max(150, startWidth + deltaX);
|
|
6828
|
+
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6829
|
+
newWidth = Math.min(newWidth, maxWidth);
|
|
6830
|
+
}
|
|
6831
|
+
if (resizeDirection.includes("w")) {
|
|
6832
|
+
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6833
|
+
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6834
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6835
|
+
if (proposedLeft >= videoWrapperLeft) {
|
|
6836
|
+
newWidth = proposedWidth;
|
|
6837
|
+
newLeft = proposedLeft;
|
|
6838
|
+
}
|
|
6839
|
+
}
|
|
6840
|
+
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6841
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6842
|
+
if (resizeDirection.includes("w")) {
|
|
6843
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6844
|
+
}
|
|
6845
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6846
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6847
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6848
|
+
}
|
|
6849
|
+
};
|
|
6850
|
+
const onMouseUp = () => {
|
|
6851
|
+
if (isDragging || isResizing) {
|
|
6852
|
+
this.saveSignLanguagePreferences();
|
|
6853
|
+
}
|
|
6854
|
+
isDragging = false;
|
|
6855
|
+
isResizing = false;
|
|
6856
|
+
resizeDirection = null;
|
|
6857
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6858
|
+
};
|
|
6859
|
+
const onKeyDown = (e) => {
|
|
6860
|
+
if (e.key === "d" || e.key === "D") {
|
|
6861
|
+
dragMode = !dragMode;
|
|
6862
|
+
resizeMode = false;
|
|
6863
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6864
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6865
|
+
e.preventDefault();
|
|
6866
|
+
return;
|
|
6867
|
+
}
|
|
6868
|
+
if (e.key === "r" || e.key === "R") {
|
|
6869
|
+
resizeMode = !resizeMode;
|
|
6870
|
+
dragMode = false;
|
|
6871
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6872
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6873
|
+
e.preventDefault();
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
if (e.key === "Escape") {
|
|
6877
|
+
dragMode = false;
|
|
6878
|
+
resizeMode = false;
|
|
6879
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6880
|
+
e.preventDefault();
|
|
6881
|
+
return;
|
|
6882
|
+
}
|
|
6883
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6884
|
+
const step = e.shiftKey ? 10 : 5;
|
|
6885
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6886
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6887
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6888
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6889
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6890
|
+
if (dragMode) {
|
|
6891
|
+
let left = rect.left - containerRect.left;
|
|
6892
|
+
let top = rect.top - containerRect.top;
|
|
6893
|
+
if (e.key === "ArrowLeft") left -= step;
|
|
6894
|
+
if (e.key === "ArrowRight") left += step;
|
|
6895
|
+
if (e.key === "ArrowUp") top -= step;
|
|
6896
|
+
if (e.key === "ArrowDown") top += step;
|
|
6897
|
+
const controlsHeight = 95;
|
|
6898
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6899
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6900
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6901
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6902
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6903
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6904
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6905
|
+
this.saveSignLanguagePreferences();
|
|
6906
|
+
e.preventDefault();
|
|
6907
|
+
} else if (resizeMode) {
|
|
6908
|
+
let width = rect.width;
|
|
6909
|
+
if (e.key === "ArrowLeft") width -= step;
|
|
6910
|
+
if (e.key === "ArrowRight") width += step;
|
|
6911
|
+
if (e.key === "ArrowUp") width += step;
|
|
6912
|
+
if (e.key === "ArrowDown") width -= step;
|
|
6913
|
+
width = Math.max(150, width);
|
|
6914
|
+
width = Math.min(width, videoWrapperRect.width);
|
|
6915
|
+
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6916
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6917
|
+
this.saveSignLanguagePreferences();
|
|
6918
|
+
e.preventDefault();
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
};
|
|
6922
|
+
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6923
|
+
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6924
|
+
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6925
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
6926
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
6927
|
+
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
6928
|
+
this.signLanguageInteractionHandlers = {
|
|
6929
|
+
mouseDownVideo: onMouseDownVideo,
|
|
6930
|
+
mouseDownHandle: onMouseDownHandle,
|
|
6931
|
+
mouseMove: onMouseMove,
|
|
6932
|
+
mouseUp: onMouseUp,
|
|
6933
|
+
keyDown: onKeyDown,
|
|
6934
|
+
handles
|
|
6935
|
+
};
|
|
6936
|
+
}
|
|
6937
|
+
constrainSignLanguagePosition() {
|
|
6938
|
+
if (!this.signLanguageWrapper || !this.videoWrapper) return;
|
|
6939
|
+
if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === "") {
|
|
6940
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6941
|
+
}
|
|
6942
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6943
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6944
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6945
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6946
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6947
|
+
const videoWrapperWidth = videoWrapperRect.width;
|
|
6948
|
+
const videoWrapperHeight = videoWrapperRect.height;
|
|
6949
|
+
let wrapperWidth = wrapperRect.width || 280;
|
|
6950
|
+
let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
|
|
6951
|
+
let left, top;
|
|
6952
|
+
const margin = 16;
|
|
6953
|
+
const controlsHeight = 95;
|
|
6954
|
+
const position = this.signLanguageDesiredPosition || "bottom-right";
|
|
6955
|
+
switch (position) {
|
|
6956
|
+
case "bottom-right":
|
|
6957
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6958
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6959
|
+
break;
|
|
6960
|
+
case "bottom-left":
|
|
6961
|
+
left = videoWrapperLeft + margin;
|
|
6962
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6963
|
+
break;
|
|
6964
|
+
case "top-right":
|
|
6965
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6966
|
+
top = videoWrapperTop + margin;
|
|
6967
|
+
break;
|
|
6968
|
+
case "top-left":
|
|
6969
|
+
left = videoWrapperLeft + margin;
|
|
6970
|
+
top = videoWrapperTop + margin;
|
|
6971
|
+
break;
|
|
6972
|
+
default:
|
|
6973
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6974
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6975
|
+
}
|
|
6976
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
|
|
6977
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
|
|
6978
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6979
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6980
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6981
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6982
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6983
|
+
}
|
|
6984
|
+
saveSignLanguagePreferences() {
|
|
6985
|
+
if (!this.signLanguageWrapper) return;
|
|
6986
|
+
this.storage.saveSignLanguagePreferences({
|
|
6987
|
+
size: {
|
|
6988
|
+
width: this.signLanguageWrapper.style.width
|
|
6989
|
+
// Height is auto - maintained by aspect ratio
|
|
6990
|
+
}
|
|
6991
|
+
});
|
|
6992
|
+
}
|
|
4991
6993
|
cleanupSignLanguage() {
|
|
4992
6994
|
if (this.signLanguageHandlers) {
|
|
4993
6995
|
this.off("play", this.signLanguageHandlers.play);
|
|
@@ -4996,10 +6998,29 @@ var VidPly = (() => {
|
|
|
4996
6998
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
4997
6999
|
this.signLanguageHandlers = null;
|
|
4998
7000
|
}
|
|
4999
|
-
if (this.
|
|
5000
|
-
this.signLanguageVideo
|
|
5001
|
-
|
|
5002
|
-
|
|
7001
|
+
if (this.signLanguageInteractionHandlers) {
|
|
7002
|
+
if (this.signLanguageVideo) {
|
|
7003
|
+
this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
|
|
7004
|
+
}
|
|
7005
|
+
if (this.signLanguageInteractionHandlers.handles) {
|
|
7006
|
+
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
7007
|
+
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
7008
|
+
});
|
|
7009
|
+
}
|
|
7010
|
+
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
7011
|
+
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
7012
|
+
if (this.signLanguageWrapper) {
|
|
7013
|
+
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
7014
|
+
}
|
|
7015
|
+
this.signLanguageInteractionHandlers = null;
|
|
7016
|
+
}
|
|
7017
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
7018
|
+
if (this.signLanguageVideo) {
|
|
7019
|
+
this.signLanguageVideo.pause();
|
|
7020
|
+
this.signLanguageVideo.src = "";
|
|
7021
|
+
}
|
|
7022
|
+
this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
|
|
7023
|
+
this.signLanguageWrapper = null;
|
|
5003
7024
|
this.signLanguageVideo = null;
|
|
5004
7025
|
}
|
|
5005
7026
|
}
|
|
@@ -5102,6 +7123,16 @@ var VidPly = (() => {
|
|
|
5102
7123
|
if (this.controlBar) {
|
|
5103
7124
|
this.controlBar.updateFullscreenButton();
|
|
5104
7125
|
}
|
|
7126
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
7127
|
+
setTimeout(() => {
|
|
7128
|
+
requestAnimationFrame(() => {
|
|
7129
|
+
this.storage.saveSignLanguagePreferences({ size: null });
|
|
7130
|
+
this.signLanguageDesiredPosition = "bottom-right";
|
|
7131
|
+
this.signLanguageWrapper.style.width = isFullscreen ? "400px" : "280px";
|
|
7132
|
+
this.constrainSignLanguagePosition();
|
|
7133
|
+
});
|
|
7134
|
+
}, 500);
|
|
7135
|
+
}
|
|
5105
7136
|
}
|
|
5106
7137
|
};
|
|
5107
7138
|
document.addEventListener("fullscreenchange", this.fullscreenChangeHandler);
|