vidply 1.0.6 → 1.0.7

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.
@@ -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
- medium: "Medium",
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
- medium: "Mittel",
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
- medium: "Mediano",
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
- medium: "Moyen",
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
- medium: "\u4E2D",
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: `<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-7z"/><path d="M10.5 19c-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"/>`,
1112
- audioDescriptionOn: `<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-7z"/><path d="M10.5 19c-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"/><circle cx="19" cy="16" r="3" fill="#3b82f6"/><path d="M18.5 17.5l1-1 1.5 1.5" stroke="white" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`,
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
- return this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0;
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: "80%" },
2026
- { label: i18n.t("fontSizes.medium"), value: "100%" },
2027
- { label: i18n.t("fontSizes.large"), value: "120%" },
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(title);
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 transcriptTrack = textTracks.find(
3585
+ const captionTrack = textTracks.find(
3268
3586
  (track) => track.kind === "captions" || track.kind === "subtitles"
3269
3587
  );
3270
- if (!transcriptTrack) {
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
- if (transcriptTrack.mode === "disabled") {
3275
- transcriptTrack.mode = "hidden";
3276
- }
3277
- if (!transcriptTrack.cues || transcriptTrack.cues.length === 0) {
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
- this.loadTranscriptData();
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 cues = Array.from(transcriptTrack.cues);
3295
- cues.forEach((cue, index) => {
3296
- const entry = this.createTranscriptEntry(cue, index);
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
- startTime: cue.startTime,
3301
- endTime: cue.endTime
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 (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "Escape"].includes(e.key)) {
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
- this.hideTranscript();
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);
@@ -3572,10 +4002,602 @@ var TranscriptManager = class {
3572
4002
  this.transcriptWindow.style.top = "50%";
3573
4003
  this.transcriptWindow.style.transform = "translate(-50%, -50%)";
3574
4004
  }
4005
+ /**
4006
+ * Toggle keyboard drag mode
4007
+ */
4008
+ toggleKeyboardDragMode() {
4009
+ if (this.keyboardDragMode) {
4010
+ this.disableKeyboardDragMode();
4011
+ } else {
4012
+ this.enableKeyboardDragMode();
4013
+ }
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.");
4023
+ }
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();
4031
+ }
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");
4042
+ }
4043
+ const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
4044
+ if (indicator) {
4045
+ indicator.remove();
4046
+ }
4047
+ if (this.settingsButton) {
4048
+ this.settingsButton.focus();
4049
+ }
4050
+ }
4051
+ /**
4052
+ * Toggle settings menu visibility
4053
+ */
4054
+ toggleSettingsMenu() {
4055
+ if (this.settingsMenuVisible) {
4056
+ this.hideSettingsMenu();
4057
+ } else {
4058
+ this.showSettingsMenu();
4059
+ }
4060
+ }
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);
4074
+ }
4075
+ if (this.settingsMenu) {
4076
+ this.settingsMenu.style.display = "block";
4077
+ this.settingsMenuVisible = true;
4078
+ return;
4079
+ }
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")
4088
+ }
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
+ }
3575
4591
  /**
3576
4592
  * Cleanup
3577
4593
  */
3578
4594
  destroy() {
4595
+ if (this.resizeEnabled) {
4596
+ this.disableResizeHandles();
4597
+ }
4598
+ if (this.keyboardDragMode) {
4599
+ this.disableKeyboardDragMode();
4600
+ }
3579
4601
  if (this.handlers.timeupdate) {
3580
4602
  this.player.off("timeupdate", this.handlers.timeupdate);
3581
4603
  }
@@ -3590,6 +4612,17 @@ var TranscriptManager = class {
3590
4612
  this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
3591
4613
  }
3592
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
+ }
3593
4626
  if (this.handlers.mousemove) {
3594
4627
  document.removeEventListener("mousemove", this.handlers.mousemove);
3595
4628
  }
