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.esm.js
CHANGED
|
@@ -448,7 +448,11 @@ var translations = {
|
|
|
448
448
|
noCaptions: "No captions available",
|
|
449
449
|
auto: "Auto",
|
|
450
450
|
autoQuality: "Auto (no quality selection available)",
|
|
451
|
-
noQuality: "Quality selection not available"
|
|
451
|
+
noQuality: "Quality selection not available",
|
|
452
|
+
signLanguageDragResize: "Sign Language Video - Press D to drag with keyboard, R to resize",
|
|
453
|
+
signLanguageDragActive: "Sign Language Video - Drag mode active. Use arrow keys to move, Escape to exit.",
|
|
454
|
+
signLanguageResizeActive: "Sign Language Video - Resize mode active. Use left/right arrow keys to resize, Escape to exit.",
|
|
455
|
+
resizeHandle: "Resize {direction} corner"
|
|
452
456
|
},
|
|
453
457
|
captions: {
|
|
454
458
|
off: "Off",
|
|
@@ -461,7 +465,7 @@ var translations = {
|
|
|
461
465
|
},
|
|
462
466
|
fontSizes: {
|
|
463
467
|
small: "Small",
|
|
464
|
-
|
|
468
|
+
normal: "Normal",
|
|
465
469
|
large: "Large",
|
|
466
470
|
xlarge: "X-Large"
|
|
467
471
|
},
|
|
@@ -489,7 +493,14 @@ var translations = {
|
|
|
489
493
|
title: "Transcript",
|
|
490
494
|
close: "Close transcript",
|
|
491
495
|
loading: "Loading transcript...",
|
|
492
|
-
noTranscript: "No transcript available for this video."
|
|
496
|
+
noTranscript: "No transcript available for this video.",
|
|
497
|
+
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
498
|
+
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
499
|
+
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
500
|
+
resizeWindow: "Resize Window",
|
|
501
|
+
styleTranscript: "Open transcript style settings",
|
|
502
|
+
closeMenu: "Close Menu",
|
|
503
|
+
styleTitle: "Transcript Style"
|
|
493
504
|
},
|
|
494
505
|
settings: {
|
|
495
506
|
title: "Settings",
|
|
@@ -558,7 +569,11 @@ var translations = {
|
|
|
558
569
|
noCaptions: "Keine Untertitel verf\xFCgbar",
|
|
559
570
|
auto: "Automatisch",
|
|
560
571
|
autoQuality: "Automatisch (keine Qualit\xE4tsauswahl verf\xFCgbar)",
|
|
561
|
-
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar"
|
|
572
|
+
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar",
|
|
573
|
+
signLanguageDragResize: "Geb\xE4rdensprache-Video - Dr\xFCcken Sie D zum Verschieben per Tastatur, R zum \xC4ndern der Gr\xF6\xDFe",
|
|
574
|
+
signLanguageDragActive: "Geb\xE4rdensprache-Video - Verschiebemodus aktiv. Pfeiltasten zum Bewegen, Escape zum Beenden.",
|
|
575
|
+
signLanguageResizeActive: "Geb\xE4rdensprache-Video - Gr\xF6\xDFen\xE4nderungsmodus aktiv. Links-/Rechts-Pfeiltasten zum \xC4ndern der Gr\xF6\xDFe, Escape zum Beenden.",
|
|
576
|
+
resizeHandle: "Gr\xF6\xDFen\xE4nderung {direction}-Ecke"
|
|
562
577
|
},
|
|
563
578
|
captions: {
|
|
564
579
|
off: "Aus",
|
|
@@ -571,7 +586,7 @@ var translations = {
|
|
|
571
586
|
},
|
|
572
587
|
fontSizes: {
|
|
573
588
|
small: "Klein",
|
|
574
|
-
|
|
589
|
+
normal: "Normal",
|
|
575
590
|
large: "Gro\xDF",
|
|
576
591
|
xlarge: "Sehr gro\xDF"
|
|
577
592
|
},
|
|
@@ -599,7 +614,14 @@ var translations = {
|
|
|
599
614
|
title: "Transkript",
|
|
600
615
|
close: "Transkript schlie\xDFen",
|
|
601
616
|
loading: "Transkript wird geladen...",
|
|
602
|
-
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar."
|
|
617
|
+
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar.",
|
|
618
|
+
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
619
|
+
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
620
|
+
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
621
|
+
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
622
|
+
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
623
|
+
closeMenu: "Men\xFC schlie\xDFen",
|
|
624
|
+
styleTitle: "Transkript-Stil"
|
|
603
625
|
},
|
|
604
626
|
settings: {
|
|
605
627
|
title: "Einstellungen",
|
|
@@ -668,7 +690,11 @@ var translations = {
|
|
|
668
690
|
noCaptions: "No hay subt\xEDtulos disponibles",
|
|
669
691
|
auto: "Autom\xE1tico",
|
|
670
692
|
autoQuality: "Autom\xE1tico (selecci\xF3n de calidad no disponible)",
|
|
671
|
-
noQuality: "Selecci\xF3n de calidad no disponible"
|
|
693
|
+
noQuality: "Selecci\xF3n de calidad no disponible",
|
|
694
|
+
signLanguageDragResize: "Video en Lengua de Se\xF1as - Presione D para arrastrar con el teclado, R para cambiar el tama\xF1o",
|
|
695
|
+
signLanguageDragActive: "Video en Lengua de Se\xF1as - Modo de arrastre activo. Use las teclas de flecha para mover, Escape para salir.",
|
|
696
|
+
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.",
|
|
697
|
+
resizeHandle: "Cambiar tama\xF1o esquina {direction}"
|
|
672
698
|
},
|
|
673
699
|
captions: {
|
|
674
700
|
off: "Desactivado",
|
|
@@ -681,7 +707,7 @@ var translations = {
|
|
|
681
707
|
},
|
|
682
708
|
fontSizes: {
|
|
683
709
|
small: "Peque\xF1o",
|
|
684
|
-
|
|
710
|
+
normal: "Normal",
|
|
685
711
|
large: "Grande",
|
|
686
712
|
xlarge: "Muy grande"
|
|
687
713
|
},
|
|
@@ -709,7 +735,14 @@ var translations = {
|
|
|
709
735
|
title: "Transcripci\xF3n",
|
|
710
736
|
close: "Cerrar transcripci\xF3n",
|
|
711
737
|
loading: "Cargando transcripci\xF3n...",
|
|
712
|
-
noTranscript: "No hay transcripci\xF3n disponible para este video."
|
|
738
|
+
noTranscript: "No hay transcripci\xF3n disponible para este video.",
|
|
739
|
+
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
740
|
+
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
741
|
+
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)",
|
|
742
|
+
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
743
|
+
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
744
|
+
closeMenu: "Cerrar men\xFA",
|
|
745
|
+
styleTitle: "Estilo de Transcripci\xF3n"
|
|
713
746
|
},
|
|
714
747
|
settings: {
|
|
715
748
|
title: "Configuraci\xF3n",
|
|
@@ -778,7 +811,11 @@ var translations = {
|
|
|
778
811
|
noCaptions: "Aucun sous-titre disponible",
|
|
779
812
|
auto: "Automatique",
|
|
780
813
|
autoQuality: "Automatique (s\xE9lection de qualit\xE9 non disponible)",
|
|
781
|
-
noQuality: "S\xE9lection de qualit\xE9 non disponible"
|
|
814
|
+
noQuality: "S\xE9lection de qualit\xE9 non disponible",
|
|
815
|
+
signLanguageDragResize: "Vid\xE9o en Langue des Signes - Appuyez sur D pour d\xE9placer avec le clavier, R pour redimensionner",
|
|
816
|
+
signLanguageDragActive: "Vid\xE9o en Langue des Signes - Mode glissement actif. Utilisez les touches fl\xE9ch\xE9es pour d\xE9placer, \xC9chap pour quitter.",
|
|
817
|
+
signLanguageResizeActive: "Vid\xE9o en Langue des Signes - Mode redimensionnement actif. Utilisez les touches fl\xE9ch\xE9es gauche/droite pour redimensionner, \xC9chap pour quitter.",
|
|
818
|
+
resizeHandle: "Redimensionner coin {direction}"
|
|
782
819
|
},
|
|
783
820
|
captions: {
|
|
784
821
|
off: "D\xE9sactiv\xE9",
|
|
@@ -791,7 +828,7 @@ var translations = {
|
|
|
791
828
|
},
|
|
792
829
|
fontSizes: {
|
|
793
830
|
small: "Petit",
|
|
794
|
-
|
|
831
|
+
normal: "Normal",
|
|
795
832
|
large: "Grand",
|
|
796
833
|
xlarge: "Tr\xE8s grand"
|
|
797
834
|
},
|
|
@@ -819,7 +856,14 @@ var translations = {
|
|
|
819
856
|
title: "Transcription",
|
|
820
857
|
close: "Fermer la transcription",
|
|
821
858
|
loading: "Chargement de la transcription...",
|
|
822
|
-
noTranscript: "Aucune transcription disponible pour cette vid\xE9o."
|
|
859
|
+
noTranscript: "Aucune transcription disponible pour cette vid\xE9o.",
|
|
860
|
+
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
861
|
+
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
862
|
+
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)",
|
|
863
|
+
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
864
|
+
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
865
|
+
closeMenu: "Fermer le menu",
|
|
866
|
+
styleTitle: "Style de Transcription"
|
|
823
867
|
},
|
|
824
868
|
settings: {
|
|
825
869
|
title: "Param\xE8tres",
|
|
@@ -888,7 +932,11 @@ var translations = {
|
|
|
888
932
|
noCaptions: "\u5B57\u5E55\u304C\u3042\u308A\u307E\u305B\u3093",
|
|
889
933
|
auto: "\u81EA\u52D5",
|
|
890
934
|
autoQuality: "\u81EA\u52D5\uFF08\u753B\u8CEA\u9078\u629E\u4E0D\u53EF\uFF09",
|
|
891
|
-
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF"
|
|
935
|
+
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF",
|
|
936
|
+
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",
|
|
937
|
+
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",
|
|
938
|
+
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",
|
|
939
|
+
resizeHandle: "{direction}\u30B3\u30FC\u30CA\u30FC\u306E\u30B5\u30A4\u30BA\u5909\u66F4"
|
|
892
940
|
},
|
|
893
941
|
captions: {
|
|
894
942
|
off: "\u30AA\u30D5",
|
|
@@ -901,7 +949,7 @@ var translations = {
|
|
|
901
949
|
},
|
|
902
950
|
fontSizes: {
|
|
903
951
|
small: "\u5C0F",
|
|
904
|
-
|
|
952
|
+
normal: "\u6A19\u6E96",
|
|
905
953
|
large: "\u5927",
|
|
906
954
|
xlarge: "\u7279\u5927"
|
|
907
955
|
},
|
|
@@ -929,7 +977,14 @@ var translations = {
|
|
|
929
977
|
title: "\u6587\u5B57\u8D77\u3053\u3057",
|
|
930
978
|
close: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u9589\u3058\u308B",
|
|
931
979
|
loading: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D...",
|
|
932
|
-
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002"
|
|
980
|
+
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
981
|
+
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",
|
|
982
|
+
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",
|
|
983
|
+
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",
|
|
984
|
+
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
985
|
+
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
986
|
+
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
987
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
933
988
|
},
|
|
934
989
|
settings: {
|
|
935
990
|
title: "\u8A2D\u5B9A",
|
|
@@ -1108,14 +1163,16 @@ var iconPaths = {
|
|
|
1108
1163
|
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"/>`,
|
|
1109
1164
|
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"/>`,
|
|
1110
1165
|
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"/>`,
|
|
1111
|
-
audioDescription: `<
|
|
1112
|
-
audioDescriptionOn: `<
|
|
1166
|
+
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>`,
|
|
1167
|
+
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>`,
|
|
1113
1168
|
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>`,
|
|
1114
1169
|
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>`,
|
|
1115
1170
|
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"/>`,
|
|
1116
1171
|
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"/>`,
|
|
1117
1172
|
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"/>`,
|
|
1118
|
-
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"
|
|
1173
|
+
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"/>`,
|
|
1174
|
+
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"/>`,
|
|
1175
|
+
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"/>`
|
|
1119
1176
|
};
|
|
1120
1177
|
var svgWrapper = (paths) => `<svg viewBox="0 0 24 24" fill="currentColor">${paths}</svg>`;
|
|
1121
1178
|
var Icons = Object.fromEntries(
|
|
@@ -1411,7 +1468,11 @@ var ControlBar = class {
|
|
|
1411
1468
|
return false;
|
|
1412
1469
|
}
|
|
1413
1470
|
hasAudioDescription() {
|
|
1414
|
-
|
|
1471
|
+
if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
const textTracks = Array.from(this.player.element.textTracks || []);
|
|
1475
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
1415
1476
|
}
|
|
1416
1477
|
hasSignLanguage() {
|
|
1417
1478
|
return this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;
|
|
@@ -2022,9 +2083,9 @@ var ControlBar = class {
|
|
|
2022
2083
|
i18n.t("styleLabels.fontSize"),
|
|
2023
2084
|
"captionsFontSize",
|
|
2024
2085
|
[
|
|
2025
|
-
{ label: i18n.t("fontSizes.small"), value: "
|
|
2026
|
-
{ label: i18n.t("fontSizes.
|
|
2027
|
-
{ label: i18n.t("fontSizes.large"), value: "
|
|
2086
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
2087
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
2088
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
2028
2089
|
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
2029
2090
|
]
|
|
2030
2091
|
);
|
|
@@ -2713,6 +2774,141 @@ var ControlBar = class {
|
|
|
2713
2774
|
}
|
|
2714
2775
|
};
|
|
2715
2776
|
|
|
2777
|
+
// src/utils/StorageManager.js
|
|
2778
|
+
var StorageManager = class {
|
|
2779
|
+
constructor(namespace = "vidply") {
|
|
2780
|
+
this.namespace = namespace;
|
|
2781
|
+
this.storage = this.isStorageAvailable() ? localStorage : null;
|
|
2782
|
+
}
|
|
2783
|
+
/**
|
|
2784
|
+
* Check if localStorage is available
|
|
2785
|
+
*/
|
|
2786
|
+
isStorageAvailable() {
|
|
2787
|
+
try {
|
|
2788
|
+
const test = "__storage_test__";
|
|
2789
|
+
localStorage.setItem(test, test);
|
|
2790
|
+
localStorage.removeItem(test);
|
|
2791
|
+
return true;
|
|
2792
|
+
} catch (e) {
|
|
2793
|
+
return false;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* Get a namespaced key
|
|
2798
|
+
*/
|
|
2799
|
+
getKey(key) {
|
|
2800
|
+
return `${this.namespace}_${key}`;
|
|
2801
|
+
}
|
|
2802
|
+
/**
|
|
2803
|
+
* Save a value to storage
|
|
2804
|
+
*/
|
|
2805
|
+
set(key, value) {
|
|
2806
|
+
if (!this.storage) return false;
|
|
2807
|
+
try {
|
|
2808
|
+
const namespacedKey = this.getKey(key);
|
|
2809
|
+
this.storage.setItem(namespacedKey, JSON.stringify(value));
|
|
2810
|
+
return true;
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
console.warn("Failed to save to localStorage:", e);
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* Get a value from storage
|
|
2818
|
+
*/
|
|
2819
|
+
get(key, defaultValue = null) {
|
|
2820
|
+
if (!this.storage) return defaultValue;
|
|
2821
|
+
try {
|
|
2822
|
+
const namespacedKey = this.getKey(key);
|
|
2823
|
+
const value = this.storage.getItem(namespacedKey);
|
|
2824
|
+
return value ? JSON.parse(value) : defaultValue;
|
|
2825
|
+
} catch (e) {
|
|
2826
|
+
console.warn("Failed to read from localStorage:", e);
|
|
2827
|
+
return defaultValue;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
/**
|
|
2831
|
+
* Remove a value from storage
|
|
2832
|
+
*/
|
|
2833
|
+
remove(key) {
|
|
2834
|
+
if (!this.storage) return false;
|
|
2835
|
+
try {
|
|
2836
|
+
const namespacedKey = this.getKey(key);
|
|
2837
|
+
this.storage.removeItem(namespacedKey);
|
|
2838
|
+
return true;
|
|
2839
|
+
} catch (e) {
|
|
2840
|
+
console.warn("Failed to remove from localStorage:", e);
|
|
2841
|
+
return false;
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Clear all namespaced values
|
|
2846
|
+
*/
|
|
2847
|
+
clear() {
|
|
2848
|
+
if (!this.storage) return false;
|
|
2849
|
+
try {
|
|
2850
|
+
const keys = Object.keys(this.storage);
|
|
2851
|
+
keys.forEach((key) => {
|
|
2852
|
+
if (key.startsWith(this.namespace)) {
|
|
2853
|
+
this.storage.removeItem(key);
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
return true;
|
|
2857
|
+
} catch (e) {
|
|
2858
|
+
console.warn("Failed to clear localStorage:", e);
|
|
2859
|
+
return false;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
/**
|
|
2863
|
+
* Save transcript preferences
|
|
2864
|
+
*/
|
|
2865
|
+
saveTranscriptPreferences(preferences) {
|
|
2866
|
+
return this.set("transcript_preferences", preferences);
|
|
2867
|
+
}
|
|
2868
|
+
/**
|
|
2869
|
+
* Get transcript preferences
|
|
2870
|
+
*/
|
|
2871
|
+
getTranscriptPreferences() {
|
|
2872
|
+
return this.get("transcript_preferences", null);
|
|
2873
|
+
}
|
|
2874
|
+
/**
|
|
2875
|
+
* Save caption preferences
|
|
2876
|
+
*/
|
|
2877
|
+
saveCaptionPreferences(preferences) {
|
|
2878
|
+
return this.set("caption_preferences", preferences);
|
|
2879
|
+
}
|
|
2880
|
+
/**
|
|
2881
|
+
* Get caption preferences
|
|
2882
|
+
*/
|
|
2883
|
+
getCaptionPreferences() {
|
|
2884
|
+
return this.get("caption_preferences", null);
|
|
2885
|
+
}
|
|
2886
|
+
/**
|
|
2887
|
+
* Save player preferences (volume, speed, etc.)
|
|
2888
|
+
*/
|
|
2889
|
+
savePlayerPreferences(preferences) {
|
|
2890
|
+
return this.set("player_preferences", preferences);
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Get player preferences
|
|
2894
|
+
*/
|
|
2895
|
+
getPlayerPreferences() {
|
|
2896
|
+
return this.get("player_preferences", null);
|
|
2897
|
+
}
|
|
2898
|
+
/**
|
|
2899
|
+
* Save sign language preferences (position and size)
|
|
2900
|
+
*/
|
|
2901
|
+
saveSignLanguagePreferences(preferences) {
|
|
2902
|
+
return this.set("sign_language_preferences", preferences);
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Get sign language preferences
|
|
2906
|
+
*/
|
|
2907
|
+
getSignLanguagePreferences() {
|
|
2908
|
+
return this.get("sign_language_preferences", null);
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
2911
|
+
|
|
2716
2912
|
// src/controls/CaptionManager.js
|
|
2717
2913
|
var CaptionManager = class {
|
|
2718
2914
|
constructor(player) {
|
|
@@ -2721,8 +2917,29 @@ var CaptionManager = class {
|
|
|
2721
2917
|
this.tracks = [];
|
|
2722
2918
|
this.currentTrack = null;
|
|
2723
2919
|
this.currentCue = null;
|
|
2920
|
+
this.storage = new StorageManager("vidply");
|
|
2921
|
+
this.loadSavedPreferences();
|
|
2724
2922
|
this.init();
|
|
2725
2923
|
}
|
|
2924
|
+
loadSavedPreferences() {
|
|
2925
|
+
const saved = this.storage.getCaptionPreferences();
|
|
2926
|
+
if (saved) {
|
|
2927
|
+
if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;
|
|
2928
|
+
if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;
|
|
2929
|
+
if (saved.color) this.player.options.captionsColor = saved.color;
|
|
2930
|
+
if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;
|
|
2931
|
+
if (saved.opacity !== void 0) this.player.options.captionsOpacity = saved.opacity;
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
saveCaptionPreferences() {
|
|
2935
|
+
this.storage.saveCaptionPreferences({
|
|
2936
|
+
fontSize: this.player.options.captionsFontSize,
|
|
2937
|
+
fontFamily: this.player.options.captionsFontFamily,
|
|
2938
|
+
color: this.player.options.captionsColor,
|
|
2939
|
+
backgroundColor: this.player.options.captionsBackgroundColor,
|
|
2940
|
+
opacity: this.player.options.captionsOpacity
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2726
2943
|
init() {
|
|
2727
2944
|
this.createElement();
|
|
2728
2945
|
this.loadTracks();
|
|
@@ -2871,6 +3088,7 @@ var CaptionManager = class {
|
|
|
2871
3088
|
break;
|
|
2872
3089
|
}
|
|
2873
3090
|
this.updateStyles();
|
|
3091
|
+
this.saveCaptionPreferences();
|
|
2874
3092
|
this.player.emit("captionschange");
|
|
2875
3093
|
}
|
|
2876
3094
|
getAvailableTracks() {
|
|
@@ -3081,11 +3299,36 @@ var TranscriptManager = class {
|
|
|
3081
3299
|
this.player = player;
|
|
3082
3300
|
this.transcriptWindow = null;
|
|
3083
3301
|
this.transcriptEntries = [];
|
|
3302
|
+
this.metadataCues = [];
|
|
3084
3303
|
this.currentActiveEntry = null;
|
|
3085
3304
|
this.isVisible = false;
|
|
3305
|
+
this.storage = new StorageManager("vidply");
|
|
3086
3306
|
this.isDragging = false;
|
|
3087
3307
|
this.dragOffsetX = 0;
|
|
3088
3308
|
this.dragOffsetY = 0;
|
|
3309
|
+
this.isResizing = false;
|
|
3310
|
+
this.resizeDirection = null;
|
|
3311
|
+
this.resizeStartX = 0;
|
|
3312
|
+
this.resizeStartY = 0;
|
|
3313
|
+
this.resizeStartWidth = 0;
|
|
3314
|
+
this.resizeStartHeight = 0;
|
|
3315
|
+
this.resizeEnabled = false;
|
|
3316
|
+
this.settingsMenuVisible = false;
|
|
3317
|
+
this.settingsMenu = null;
|
|
3318
|
+
this.settingsButton = null;
|
|
3319
|
+
this.settingsMenuJustOpened = false;
|
|
3320
|
+
this.keyboardDragMode = false;
|
|
3321
|
+
this.styleDialog = null;
|
|
3322
|
+
this.styleDialogVisible = false;
|
|
3323
|
+
this.styleDialogJustOpened = false;
|
|
3324
|
+
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3325
|
+
this.transcriptStyle = {
|
|
3326
|
+
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3327
|
+
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
3328
|
+
color: (savedPreferences == null ? void 0 : savedPreferences.color) || this.player.options.transcriptColor || "#ffffff",
|
|
3329
|
+
backgroundColor: (savedPreferences == null ? void 0 : savedPreferences.backgroundColor) || this.player.options.transcriptBackgroundColor || "#1e1e1e",
|
|
3330
|
+
opacity: (savedPreferences == null ? void 0 : savedPreferences.opacity) ?? this.player.options.transcriptOpacity ?? 0.98
|
|
3331
|
+
};
|
|
3089
3332
|
this.handlers = {
|
|
3090
3333
|
timeupdate: () => this.updateActiveEntry(),
|
|
3091
3334
|
resize: null,
|
|
@@ -3095,7 +3338,11 @@ var TranscriptManager = class {
|
|
|
3095
3338
|
touchend: null,
|
|
3096
3339
|
mousedown: null,
|
|
3097
3340
|
touchstart: null,
|
|
3098
|
-
keydown: null
|
|
3341
|
+
keydown: null,
|
|
3342
|
+
settingsClick: null,
|
|
3343
|
+
settingsKeydown: null,
|
|
3344
|
+
documentClick: null,
|
|
3345
|
+
styleDialogKeydown: null
|
|
3099
3346
|
};
|
|
3100
3347
|
this.init();
|
|
3101
3348
|
}
|
|
@@ -3124,6 +3371,11 @@ var TranscriptManager = class {
|
|
|
3124
3371
|
if (this.transcriptWindow) {
|
|
3125
3372
|
this.transcriptWindow.style.display = "flex";
|
|
3126
3373
|
this.isVisible = true;
|
|
3374
|
+
setTimeout(() => {
|
|
3375
|
+
if (this.settingsButton) {
|
|
3376
|
+
this.settingsButton.focus();
|
|
3377
|
+
}
|
|
3378
|
+
}, 150);
|
|
3127
3379
|
return;
|
|
3128
3380
|
}
|
|
3129
3381
|
this.createTranscriptWindow();
|
|
@@ -3131,6 +3383,11 @@ var TranscriptManager = class {
|
|
|
3131
3383
|
if (this.transcriptWindow) {
|
|
3132
3384
|
this.transcriptWindow.style.display = "flex";
|
|
3133
3385
|
setTimeout(() => this.positionTranscript(), 0);
|
|
3386
|
+
setTimeout(() => {
|
|
3387
|
+
if (this.settingsButton) {
|
|
3388
|
+
this.settingsButton.focus();
|
|
3389
|
+
}
|
|
3390
|
+
}, 150);
|
|
3134
3391
|
}
|
|
3135
3392
|
this.isVisible = true;
|
|
3136
3393
|
}
|
|
@@ -3162,9 +3419,49 @@ var TranscriptManager = class {
|
|
|
3162
3419
|
"tabindex": "0"
|
|
3163
3420
|
}
|
|
3164
3421
|
});
|
|
3422
|
+
this.headerLeft = DOMUtils.createElement("div", {
|
|
3423
|
+
className: `${this.player.options.classPrefix}-transcript-header-left`
|
|
3424
|
+
});
|
|
3425
|
+
this.settingsButton = DOMUtils.createElement("button", {
|
|
3426
|
+
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3427
|
+
attributes: {
|
|
3428
|
+
"type": "button",
|
|
3429
|
+
"aria-label": i18n.t("transcript.settings"),
|
|
3430
|
+
"aria-expanded": "false"
|
|
3431
|
+
}
|
|
3432
|
+
});
|
|
3433
|
+
this.settingsButton.appendChild(createIconElement("settings"));
|
|
3434
|
+
this.handlers.settingsClick = (e) => {
|
|
3435
|
+
e.preventDefault();
|
|
3436
|
+
e.stopPropagation();
|
|
3437
|
+
if (this.settingsMenuVisible) {
|
|
3438
|
+
this.hideSettingsMenu();
|
|
3439
|
+
} else {
|
|
3440
|
+
this.showSettingsMenu();
|
|
3441
|
+
}
|
|
3442
|
+
};
|
|
3443
|
+
this.settingsButton.addEventListener("click", this.handlers.settingsClick);
|
|
3444
|
+
this.handlers.settingsKeydown = (e) => {
|
|
3445
|
+
if (e.key === "d" || e.key === "D") {
|
|
3446
|
+
e.preventDefault();
|
|
3447
|
+
e.stopPropagation();
|
|
3448
|
+
this.toggleKeyboardDragMode();
|
|
3449
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
3450
|
+
e.preventDefault();
|
|
3451
|
+
e.stopPropagation();
|
|
3452
|
+
this.toggleResizeMode();
|
|
3453
|
+
} else if (e.key === "Escape" && this.settingsMenuVisible) {
|
|
3454
|
+
e.preventDefault();
|
|
3455
|
+
e.stopPropagation();
|
|
3456
|
+
this.hideSettingsMenu();
|
|
3457
|
+
}
|
|
3458
|
+
};
|
|
3459
|
+
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3165
3460
|
const title = DOMUtils.createElement("h3", {
|
|
3166
3461
|
textContent: i18n.t("transcript.title")
|
|
3167
3462
|
});
|
|
3463
|
+
this.headerLeft.appendChild(this.settingsButton);
|
|
3464
|
+
this.headerLeft.appendChild(title);
|
|
3168
3465
|
const closeButton = DOMUtils.createElement("button", {
|
|
3169
3466
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3170
3467
|
attributes: {
|
|
@@ -3174,7 +3471,7 @@ var TranscriptManager = class {
|
|
|
3174
3471
|
});
|
|
3175
3472
|
closeButton.appendChild(createIconElement("close"));
|
|
3176
3473
|
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
3177
|
-
this.transcriptHeader.appendChild(
|
|
3474
|
+
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3178
3475
|
this.transcriptHeader.appendChild(closeButton);
|
|
3179
3476
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
3180
3477
|
className: `${this.player.options.classPrefix}-transcript-content`
|
|
@@ -3184,6 +3481,27 @@ var TranscriptManager = class {
|
|
|
3184
3481
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3185
3482
|
this.positionTranscript();
|
|
3186
3483
|
this.setupDragAndDrop();
|
|
3484
|
+
this.handlers.documentClick = (e) => {
|
|
3485
|
+
if (this.settingsMenuJustOpened) {
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
if (this.styleDialogJustOpened) {
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
if (this.settingsButton && this.settingsButton.contains(e.target)) {
|
|
3492
|
+
return;
|
|
3493
|
+
}
|
|
3494
|
+
if (this.settingsMenu && this.settingsMenu.contains(e.target)) {
|
|
3495
|
+
return;
|
|
3496
|
+
}
|
|
3497
|
+
if (this.settingsMenuVisible) {
|
|
3498
|
+
this.hideSettingsMenu();
|
|
3499
|
+
}
|
|
3500
|
+
if (this.styleDialogVisible && this.styleDialog && !this.styleDialog.contains(e.target)) {
|
|
3501
|
+
this.hideStyleDialog();
|
|
3502
|
+
}
|
|
3503
|
+
};
|
|
3504
|
+
this.documentClickHandlerAdded = false;
|
|
3187
3505
|
let resizeTimeout;
|
|
3188
3506
|
this.handlers.resize = () => {
|
|
3189
3507
|
clearTimeout(resizeTimeout);
|
|
@@ -3264,54 +3582,133 @@ var TranscriptManager = class {
|
|
|
3264
3582
|
this.transcriptEntries = [];
|
|
3265
3583
|
this.transcriptContent.innerHTML = "";
|
|
3266
3584
|
const textTracks = Array.from(this.player.element.textTracks);
|
|
3267
|
-
const
|
|
3585
|
+
const captionTrack = textTracks.find(
|
|
3268
3586
|
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
3269
3587
|
);
|
|
3270
|
-
|
|
3588
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3589
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3590
|
+
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3271
3591
|
this.showNoTranscriptMessage();
|
|
3272
3592
|
return;
|
|
3273
3593
|
}
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3594
|
+
const tracksToLoad = [captionTrack, descriptionTrack, metadataTrack].filter(Boolean);
|
|
3595
|
+
tracksToLoad.forEach((track) => {
|
|
3596
|
+
if (track.mode === "disabled") {
|
|
3597
|
+
track.mode = "hidden";
|
|
3598
|
+
}
|
|
3599
|
+
});
|
|
3600
|
+
const needsLoading = tracksToLoad.some((track) => !track.cues || track.cues.length === 0);
|
|
3601
|
+
if (needsLoading) {
|
|
3278
3602
|
const loadingMessage = DOMUtils.createElement("div", {
|
|
3279
3603
|
className: `${this.player.options.classPrefix}-transcript-loading`,
|
|
3280
3604
|
textContent: i18n.t("transcript.loading")
|
|
3281
3605
|
});
|
|
3282
3606
|
this.transcriptContent.appendChild(loadingMessage);
|
|
3607
|
+
let loaded = 0;
|
|
3283
3608
|
const onLoad = () => {
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
transcriptTrack.addEventListener("load", onLoad, { once: true });
|
|
3287
|
-
setTimeout(() => {
|
|
3288
|
-
if (transcriptTrack.cues && transcriptTrack.cues.length > 0) {
|
|
3609
|
+
loaded++;
|
|
3610
|
+
if (loaded >= tracksToLoad.length) {
|
|
3289
3611
|
this.loadTranscriptData();
|
|
3290
3612
|
}
|
|
3613
|
+
};
|
|
3614
|
+
tracksToLoad.forEach((track) => {
|
|
3615
|
+
track.addEventListener("load", onLoad, { once: true });
|
|
3616
|
+
});
|
|
3617
|
+
setTimeout(() => {
|
|
3618
|
+
this.loadTranscriptData();
|
|
3291
3619
|
}, 500);
|
|
3292
3620
|
return;
|
|
3293
3621
|
}
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3622
|
+
const allCues = [];
|
|
3623
|
+
if (captionTrack && captionTrack.cues) {
|
|
3624
|
+
Array.from(captionTrack.cues).forEach((cue) => {
|
|
3625
|
+
allCues.push({ cue, type: "caption" });
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
if (descriptionTrack && descriptionTrack.cues) {
|
|
3629
|
+
Array.from(descriptionTrack.cues).forEach((cue) => {
|
|
3630
|
+
allCues.push({ cue, type: "description" });
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
if (metadataTrack && metadataTrack.cues) {
|
|
3634
|
+
this.metadataCues = Array.from(metadataTrack.cues);
|
|
3635
|
+
this.setupMetadataHandling();
|
|
3636
|
+
}
|
|
3637
|
+
allCues.sort((a, b) => a.cue.startTime - b.cue.startTime);
|
|
3638
|
+
allCues.forEach((item, index) => {
|
|
3639
|
+
const entry = this.createTranscriptEntry(item.cue, index, item.type);
|
|
3297
3640
|
this.transcriptEntries.push({
|
|
3298
3641
|
element: entry,
|
|
3299
|
-
cue,
|
|
3300
|
-
|
|
3301
|
-
|
|
3642
|
+
cue: item.cue,
|
|
3643
|
+
type: item.type,
|
|
3644
|
+
startTime: item.cue.startTime,
|
|
3645
|
+
endTime: item.cue.endTime
|
|
3302
3646
|
});
|
|
3303
3647
|
this.transcriptContent.appendChild(entry);
|
|
3304
3648
|
});
|
|
3649
|
+
this.applyTranscriptStyles();
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Setup metadata handling
|
|
3653
|
+
* Metadata cues are not displayed but can be used programmatically
|
|
3654
|
+
*/
|
|
3655
|
+
setupMetadataHandling() {
|
|
3656
|
+
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
const textTracks = Array.from(this.player.element.textTracks);
|
|
3660
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3661
|
+
if (metadataTrack) {
|
|
3662
|
+
metadataTrack.addEventListener("cuechange", () => {
|
|
3663
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3664
|
+
activeCues.forEach((cue) => {
|
|
3665
|
+
this.handleMetadataCue(cue);
|
|
3666
|
+
});
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
/**
|
|
3671
|
+
* Handle individual metadata cues
|
|
3672
|
+
* Parses metadata text and emits events or triggers actions
|
|
3673
|
+
*/
|
|
3674
|
+
handleMetadataCue(cue) {
|
|
3675
|
+
const text = cue.text.trim();
|
|
3676
|
+
this.player.emit("metadata", {
|
|
3677
|
+
time: cue.startTime,
|
|
3678
|
+
endTime: cue.endTime,
|
|
3679
|
+
text,
|
|
3680
|
+
cue
|
|
3681
|
+
});
|
|
3682
|
+
if (text.includes("PAUSE")) {
|
|
3683
|
+
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3684
|
+
}
|
|
3685
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3686
|
+
if (focusMatch) {
|
|
3687
|
+
this.player.emit("metadata:focus", {
|
|
3688
|
+
time: cue.startTime,
|
|
3689
|
+
target: focusMatch[1],
|
|
3690
|
+
text
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
3694
|
+
if (hashtags) {
|
|
3695
|
+
this.player.emit("metadata:hashtags", {
|
|
3696
|
+
time: cue.startTime,
|
|
3697
|
+
hashtags,
|
|
3698
|
+
text
|
|
3699
|
+
});
|
|
3700
|
+
}
|
|
3305
3701
|
}
|
|
3306
3702
|
/**
|
|
3307
3703
|
* Create a single transcript entry element
|
|
3308
3704
|
*/
|
|
3309
|
-
createTranscriptEntry(cue, index) {
|
|
3705
|
+
createTranscriptEntry(cue, index, type = "caption") {
|
|
3310
3706
|
const entry = DOMUtils.createElement("div", {
|
|
3311
|
-
className: `${this.player.options.classPrefix}-transcript-entry`,
|
|
3707
|
+
className: `${this.player.options.classPrefix}-transcript-entry ${this.player.options.classPrefix}-transcript-${type}`,
|
|
3312
3708
|
attributes: {
|
|
3313
3709
|
"data-start": String(cue.startTime),
|
|
3314
3710
|
"data-end": String(cue.endTime),
|
|
3711
|
+
"data-type": type,
|
|
3315
3712
|
"role": "button",
|
|
3316
3713
|
"tabindex": "0"
|
|
3317
3714
|
}
|
|
@@ -3408,6 +3805,15 @@ var TranscriptManager = class {
|
|
|
3408
3805
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3409
3806
|
return;
|
|
3410
3807
|
}
|
|
3808
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3411
3817
|
this.startDragging(e.clientX, e.clientY);
|
|
3412
3818
|
e.preventDefault();
|
|
3413
3819
|
};
|
|
@@ -3425,6 +3831,15 @@ var TranscriptManager = class {
|
|
|
3425
3831
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3426
3832
|
return;
|
|
3427
3833
|
}
|
|
3834
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3835
|
+
return;
|
|
3836
|
+
}
|
|
3837
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3838
|
+
return;
|
|
3839
|
+
}
|
|
3840
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3428
3843
|
const isMobile = window.innerWidth < 640;
|
|
3429
3844
|
const isFullscreen = this.player.state.fullscreen;
|
|
3430
3845
|
const touch = e.touches[0];
|
|
@@ -3451,49 +3866,64 @@ var TranscriptManager = class {
|
|
|
3451
3866
|
}
|
|
3452
3867
|
};
|
|
3453
3868
|
this.handlers.keydown = (e) => {
|
|
3454
|
-
if (
|
|
3869
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3870
|
+
if (!this.keyboardDragMode) {
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
e.preventDefault();
|
|
3874
|
+
e.stopPropagation();
|
|
3875
|
+
const step = e.shiftKey ? 50 : 10;
|
|
3876
|
+
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3877
|
+
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3878
|
+
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3879
|
+
if (computedStyle.transform !== "none") {
|
|
3880
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3881
|
+
currentLeft = rect.left;
|
|
3882
|
+
currentTop = rect.top;
|
|
3883
|
+
this.transcriptWindow.style.transform = "none";
|
|
3884
|
+
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3885
|
+
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3886
|
+
}
|
|
3887
|
+
let newX = currentLeft;
|
|
3888
|
+
let newY = currentTop;
|
|
3889
|
+
switch (e.key) {
|
|
3890
|
+
case "ArrowLeft":
|
|
3891
|
+
newX -= step;
|
|
3892
|
+
break;
|
|
3893
|
+
case "ArrowRight":
|
|
3894
|
+
newX += step;
|
|
3895
|
+
break;
|
|
3896
|
+
case "ArrowUp":
|
|
3897
|
+
newY -= step;
|
|
3898
|
+
break;
|
|
3899
|
+
case "ArrowDown":
|
|
3900
|
+
newY += step;
|
|
3901
|
+
break;
|
|
3902
|
+
}
|
|
3903
|
+
this.transcriptWindow.style.left = `${newX}px`;
|
|
3904
|
+
this.transcriptWindow.style.top = `${newY}px`;
|
|
3455
3905
|
return;
|
|
3456
3906
|
}
|
|
3457
|
-
e.preventDefault();
|
|
3458
|
-
e.stopPropagation();
|
|
3459
3907
|
if (e.key === "Home") {
|
|
3908
|
+
e.preventDefault();
|
|
3909
|
+
e.stopPropagation();
|
|
3460
3910
|
this.resetPosition();
|
|
3461
3911
|
return;
|
|
3462
3912
|
}
|
|
3463
3913
|
if (e.key === "Escape") {
|
|
3464
|
-
|
|
3914
|
+
e.preventDefault();
|
|
3915
|
+
e.stopPropagation();
|
|
3916
|
+
if (this.styleDialogVisible) {
|
|
3917
|
+
this.hideStyleDialog();
|
|
3918
|
+
} else if (this.keyboardDragMode) {
|
|
3919
|
+
this.disableKeyboardDragMode();
|
|
3920
|
+
} else if (this.settingsMenuVisible) {
|
|
3921
|
+
this.hideSettingsMenu();
|
|
3922
|
+
} else {
|
|
3923
|
+
this.hideTranscript();
|
|
3924
|
+
}
|
|
3465
3925
|
return;
|
|
3466
3926
|
}
|
|
3467
|
-
const step = e.shiftKey ? 50 : 10;
|
|
3468
|
-
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3469
|
-
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3470
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3471
|
-
if (computedStyle.transform !== "none") {
|
|
3472
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3473
|
-
currentLeft = rect.left;
|
|
3474
|
-
currentTop = rect.top;
|
|
3475
|
-
this.transcriptWindow.style.transform = "none";
|
|
3476
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3477
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3478
|
-
}
|
|
3479
|
-
let newX = currentLeft;
|
|
3480
|
-
let newY = currentTop;
|
|
3481
|
-
switch (e.key) {
|
|
3482
|
-
case "ArrowLeft":
|
|
3483
|
-
newX -= step;
|
|
3484
|
-
break;
|
|
3485
|
-
case "ArrowRight":
|
|
3486
|
-
newX += step;
|
|
3487
|
-
break;
|
|
3488
|
-
case "ArrowUp":
|
|
3489
|
-
newY -= step;
|
|
3490
|
-
break;
|
|
3491
|
-
case "ArrowDown":
|
|
3492
|
-
newY += step;
|
|
3493
|
-
break;
|
|
3494
|
-
}
|
|
3495
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3496
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3497
3927
|
};
|
|
3498
3928
|
this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
|
|
3499
3929
|
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
@@ -3573,99 +4003,707 @@ var TranscriptManager = class {
|
|
|
3573
4003
|
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
3574
4004
|
}
|
|
3575
4005
|
/**
|
|
3576
|
-
*
|
|
4006
|
+
* Toggle keyboard drag mode
|
|
3577
4007
|
*/
|
|
3578
|
-
|
|
3579
|
-
if (this.
|
|
3580
|
-
this.
|
|
3581
|
-
}
|
|
3582
|
-
|
|
3583
|
-
if (this.handlers.mousedown) {
|
|
3584
|
-
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
3585
|
-
}
|
|
3586
|
-
if (this.handlers.touchstart) {
|
|
3587
|
-
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
3588
|
-
}
|
|
3589
|
-
if (this.handlers.keydown) {
|
|
3590
|
-
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
3591
|
-
}
|
|
3592
|
-
}
|
|
3593
|
-
if (this.handlers.mousemove) {
|
|
3594
|
-
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4008
|
+
toggleKeyboardDragMode() {
|
|
4009
|
+
if (this.keyboardDragMode) {
|
|
4010
|
+
this.disableKeyboardDragMode();
|
|
4011
|
+
} else {
|
|
4012
|
+
this.enableKeyboardDragMode();
|
|
3595
4013
|
}
|
|
3596
|
-
|
|
3597
|
-
|
|
4014
|
+
}
|
|
4015
|
+
/**
|
|
4016
|
+
* Enable keyboard drag mode
|
|
4017
|
+
*/
|
|
4018
|
+
enableKeyboardDragMode() {
|
|
4019
|
+
this.keyboardDragMode = true;
|
|
4020
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4021
|
+
if (this.settingsButton) {
|
|
4022
|
+
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
3598
4023
|
}
|
|
3599
|
-
|
|
3600
|
-
|
|
4024
|
+
const indicator = DOMUtils.createElement("div", {
|
|
4025
|
+
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4026
|
+
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4027
|
+
});
|
|
4028
|
+
this.transcriptHeader.appendChild(indicator);
|
|
4029
|
+
if (this.settingsMenuVisible) {
|
|
4030
|
+
this.hideSettingsMenu();
|
|
3601
4031
|
}
|
|
3602
|
-
|
|
3603
|
-
|
|
4032
|
+
this.transcriptHeader.focus();
|
|
4033
|
+
}
|
|
4034
|
+
/**
|
|
4035
|
+
* Disable keyboard drag mode
|
|
4036
|
+
*/
|
|
4037
|
+
disableKeyboardDragMode() {
|
|
4038
|
+
this.keyboardDragMode = false;
|
|
4039
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4040
|
+
if (this.settingsButton) {
|
|
4041
|
+
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
3604
4042
|
}
|
|
3605
|
-
|
|
3606
|
-
|
|
4043
|
+
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4044
|
+
if (indicator) {
|
|
4045
|
+
indicator.remove();
|
|
3607
4046
|
}
|
|
3608
|
-
this.
|
|
3609
|
-
|
|
3610
|
-
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
4047
|
+
if (this.settingsButton) {
|
|
4048
|
+
this.settingsButton.focus();
|
|
3611
4049
|
}
|
|
3612
|
-
this.transcriptWindow = null;
|
|
3613
|
-
this.transcriptHeader = null;
|
|
3614
|
-
this.transcriptContent = null;
|
|
3615
|
-
this.transcriptEntries = [];
|
|
3616
|
-
}
|
|
3617
|
-
};
|
|
3618
|
-
|
|
3619
|
-
// src/core/Player.js
|
|
3620
|
-
init_HTML5Renderer();
|
|
3621
|
-
|
|
3622
|
-
// src/renderers/YouTubeRenderer.js
|
|
3623
|
-
var YouTubeRenderer = class {
|
|
3624
|
-
constructor(player) {
|
|
3625
|
-
this.player = player;
|
|
3626
|
-
this.youtube = null;
|
|
3627
|
-
this.videoId = null;
|
|
3628
|
-
this.isReady = false;
|
|
3629
|
-
this.iframe = null;
|
|
3630
4050
|
}
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
4051
|
+
/**
|
|
4052
|
+
* Toggle settings menu visibility
|
|
4053
|
+
*/
|
|
4054
|
+
toggleSettingsMenu() {
|
|
4055
|
+
if (this.settingsMenuVisible) {
|
|
4056
|
+
this.hideSettingsMenu();
|
|
4057
|
+
} else {
|
|
4058
|
+
this.showSettingsMenu();
|
|
3635
4059
|
}
|
|
3636
|
-
await this.loadYouTubeAPI();
|
|
3637
|
-
this.createIframe();
|
|
3638
|
-
await this.initializePlayer();
|
|
3639
4060
|
}
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
4061
|
+
/**
|
|
4062
|
+
* Show settings menu
|
|
4063
|
+
*/
|
|
4064
|
+
showSettingsMenu() {
|
|
4065
|
+
this.settingsMenuJustOpened = true;
|
|
4066
|
+
setTimeout(() => {
|
|
4067
|
+
this.settingsMenuJustOpened = false;
|
|
4068
|
+
}, 350);
|
|
4069
|
+
if (!this.documentClickHandlerAdded) {
|
|
4070
|
+
setTimeout(() => {
|
|
4071
|
+
document.addEventListener("click", this.handlers.documentClick);
|
|
4072
|
+
this.documentClickHandlerAdded = true;
|
|
4073
|
+
}, 300);
|
|
3650
4074
|
}
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
return Promise.resolve();
|
|
4075
|
+
if (this.settingsMenu) {
|
|
4076
|
+
this.settingsMenu.style.display = "block";
|
|
4077
|
+
this.settingsMenuVisible = true;
|
|
4078
|
+
return;
|
|
3656
4079
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
4080
|
+
this.settingsMenu = DOMUtils.createElement("div", {
|
|
4081
|
+
className: `${this.player.options.classPrefix}-transcript-settings-menu`
|
|
4082
|
+
});
|
|
4083
|
+
const keyboardDragOption = DOMUtils.createElement("button", {
|
|
4084
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4085
|
+
attributes: {
|
|
4086
|
+
"type": "button",
|
|
4087
|
+
"aria-label": i18n.t("transcript.keyboardDragMode")
|
|
3665
4088
|
}
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
4089
|
+
});
|
|
4090
|
+
const keyboardIcon = createIconElement("move");
|
|
4091
|
+
const keyboardText = DOMUtils.createElement("span", {
|
|
4092
|
+
textContent: i18n.t("transcript.keyboardDragMode")
|
|
4093
|
+
});
|
|
4094
|
+
keyboardDragOption.appendChild(keyboardIcon);
|
|
4095
|
+
keyboardDragOption.appendChild(keyboardText);
|
|
4096
|
+
keyboardDragOption.addEventListener("click", () => {
|
|
4097
|
+
this.toggleKeyboardDragMode();
|
|
4098
|
+
this.hideSettingsMenu();
|
|
4099
|
+
});
|
|
4100
|
+
const styleOption = DOMUtils.createElement("button", {
|
|
4101
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4102
|
+
attributes: {
|
|
4103
|
+
"type": "button",
|
|
4104
|
+
"aria-label": i18n.t("transcript.styleTranscript")
|
|
4105
|
+
}
|
|
4106
|
+
});
|
|
4107
|
+
const styleIcon = createIconElement("settings");
|
|
4108
|
+
const styleText = DOMUtils.createElement("span", {
|
|
4109
|
+
textContent: i18n.t("transcript.styleTranscript")
|
|
4110
|
+
});
|
|
4111
|
+
styleOption.appendChild(styleIcon);
|
|
4112
|
+
styleOption.appendChild(styleText);
|
|
4113
|
+
styleOption.addEventListener("click", (e) => {
|
|
4114
|
+
e.preventDefault();
|
|
4115
|
+
e.stopPropagation();
|
|
4116
|
+
this.hideSettingsMenu();
|
|
4117
|
+
setTimeout(() => {
|
|
4118
|
+
this.showStyleDialog();
|
|
4119
|
+
}, 50);
|
|
4120
|
+
});
|
|
4121
|
+
const resizeOption = DOMUtils.createElement("button", {
|
|
4122
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4123
|
+
attributes: {
|
|
4124
|
+
"type": "button",
|
|
4125
|
+
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4128
|
+
const resizeIcon = createIconElement("resize");
|
|
4129
|
+
const resizeText = DOMUtils.createElement("span", {
|
|
4130
|
+
textContent: i18n.t("transcript.resizeWindow")
|
|
4131
|
+
});
|
|
4132
|
+
resizeOption.appendChild(resizeIcon);
|
|
4133
|
+
resizeOption.appendChild(resizeText);
|
|
4134
|
+
resizeOption.addEventListener("click", () => {
|
|
4135
|
+
this.toggleResizeMode();
|
|
4136
|
+
this.hideSettingsMenu();
|
|
4137
|
+
});
|
|
4138
|
+
const closeOption = DOMUtils.createElement("button", {
|
|
4139
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4140
|
+
attributes: {
|
|
4141
|
+
"type": "button",
|
|
4142
|
+
"aria-label": i18n.t("transcript.closeMenu")
|
|
4143
|
+
}
|
|
4144
|
+
});
|
|
4145
|
+
const closeIcon = createIconElement("close");
|
|
4146
|
+
const closeText = DOMUtils.createElement("span", {
|
|
4147
|
+
textContent: i18n.t("transcript.closeMenu")
|
|
4148
|
+
});
|
|
4149
|
+
closeOption.appendChild(closeIcon);
|
|
4150
|
+
closeOption.appendChild(closeText);
|
|
4151
|
+
closeOption.addEventListener("click", () => {
|
|
4152
|
+
this.hideSettingsMenu();
|
|
4153
|
+
});
|
|
4154
|
+
this.settingsMenu.appendChild(keyboardDragOption);
|
|
4155
|
+
this.settingsMenu.appendChild(resizeOption);
|
|
4156
|
+
this.settingsMenu.appendChild(styleOption);
|
|
4157
|
+
this.settingsMenu.appendChild(closeOption);
|
|
4158
|
+
if (this.headerLeft) {
|
|
4159
|
+
this.headerLeft.appendChild(this.settingsMenu);
|
|
4160
|
+
} else {
|
|
4161
|
+
this.transcriptHeader.appendChild(this.settingsMenu);
|
|
4162
|
+
}
|
|
4163
|
+
this.settingsMenuVisible = true;
|
|
4164
|
+
this.settingsMenu.style.display = "block";
|
|
4165
|
+
if (this.settingsButton) {
|
|
4166
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4167
|
+
}
|
|
4168
|
+
setTimeout(() => {
|
|
4169
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4170
|
+
if (firstItem) {
|
|
4171
|
+
firstItem.focus();
|
|
4172
|
+
}
|
|
4173
|
+
}, 0);
|
|
4174
|
+
}
|
|
4175
|
+
/**
|
|
4176
|
+
* Hide settings menu
|
|
4177
|
+
*/
|
|
4178
|
+
hideSettingsMenu() {
|
|
4179
|
+
if (this.settingsMenu) {
|
|
4180
|
+
this.settingsMenu.style.display = "none";
|
|
4181
|
+
this.settingsMenuVisible = false;
|
|
4182
|
+
this.settingsMenuJustOpened = false;
|
|
4183
|
+
if (this.settingsButton) {
|
|
4184
|
+
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4185
|
+
this.settingsButton.focus();
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
/**
|
|
4190
|
+
* Enable move mode (gives visual feedback)
|
|
4191
|
+
*/
|
|
4192
|
+
enableMoveMode() {
|
|
4193
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4194
|
+
const tooltip = DOMUtils.createElement("div", {
|
|
4195
|
+
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
4196
|
+
textContent: "Drag with mouse or press D for keyboard drag mode"
|
|
4197
|
+
});
|
|
4198
|
+
this.transcriptHeader.appendChild(tooltip);
|
|
4199
|
+
setTimeout(() => {
|
|
4200
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4201
|
+
if (tooltip.parentNode) {
|
|
4202
|
+
tooltip.remove();
|
|
4203
|
+
}
|
|
4204
|
+
}, 2e3);
|
|
4205
|
+
}
|
|
4206
|
+
/**
|
|
4207
|
+
* Toggle resize mode
|
|
4208
|
+
*/
|
|
4209
|
+
toggleResizeMode() {
|
|
4210
|
+
this.resizeEnabled = !this.resizeEnabled;
|
|
4211
|
+
if (this.resizeEnabled) {
|
|
4212
|
+
this.enableResizeHandles();
|
|
4213
|
+
} else {
|
|
4214
|
+
this.disableResizeHandles();
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
/**
|
|
4218
|
+
* Enable resize handles
|
|
4219
|
+
*/
|
|
4220
|
+
enableResizeHandles() {
|
|
4221
|
+
if (!this.transcriptWindow) return;
|
|
4222
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4223
|
+
directions.forEach((direction) => {
|
|
4224
|
+
const handle = DOMUtils.createElement("div", {
|
|
4225
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4226
|
+
attributes: {
|
|
4227
|
+
"data-direction": direction
|
|
4228
|
+
}
|
|
4229
|
+
});
|
|
4230
|
+
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4231
|
+
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4232
|
+
this.transcriptWindow.appendChild(handle);
|
|
4233
|
+
});
|
|
4234
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4235
|
+
this.handlers.resizeMove = (e) => {
|
|
4236
|
+
if (this.isResizing) {
|
|
4237
|
+
this.performResize(e.clientX, e.clientY);
|
|
4238
|
+
}
|
|
4239
|
+
};
|
|
4240
|
+
this.handlers.resizeEnd = () => {
|
|
4241
|
+
if (this.isResizing) {
|
|
4242
|
+
this.stopResize();
|
|
4243
|
+
}
|
|
4244
|
+
};
|
|
4245
|
+
this.handlers.resizeTouchMove = (e) => {
|
|
4246
|
+
if (this.isResizing) {
|
|
4247
|
+
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4248
|
+
e.preventDefault();
|
|
4249
|
+
}
|
|
4250
|
+
};
|
|
4251
|
+
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4252
|
+
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4253
|
+
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4254
|
+
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4255
|
+
}
|
|
4256
|
+
/**
|
|
4257
|
+
* Disable resize handles
|
|
4258
|
+
*/
|
|
4259
|
+
disableResizeHandles() {
|
|
4260
|
+
if (!this.transcriptWindow) return;
|
|
4261
|
+
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4262
|
+
handles.forEach((handle) => handle.remove());
|
|
4263
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4264
|
+
if (this.handlers.resizeMove) {
|
|
4265
|
+
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
4266
|
+
}
|
|
4267
|
+
if (this.handlers.resizeEnd) {
|
|
4268
|
+
document.removeEventListener("mouseup", this.handlers.resizeEnd);
|
|
4269
|
+
}
|
|
4270
|
+
if (this.handlers.resizeTouchMove) {
|
|
4271
|
+
document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4272
|
+
}
|
|
4273
|
+
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4274
|
+
}
|
|
4275
|
+
/**
|
|
4276
|
+
* Start resizing
|
|
4277
|
+
*/
|
|
4278
|
+
startResize(e, direction) {
|
|
4279
|
+
e.stopPropagation();
|
|
4280
|
+
e.preventDefault();
|
|
4281
|
+
this.isResizing = true;
|
|
4282
|
+
this.resizeDirection = direction;
|
|
4283
|
+
this.resizeStartX = e.clientX;
|
|
4284
|
+
this.resizeStartY = e.clientY;
|
|
4285
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4286
|
+
this.resizeStartWidth = rect.width;
|
|
4287
|
+
this.resizeStartHeight = rect.height;
|
|
4288
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4289
|
+
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4290
|
+
document.body.style.userSelect = "none";
|
|
4291
|
+
}
|
|
4292
|
+
/**
|
|
4293
|
+
* Perform resize
|
|
4294
|
+
*/
|
|
4295
|
+
performResize(clientX, clientY) {
|
|
4296
|
+
if (!this.isResizing) return;
|
|
4297
|
+
const deltaX = clientX - this.resizeStartX;
|
|
4298
|
+
const deltaY = clientY - this.resizeStartY;
|
|
4299
|
+
let newWidth = this.resizeStartWidth;
|
|
4300
|
+
let newHeight = this.resizeStartHeight;
|
|
4301
|
+
const direction = this.resizeDirection;
|
|
4302
|
+
if (direction.includes("e")) {
|
|
4303
|
+
newWidth = this.resizeStartWidth + deltaX;
|
|
4304
|
+
}
|
|
4305
|
+
if (direction.includes("w")) {
|
|
4306
|
+
newWidth = this.resizeStartWidth - deltaX;
|
|
4307
|
+
}
|
|
4308
|
+
if (direction.includes("s")) {
|
|
4309
|
+
newHeight = this.resizeStartHeight + deltaY;
|
|
4310
|
+
}
|
|
4311
|
+
if (direction.includes("n")) {
|
|
4312
|
+
newHeight = this.resizeStartHeight - deltaY;
|
|
4313
|
+
}
|
|
4314
|
+
const minWidth = 300;
|
|
4315
|
+
const minHeight = 200;
|
|
4316
|
+
const maxWidth = window.innerWidth - 40;
|
|
4317
|
+
const maxHeight = window.innerHeight - 40;
|
|
4318
|
+
newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
|
|
4319
|
+
newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
|
|
4320
|
+
this.transcriptWindow.style.width = `${newWidth}px`;
|
|
4321
|
+
this.transcriptWindow.style.height = `${newHeight}px`;
|
|
4322
|
+
this.transcriptWindow.style.maxWidth = `${newWidth}px`;
|
|
4323
|
+
this.transcriptWindow.style.maxHeight = `${newHeight}px`;
|
|
4324
|
+
if (direction.includes("w")) {
|
|
4325
|
+
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4326
|
+
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4327
|
+
}
|
|
4328
|
+
if (direction.includes("n")) {
|
|
4329
|
+
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4330
|
+
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
/**
|
|
4334
|
+
* Stop resizing
|
|
4335
|
+
*/
|
|
4336
|
+
stopResize() {
|
|
4337
|
+
this.isResizing = false;
|
|
4338
|
+
this.resizeDirection = null;
|
|
4339
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4340
|
+
document.body.style.cursor = "";
|
|
4341
|
+
document.body.style.userSelect = "";
|
|
4342
|
+
}
|
|
4343
|
+
/**
|
|
4344
|
+
* Get cursor style for resize direction
|
|
4345
|
+
*/
|
|
4346
|
+
getResizeCursor(direction) {
|
|
4347
|
+
const cursors = {
|
|
4348
|
+
"n": "ns-resize",
|
|
4349
|
+
"s": "ns-resize",
|
|
4350
|
+
"e": "ew-resize",
|
|
4351
|
+
"w": "ew-resize",
|
|
4352
|
+
"ne": "nesw-resize",
|
|
4353
|
+
"nw": "nwse-resize",
|
|
4354
|
+
"se": "nwse-resize",
|
|
4355
|
+
"sw": "nesw-resize"
|
|
4356
|
+
};
|
|
4357
|
+
return cursors[direction] || "default";
|
|
4358
|
+
}
|
|
4359
|
+
/**
|
|
4360
|
+
* Show style dialog
|
|
4361
|
+
*/
|
|
4362
|
+
showStyleDialog() {
|
|
4363
|
+
if (this.styleDialog) {
|
|
4364
|
+
this.styleDialog.style.display = "block";
|
|
4365
|
+
this.styleDialogVisible = true;
|
|
4366
|
+
this.styleDialogJustOpened = true;
|
|
4367
|
+
setTimeout(() => {
|
|
4368
|
+
this.styleDialogJustOpened = false;
|
|
4369
|
+
}, 350);
|
|
4370
|
+
setTimeout(() => {
|
|
4371
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4372
|
+
if (firstSelect) {
|
|
4373
|
+
firstSelect.focus();
|
|
4374
|
+
}
|
|
4375
|
+
}, 0);
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
this.styleDialog = DOMUtils.createElement("div", {
|
|
4379
|
+
className: `${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4380
|
+
});
|
|
4381
|
+
const title = DOMUtils.createElement("h4", {
|
|
4382
|
+
textContent: i18n.t("transcript.styleTitle"),
|
|
4383
|
+
className: `${this.player.options.classPrefix}-transcript-style-title`
|
|
4384
|
+
});
|
|
4385
|
+
this.styleDialog.appendChild(title);
|
|
4386
|
+
const fontSizeControl = this.createStyleSelectControl(
|
|
4387
|
+
i18n.t("captions.fontSize"),
|
|
4388
|
+
"fontSize",
|
|
4389
|
+
[
|
|
4390
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
4391
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
4392
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
4393
|
+
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
4394
|
+
]
|
|
4395
|
+
);
|
|
4396
|
+
this.styleDialog.appendChild(fontSizeControl);
|
|
4397
|
+
const fontFamilyControl = this.createStyleSelectControl(
|
|
4398
|
+
i18n.t("captions.fontFamily"),
|
|
4399
|
+
"fontFamily",
|
|
4400
|
+
[
|
|
4401
|
+
{ label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
|
|
4402
|
+
{ label: i18n.t("fontFamilies.serif"), value: "serif" },
|
|
4403
|
+
{ label: i18n.t("fontFamilies.monospace"), value: "monospace" }
|
|
4404
|
+
]
|
|
4405
|
+
);
|
|
4406
|
+
this.styleDialog.appendChild(fontFamilyControl);
|
|
4407
|
+
const colorControl = this.createStyleColorControl(i18n.t("captions.color"), "color");
|
|
4408
|
+
this.styleDialog.appendChild(colorControl);
|
|
4409
|
+
const bgColorControl = this.createStyleColorControl(i18n.t("captions.backgroundColor"), "backgroundColor");
|
|
4410
|
+
this.styleDialog.appendChild(bgColorControl);
|
|
4411
|
+
const opacityControl = this.createStyleOpacityControl(i18n.t("captions.opacity"), "opacity");
|
|
4412
|
+
this.styleDialog.appendChild(opacityControl);
|
|
4413
|
+
const closeBtn = DOMUtils.createElement("button", {
|
|
4414
|
+
className: `${this.player.options.classPrefix}-transcript-style-close`,
|
|
4415
|
+
textContent: i18n.t("settings.close"),
|
|
4416
|
+
attributes: {
|
|
4417
|
+
"type": "button"
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
closeBtn.addEventListener("click", () => this.hideStyleDialog());
|
|
4421
|
+
this.styleDialog.appendChild(closeBtn);
|
|
4422
|
+
this.handlers.styleDialogKeydown = (e) => {
|
|
4423
|
+
if (e.key === "Escape") {
|
|
4424
|
+
e.preventDefault();
|
|
4425
|
+
e.stopPropagation();
|
|
4426
|
+
this.hideStyleDialog();
|
|
4427
|
+
}
|
|
4428
|
+
};
|
|
4429
|
+
this.styleDialog.addEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4430
|
+
if (this.headerLeft) {
|
|
4431
|
+
this.headerLeft.appendChild(this.styleDialog);
|
|
4432
|
+
} else {
|
|
4433
|
+
this.transcriptHeader.appendChild(this.styleDialog);
|
|
4434
|
+
}
|
|
4435
|
+
this.applyTranscriptStyles();
|
|
4436
|
+
this.styleDialogVisible = true;
|
|
4437
|
+
this.styleDialog.style.display = "block";
|
|
4438
|
+
this.styleDialogJustOpened = true;
|
|
4439
|
+
setTimeout(() => {
|
|
4440
|
+
this.styleDialogJustOpened = false;
|
|
4441
|
+
}, 350);
|
|
4442
|
+
setTimeout(() => {
|
|
4443
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4444
|
+
if (firstSelect) {
|
|
4445
|
+
firstSelect.focus();
|
|
4446
|
+
}
|
|
4447
|
+
}, 0);
|
|
4448
|
+
}
|
|
4449
|
+
/**
|
|
4450
|
+
* Hide style dialog
|
|
4451
|
+
*/
|
|
4452
|
+
hideStyleDialog() {
|
|
4453
|
+
if (this.styleDialog) {
|
|
4454
|
+
this.styleDialog.style.display = "none";
|
|
4455
|
+
this.styleDialogVisible = false;
|
|
4456
|
+
if (this.settingsButton) {
|
|
4457
|
+
this.settingsButton.focus();
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
/**
|
|
4462
|
+
* Create style select control
|
|
4463
|
+
*/
|
|
4464
|
+
createStyleSelectControl(label, property, options) {
|
|
4465
|
+
const group = DOMUtils.createElement("div", {
|
|
4466
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4467
|
+
});
|
|
4468
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4469
|
+
textContent: label
|
|
4470
|
+
});
|
|
4471
|
+
group.appendChild(labelEl);
|
|
4472
|
+
const select = DOMUtils.createElement("select", {
|
|
4473
|
+
className: `${this.player.options.classPrefix}-transcript-style-select`
|
|
4474
|
+
});
|
|
4475
|
+
options.forEach((opt) => {
|
|
4476
|
+
const option = DOMUtils.createElement("option", {
|
|
4477
|
+
textContent: opt.label,
|
|
4478
|
+
attributes: {
|
|
4479
|
+
"value": opt.value
|
|
4480
|
+
}
|
|
4481
|
+
});
|
|
4482
|
+
if (this.transcriptStyle[property] === opt.value) {
|
|
4483
|
+
option.selected = true;
|
|
4484
|
+
}
|
|
4485
|
+
select.appendChild(option);
|
|
4486
|
+
});
|
|
4487
|
+
select.addEventListener("change", (e) => {
|
|
4488
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4489
|
+
this.applyTranscriptStyles();
|
|
4490
|
+
this.savePreferences();
|
|
4491
|
+
});
|
|
4492
|
+
group.appendChild(select);
|
|
4493
|
+
return group;
|
|
4494
|
+
}
|
|
4495
|
+
/**
|
|
4496
|
+
* Create style color control
|
|
4497
|
+
*/
|
|
4498
|
+
createStyleColorControl(label, property) {
|
|
4499
|
+
const group = DOMUtils.createElement("div", {
|
|
4500
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4501
|
+
});
|
|
4502
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4503
|
+
textContent: label
|
|
4504
|
+
});
|
|
4505
|
+
group.appendChild(labelEl);
|
|
4506
|
+
const input = DOMUtils.createElement("input", {
|
|
4507
|
+
attributes: {
|
|
4508
|
+
"type": "color",
|
|
4509
|
+
"value": this.transcriptStyle[property]
|
|
4510
|
+
},
|
|
4511
|
+
className: `${this.player.options.classPrefix}-transcript-style-color`
|
|
4512
|
+
});
|
|
4513
|
+
input.addEventListener("input", (e) => {
|
|
4514
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4515
|
+
this.applyTranscriptStyles();
|
|
4516
|
+
this.savePreferences();
|
|
4517
|
+
});
|
|
4518
|
+
group.appendChild(input);
|
|
4519
|
+
return group;
|
|
4520
|
+
}
|
|
4521
|
+
/**
|
|
4522
|
+
* Create style opacity control
|
|
4523
|
+
*/
|
|
4524
|
+
createStyleOpacityControl(label, property) {
|
|
4525
|
+
const group = DOMUtils.createElement("div", {
|
|
4526
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4527
|
+
});
|
|
4528
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4529
|
+
textContent: label
|
|
4530
|
+
});
|
|
4531
|
+
group.appendChild(labelEl);
|
|
4532
|
+
const valueDisplay = DOMUtils.createElement("span", {
|
|
4533
|
+
textContent: Math.round(this.transcriptStyle[property] * 100) + "%",
|
|
4534
|
+
className: `${this.player.options.classPrefix}-transcript-style-value`
|
|
4535
|
+
});
|
|
4536
|
+
const input = DOMUtils.createElement("input", {
|
|
4537
|
+
attributes: {
|
|
4538
|
+
"type": "range",
|
|
4539
|
+
"min": "0",
|
|
4540
|
+
"max": "1",
|
|
4541
|
+
"step": "0.1",
|
|
4542
|
+
"value": String(this.transcriptStyle[property])
|
|
4543
|
+
},
|
|
4544
|
+
className: `${this.player.options.classPrefix}-transcript-style-range`
|
|
4545
|
+
});
|
|
4546
|
+
input.addEventListener("input", (e) => {
|
|
4547
|
+
const value = parseFloat(e.target.value);
|
|
4548
|
+
this.transcriptStyle[property] = value;
|
|
4549
|
+
valueDisplay.textContent = Math.round(value * 100) + "%";
|
|
4550
|
+
this.applyTranscriptStyles();
|
|
4551
|
+
this.savePreferences();
|
|
4552
|
+
});
|
|
4553
|
+
const inputContainer = DOMUtils.createElement("div", {
|
|
4554
|
+
className: `${this.player.options.classPrefix}-transcript-style-range-container`
|
|
4555
|
+
});
|
|
4556
|
+
inputContainer.appendChild(input);
|
|
4557
|
+
inputContainer.appendChild(valueDisplay);
|
|
4558
|
+
group.appendChild(labelEl);
|
|
4559
|
+
group.appendChild(inputContainer);
|
|
4560
|
+
return group;
|
|
4561
|
+
}
|
|
4562
|
+
/**
|
|
4563
|
+
* Save transcript preferences to localStorage
|
|
4564
|
+
*/
|
|
4565
|
+
savePreferences() {
|
|
4566
|
+
this.storage.saveTranscriptPreferences(this.transcriptStyle);
|
|
4567
|
+
}
|
|
4568
|
+
/**
|
|
4569
|
+
* Apply transcript styles
|
|
4570
|
+
*/
|
|
4571
|
+
applyTranscriptStyles() {
|
|
4572
|
+
if (!this.transcriptWindow) return;
|
|
4573
|
+
this.transcriptWindow.style.backgroundColor = this.transcriptStyle.backgroundColor;
|
|
4574
|
+
this.transcriptWindow.style.opacity = String(this.transcriptStyle.opacity);
|
|
4575
|
+
if (this.transcriptContent) {
|
|
4576
|
+
this.transcriptContent.style.fontSize = this.transcriptStyle.fontSize;
|
|
4577
|
+
this.transcriptContent.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4578
|
+
this.transcriptContent.style.color = this.transcriptStyle.color;
|
|
4579
|
+
}
|
|
4580
|
+
const textEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-text`);
|
|
4581
|
+
textEntries.forEach((entry) => {
|
|
4582
|
+
entry.style.fontSize = this.transcriptStyle.fontSize;
|
|
4583
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4584
|
+
entry.style.color = this.transcriptStyle.color;
|
|
4585
|
+
});
|
|
4586
|
+
const timeEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-time`);
|
|
4587
|
+
timeEntries.forEach((entry) => {
|
|
4588
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
/**
|
|
4592
|
+
* Cleanup
|
|
4593
|
+
*/
|
|
4594
|
+
destroy() {
|
|
4595
|
+
if (this.resizeEnabled) {
|
|
4596
|
+
this.disableResizeHandles();
|
|
4597
|
+
}
|
|
4598
|
+
if (this.keyboardDragMode) {
|
|
4599
|
+
this.disableKeyboardDragMode();
|
|
4600
|
+
}
|
|
4601
|
+
if (this.handlers.timeupdate) {
|
|
4602
|
+
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
4603
|
+
}
|
|
4604
|
+
if (this.transcriptHeader) {
|
|
4605
|
+
if (this.handlers.mousedown) {
|
|
4606
|
+
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
4607
|
+
}
|
|
4608
|
+
if (this.handlers.touchstart) {
|
|
4609
|
+
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
4610
|
+
}
|
|
4611
|
+
if (this.handlers.keydown) {
|
|
4612
|
+
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
if (this.settingsButton) {
|
|
4616
|
+
if (this.handlers.settingsClick) {
|
|
4617
|
+
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
4618
|
+
}
|
|
4619
|
+
if (this.handlers.settingsKeydown) {
|
|
4620
|
+
this.settingsButton.removeEventListener("keydown", this.handlers.settingsKeydown);
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4624
|
+
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4625
|
+
}
|
|
4626
|
+
if (this.handlers.mousemove) {
|
|
4627
|
+
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4628
|
+
}
|
|
4629
|
+
if (this.handlers.mouseup) {
|
|
4630
|
+
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
4631
|
+
}
|
|
4632
|
+
if (this.handlers.touchmove) {
|
|
4633
|
+
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
4634
|
+
}
|
|
4635
|
+
if (this.handlers.touchend) {
|
|
4636
|
+
document.removeEventListener("touchend", this.handlers.touchend);
|
|
4637
|
+
}
|
|
4638
|
+
if (this.handlers.documentClick) {
|
|
4639
|
+
document.removeEventListener("click", this.handlers.documentClick);
|
|
4640
|
+
}
|
|
4641
|
+
if (this.handlers.resize) {
|
|
4642
|
+
window.removeEventListener("resize", this.handlers.resize);
|
|
4643
|
+
}
|
|
4644
|
+
this.handlers = null;
|
|
4645
|
+
if (this.transcriptWindow && this.transcriptWindow.parentNode) {
|
|
4646
|
+
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
4647
|
+
}
|
|
4648
|
+
this.transcriptWindow = null;
|
|
4649
|
+
this.transcriptHeader = null;
|
|
4650
|
+
this.transcriptContent = null;
|
|
4651
|
+
this.transcriptEntries = [];
|
|
4652
|
+
this.settingsMenu = null;
|
|
4653
|
+
this.styleDialog = null;
|
|
4654
|
+
}
|
|
4655
|
+
};
|
|
4656
|
+
|
|
4657
|
+
// src/core/Player.js
|
|
4658
|
+
init_HTML5Renderer();
|
|
4659
|
+
|
|
4660
|
+
// src/renderers/YouTubeRenderer.js
|
|
4661
|
+
var YouTubeRenderer = class {
|
|
4662
|
+
constructor(player) {
|
|
4663
|
+
this.player = player;
|
|
4664
|
+
this.youtube = null;
|
|
4665
|
+
this.videoId = null;
|
|
4666
|
+
this.isReady = false;
|
|
4667
|
+
this.iframe = null;
|
|
4668
|
+
}
|
|
4669
|
+
async init() {
|
|
4670
|
+
this.videoId = this.extractVideoId(this.player.element.src);
|
|
4671
|
+
if (!this.videoId) {
|
|
4672
|
+
throw new Error("Invalid YouTube URL");
|
|
4673
|
+
}
|
|
4674
|
+
await this.loadYouTubeAPI();
|
|
4675
|
+
this.createIframe();
|
|
4676
|
+
await this.initializePlayer();
|
|
4677
|
+
}
|
|
4678
|
+
extractVideoId(url) {
|
|
4679
|
+
const patterns = [
|
|
4680
|
+
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\s]+)/,
|
|
4681
|
+
/youtube\.com\/embed\/([^&\s]+)/
|
|
4682
|
+
];
|
|
4683
|
+
for (const pattern of patterns) {
|
|
4684
|
+
const match = url.match(pattern);
|
|
4685
|
+
if (match && match[1]) {
|
|
4686
|
+
return match[1];
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
return null;
|
|
4690
|
+
}
|
|
4691
|
+
async loadYouTubeAPI() {
|
|
4692
|
+
if (window.YT && window.YT.Player) {
|
|
4693
|
+
return Promise.resolve();
|
|
4694
|
+
}
|
|
4695
|
+
return new Promise((resolve, reject) => {
|
|
4696
|
+
if (window.onYouTubeIframeAPIReady) {
|
|
4697
|
+
const originalCallback = window.onYouTubeIframeAPIReady;
|
|
4698
|
+
window.onYouTubeIframeAPIReady = () => {
|
|
4699
|
+
originalCallback();
|
|
4700
|
+
resolve();
|
|
4701
|
+
};
|
|
4702
|
+
return;
|
|
4703
|
+
}
|
|
4704
|
+
const tag = document.createElement("script");
|
|
4705
|
+
tag.src = "https://www.youtube.com/iframe_api";
|
|
4706
|
+
window.onYouTubeIframeAPIReady = () => {
|
|
3669
4707
|
resolve();
|
|
3670
4708
|
};
|
|
3671
4709
|
tag.onerror = () => reject(new Error("Failed to load YouTube API"));
|
|
@@ -4330,7 +5368,7 @@ var Player = class extends EventEmitter {
|
|
|
4330
5368
|
captionsButton: true,
|
|
4331
5369
|
transcriptButton: true,
|
|
4332
5370
|
fullscreenButton: true,
|
|
4333
|
-
pipButton:
|
|
5371
|
+
pipButton: false,
|
|
4334
5372
|
// Seeking
|
|
4335
5373
|
seekInterval: 10,
|
|
4336
5374
|
seekIntervalLarge: 30,
|
|
@@ -4400,6 +5438,13 @@ var Player = class extends EventEmitter {
|
|
|
4400
5438
|
onError: null,
|
|
4401
5439
|
...options
|
|
4402
5440
|
};
|
|
5441
|
+
this.storage = new StorageManager("vidply");
|
|
5442
|
+
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5443
|
+
if (savedPrefs) {
|
|
5444
|
+
if (savedPrefs.volume !== void 0) this.options.volume = savedPrefs.volume;
|
|
5445
|
+
if (savedPrefs.playbackSpeed !== void 0) this.options.playbackSpeed = savedPrefs.playbackSpeed;
|
|
5446
|
+
if (savedPrefs.muted !== void 0) this.options.muted = savedPrefs.muted;
|
|
5447
|
+
}
|
|
4403
5448
|
this.state = {
|
|
4404
5449
|
ready: false,
|
|
4405
5450
|
playing: false,
|
|
@@ -4424,6 +5469,9 @@ var Player = class extends EventEmitter {
|
|
|
4424
5469
|
this.audioDescriptionSrc = this.options.audioDescriptionSrc;
|
|
4425
5470
|
this.signLanguageSrc = this.options.signLanguageSrc;
|
|
4426
5471
|
this.signLanguageVideo = null;
|
|
5472
|
+
this.audioDescriptionSourceElement = null;
|
|
5473
|
+
this.originalAudioDescriptionSource = null;
|
|
5474
|
+
this.audioDescriptionCaptionTracks = [];
|
|
4427
5475
|
this.container = null;
|
|
4428
5476
|
this.renderer = null;
|
|
4429
5477
|
this.controlBar = null;
|
|
@@ -4578,6 +5626,53 @@ var Player = class extends EventEmitter {
|
|
|
4578
5626
|
if (!src) {
|
|
4579
5627
|
throw new Error("No media source found");
|
|
4580
5628
|
}
|
|
5629
|
+
const sourceElements = this.element.querySelectorAll("source");
|
|
5630
|
+
for (const sourceEl of sourceElements) {
|
|
5631
|
+
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
5632
|
+
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
5633
|
+
if (descSrc || origSrc) {
|
|
5634
|
+
if (!this.audioDescriptionSourceElement) {
|
|
5635
|
+
this.audioDescriptionSourceElement = sourceEl;
|
|
5636
|
+
}
|
|
5637
|
+
if (origSrc) {
|
|
5638
|
+
if (!this.originalAudioDescriptionSource) {
|
|
5639
|
+
this.originalAudioDescriptionSource = origSrc;
|
|
5640
|
+
}
|
|
5641
|
+
if (!this.originalSrc) {
|
|
5642
|
+
this.originalSrc = origSrc;
|
|
5643
|
+
}
|
|
5644
|
+
} else {
|
|
5645
|
+
const currentSrcAttr = sourceEl.getAttribute("src");
|
|
5646
|
+
if (!this.originalAudioDescriptionSource && currentSrcAttr) {
|
|
5647
|
+
this.originalAudioDescriptionSource = currentSrcAttr;
|
|
5648
|
+
}
|
|
5649
|
+
if (!this.originalSrc && currentSrcAttr) {
|
|
5650
|
+
this.originalSrc = currentSrcAttr;
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
if (descSrc && !this.audioDescriptionSrc) {
|
|
5654
|
+
this.audioDescriptionSrc = descSrc;
|
|
5655
|
+
}
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5658
|
+
const trackElements = this.element.querySelectorAll("track");
|
|
5659
|
+
trackElements.forEach((trackEl) => {
|
|
5660
|
+
const trackKind = trackEl.getAttribute("kind");
|
|
5661
|
+
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
5662
|
+
if (trackKind === "captions" || trackKind === "subtitles" || trackKind === "chapters") {
|
|
5663
|
+
if (trackDescSrc) {
|
|
5664
|
+
this.audioDescriptionCaptionTracks.push({
|
|
5665
|
+
trackElement: trackEl,
|
|
5666
|
+
originalSrc: trackEl.getAttribute("src"),
|
|
5667
|
+
describedSrc: trackDescSrc,
|
|
5668
|
+
originalTrackSrc: trackEl.getAttribute("data-orig-src") || trackEl.getAttribute("src"),
|
|
5669
|
+
explicit: true
|
|
5670
|
+
// Explicitly defined, so we should validate it
|
|
5671
|
+
});
|
|
5672
|
+
this.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute("src")} -> ${trackDescSrc}`);
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
});
|
|
4581
5676
|
if (!this.originalSrc) {
|
|
4582
5677
|
this.originalSrc = src;
|
|
4583
5678
|
}
|
|
@@ -4734,6 +5829,7 @@ var Player = class extends EventEmitter {
|
|
|
4734
5829
|
if (newVolume > 0 && this.state.muted) {
|
|
4735
5830
|
this.state.muted = false;
|
|
4736
5831
|
}
|
|
5832
|
+
this.savePlayerPreferences();
|
|
4737
5833
|
}
|
|
4738
5834
|
getVolume() {
|
|
4739
5835
|
return this.state.volume;
|
|
@@ -4743,6 +5839,7 @@ var Player = class extends EventEmitter {
|
|
|
4743
5839
|
this.renderer.setMuted(true);
|
|
4744
5840
|
}
|
|
4745
5841
|
this.state.muted = true;
|
|
5842
|
+
this.savePlayerPreferences();
|
|
4746
5843
|
this.emit("volumechange");
|
|
4747
5844
|
}
|
|
4748
5845
|
unmute() {
|
|
@@ -4750,6 +5847,7 @@ var Player = class extends EventEmitter {
|
|
|
4750
5847
|
this.renderer.setMuted(false);
|
|
4751
5848
|
}
|
|
4752
5849
|
this.state.muted = false;
|
|
5850
|
+
this.savePlayerPreferences();
|
|
4753
5851
|
this.emit("volumechange");
|
|
4754
5852
|
}
|
|
4755
5853
|
toggleMute() {
|
|
@@ -4766,11 +5864,20 @@ var Player = class extends EventEmitter {
|
|
|
4766
5864
|
this.renderer.setPlaybackSpeed(newSpeed);
|
|
4767
5865
|
}
|
|
4768
5866
|
this.state.playbackSpeed = newSpeed;
|
|
5867
|
+
this.savePlayerPreferences();
|
|
4769
5868
|
this.emit("playbackspeedchange", newSpeed);
|
|
4770
5869
|
}
|
|
4771
5870
|
getPlaybackSpeed() {
|
|
4772
5871
|
return this.state.playbackSpeed;
|
|
4773
5872
|
}
|
|
5873
|
+
// Save player preferences to localStorage
|
|
5874
|
+
savePlayerPreferences() {
|
|
5875
|
+
this.storage.savePlayerPreferences({
|
|
5876
|
+
volume: this.state.volume,
|
|
5877
|
+
muted: this.state.muted,
|
|
5878
|
+
playbackSpeed: this.state.playbackSpeed
|
|
5879
|
+
});
|
|
5880
|
+
}
|
|
4774
5881
|
// Fullscreen
|
|
4775
5882
|
enterFullscreen() {
|
|
4776
5883
|
const elem = this.container;
|
|
@@ -4850,15 +5957,396 @@ var Player = class extends EventEmitter {
|
|
|
4850
5957
|
this.enableCaptions();
|
|
4851
5958
|
}
|
|
4852
5959
|
}
|
|
5960
|
+
/**
|
|
5961
|
+
* Check if a track file exists
|
|
5962
|
+
* @param {string} url - Track file URL
|
|
5963
|
+
* @returns {Promise<boolean>} - True if file exists
|
|
5964
|
+
*/
|
|
5965
|
+
async validateTrackExists(url) {
|
|
5966
|
+
try {
|
|
5967
|
+
const response = await fetch(url, { method: "HEAD", cache: "no-cache" });
|
|
5968
|
+
return response.ok;
|
|
5969
|
+
} catch (error) {
|
|
5970
|
+
return false;
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
4853
5973
|
// Audio Description
|
|
4854
5974
|
async enableAudioDescription() {
|
|
4855
|
-
|
|
4856
|
-
|
|
5975
|
+
const hasSourceElementsWithDesc = Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
5976
|
+
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
5977
|
+
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
5978
|
+
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
4857
5979
|
return;
|
|
4858
5980
|
}
|
|
4859
5981
|
const currentTime = this.state.currentTime;
|
|
4860
5982
|
const wasPlaying = this.state.playing;
|
|
4861
|
-
|
|
5983
|
+
let swappedTracksForTranscript = [];
|
|
5984
|
+
if (this.audioDescriptionSourceElement) {
|
|
5985
|
+
const currentSrc = this.element.currentSrc || this.element.src;
|
|
5986
|
+
const sourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
5987
|
+
let sourceElementToUpdate = null;
|
|
5988
|
+
let descSrc = this.audioDescriptionSrc;
|
|
5989
|
+
for (const sourceEl of sourceElements) {
|
|
5990
|
+
const sourceSrc = sourceEl.getAttribute("src");
|
|
5991
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
5992
|
+
const sourceFilename = sourceSrc ? sourceSrc.split("/").pop() : "";
|
|
5993
|
+
const currentFilename = currentSrc ? currentSrc.split("/").pop() : "";
|
|
5994
|
+
if (currentSrc && (currentSrc === sourceSrc || currentSrc.includes(sourceSrc) || currentSrc.includes(sourceFilename) || sourceFilename && currentFilename === sourceFilename)) {
|
|
5995
|
+
sourceElementToUpdate = sourceEl;
|
|
5996
|
+
if (descSrcAttr) {
|
|
5997
|
+
descSrc = descSrcAttr;
|
|
5998
|
+
} else if (sourceSrc) {
|
|
5999
|
+
descSrc = this.audioDescriptionSrc || descSrc;
|
|
6000
|
+
}
|
|
6001
|
+
break;
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
if (!sourceElementToUpdate) {
|
|
6005
|
+
sourceElementToUpdate = this.audioDescriptionSourceElement;
|
|
6006
|
+
const storedDescSrc = sourceElementToUpdate.getAttribute("data-desc-src");
|
|
6007
|
+
if (storedDescSrc) {
|
|
6008
|
+
descSrc = storedDescSrc;
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6012
|
+
const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
|
|
6013
|
+
if (trackInfo.trackElement && trackInfo.describedSrc) {
|
|
6014
|
+
if (trackInfo.explicit === true) {
|
|
6015
|
+
try {
|
|
6016
|
+
const exists = await this.validateTrackExists(trackInfo.describedSrc);
|
|
6017
|
+
return { trackInfo, exists };
|
|
6018
|
+
} catch (error) {
|
|
6019
|
+
return { trackInfo, exists: false };
|
|
6020
|
+
}
|
|
6021
|
+
} else {
|
|
6022
|
+
return { trackInfo, exists: false };
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
return { trackInfo, exists: false };
|
|
6026
|
+
});
|
|
6027
|
+
const validationResults = await Promise.all(validationPromises);
|
|
6028
|
+
const tracksToSwap = validationResults.filter((result) => result.exists);
|
|
6029
|
+
if (tracksToSwap.length > 0) {
|
|
6030
|
+
const trackModes = /* @__PURE__ */ new Map();
|
|
6031
|
+
tracksToSwap.forEach(({ trackInfo }) => {
|
|
6032
|
+
const textTrack = trackInfo.trackElement.track;
|
|
6033
|
+
if (textTrack) {
|
|
6034
|
+
trackModes.set(trackInfo, {
|
|
6035
|
+
wasShowing: textTrack.mode === "showing",
|
|
6036
|
+
wasHidden: textTrack.mode === "hidden"
|
|
6037
|
+
});
|
|
6038
|
+
} else {
|
|
6039
|
+
trackModes.set(trackInfo, {
|
|
6040
|
+
wasShowing: false,
|
|
6041
|
+
wasHidden: false
|
|
6042
|
+
});
|
|
6043
|
+
}
|
|
6044
|
+
});
|
|
6045
|
+
const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
|
|
6046
|
+
const oldSrc = trackInfo.trackElement.getAttribute("src");
|
|
6047
|
+
const parent = trackInfo.trackElement.parentNode;
|
|
6048
|
+
const nextSibling = trackInfo.trackElement.nextSibling;
|
|
6049
|
+
const attributes = {};
|
|
6050
|
+
Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
|
|
6051
|
+
attributes[attr.name] = attr.value;
|
|
6052
|
+
});
|
|
6053
|
+
return {
|
|
6054
|
+
trackInfo,
|
|
6055
|
+
oldSrc,
|
|
6056
|
+
parent,
|
|
6057
|
+
nextSibling,
|
|
6058
|
+
attributes
|
|
6059
|
+
};
|
|
6060
|
+
});
|
|
6061
|
+
tracksToReadd.forEach(({ trackInfo }) => {
|
|
6062
|
+
trackInfo.trackElement.remove();
|
|
6063
|
+
});
|
|
6064
|
+
this.element.load();
|
|
6065
|
+
setTimeout(() => {
|
|
6066
|
+
tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
|
|
6067
|
+
swappedTracksForTranscript.push(trackInfo);
|
|
6068
|
+
const newTrackElement = document.createElement("track");
|
|
6069
|
+
newTrackElement.setAttribute("src", trackInfo.describedSrc);
|
|
6070
|
+
Object.keys(attributes).forEach((attrName) => {
|
|
6071
|
+
if (attrName !== "src" && attrName !== "data-desc-src") {
|
|
6072
|
+
newTrackElement.setAttribute(attrName, attributes[attrName]);
|
|
6073
|
+
}
|
|
6074
|
+
});
|
|
6075
|
+
if (nextSibling && nextSibling.parentNode) {
|
|
6076
|
+
parent.insertBefore(newTrackElement, nextSibling);
|
|
6077
|
+
} else {
|
|
6078
|
+
parent.appendChild(newTrackElement);
|
|
6079
|
+
}
|
|
6080
|
+
trackInfo.trackElement = newTrackElement;
|
|
6081
|
+
});
|
|
6082
|
+
this.element.load();
|
|
6083
|
+
const setupNewTracks = () => {
|
|
6084
|
+
setTimeout(() => {
|
|
6085
|
+
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6086
|
+
const trackElement = trackInfo.trackElement;
|
|
6087
|
+
const newTextTrack = trackElement.track;
|
|
6088
|
+
if (newTextTrack) {
|
|
6089
|
+
const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
|
|
6090
|
+
newTextTrack.mode = "hidden";
|
|
6091
|
+
const restoreMode = () => {
|
|
6092
|
+
if (modeInfo.wasShowing) {
|
|
6093
|
+
newTextTrack.mode = "hidden";
|
|
6094
|
+
} else if (modeInfo.wasHidden) {
|
|
6095
|
+
newTextTrack.mode = "hidden";
|
|
6096
|
+
} else {
|
|
6097
|
+
newTextTrack.mode = "disabled";
|
|
6098
|
+
}
|
|
6099
|
+
};
|
|
6100
|
+
if (newTextTrack.readyState >= 2) {
|
|
6101
|
+
restoreMode();
|
|
6102
|
+
} else {
|
|
6103
|
+
newTextTrack.addEventListener("load", restoreMode, { once: true });
|
|
6104
|
+
newTextTrack.addEventListener("error", restoreMode, { once: true });
|
|
6105
|
+
}
|
|
6106
|
+
}
|
|
6107
|
+
});
|
|
6108
|
+
}, 300);
|
|
6109
|
+
};
|
|
6110
|
+
if (this.element.readyState >= 1) {
|
|
6111
|
+
setTimeout(setupNewTracks, 200);
|
|
6112
|
+
} else {
|
|
6113
|
+
this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
|
|
6114
|
+
setTimeout(setupNewTracks, 2e3);
|
|
6115
|
+
}
|
|
6116
|
+
}, 100);
|
|
6117
|
+
const skippedCount = validationResults.length - tracksToSwap.length;
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
const allSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6121
|
+
const sourcesToUpdate = [];
|
|
6122
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6123
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6124
|
+
const currentSrc2 = sourceEl.getAttribute("src");
|
|
6125
|
+
if (descSrcAttr) {
|
|
6126
|
+
const type = sourceEl.getAttribute("type");
|
|
6127
|
+
let origSrc = sourceEl.getAttribute("data-orig-src");
|
|
6128
|
+
if (!origSrc) {
|
|
6129
|
+
origSrc = currentSrc2;
|
|
6130
|
+
}
|
|
6131
|
+
sourcesToUpdate.push({
|
|
6132
|
+
src: descSrcAttr,
|
|
6133
|
+
// Use described version
|
|
6134
|
+
type,
|
|
6135
|
+
origSrc,
|
|
6136
|
+
descSrc: descSrcAttr
|
|
6137
|
+
});
|
|
6138
|
+
} else {
|
|
6139
|
+
const type = sourceEl.getAttribute("type");
|
|
6140
|
+
const src = sourceEl.getAttribute("src");
|
|
6141
|
+
sourcesToUpdate.push({
|
|
6142
|
+
src,
|
|
6143
|
+
type,
|
|
6144
|
+
origSrc: null,
|
|
6145
|
+
descSrc: null
|
|
6146
|
+
});
|
|
6147
|
+
}
|
|
6148
|
+
});
|
|
6149
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6150
|
+
sourceEl.remove();
|
|
6151
|
+
});
|
|
6152
|
+
sourcesToUpdate.forEach((sourceInfo) => {
|
|
6153
|
+
const newSource = document.createElement("source");
|
|
6154
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6155
|
+
if (sourceInfo.type) {
|
|
6156
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6157
|
+
}
|
|
6158
|
+
if (sourceInfo.origSrc) {
|
|
6159
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6160
|
+
}
|
|
6161
|
+
if (sourceInfo.descSrc) {
|
|
6162
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6163
|
+
}
|
|
6164
|
+
this.element.appendChild(newSource);
|
|
6165
|
+
});
|
|
6166
|
+
this.element.load();
|
|
6167
|
+
await new Promise((resolve) => {
|
|
6168
|
+
const onLoadedMetadata = () => {
|
|
6169
|
+
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
6170
|
+
resolve();
|
|
6171
|
+
};
|
|
6172
|
+
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
6173
|
+
});
|
|
6174
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
6175
|
+
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6176
|
+
if (this.element.readyState >= 1) {
|
|
6177
|
+
this.element.currentTime = 1e-3;
|
|
6178
|
+
setTimeout(() => {
|
|
6179
|
+
this.element.currentTime = 0;
|
|
6180
|
+
}, 10);
|
|
6181
|
+
}
|
|
6182
|
+
}
|
|
6183
|
+
this.seek(currentTime);
|
|
6184
|
+
if (wasPlaying) {
|
|
6185
|
+
this.play();
|
|
6186
|
+
}
|
|
6187
|
+
this.state.audioDescriptionEnabled = true;
|
|
6188
|
+
this.emit("audiodescriptionenabled");
|
|
6189
|
+
} else {
|
|
6190
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6191
|
+
const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
|
|
6192
|
+
if (trackInfo.trackElement && trackInfo.describedSrc) {
|
|
6193
|
+
if (trackInfo.explicit === true) {
|
|
6194
|
+
try {
|
|
6195
|
+
const exists = await this.validateTrackExists(trackInfo.describedSrc);
|
|
6196
|
+
return { trackInfo, exists };
|
|
6197
|
+
} catch (error) {
|
|
6198
|
+
return { trackInfo, exists: false };
|
|
6199
|
+
}
|
|
6200
|
+
} else {
|
|
6201
|
+
return { trackInfo, exists: false };
|
|
6202
|
+
}
|
|
6203
|
+
}
|
|
6204
|
+
return { trackInfo, exists: false };
|
|
6205
|
+
});
|
|
6206
|
+
const validationResults = await Promise.all(validationPromises);
|
|
6207
|
+
const tracksToSwap = validationResults.filter((result) => result.exists);
|
|
6208
|
+
if (tracksToSwap.length > 0) {
|
|
6209
|
+
const trackModes = /* @__PURE__ */ new Map();
|
|
6210
|
+
tracksToSwap.forEach(({ trackInfo }) => {
|
|
6211
|
+
const textTrack = trackInfo.trackElement.track;
|
|
6212
|
+
if (textTrack) {
|
|
6213
|
+
trackModes.set(trackInfo, {
|
|
6214
|
+
wasShowing: textTrack.mode === "showing",
|
|
6215
|
+
wasHidden: textTrack.mode === "hidden"
|
|
6216
|
+
});
|
|
6217
|
+
} else {
|
|
6218
|
+
trackModes.set(trackInfo, {
|
|
6219
|
+
wasShowing: false,
|
|
6220
|
+
wasHidden: false
|
|
6221
|
+
});
|
|
6222
|
+
}
|
|
6223
|
+
});
|
|
6224
|
+
const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
|
|
6225
|
+
const oldSrc = trackInfo.trackElement.getAttribute("src");
|
|
6226
|
+
const parent = trackInfo.trackElement.parentNode;
|
|
6227
|
+
const nextSibling = trackInfo.trackElement.nextSibling;
|
|
6228
|
+
const attributes = {};
|
|
6229
|
+
Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
|
|
6230
|
+
attributes[attr.name] = attr.value;
|
|
6231
|
+
});
|
|
6232
|
+
return {
|
|
6233
|
+
trackInfo,
|
|
6234
|
+
oldSrc,
|
|
6235
|
+
parent,
|
|
6236
|
+
nextSibling,
|
|
6237
|
+
attributes
|
|
6238
|
+
};
|
|
6239
|
+
});
|
|
6240
|
+
tracksToReadd.forEach(({ trackInfo }) => {
|
|
6241
|
+
trackInfo.trackElement.remove();
|
|
6242
|
+
});
|
|
6243
|
+
this.element.load();
|
|
6244
|
+
setTimeout(() => {
|
|
6245
|
+
tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
|
|
6246
|
+
swappedTracksForTranscript.push(trackInfo);
|
|
6247
|
+
const newTrackElement = document.createElement("track");
|
|
6248
|
+
newTrackElement.setAttribute("src", trackInfo.describedSrc);
|
|
6249
|
+
Object.keys(attributes).forEach((attrName) => {
|
|
6250
|
+
if (attrName !== "src" && attrName !== "data-desc-src") {
|
|
6251
|
+
newTrackElement.setAttribute(attrName, attributes[attrName]);
|
|
6252
|
+
}
|
|
6253
|
+
});
|
|
6254
|
+
if (nextSibling && nextSibling.parentNode) {
|
|
6255
|
+
parent.insertBefore(newTrackElement, nextSibling);
|
|
6256
|
+
} else {
|
|
6257
|
+
parent.appendChild(newTrackElement);
|
|
6258
|
+
}
|
|
6259
|
+
trackInfo.trackElement = newTrackElement;
|
|
6260
|
+
});
|
|
6261
|
+
this.element.load();
|
|
6262
|
+
const setupNewTracks = () => {
|
|
6263
|
+
setTimeout(() => {
|
|
6264
|
+
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6265
|
+
const trackElement = trackInfo.trackElement;
|
|
6266
|
+
const newTextTrack = trackElement.track;
|
|
6267
|
+
if (newTextTrack) {
|
|
6268
|
+
const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
|
|
6269
|
+
newTextTrack.mode = "hidden";
|
|
6270
|
+
const restoreMode = () => {
|
|
6271
|
+
if (modeInfo.wasShowing) {
|
|
6272
|
+
newTextTrack.mode = "hidden";
|
|
6273
|
+
} else if (modeInfo.wasHidden) {
|
|
6274
|
+
newTextTrack.mode = "hidden";
|
|
6275
|
+
} else {
|
|
6276
|
+
newTextTrack.mode = "disabled";
|
|
6277
|
+
}
|
|
6278
|
+
};
|
|
6279
|
+
if (newTextTrack.readyState >= 2) {
|
|
6280
|
+
restoreMode();
|
|
6281
|
+
} else {
|
|
6282
|
+
newTextTrack.addEventListener("load", restoreMode, { once: true });
|
|
6283
|
+
newTextTrack.addEventListener("error", restoreMode, { once: true });
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
});
|
|
6287
|
+
}, 300);
|
|
6288
|
+
};
|
|
6289
|
+
if (this.element.readyState >= 1) {
|
|
6290
|
+
setTimeout(setupNewTracks, 200);
|
|
6291
|
+
} else {
|
|
6292
|
+
this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
|
|
6293
|
+
setTimeout(setupNewTracks, 2e3);
|
|
6294
|
+
}
|
|
6295
|
+
}, 100);
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
const fallbackSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6299
|
+
const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6300
|
+
if (hasSourceElementsWithDesc2) {
|
|
6301
|
+
const fallbackSourcesToUpdate = [];
|
|
6302
|
+
fallbackSourceElements.forEach((sourceEl) => {
|
|
6303
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6304
|
+
const currentSrc = sourceEl.getAttribute("src");
|
|
6305
|
+
if (descSrcAttr) {
|
|
6306
|
+
const type = sourceEl.getAttribute("type");
|
|
6307
|
+
let origSrc = sourceEl.getAttribute("data-orig-src");
|
|
6308
|
+
if (!origSrc) {
|
|
6309
|
+
origSrc = currentSrc;
|
|
6310
|
+
}
|
|
6311
|
+
fallbackSourcesToUpdate.push({
|
|
6312
|
+
src: descSrcAttr,
|
|
6313
|
+
type,
|
|
6314
|
+
origSrc,
|
|
6315
|
+
descSrc: descSrcAttr
|
|
6316
|
+
});
|
|
6317
|
+
} else {
|
|
6318
|
+
const type = sourceEl.getAttribute("type");
|
|
6319
|
+
const src = sourceEl.getAttribute("src");
|
|
6320
|
+
fallbackSourcesToUpdate.push({
|
|
6321
|
+
src,
|
|
6322
|
+
type,
|
|
6323
|
+
origSrc: null,
|
|
6324
|
+
descSrc: null
|
|
6325
|
+
});
|
|
6326
|
+
}
|
|
6327
|
+
});
|
|
6328
|
+
fallbackSourceElements.forEach((sourceEl) => {
|
|
6329
|
+
sourceEl.remove();
|
|
6330
|
+
});
|
|
6331
|
+
fallbackSourcesToUpdate.forEach((sourceInfo) => {
|
|
6332
|
+
const newSource = document.createElement("source");
|
|
6333
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6334
|
+
if (sourceInfo.type) {
|
|
6335
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6336
|
+
}
|
|
6337
|
+
if (sourceInfo.origSrc) {
|
|
6338
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6339
|
+
}
|
|
6340
|
+
if (sourceInfo.descSrc) {
|
|
6341
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6342
|
+
}
|
|
6343
|
+
this.element.appendChild(newSource);
|
|
6344
|
+
});
|
|
6345
|
+
this.element.load();
|
|
6346
|
+
} else {
|
|
6347
|
+
this.element.src = this.audioDescriptionSrc;
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
4862
6350
|
await new Promise((resolve) => {
|
|
4863
6351
|
const onLoadedMetadata = () => {
|
|
4864
6352
|
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
@@ -4866,10 +6354,183 @@ var Player = class extends EventEmitter {
|
|
|
4866
6354
|
};
|
|
4867
6355
|
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
4868
6356
|
});
|
|
6357
|
+
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6358
|
+
if (this.element.readyState >= 1) {
|
|
6359
|
+
this.element.currentTime = 1e-3;
|
|
6360
|
+
setTimeout(() => {
|
|
6361
|
+
this.element.currentTime = 0;
|
|
6362
|
+
}, 10);
|
|
6363
|
+
}
|
|
6364
|
+
}
|
|
4869
6365
|
this.seek(currentTime);
|
|
4870
6366
|
if (wasPlaying) {
|
|
4871
6367
|
this.play();
|
|
4872
6368
|
}
|
|
6369
|
+
if (swappedTracksForTranscript.length > 0 && this.captionManager) {
|
|
6370
|
+
const wasCaptionsEnabled = this.state.captionsEnabled;
|
|
6371
|
+
let currentTrackInfo = null;
|
|
6372
|
+
if (this.captionManager.currentTrack) {
|
|
6373
|
+
const currentTrackIndex = this.captionManager.tracks.findIndex((t) => t.track === this.captionManager.currentTrack.track);
|
|
6374
|
+
if (currentTrackIndex >= 0) {
|
|
6375
|
+
currentTrackInfo = {
|
|
6376
|
+
language: this.captionManager.tracks[currentTrackIndex].language,
|
|
6377
|
+
kind: this.captionManager.tracks[currentTrackIndex].kind
|
|
6378
|
+
};
|
|
6379
|
+
}
|
|
6380
|
+
}
|
|
6381
|
+
setTimeout(() => {
|
|
6382
|
+
this.captionManager.tracks = [];
|
|
6383
|
+
this.captionManager.loadTracks();
|
|
6384
|
+
if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {
|
|
6385
|
+
const matchingTrackIndex = this.captionManager.tracks.findIndex(
|
|
6386
|
+
(t) => t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind
|
|
6387
|
+
);
|
|
6388
|
+
if (matchingTrackIndex >= 0) {
|
|
6389
|
+
this.captionManager.enable(matchingTrackIndex);
|
|
6390
|
+
} else if (this.captionManager.tracks.length > 0) {
|
|
6391
|
+
this.captionManager.enable(0);
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
}, 600);
|
|
6395
|
+
}
|
|
6396
|
+
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6397
|
+
const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
|
|
6398
|
+
if (swappedTracks.length > 0) {
|
|
6399
|
+
const onMetadataLoaded = () => {
|
|
6400
|
+
const allTextTracks = Array.from(this.element.textTracks);
|
|
6401
|
+
const freshTracks = swappedTracks.map((trackInfo) => {
|
|
6402
|
+
const trackEl = trackInfo.trackElement;
|
|
6403
|
+
const expectedSrc = trackEl.getAttribute("src");
|
|
6404
|
+
const srclang = trackEl.getAttribute("srclang");
|
|
6405
|
+
const kind = trackEl.getAttribute("kind");
|
|
6406
|
+
let foundTrack = allTextTracks.find((track) => trackEl.track === track);
|
|
6407
|
+
if (!foundTrack) {
|
|
6408
|
+
foundTrack = allTextTracks.find((track) => {
|
|
6409
|
+
if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
|
|
6410
|
+
const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
|
|
6411
|
+
(el) => el.track === track
|
|
6412
|
+
);
|
|
6413
|
+
if (trackElementForTrack) {
|
|
6414
|
+
const actualSrc = trackElementForTrack.getAttribute("src");
|
|
6415
|
+
if (actualSrc === expectedSrc) {
|
|
6416
|
+
return true;
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
return false;
|
|
6421
|
+
});
|
|
6422
|
+
}
|
|
6423
|
+
if (foundTrack) {
|
|
6424
|
+
const trackElement = Array.from(this.element.querySelectorAll("track")).find(
|
|
6425
|
+
(el) => el.track === foundTrack
|
|
6426
|
+
);
|
|
6427
|
+
if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
|
|
6428
|
+
return null;
|
|
6429
|
+
}
|
|
6430
|
+
}
|
|
6431
|
+
return foundTrack;
|
|
6432
|
+
}).filter(Boolean);
|
|
6433
|
+
if (freshTracks.length === 0) {
|
|
6434
|
+
setTimeout(() => {
|
|
6435
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6436
|
+
this.transcriptManager.loadTranscriptData();
|
|
6437
|
+
}
|
|
6438
|
+
}, 1e3);
|
|
6439
|
+
return;
|
|
6440
|
+
}
|
|
6441
|
+
freshTracks.forEach((track) => {
|
|
6442
|
+
if (track.mode === "disabled") {
|
|
6443
|
+
track.mode = "hidden";
|
|
6444
|
+
}
|
|
6445
|
+
});
|
|
6446
|
+
let loadedCount = 0;
|
|
6447
|
+
const checkLoaded = () => {
|
|
6448
|
+
loadedCount++;
|
|
6449
|
+
if (loadedCount >= freshTracks.length) {
|
|
6450
|
+
setTimeout(() => {
|
|
6451
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6452
|
+
const allTextTracks2 = Array.from(this.element.textTracks);
|
|
6453
|
+
const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
|
|
6454
|
+
const hasCorrectTracks = freshTracks.some((track) => {
|
|
6455
|
+
const trackEl = Array.from(this.element.querySelectorAll("track")).find(
|
|
6456
|
+
(el) => el.track === track
|
|
6457
|
+
);
|
|
6458
|
+
return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
|
|
6459
|
+
});
|
|
6460
|
+
if (hasCorrectTracks || freshTracks.length > 0) {
|
|
6461
|
+
this.transcriptManager.loadTranscriptData();
|
|
6462
|
+
}
|
|
6463
|
+
}
|
|
6464
|
+
}, 800);
|
|
6465
|
+
}
|
|
6466
|
+
};
|
|
6467
|
+
freshTracks.forEach((track) => {
|
|
6468
|
+
if (track.mode === "disabled") {
|
|
6469
|
+
track.mode = "hidden";
|
|
6470
|
+
}
|
|
6471
|
+
const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
|
|
6472
|
+
(el) => el.track === track
|
|
6473
|
+
);
|
|
6474
|
+
const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
|
|
6475
|
+
const expectedTrackInfo = swappedTracks.find((t) => {
|
|
6476
|
+
const tEl = t.trackElement;
|
|
6477
|
+
return tEl && (tEl.track === track || tEl.getAttribute("srclang") === track.language && tEl.getAttribute("kind") === track.kind);
|
|
6478
|
+
});
|
|
6479
|
+
const expectedSrc = expectedTrackInfo ? expectedTrackInfo.describedSrc : null;
|
|
6480
|
+
if (expectedSrc && actualSrc && actualSrc !== expectedSrc) {
|
|
6481
|
+
checkLoaded();
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
if (track.readyState >= 2 && track.cues && track.cues.length > 0) {
|
|
6485
|
+
checkLoaded();
|
|
6486
|
+
} else {
|
|
6487
|
+
if (track.mode === "disabled") {
|
|
6488
|
+
track.mode = "hidden";
|
|
6489
|
+
}
|
|
6490
|
+
const onTrackLoad = () => {
|
|
6491
|
+
setTimeout(checkLoaded, 300);
|
|
6492
|
+
};
|
|
6493
|
+
if (track.readyState >= 2) {
|
|
6494
|
+
setTimeout(() => {
|
|
6495
|
+
if (track.cues && track.cues.length > 0) {
|
|
6496
|
+
checkLoaded();
|
|
6497
|
+
} else {
|
|
6498
|
+
track.addEventListener("load", onTrackLoad, { once: true });
|
|
6499
|
+
}
|
|
6500
|
+
}, 100);
|
|
6501
|
+
} else {
|
|
6502
|
+
track.addEventListener("load", onTrackLoad, { once: true });
|
|
6503
|
+
track.addEventListener("error", () => {
|
|
6504
|
+
checkLoaded();
|
|
6505
|
+
}, { once: true });
|
|
6506
|
+
}
|
|
6507
|
+
}
|
|
6508
|
+
});
|
|
6509
|
+
};
|
|
6510
|
+
const waitForTracks = () => {
|
|
6511
|
+
setTimeout(() => {
|
|
6512
|
+
if (this.element.readyState >= 1) {
|
|
6513
|
+
onMetadataLoaded();
|
|
6514
|
+
} else {
|
|
6515
|
+
this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
|
|
6516
|
+
setTimeout(onMetadataLoaded, 2e3);
|
|
6517
|
+
}
|
|
6518
|
+
}, 500);
|
|
6519
|
+
};
|
|
6520
|
+
waitForTracks();
|
|
6521
|
+
setTimeout(() => {
|
|
6522
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6523
|
+
this.transcriptManager.loadTranscriptData();
|
|
6524
|
+
}
|
|
6525
|
+
}, 5e3);
|
|
6526
|
+
} else {
|
|
6527
|
+
setTimeout(() => {
|
|
6528
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6529
|
+
this.transcriptManager.loadTranscriptData();
|
|
6530
|
+
}
|
|
6531
|
+
}, 800);
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
4873
6534
|
this.state.audioDescriptionEnabled = true;
|
|
4874
6535
|
this.emit("audiodescriptionenabled");
|
|
4875
6536
|
}
|
|
@@ -4879,7 +6540,64 @@ var Player = class extends EventEmitter {
|
|
|
4879
6540
|
}
|
|
4880
6541
|
const currentTime = this.state.currentTime;
|
|
4881
6542
|
const wasPlaying = this.state.playing;
|
|
4882
|
-
this.
|
|
6543
|
+
if (this.audioDescriptionCaptionTracks.length > 0) {
|
|
6544
|
+
this.audioDescriptionCaptionTracks.forEach((trackInfo) => {
|
|
6545
|
+
if (trackInfo.trackElement && trackInfo.originalTrackSrc) {
|
|
6546
|
+
trackInfo.trackElement.setAttribute("src", trackInfo.originalTrackSrc);
|
|
6547
|
+
}
|
|
6548
|
+
});
|
|
6549
|
+
}
|
|
6550
|
+
const allSourceElements = Array.from(this.element.querySelectorAll("source"));
|
|
6551
|
+
const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
|
|
6552
|
+
if (hasSourceElementsToSwap) {
|
|
6553
|
+
const sourcesToRestore = [];
|
|
6554
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6555
|
+
const origSrcAttr = sourceEl.getAttribute("data-orig-src");
|
|
6556
|
+
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
6557
|
+
if (origSrcAttr) {
|
|
6558
|
+
const type = sourceEl.getAttribute("type");
|
|
6559
|
+
sourcesToRestore.push({
|
|
6560
|
+
src: origSrcAttr,
|
|
6561
|
+
// Use original version
|
|
6562
|
+
type,
|
|
6563
|
+
origSrc: origSrcAttr,
|
|
6564
|
+
descSrc: descSrcAttr
|
|
6565
|
+
// Keep data-desc-src for future swaps
|
|
6566
|
+
});
|
|
6567
|
+
} else {
|
|
6568
|
+
const type = sourceEl.getAttribute("type");
|
|
6569
|
+
const src = sourceEl.getAttribute("src");
|
|
6570
|
+
sourcesToRestore.push({
|
|
6571
|
+
src,
|
|
6572
|
+
type,
|
|
6573
|
+
origSrc: null,
|
|
6574
|
+
descSrc: descSrcAttr
|
|
6575
|
+
});
|
|
6576
|
+
}
|
|
6577
|
+
});
|
|
6578
|
+
allSourceElements.forEach((sourceEl) => {
|
|
6579
|
+
sourceEl.remove();
|
|
6580
|
+
});
|
|
6581
|
+
sourcesToRestore.forEach((sourceInfo) => {
|
|
6582
|
+
const newSource = document.createElement("source");
|
|
6583
|
+
newSource.setAttribute("src", sourceInfo.src);
|
|
6584
|
+
if (sourceInfo.type) {
|
|
6585
|
+
newSource.setAttribute("type", sourceInfo.type);
|
|
6586
|
+
}
|
|
6587
|
+
if (sourceInfo.origSrc) {
|
|
6588
|
+
newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
|
|
6589
|
+
}
|
|
6590
|
+
if (sourceInfo.descSrc) {
|
|
6591
|
+
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6592
|
+
}
|
|
6593
|
+
this.element.appendChild(newSource);
|
|
6594
|
+
});
|
|
6595
|
+
this.element.load();
|
|
6596
|
+
} else {
|
|
6597
|
+
const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
|
|
6598
|
+
this.element.src = originalSrcToUse;
|
|
6599
|
+
this.element.load();
|
|
6600
|
+
}
|
|
4883
6601
|
await new Promise((resolve) => {
|
|
4884
6602
|
const onLoadedMetadata = () => {
|
|
4885
6603
|
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
@@ -4891,14 +6609,44 @@ var Player = class extends EventEmitter {
|
|
|
4891
6609
|
if (wasPlaying) {
|
|
4892
6610
|
this.play();
|
|
4893
6611
|
}
|
|
6612
|
+
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6613
|
+
setTimeout(() => {
|
|
6614
|
+
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6615
|
+
this.transcriptManager.loadTranscriptData();
|
|
6616
|
+
}
|
|
6617
|
+
}, 500);
|
|
6618
|
+
}
|
|
4894
6619
|
this.state.audioDescriptionEnabled = false;
|
|
4895
6620
|
this.emit("audiodescriptiondisabled");
|
|
4896
6621
|
}
|
|
4897
6622
|
async toggleAudioDescription() {
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
6623
|
+
const textTracks = Array.from(this.element.textTracks || []);
|
|
6624
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
6625
|
+
const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
6626
|
+
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
6627
|
+
if (this.state.audioDescriptionEnabled) {
|
|
6628
|
+
descriptionTrack.mode = "hidden";
|
|
6629
|
+
await this.disableAudioDescription();
|
|
6630
|
+
} else {
|
|
6631
|
+
await this.enableAudioDescription();
|
|
6632
|
+
descriptionTrack.mode = "showing";
|
|
6633
|
+
}
|
|
6634
|
+
} else if (descriptionTrack) {
|
|
6635
|
+
if (descriptionTrack.mode === "showing") {
|
|
6636
|
+
descriptionTrack.mode = "hidden";
|
|
6637
|
+
this.state.audioDescriptionEnabled = false;
|
|
6638
|
+
this.emit("audiodescriptiondisabled");
|
|
6639
|
+
} else {
|
|
6640
|
+
descriptionTrack.mode = "showing";
|
|
6641
|
+
this.state.audioDescriptionEnabled = true;
|
|
6642
|
+
this.emit("audiodescriptionenabled");
|
|
6643
|
+
}
|
|
6644
|
+
} else if (hasAudioDescriptionSrc) {
|
|
6645
|
+
if (this.state.audioDescriptionEnabled) {
|
|
6646
|
+
await this.disableAudioDescription();
|
|
6647
|
+
} else {
|
|
6648
|
+
await this.enableAudioDescription();
|
|
6649
|
+
}
|
|
4902
6650
|
}
|
|
4903
6651
|
}
|
|
4904
6652
|
// Sign Language
|
|
@@ -4907,24 +6655,47 @@ var Player = class extends EventEmitter {
|
|
|
4907
6655
|
console.warn("No sign language video source provided");
|
|
4908
6656
|
return;
|
|
4909
6657
|
}
|
|
4910
|
-
if (this.
|
|
4911
|
-
this.
|
|
6658
|
+
if (this.signLanguageWrapper) {
|
|
6659
|
+
this.signLanguageWrapper.style.display = "block";
|
|
4912
6660
|
this.state.signLanguageEnabled = true;
|
|
4913
6661
|
this.emit("signlanguageenabled");
|
|
4914
6662
|
return;
|
|
4915
6663
|
}
|
|
6664
|
+
this.signLanguageWrapper = document.createElement("div");
|
|
6665
|
+
this.signLanguageWrapper.className = "vidply-sign-language-wrapper";
|
|
6666
|
+
this.signLanguageWrapper.setAttribute("tabindex", "0");
|
|
6667
|
+
this.signLanguageWrapper.setAttribute("aria-label", "Sign Language Video - Press D to drag with keyboard, R to resize");
|
|
4916
6668
|
this.signLanguageVideo = document.createElement("video");
|
|
4917
6669
|
this.signLanguageVideo.className = "vidply-sign-language-video";
|
|
4918
6670
|
this.signLanguageVideo.src = this.signLanguageSrc;
|
|
4919
6671
|
this.signLanguageVideo.setAttribute("aria-label", i18n.t("player.signLanguage"));
|
|
4920
|
-
const position = this.options.signLanguagePosition || "bottom-right";
|
|
4921
|
-
this.signLanguageVideo.classList.add(`vidply-sign-position-${position}`);
|
|
4922
6672
|
this.signLanguageVideo.muted = true;
|
|
6673
|
+
const resizeHandles = ["nw", "ne", "sw", "se"].map((dir) => {
|
|
6674
|
+
const handle = document.createElement("div");
|
|
6675
|
+
handle.className = `vidply-sign-resize-handle vidply-sign-resize-${dir}`;
|
|
6676
|
+
handle.setAttribute("data-direction", dir);
|
|
6677
|
+
handle.setAttribute("aria-label", `Resize ${dir.toUpperCase()}`);
|
|
6678
|
+
return handle;
|
|
6679
|
+
});
|
|
6680
|
+
this.signLanguageWrapper.appendChild(this.signLanguageVideo);
|
|
6681
|
+
resizeHandles.forEach((handle) => this.signLanguageWrapper.appendChild(handle));
|
|
6682
|
+
const saved = this.storage.getSignLanguagePreferences();
|
|
6683
|
+
if (saved && saved.size && saved.size.width) {
|
|
6684
|
+
this.signLanguageWrapper.style.width = saved.size.width;
|
|
6685
|
+
} else {
|
|
6686
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6687
|
+
}
|
|
6688
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6689
|
+
this.signLanguageDesiredPosition = this.options.signLanguagePosition || "bottom-right";
|
|
6690
|
+
this.container.appendChild(this.signLanguageWrapper);
|
|
6691
|
+
requestAnimationFrame(() => {
|
|
6692
|
+
this.constrainSignLanguagePosition();
|
|
6693
|
+
});
|
|
4923
6694
|
this.signLanguageVideo.currentTime = this.state.currentTime;
|
|
4924
6695
|
if (!this.state.paused) {
|
|
4925
6696
|
this.signLanguageVideo.play();
|
|
4926
6697
|
}
|
|
4927
|
-
this.
|
|
6698
|
+
this.setupSignLanguageInteraction();
|
|
4928
6699
|
this.signLanguageHandlers = {
|
|
4929
6700
|
play: () => {
|
|
4930
6701
|
if (this.signLanguageVideo) {
|
|
@@ -4955,8 +6726,8 @@ var Player = class extends EventEmitter {
|
|
|
4955
6726
|
this.emit("signlanguageenabled");
|
|
4956
6727
|
}
|
|
4957
6728
|
disableSignLanguage() {
|
|
4958
|
-
if (this.
|
|
4959
|
-
this.
|
|
6729
|
+
if (this.signLanguageWrapper) {
|
|
6730
|
+
this.signLanguageWrapper.style.display = "none";
|
|
4960
6731
|
}
|
|
4961
6732
|
this.state.signLanguageEnabled = false;
|
|
4962
6733
|
this.emit("signlanguagedisabled");
|
|
@@ -4968,6 +6739,237 @@ var Player = class extends EventEmitter {
|
|
|
4968
6739
|
this.enableSignLanguage();
|
|
4969
6740
|
}
|
|
4970
6741
|
}
|
|
6742
|
+
setupSignLanguageInteraction() {
|
|
6743
|
+
if (!this.signLanguageWrapper) return;
|
|
6744
|
+
let isDragging = false;
|
|
6745
|
+
let isResizing = false;
|
|
6746
|
+
let resizeDirection = null;
|
|
6747
|
+
let startX = 0;
|
|
6748
|
+
let startY = 0;
|
|
6749
|
+
let startLeft = 0;
|
|
6750
|
+
let startTop = 0;
|
|
6751
|
+
let startWidth = 0;
|
|
6752
|
+
let startHeight = 0;
|
|
6753
|
+
let dragMode = false;
|
|
6754
|
+
let resizeMode = false;
|
|
6755
|
+
const onMouseDownVideo = (e) => {
|
|
6756
|
+
if (e.target !== this.signLanguageVideo) return;
|
|
6757
|
+
e.preventDefault();
|
|
6758
|
+
isDragging = true;
|
|
6759
|
+
startX = e.clientX;
|
|
6760
|
+
startY = e.clientY;
|
|
6761
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6762
|
+
startLeft = rect.left;
|
|
6763
|
+
startTop = rect.top;
|
|
6764
|
+
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6765
|
+
};
|
|
6766
|
+
const onMouseDownHandle = (e) => {
|
|
6767
|
+
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6768
|
+
e.preventDefault();
|
|
6769
|
+
e.stopPropagation();
|
|
6770
|
+
isResizing = true;
|
|
6771
|
+
resizeDirection = e.target.getAttribute("data-direction");
|
|
6772
|
+
startX = e.clientX;
|
|
6773
|
+
startY = e.clientY;
|
|
6774
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6775
|
+
startLeft = rect.left;
|
|
6776
|
+
startTop = rect.top;
|
|
6777
|
+
startWidth = rect.width;
|
|
6778
|
+
startHeight = rect.height;
|
|
6779
|
+
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6780
|
+
};
|
|
6781
|
+
const onMouseMove = (e) => {
|
|
6782
|
+
if (isDragging) {
|
|
6783
|
+
const deltaX = e.clientX - startX;
|
|
6784
|
+
const deltaY = e.clientY - startY;
|
|
6785
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6786
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6787
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6788
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6789
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6790
|
+
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6791
|
+
let newTop = startTop + deltaY - containerRect.top;
|
|
6792
|
+
const controlsHeight = 95;
|
|
6793
|
+
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6794
|
+
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6795
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6796
|
+
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6797
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6798
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6799
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6800
|
+
} else if (isResizing) {
|
|
6801
|
+
const deltaX = e.clientX - startX;
|
|
6802
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6803
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6804
|
+
let newWidth = startWidth;
|
|
6805
|
+
let newLeft = startLeft - containerRect.left;
|
|
6806
|
+
if (resizeDirection.includes("e")) {
|
|
6807
|
+
newWidth = Math.max(150, startWidth + deltaX);
|
|
6808
|
+
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6809
|
+
newWidth = Math.min(newWidth, maxWidth);
|
|
6810
|
+
}
|
|
6811
|
+
if (resizeDirection.includes("w")) {
|
|
6812
|
+
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6813
|
+
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6814
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6815
|
+
if (proposedLeft >= videoWrapperLeft) {
|
|
6816
|
+
newWidth = proposedWidth;
|
|
6817
|
+
newLeft = proposedLeft;
|
|
6818
|
+
}
|
|
6819
|
+
}
|
|
6820
|
+
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6821
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6822
|
+
if (resizeDirection.includes("w")) {
|
|
6823
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6824
|
+
}
|
|
6825
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6826
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6827
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6828
|
+
}
|
|
6829
|
+
};
|
|
6830
|
+
const onMouseUp = () => {
|
|
6831
|
+
if (isDragging || isResizing) {
|
|
6832
|
+
this.saveSignLanguagePreferences();
|
|
6833
|
+
}
|
|
6834
|
+
isDragging = false;
|
|
6835
|
+
isResizing = false;
|
|
6836
|
+
resizeDirection = null;
|
|
6837
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6838
|
+
};
|
|
6839
|
+
const onKeyDown = (e) => {
|
|
6840
|
+
if (e.key === "d" || e.key === "D") {
|
|
6841
|
+
dragMode = !dragMode;
|
|
6842
|
+
resizeMode = false;
|
|
6843
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6844
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6845
|
+
e.preventDefault();
|
|
6846
|
+
return;
|
|
6847
|
+
}
|
|
6848
|
+
if (e.key === "r" || e.key === "R") {
|
|
6849
|
+
resizeMode = !resizeMode;
|
|
6850
|
+
dragMode = false;
|
|
6851
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6852
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6853
|
+
e.preventDefault();
|
|
6854
|
+
return;
|
|
6855
|
+
}
|
|
6856
|
+
if (e.key === "Escape") {
|
|
6857
|
+
dragMode = false;
|
|
6858
|
+
resizeMode = false;
|
|
6859
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6860
|
+
e.preventDefault();
|
|
6861
|
+
return;
|
|
6862
|
+
}
|
|
6863
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6864
|
+
const step = e.shiftKey ? 10 : 5;
|
|
6865
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6866
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6867
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6868
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6869
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6870
|
+
if (dragMode) {
|
|
6871
|
+
let left = rect.left - containerRect.left;
|
|
6872
|
+
let top = rect.top - containerRect.top;
|
|
6873
|
+
if (e.key === "ArrowLeft") left -= step;
|
|
6874
|
+
if (e.key === "ArrowRight") left += step;
|
|
6875
|
+
if (e.key === "ArrowUp") top -= step;
|
|
6876
|
+
if (e.key === "ArrowDown") top += step;
|
|
6877
|
+
const controlsHeight = 95;
|
|
6878
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6879
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6880
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6881
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6882
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6883
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6884
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6885
|
+
this.saveSignLanguagePreferences();
|
|
6886
|
+
e.preventDefault();
|
|
6887
|
+
} else if (resizeMode) {
|
|
6888
|
+
let width = rect.width;
|
|
6889
|
+
if (e.key === "ArrowLeft") width -= step;
|
|
6890
|
+
if (e.key === "ArrowRight") width += step;
|
|
6891
|
+
if (e.key === "ArrowUp") width += step;
|
|
6892
|
+
if (e.key === "ArrowDown") width -= step;
|
|
6893
|
+
width = Math.max(150, width);
|
|
6894
|
+
width = Math.min(width, videoWrapperRect.width);
|
|
6895
|
+
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6896
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6897
|
+
this.saveSignLanguagePreferences();
|
|
6898
|
+
e.preventDefault();
|
|
6899
|
+
}
|
|
6900
|
+
}
|
|
6901
|
+
};
|
|
6902
|
+
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6903
|
+
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6904
|
+
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6905
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
6906
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
6907
|
+
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
6908
|
+
this.signLanguageInteractionHandlers = {
|
|
6909
|
+
mouseDownVideo: onMouseDownVideo,
|
|
6910
|
+
mouseDownHandle: onMouseDownHandle,
|
|
6911
|
+
mouseMove: onMouseMove,
|
|
6912
|
+
mouseUp: onMouseUp,
|
|
6913
|
+
keyDown: onKeyDown,
|
|
6914
|
+
handles
|
|
6915
|
+
};
|
|
6916
|
+
}
|
|
6917
|
+
constrainSignLanguagePosition() {
|
|
6918
|
+
if (!this.signLanguageWrapper || !this.videoWrapper) return;
|
|
6919
|
+
if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === "") {
|
|
6920
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6921
|
+
}
|
|
6922
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6923
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6924
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6925
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6926
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6927
|
+
const videoWrapperWidth = videoWrapperRect.width;
|
|
6928
|
+
const videoWrapperHeight = videoWrapperRect.height;
|
|
6929
|
+
let wrapperWidth = wrapperRect.width || 280;
|
|
6930
|
+
let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
|
|
6931
|
+
let left, top;
|
|
6932
|
+
const margin = 16;
|
|
6933
|
+
const controlsHeight = 95;
|
|
6934
|
+
const position = this.signLanguageDesiredPosition || "bottom-right";
|
|
6935
|
+
switch (position) {
|
|
6936
|
+
case "bottom-right":
|
|
6937
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6938
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6939
|
+
break;
|
|
6940
|
+
case "bottom-left":
|
|
6941
|
+
left = videoWrapperLeft + margin;
|
|
6942
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6943
|
+
break;
|
|
6944
|
+
case "top-right":
|
|
6945
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6946
|
+
top = videoWrapperTop + margin;
|
|
6947
|
+
break;
|
|
6948
|
+
case "top-left":
|
|
6949
|
+
left = videoWrapperLeft + margin;
|
|
6950
|
+
top = videoWrapperTop + margin;
|
|
6951
|
+
break;
|
|
6952
|
+
default:
|
|
6953
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6954
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6955
|
+
}
|
|
6956
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
|
|
6957
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
|
|
6958
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6959
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6960
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6961
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6962
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6963
|
+
}
|
|
6964
|
+
saveSignLanguagePreferences() {
|
|
6965
|
+
if (!this.signLanguageWrapper) return;
|
|
6966
|
+
this.storage.saveSignLanguagePreferences({
|
|
6967
|
+
size: {
|
|
6968
|
+
width: this.signLanguageWrapper.style.width
|
|
6969
|
+
// Height is auto - maintained by aspect ratio
|
|
6970
|
+
}
|
|
6971
|
+
});
|
|
6972
|
+
}
|
|
4971
6973
|
cleanupSignLanguage() {
|
|
4972
6974
|
if (this.signLanguageHandlers) {
|
|
4973
6975
|
this.off("play", this.signLanguageHandlers.play);
|
|
@@ -4976,10 +6978,29 @@ var Player = class extends EventEmitter {
|
|
|
4976
6978
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
4977
6979
|
this.signLanguageHandlers = null;
|
|
4978
6980
|
}
|
|
4979
|
-
if (this.
|
|
4980
|
-
this.signLanguageVideo
|
|
4981
|
-
|
|
4982
|
-
|
|
6981
|
+
if (this.signLanguageInteractionHandlers) {
|
|
6982
|
+
if (this.signLanguageVideo) {
|
|
6983
|
+
this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
|
|
6984
|
+
}
|
|
6985
|
+
if (this.signLanguageInteractionHandlers.handles) {
|
|
6986
|
+
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
6987
|
+
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
6988
|
+
});
|
|
6989
|
+
}
|
|
6990
|
+
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
6991
|
+
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
6992
|
+
if (this.signLanguageWrapper) {
|
|
6993
|
+
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
6994
|
+
}
|
|
6995
|
+
this.signLanguageInteractionHandlers = null;
|
|
6996
|
+
}
|
|
6997
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
6998
|
+
if (this.signLanguageVideo) {
|
|
6999
|
+
this.signLanguageVideo.pause();
|
|
7000
|
+
this.signLanguageVideo.src = "";
|
|
7001
|
+
}
|
|
7002
|
+
this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
|
|
7003
|
+
this.signLanguageWrapper = null;
|
|
4983
7004
|
this.signLanguageVideo = null;
|
|
4984
7005
|
}
|
|
4985
7006
|
}
|
|
@@ -5082,6 +7103,16 @@ var Player = class extends EventEmitter {
|
|
|
5082
7103
|
if (this.controlBar) {
|
|
5083
7104
|
this.controlBar.updateFullscreenButton();
|
|
5084
7105
|
}
|
|
7106
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
7107
|
+
setTimeout(() => {
|
|
7108
|
+
requestAnimationFrame(() => {
|
|
7109
|
+
this.storage.saveSignLanguagePreferences({ size: null });
|
|
7110
|
+
this.signLanguageDesiredPosition = "bottom-right";
|
|
7111
|
+
this.signLanguageWrapper.style.width = isFullscreen ? "400px" : "280px";
|
|
7112
|
+
this.constrainSignLanguagePosition();
|
|
7113
|
+
});
|
|
7114
|
+
}, 500);
|
|
7115
|
+
}
|
|
5085
7116
|
}
|
|
5086
7117
|
};
|
|
5087
7118
|
document.addEventListener("fullscreenchange", this.fullscreenChangeHandler);
|