@@ -3602,6 +4635,9 @@ var TranscriptManager = class {
3602
4635
  if (this.handlers.touchend) {
3603
4636
  document.removeEventListener("touchend", this.handlers.touchend);
3604
4637
  }
4638
+ if (this.handlers.documentClick) {
4639
+ document.removeEventListener("click", this.handlers.documentClick);
4640
+ }
3605
4641
  if (this.handlers.resize) {
3606
4642
  window.removeEventListener("resize", this.handlers.resize);
3607
4643
  }
@@ -3613,6 +4649,8 @@ var TranscriptManager = class {
3613
4649
  this.transcriptHeader = null;
3614
4650
  this.transcriptContent = null;
3615
4651
  this.transcriptEntries = [];
4652
+ this.settingsMenu = null;
4653
+ this.styleDialog = null;
3616
4654
  }
3617
4655
  };
3618
4656
 
@@ -4330,7 +5368,7 @@ var Player = class extends EventEmitter {
4330
5368
  captionsButton: true,
4331
5369
  transcriptButton: true,
4332
5370
  fullscreenButton: true,
4333
- pipButton: true,
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,
@@ -4734,6 +5779,7 @@ var Player = class extends EventEmitter {
4734
5779
  if (newVolume > 0 && this.state.muted) {
4735
5780
  this.state.muted = false;
4736
5781
  }
5782
+ this.savePlayerPreferences();
4737
5783
  }
4738
5784
  getVolume() {
4739
5785
  return this.state.volume;
@@ -4743,6 +5789,7 @@ var Player = class extends EventEmitter {
4743
5789
  this.renderer.setMuted(true);
4744
5790
  }
4745
5791
  this.state.muted = true;
5792
+ this.savePlayerPreferences();
4746
5793
  this.emit("volumechange");
4747
5794
  }
4748
5795
  unmute() {
@@ -4750,6 +5797,7 @@ var Player = class extends EventEmitter {
4750
5797
  this.renderer.setMuted(false);
4751
5798
  }
4752
5799
  this.state.muted = false;
5800
+ this.savePlayerPreferences();
4753
5801
  this.emit("volumechange");
4754
5802
  }
4755
5803
  toggleMute() {
@@ -4766,11 +5814,20 @@ var Player = class extends EventEmitter {
4766
5814
  this.renderer.setPlaybackSpeed(newSpeed);
4767
5815
  }
4768
5816
  this.state.playbackSpeed = newSpeed;
5817
+ this.savePlayerPreferences();
4769
5818
  this.emit("playbackspeedchange", newSpeed);
4770
5819
  }
4771
5820
  getPlaybackSpeed() {
4772
5821
  return this.state.playbackSpeed;
4773
5822
  }
5823
+ // Save player preferences to localStorage
5824
+ savePlayerPreferences() {
5825
+ this.storage.savePlayerPreferences({
5826
+ volume: this.state.volume,
5827
+ muted: this.state.muted,
5828
+ playbackSpeed: this.state.playbackSpeed
5829
+ });
5830
+ }
4774
5831
  // Fullscreen
4775
5832
  enterFullscreen() {
4776
5833
  const elem = this.container;
@@ -4895,10 +5952,24 @@ var Player = class extends EventEmitter {
4895
5952
  this.emit("audiodescriptiondisabled");
4896
5953
  }
4897
5954
  async toggleAudioDescription() {
4898
- if (this.state.audioDescriptionEnabled) {
4899
- await this.disableAudioDescription();
4900
- } else {
4901
- await this.enableAudioDescription();
5955
+ const textTracks = Array.from(this.element.textTracks || []);
5956
+ const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
5957
+ if (descriptionTrack) {
5958
+ if (descriptionTrack.mode === "showing") {
5959
+ descriptionTrack.mode = "hidden";
5960
+ this.state.audioDescriptionEnabled = false;
5961
+ this.emit("audiodescriptiondisabled");
5962
+ } else {
5963
+ descriptionTrack.mode = "showing";
5964
+ this.state.audioDescriptionEnabled = true;
5965
+ this.emit("audiodescriptionenabled");
5966
+ }
5967
+ } else if (this.audioDescriptionSrc) {
5968
+ if (this.state.audioDescriptionEnabled) {
5969
+ await this.disableAudioDescription();
5970
+ } else {
5971
+ await this.enableAudioDescription();
5972
+ }
4902
5973
  }
4903
5974
  }
4904
5975
  // Sign Language
@@ -4907,24 +5978,47 @@ var Player = class extends EventEmitter {
4907
5978
  console.warn("No sign language video source provided");
4908
5979
  return;
4909
5980
  }
4910
- if (this.signLanguageVideo) {
4911
- this.signLanguageVideo.style.display = "block";
5981
+ if (this.signLanguageWrapper) {
5982
+ this.signLanguageWrapper.style.display = "block";
4912
5983
  this.state.signLanguageEnabled = true;
4913
5984
  this.emit("signlanguageenabled");
4914
5985
  return;
4915
5986
  }
5987
+ this.signLanguageWrapper = document.createElement("div");
5988
+ this.signLanguageWrapper.className = "vidply-sign-language-wrapper";
5989
+ this.signLanguageWrapper.setAttribute("tabindex", "0");
5990
+ this.signLanguageWrapper.setAttribute("aria-label", "Sign Language Video - Press D to drag with keyboard, R to resize");
4916
5991
  this.signLanguageVideo = document.createElement("video");
4917
5992
  this.signLanguageVideo.className = "vidply-sign-language-video";
4918
5993
  this.signLanguageVideo.src = this.signLanguageSrc;
4919
5994
  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
5995
  this.signLanguageVideo.muted = true;
5996
+ const resizeHandles = ["nw", "ne", "sw", "se"].map((dir) => {
5997
+ const handle = document.createElement("div");
5998
+ handle.className = `vidply-sign-resize-handle vidply-sign-resize-${dir}`;
5999
+ handle.setAttribute("data-direction", dir);
6000
+ handle.setAttribute("aria-label", `Resize ${dir.toUpperCase()}`);
6001
+ return handle;
6002
+ });
6003
+ this.signLanguageWrapper.appendChild(this.signLanguageVideo);
6004
+ resizeHandles.forEach((handle) => this.signLanguageWrapper.appendChild(handle));
6005
+ const saved = this.storage.getSignLanguagePreferences();
6006
+ if (saved && saved.size && saved.size.width) {
6007
+ this.signLanguageWrapper.style.width = saved.size.width;
6008
+ } else {
6009
+ this.signLanguageWrapper.style.width = "280px";
6010
+ }
6011
+ this.signLanguageWrapper.style.height = "auto";
6012
+ this.signLanguageDesiredPosition = this.options.signLanguagePosition || "bottom-right";
6013
+ this.container.appendChild(this.signLanguageWrapper);
6014
+ requestAnimationFrame(() => {
6015
+ this.constrainSignLanguagePosition();
6016
+ });
4923
6017
  this.signLanguageVideo.currentTime = this.state.currentTime;
4924
6018
  if (!this.state.paused) {
4925
6019
  this.signLanguageVideo.play();
4926
6020
  }
4927
- this.videoWrapper.appendChild(this.signLanguageVideo);
6021
+ this.setupSignLanguageInteraction();
4928
6022
  this.signLanguageHandlers = {
4929
6023
  play: () => {
4930
6024
  if (this.signLanguageVideo) {
@@ -4955,8 +6049,8 @@ var Player = class extends EventEmitter {
4955
6049
  this.emit("signlanguageenabled");
4956
6050
  }
4957
6051
  disableSignLanguage() {
4958
- if (this.signLanguageVideo) {
4959
- this.signLanguageVideo.style.display = "none";
6052
+ if (this.signLanguageWrapper) {
6053
+ this.signLanguageWrapper.style.display = "none";
4960
6054
  }
4961
6055
  this.state.signLanguageEnabled = false;
4962
6056
  this.emit("signlanguagedisabled");
@@ -4968,6 +6062,237 @@ var Player = class extends EventEmitter {
4968
6062
  this.enableSignLanguage();
4969
6063
  }
4970
6064
  }
6065
+ setupSignLanguageInteraction() {
6066
+ if (!this.signLanguageWrapper) return;
6067
+ let isDragging = false;
6068
+ let isResizing = false;
6069
+ let resizeDirection = null;
6070
+ let startX = 0;
6071
+ let startY = 0;
6072
+ let startLeft = 0;
6073
+ let startTop = 0;
6074
+ let startWidth = 0;
6075
+ let startHeight = 0;
6076
+ let dragMode = false;
6077
+ let resizeMode = false;
6078
+ const onMouseDownVideo = (e) => {
6079
+ if (e.target !== this.signLanguageVideo) return;
6080
+ e.preventDefault();
6081
+ isDragging = true;
6082
+ startX = e.clientX;
6083
+ startY = e.clientY;
6084
+ const rect = this.signLanguageWrapper.getBoundingClientRect();
6085
+ startLeft = rect.left;
6086
+ startTop = rect.top;
6087
+ this.signLanguageWrapper.classList.add("vidply-sign-dragging");
6088
+ };
6089
+ const onMouseDownHandle = (e) => {
6090
+ if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
6091
+ e.preventDefault();
6092
+ e.stopPropagation();
6093
+ isResizing = true;
6094
+ resizeDirection = e.target.getAttribute("data-direction");
6095
+ startX = e.clientX;
6096
+ startY = e.clientY;
6097
+ const rect = this.signLanguageWrapper.getBoundingClientRect();
6098
+ startLeft = rect.left;
6099
+ startTop = rect.top;
6100
+ startWidth = rect.width;
6101
+ startHeight = rect.height;
6102
+ this.signLanguageWrapper.classList.add("vidply-sign-resizing");
6103
+ };
6104
+ const onMouseMove = (e) => {
6105
+ if (isDragging) {
6106
+ const deltaX = e.clientX - startX;
6107
+ const deltaY = e.clientY - startY;
6108
+ const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
6109
+ const containerRect = this.container.getBoundingClientRect();
6110
+ const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
6111
+ const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
6112
+ const videoWrapperTop = videoWrapperRect.top - containerRect.top;
6113
+ let newLeft = startLeft + deltaX - containerRect.left;
6114
+ let newTop = startTop + deltaY - containerRect.top;
6115
+ const controlsHeight = 95;
6116
+ newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
6117
+ newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
6118
+ this.signLanguageWrapper.style.left = `${newLeft}px`;
6119
+ this.signLanguageWrapper.style.top = `${newTop}px`;
6120
+ this.signLanguageWrapper.style.right = "auto";
6121
+ this.signLanguageWrapper.style.bottom = "auto";
6122
+ this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
6123
+ } else if (isResizing) {
6124
+ const deltaX = e.clientX - startX;
6125
+ const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
6126
+ const containerRect = this.container.getBoundingClientRect();
6127
+ let newWidth = startWidth;
6128
+ let newLeft = startLeft - containerRect.left;
6129
+ if (resizeDirection.includes("e")) {
6130
+ newWidth = Math.max(150, startWidth + deltaX);
6131
+ const maxWidth = videoWrapperRect.right - startLeft;
6132
+ newWidth = Math.min(newWidth, maxWidth);
6133
+ }
6134
+ if (resizeDirection.includes("w")) {
6135
+ const proposedWidth = Math.max(150, startWidth - deltaX);
6136
+ const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
6137
+ const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
6138
+ if (proposedLeft >= videoWrapperLeft) {
6139
+ newWidth = proposedWidth;
6140
+ newLeft = proposedLeft;
6141
+ }
6142
+ }
6143
+ this.signLanguageWrapper.style.width = `${newWidth}px`;
6144
+ this.signLanguageWrapper.style.height = "auto";
6145
+ if (resizeDirection.includes("w")) {
6146
+ this.signLanguageWrapper.style.left = `${newLeft}px`;
6147
+ }
6148
+ this.signLanguageWrapper.style.right = "auto";
6149
+ this.signLanguageWrapper.style.bottom = "auto";
6150
+ this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
6151
+ }
6152
+ };
6153
+ const onMouseUp = () => {
6154
+ if (isDragging || isResizing) {
6155
+ this.saveSignLanguagePreferences();
6156
+ }
6157
+ isDragging = false;
6158
+ isResizing = false;
6159
+ resizeDirection = null;
6160
+ this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
6161
+ };
6162
+ const onKeyDown = (e) => {
6163
+ if (e.key === "d" || e.key === "D") {
6164
+ dragMode = !dragMode;
6165
+ resizeMode = false;
6166
+ this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
6167
+ this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
6168
+ e.preventDefault();
6169
+ return;
6170
+ }
6171
+ if (e.key === "r" || e.key === "R") {
6172
+ resizeMode = !resizeMode;
6173
+ dragMode = false;
6174
+ this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
6175
+ this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
6176
+ e.preventDefault();
6177
+ return;
6178
+ }
6179
+ if (e.key === "Escape") {
6180
+ dragMode = false;
6181
+ resizeMode = false;
6182
+ this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
6183
+ e.preventDefault();
6184
+ return;
6185
+ }
6186
+ if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
6187
+ const step = e.shiftKey ? 10 : 5;
6188
+ const rect = this.signLanguageWrapper.getBoundingClientRect();
6189
+ const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
6190
+ const containerRect = this.container.getBoundingClientRect();
6191
+ const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
6192
+ const videoWrapperTop = videoWrapperRect.top - containerRect.top;
6193
+ if (dragMode) {
6194
+ let left = rect.left - containerRect.left;
6195
+ let top = rect.top - containerRect.top;
6196
+ if (e.key === "ArrowLeft") left -= step;
6197
+ if (e.key === "ArrowRight") left += step;
6198
+ if (e.key === "ArrowUp") top -= step;
6199
+ if (e.key === "ArrowDown") top += step;
6200
+ const controlsHeight = 95;
6201
+ left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
6202
+ top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
6203
+ this.signLanguageWrapper.style.left = `${left}px`;
6204
+ this.signLanguageWrapper.style.top = `${top}px`;
6205
+ this.signLanguageWrapper.style.right = "auto";
6206
+ this.signLanguageWrapper.style.bottom = "auto";
6207
+ this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
6208
+ this.saveSignLanguagePreferences();
6209
+ e.preventDefault();
6210
+ } else if (resizeMode) {
6211
+ let width = rect.width;
6212
+ if (e.key === "ArrowLeft") width -= step;
6213
+ if (e.key === "ArrowRight") width += step;
6214
+ if (e.key === "ArrowUp") width += step;
6215
+ if (e.key === "ArrowDown") width -= step;
6216
+ width = Math.max(150, width);
6217
+ width = Math.min(width, videoWrapperRect.width);
6218
+ this.signLanguageWrapper.style.width = `${width}px`;
6219
+ this.signLanguageWrapper.style.height = "auto";
6220
+ this.saveSignLanguagePreferences();
6221
+ e.preventDefault();
6222
+ }
6223
+ }
6224
+ };
6225
+ this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
6226
+ const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
6227
+ handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
6228
+ document.addEventListener("mousemove", onMouseMove);
6229
+ document.addEventListener("mouseup", onMouseUp);
6230
+ this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
6231
+ this.signLanguageInteractionHandlers = {
6232
+ mouseDownVideo: onMouseDownVideo,
6233
+ mouseDownHandle: onMouseDownHandle,
6234
+ mouseMove: onMouseMove,
6235
+ mouseUp: onMouseUp,
6236
+ keyDown: onKeyDown,
6237
+ handles
6238
+ };
6239
+ }
6240
+ constrainSignLanguagePosition() {
6241
+ if (!this.signLanguageWrapper || !this.videoWrapper) return;
6242
+ if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === "") {
6243
+ this.signLanguageWrapper.style.width = "280px";
6244
+ }
6245
+ const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
6246
+ const containerRect = this.container.getBoundingClientRect();
6247
+ const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
6248
+ const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
6249
+ const videoWrapperTop = videoWrapperRect.top - containerRect.top;
6250
+ const videoWrapperWidth = videoWrapperRect.width;
6251
+ const videoWrapperHeight = videoWrapperRect.height;
6252
+ let wrapperWidth = wrapperRect.width || 280;
6253
+ let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
6254
+ let left, top;
6255
+ const margin = 16;
6256
+ const controlsHeight = 95;
6257
+ const position = this.signLanguageDesiredPosition || "bottom-right";
6258
+ switch (position) {
6259
+ case "bottom-right":
6260
+ left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
6261
+ top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
6262
+ break;
6263
+ case "bottom-left":
6264
+ left = videoWrapperLeft + margin;
6265
+ top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
6266
+ break;
6267
+ case "top-right":
6268
+ left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
6269
+ top = videoWrapperTop + margin;
6270
+ break;
6271
+ case "top-left":
6272
+ left = videoWrapperLeft + margin;
6273
+ top = videoWrapperTop + margin;
6274
+ break;
6275
+ default:
6276
+ left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
6277
+ top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
6278
+ }
6279
+ left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
6280
+ top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
6281
+ this.signLanguageWrapper.style.left = `${left}px`;
6282
+ this.signLanguageWrapper.style.top = `${top}px`;
6283
+ this.signLanguageWrapper.style.right = "auto";
6284
+ this.signLanguageWrapper.style.bottom = "auto";
6285
+ this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
6286
+ }
6287
+ saveSignLanguagePreferences() {
6288
+ if (!this.signLanguageWrapper) return;
6289
+ this.storage.saveSignLanguagePreferences({
6290
+ size: {
6291
+ width: this.signLanguageWrapper.style.width
6292
+ // Height is auto - maintained by aspect ratio
6293
+ }
6294
+ });
6295
+ }
4971
6296
  cleanupSignLanguage() {
4972
6297
  if (this.signLanguageHandlers) {
4973
6298
  this.off("play", this.signLanguageHandlers.play);
@@ -4976,10 +6301,29 @@ var Player = class extends EventEmitter {
4976
6301
  this.off("ratechange", this.signLanguageHandlers.ratechange);
4977
6302
  this.signLanguageHandlers = null;
4978
6303
  }
4979
- if (this.signLanguageVideo && this.signLanguageVideo.parentNode) {
4980
- this.signLanguageVideo.pause();
4981
- this.signLanguageVideo.src = "";
4982
- this.signLanguageVideo.parentNode.removeChild(this.signLanguageVideo);
6304
+ if (this.signLanguageInteractionHandlers) {
6305
+ if (this.signLanguageVideo) {
6306
+ this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
6307
+ }
6308
+ if (this.signLanguageInteractionHandlers.handles) {
6309
+ this.signLanguageInteractionHandlers.handles.forEach((handle) => {
6310
+ handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
6311
+ });
6312
+ }
6313
+ document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
6314
+ document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
6315
+ if (this.signLanguageWrapper) {
6316
+ this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
6317
+ }
6318
+ this.signLanguageInteractionHandlers = null;
6319
+ }
6320
+ if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
6321
+ if (this.signLanguageVideo) {
6322
+ this.signLanguageVideo.pause();
6323
+ this.signLanguageVideo.src = "";
6324
+ }
6325
+ this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
6326
+ this.signLanguageWrapper = null;
4983
6327
  this.signLanguageVideo = null;
4984
6328
  }
4985
6329
  }
@@ -5082,6 +6426,16 @@ var Player = class extends EventEmitter {
5082
6426
  if (this.controlBar) {
5083
6427
  this.controlBar.updateFullscreenButton();
5084
6428
  }
6429
+ if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
6430
+ setTimeout(() => {
6431
+ requestAnimationFrame(() => {
6432
+ this.storage.saveSignLanguagePreferences({ size: null });
6433
+ this.signLanguageDesiredPosition = "bottom-right";
6434
+ this.signLanguageWrapper.style.width = isFullscreen ? "400px" : "280px";
6435
+ this.constrainSignLanguagePosition();
6436
+ });
6437
+ }, 500);
6438
+ }
5085
6439
  }
5086
6440
  };
5087
6441
  document.addEventListener("fullscreenchange", this.fullscreenChangeHandler);