vidply 1.2.0 → 1.2.1

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.
Files changed (164) hide show
  1. package/README.md +946 -946
  2. package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-6RFVF27Z.js} +275 -19
  3. package/dist/dev/vidply.AudioDescriptionManager-6RFVF27Z.js.map +7 -0
  4. package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-R2SCQ6VP.js} +4 -4
  5. package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-EOVEW73H.js} +3 -3
  6. package/dist/dev/vidply.DASHRenderer-EOVEW73H.js.map +7 -0
  7. package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-V5XQWS75.js} +5 -5
  8. package/dist/dev/vidply.FloatingPlayerManager-V5XQWS75.js.map +7 -0
  9. package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZBEFVH5W.js} +4 -4
  10. package/dist/dev/vidply.HLSRenderer-ZBEFVH5W.js.map +7 -0
  11. package/dist/dev/vidply.HTML5Renderer-P7ICKYU4.js +12 -0
  12. package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-7IAJOVF6.js} +8 -8
  13. package/dist/dev/vidply.SignLanguageManager-7IAJOVF6.js.map +7 -0
  14. package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-OA7QQYGN.js} +3 -3
  15. package/dist/dev/vidply.SoundCloudRenderer-OA7QQYGN.js.map +7 -0
  16. package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-BPM3T23L.js} +10 -10
  17. package/dist/dev/vidply.TranscriptManager-BPM3T23L.js.map +7 -0
  18. package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-BRHFYPNJ.js} +3 -3
  19. package/dist/dev/vidply.VimeoRenderer-BRHFYPNJ.js.map +7 -0
  20. package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-HRTN4EJ5.js} +3 -3
  21. package/dist/dev/vidply.YouTubeRenderer-HRTN4EJ5.js.map +7 -0
  22. package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-5IK3IC5V.js} +2 -2
  23. package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-C55OBT5H.js} +2 -2
  24. package/dist/dev/vidply.chunk-C55OBT5H.js.map +7 -0
  25. package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-HOYEMJSD.js} +2 -2
  26. package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-JAKZNGOR.js} +2 -2
  27. package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-LDVFAFGC.js} +5 -5
  28. package/dist/dev/vidply.chunk-LDVFAFGC.js.map +7 -0
  29. package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-NSMAZCMB.js} +6 -6
  30. package/dist/dev/vidply.chunk-NSMAZCMB.js.map +7 -0
  31. package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-RQG3MA7W.js} +2 -2
  32. package/dist/dev/vidply.chunk-RQG3MA7W.js.map +7 -0
  33. package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-UHMVDBDB.js} +3 -3
  34. package/dist/dev/vidply.chunk-UHMVDBDB.js.map +7 -0
  35. package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-W5BR65JY.js} +6 -6
  36. package/dist/dev/vidply.chunk-W5BR65JY.js.map +7 -0
  37. package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-XAK3DPTO.js} +2 -2
  38. package/dist/dev/vidply.chunk-XAK3DPTO.js.map +7 -0
  39. package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-YVCYQZJI.js} +3 -3
  40. package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-5W5LBFSJ.js} +2 -2
  41. package/dist/dev/vidply.de-5W5LBFSJ.js.map +7 -0
  42. package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-SHDAT6L6.js} +2 -2
  43. package/dist/dev/vidply.es-SHDAT6L6.js.map +7 -0
  44. package/dist/dev/vidply.esm.js +73 -34
  45. package/dist/dev/vidply.esm.js.map +2 -2
  46. package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-2JANOMNB.js} +2 -2
  47. package/dist/dev/vidply.fr-2JANOMNB.js.map +7 -0
  48. package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-WWMSTEJH.js} +2 -2
  49. package/dist/dev/vidply.ja-WWMSTEJH.js.map +7 -0
  50. package/dist/legacy/vidply.js +345 -32
  51. package/dist/legacy/vidply.js.map +3 -3
  52. package/dist/legacy/vidply.min.js +2 -2
  53. package/dist/legacy/vidply.min.meta.json +66 -47
  54. package/dist/prod/vidply.AudioDescriptionManager-YTDVDQBO.min.js +6 -0
  55. package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-2AFF3HF2.min.js} +2 -2
  56. package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-URDOTOKS.min.js} +2 -2
  57. package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-QUBFK7CQ.min.js} +2 -2
  58. package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-46KNUVAB.min.js} +2 -2
  59. package/dist/prod/vidply.HTML5Renderer-7TQDMIGY.min.js +6 -0
  60. package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-H4C36EVL.min.js} +2 -2
  61. package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-OYSWMW7D.min.js} +2 -2
  62. package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-BA3DAS63.min.js} +2 -2
  63. package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-NF3COTHU.min.js} +2 -2
  64. package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-UCQKYIJ4.min.js} +2 -2
  65. package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-2HNCP64N.min.js} +1 -1
  66. package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-6ECBIYVI.min.js} +2 -2
  67. package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-7S5AFTST.min.js} +2 -2
  68. package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-EUOA2DJK.min.js} +1 -1
  69. package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-G6KGXNEW.min.js} +1 -1
  70. package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-JPMAK3NS.min.js} +1 -1
  71. package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-L4O44K63.min.js} +1 -1
  72. package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-M76ABMKB.min.js} +1 -1
  73. package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-WRVDVD33.min.js} +2 -2
  74. package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-X2FQEQYR.min.js} +2 -2
  75. package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-XXUH7ADU.min.js} +2 -2
  76. package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-JMCATTKZ.min.js} +1 -1
  77. package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-YVG37V7Z.min.js} +1 -1
  78. package/dist/prod/vidply.esm.min.js +2 -2
  79. package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-OGKGN2R4.min.js} +1 -1
  80. package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-Z6DS7QLS.min.js} +1 -1
  81. package/dist/vidply.css +5796 -5796
  82. package/dist/vidply.esm.min.meta.json +148 -135
  83. package/package.json +7 -7
  84. package/src/controls/CaptionManager.ts +598 -598
  85. package/src/controls/ControlBar.ts +4159 -4159
  86. package/src/controls/KeyboardManager.ts +383 -383
  87. package/src/controls/SettingsDialog.ts +488 -488
  88. package/src/controls/TranscriptManager.ts +2426 -2426
  89. package/src/core/AudioDescriptionManager.ts +863 -774
  90. package/src/core/DescriptionSpeechManager.ts +232 -0
  91. package/src/core/FloatingPlayerManager.ts +674 -674
  92. package/src/core/LazyInit.ts +80 -80
  93. package/src/core/MetadataAlertsManager.ts +514 -514
  94. package/src/core/Player.ts +2915 -2872
  95. package/src/core/PosterManager.ts +169 -169
  96. package/src/core/PseudoFullscreen.ts +179 -179
  97. package/src/core/ResponsiveManager.ts +231 -231
  98. package/src/core/ResumeManager.ts +236 -236
  99. package/src/core/SignLanguageManager.ts +1308 -1308
  100. package/src/core/ThemeManager.ts +157 -157
  101. package/src/features/PlaylistManager.ts +1838 -1827
  102. package/src/i18n/i18n.ts +223 -223
  103. package/src/i18n/languages/de.ts +217 -217
  104. package/src/i18n/languages/en.ts +218 -218
  105. package/src/i18n/languages/es.ts +214 -214
  106. package/src/i18n/languages/fr.ts +214 -214
  107. package/src/i18n/languages/ja.ts +214 -214
  108. package/src/icons/Icons.ts +167 -167
  109. package/src/index.ts +196 -193
  110. package/src/renderers/DASHRenderer.ts +1077 -1077
  111. package/src/renderers/HLSRenderer.ts +944 -944
  112. package/src/renderers/HTML5Renderer.ts +389 -389
  113. package/src/renderers/SoundCloudRenderer.ts +437 -437
  114. package/src/renderers/VimeoRenderer.ts +298 -298
  115. package/src/renderers/YouTubeRenderer.ts +290 -290
  116. package/src/styles/vidply.css +5796 -5796
  117. package/src/types/events.ts +124 -122
  118. package/src/types/globals.d.ts +313 -313
  119. package/src/types/options.ts +185 -182
  120. package/src/types/renderer.ts +58 -58
  121. package/src/utils/DOMUtils.ts +281 -281
  122. package/src/utils/DownloadInfo.ts +171 -171
  123. package/src/utils/DraggablePanel.ts +539 -539
  124. package/src/utils/DraggablePanelMenu.ts +195 -195
  125. package/src/utils/DraggableResizable.ts +997 -997
  126. package/src/utils/EventEmitter.ts +59 -59
  127. package/src/utils/FormUtils.ts +95 -95
  128. package/src/utils/MenuFactory.ts +483 -483
  129. package/src/utils/Sanitize.ts +70 -70
  130. package/src/utils/SettingsMenuFactory.ts +289 -289
  131. package/src/utils/StorageManager.ts +287 -287
  132. package/src/utils/TrackLabelUtils.ts +52 -52
  133. package/src/utils/UrlSafe.ts +69 -69
  134. package/src/utils/VideoFrameCapture.ts +114 -114
  135. package/src/utils/WindowComponents.ts +250 -250
  136. package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
  137. package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
  138. package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
  139. package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
  140. package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
  141. package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
  142. package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
  143. package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
  144. package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
  145. package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
  146. package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
  147. package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
  148. package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
  149. package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
  150. package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
  151. package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
  152. package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
  153. package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
  154. package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
  155. package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
  156. package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
  157. package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
  158. package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
  159. /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-R2SCQ6VP.js.map} +0 -0
  160. /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-P7ICKYU4.js.map} +0 -0
  161. /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-5IK3IC5V.js.map} +0 -0
  162. /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-HOYEMJSD.js.map} +0 -0
  163. /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-JAKZNGOR.js.map} +0 -0
  164. /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-YVCYQZJI.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/SignLanguageManager.ts"],
4
+ "sourcesContent": ["/**\n * Sign Language Video Manager\n * Handles picture-in-picture sign language video overlay\n */\n\nimport { DOMUtils } from '../utils/DOMUtils.js';\nimport { createIconElement } from '../icons/Icons.js';\nimport { i18n } from '../i18n/i18n.js';\nimport { DraggableResizable } from '../utils/DraggableResizable.js';\nimport { createLabeledSelect, preventDragOnElement } from '../utils/FormUtils.js';\nimport { DraggablePanel } from '../utils/DraggablePanel.js';\nimport type { Player } from './Player.js';\n\n/**\n * Bag of player-event handlers the sign-language overlay binds to so it\n * can mirror the main player's playback state.\n */\ninterface SignLanguageHandlers {\n play: () => void;\n pause: () => void;\n timeupdate: () => void;\n ratechange: () => void;\n captionChange?: () => void;\n}\n\ninterface SignLanguageSettingsHandlers {\n click: (e: MouseEvent) => void;\n keydown: (e: KeyboardEvent) => void;\n}\n\ninterface SignLanguageInteractionHandlers {\n draggable: DraggableResizable | null;\n customKeyHandler: ((e: KeyboardEvent) => void) | null;\n}\n\nexport class SignLanguageManager {\n player: Player;\n _mainViewMutedBefore: boolean;\n _mainViewUsingSourceSwap: boolean;\n currentLanguage: string | null;\n customKeyHandler: ((e: KeyboardEvent) => void) | null;\n desiredPosition: string;\n draggable: DraggableResizable | null;\n handlers: SignLanguageHandlers | null;\n header: HTMLElement | null;\n inMainView: boolean;\n interactionHandlers: SignLanguageInteractionHandlers | null;\n mainViewOriginalSources: HTMLSourceElement[] | null;\n mainViewOriginalSrc: string | null;\n resizeHandles: HTMLElement[];\n selector: HTMLSelectElement | null;\n settingsButton: HTMLButtonElement | null;\n settingsHandlers: SignLanguageSettingsHandlers | null;\n sources: Record<string, string>;\n src: string | null;\n enabled: boolean;\n video: HTMLVideoElement | null;\n wrapper: HTMLElement | null;\n\n /**\n * Encapsulates the settings-menu DOM, lifecycle (show/hide/outside-\n * click/keyboard nav/positioning), and the drag/resize toggle items.\n * Owned here but lazily created once {@link _setupSettingsButton}\n * instantiates the button it needs to anchor from.\n */\n private _panel: DraggablePanel | null = null;\n\n // Back-compat getters for external callers (Player.ts exposes these\n // under `signLanguageSettingsMenu` / `signLanguageSettingsMenuVisible`)\n // and for internal readers of the shared menu-item state (which is now\n // panel-owned). Setters are no-ops by design — the panel is the\n // authoritative owner of these values.\n get settingsMenu(): HTMLElement | null {\n return this._panel?.settingsMenu ?? null;\n }\n set settingsMenu(_v: HTMLElement | null) {\n // panel-owned; ignored to keep legacy API surface inert.\n }\n\n get settingsMenuVisible(): boolean {\n return this._panel?.settingsMenuVisible ?? false;\n }\n set settingsMenuVisible(_v: boolean) {\n // panel-owned.\n }\n\n get settingsMenuJustOpened(): boolean {\n return this._panel?.justOpened ?? false;\n }\n set settingsMenuJustOpened(_v: boolean) {\n // panel-owned.\n }\n\n get dragOptionButton(): HTMLElement | null {\n return this._panel?.dragOptionButton ?? null;\n }\n get dragOptionText(): Element | null {\n return this._panel?.dragOptionText ?? null;\n }\n get resizeOptionButton(): HTMLElement | null {\n return this._panel?.resizeOptionButton ?? null;\n }\n get resizeOptionText(): Element | null {\n return this._panel?.resizeOptionText ?? null;\n }\n\n constructor(player: Player) {\n this.player = player;\n \n // Sources\n this.src = player.options.signLanguageSrc;\n this.sources = player.options.signLanguageSources || {};\n this.currentLanguage = null;\n this.desiredPosition = player.options.signLanguagePosition || 'bottom-right';\n \n // DOM elements\n this.wrapper = null;\n this.header = null;\n this.video = null;\n this.selector = null;\n this.settingsButton = null;\n this.resizeHandles = [];\n \n // State\n this.enabled = false;\n this.inMainView = false; // sign language shown in main video (src swap, like audio description)\n this.mainViewOriginalSrc = null;\n this.mainViewOriginalSources = null;\n this._mainViewUsingSourceSwap = false;\n this._mainViewMutedBefore = false;\n \n // Handlers\n this.handlers = null;\n this.settingsHandlers = null;\n this.interactionHandlers = null;\n this.draggable = null;\n this.customKeyHandler = null;\n }\n\n /**\n * Check if sign language is available\n */\n isAvailable() {\n return Object.keys(this.sources).length > 0 || Boolean(this.src);\n }\n\n /**\n * Enable sign language video\n */\n enable() {\n const hasMultipleSources = Object.keys(this.sources).length > 0;\n const hasSingleSource = Boolean(this.src);\n \n if (!hasMultipleSources && !hasSingleSource) {\n console.warn('No sign language video source provided');\n return;\n }\n\n if (this.wrapper) {\n // Already exists, just show it\n this.wrapper.style.display = 'block';\n this.enabled = true;\n this.player.state.signLanguageEnabled = true;\n this.player.emit('signlanguageenabled');\n \n // Focus settings button\n this.player.setManagedTimeout(() => {\n if (this.settingsButton && document.contains(this.settingsButton)) {\n this.settingsButton.focus({ preventScroll: true });\n }\n }, 150);\n return;\n }\n \n // Determine initial language\n let initialLang = null;\n let initialSrc = null;\n \n if (hasMultipleSources) {\n initialLang = this._determineInitialLanguage();\n initialSrc = this.sources[initialLang] ?? null;\n this.currentLanguage = initialLang;\n } else {\n initialSrc = this.src;\n }\n\n // Create UI\n this._createWrapper();\n this._createHeader(hasMultipleSources, initialLang);\n this._createVideo(initialSrc);\n this._createResizeHandles();\n \n // Assemble. The create methods mutate this.wrapper/this.video, but\n // TypeScript still sees them as null due to the earlier\n // `if (this.wrapper) return` narrowing, so re-read via a typed alias.\n const wrapper = this.wrapper as HTMLElement | null;\n const video = this.video as HTMLVideoElement | null;\n if (!wrapper || !video) {\n return;\n }\n wrapper.appendChild(this.header as Node);\n wrapper.appendChild(video);\n this.resizeHandles.forEach(handle => wrapper.appendChild(handle));\n \n // Set initial size\n this._applyInitialSize();\n \n // Add to container\n this.player.container.appendChild(wrapper);\n \n // Position\n requestAnimationFrame(() => {\n this.constrainPosition();\n });\n \n // Sync with main video\n video.currentTime = this.player.state.currentTime;\n if (!this.player.state.paused) {\n video.play();\n }\n \n // Setup interaction\n this._setupInteraction();\n \n // Setup event handlers\n this._setupEventHandlers(hasMultipleSources);\n \n this.enabled = true;\n this.player.state.signLanguageEnabled = true;\n this.player.emit('signlanguageenabled');\n \n // Focus settings button\n this.player.setManagedTimeout(() => {\n if (this.settingsButton && document.contains(this.settingsButton)) {\n this.settingsButton.focus({ preventScroll: true });\n }\n }, 150);\n }\n\n /**\n * Disable sign language video\n */\n disable() {\n if (this.settingsMenuVisible) {\n this.hideSettingsMenu({ focusButton: false });\n }\n\n // Remove the mode badge so it doesn't linger past the overlay\n // (e.g. if user hides sign language while drag/resize mode was on).\n this._hideModeBadge();\n\n if (this.wrapper) {\n this.wrapper.style.display = 'none';\n }\n this.enabled = false;\n this.player.state.signLanguageEnabled = false;\n this.player.emit('signlanguagedisabled');\n }\n\n /**\n * Toggle sign language video\n */\n toggle() {\n if (this.enabled) {\n this.disable();\n } else {\n this.enable();\n }\n }\n\n /**\n * Enable sign language in main view: replace main video src with sign language URL (like audio description).\n * Same video element, different URL; no overlay.\n */\n async enableInMainView() {\n const hasMultipleSources = Object.keys(this.sources).length > 0;\n const hasSingleSource = Boolean(this.src);\n if (!hasMultipleSources && !hasSingleSource) return;\n if (!this.player.element || this.player.element.tagName !== 'VIDEO') return;\n if (this.inMainView) return;\n\n let signSrc;\n if (hasMultipleSources) {\n const initialLang = this._determineInitialLanguage();\n this.currentLanguage = initialLang;\n signSrc = this.sources[initialLang];\n } else {\n signSrc = this.src;\n }\n\n const el = this.player.element as HTMLVideoElement;\n const currentTime = this.player.state.currentTime;\n const wasPlaying = this.player.state.playing;\n const posterValue = el.poster || el.getAttribute('poster') || this.player.options.poster;\n const shouldKeepPoster = currentTime < 0.1 && !wasPlaying;\n\n const sourceElements: HTMLSourceElement[] = Array.from(el.querySelectorAll('source'));\n const firstSource = sourceElements[0];\n this.mainViewOriginalSrc = (el.currentSrc && el.currentSrc.length > 0)\n ? el.currentSrc\n : (el.src && el.src.length > 0)\n ? el.src\n : (firstSource && firstSource.getAttribute('src'))\n ? firstSource.getAttribute('src')\n : '';\n this._mainViewMutedBefore = this.player.state.muted;\n\n if (posterValue && shouldKeepPoster && el.tagName === 'VIDEO') {\n el.poster = posterValue;\n }\n if (sourceElements.length > 0) {\n this.mainViewOriginalSources = sourceElements;\n this.mainViewOriginalSources.forEach(source => source.remove());\n const signSource = document.createElement('source');\n const signSrcValue = signSrc ?? '';\n signSource.setAttribute('src', signSrcValue);\n const type = this._inferVideoType(signSrcValue);\n if (type) {\n signSource.setAttribute('type', type);\n }\n const trackNode = el.querySelector('track');\n if (trackNode) {\n el.insertBefore(signSource, trackNode);\n } else {\n el.appendChild(signSource);\n }\n this._mainViewUsingSourceSwap = true;\n } else {\n el.src = signSrc ?? '';\n this._mainViewUsingSourceSwap = false;\n }\n el.muted = true;\n this.player.currentSource = signSrc ?? '';\n if (typeof this.player.invalidateTrackCache === 'function') {\n this.player.invalidateTrackCache();\n }\n el.load();\n\n await this._waitForMediaReadyMainView(currentTime > 0 || wasPlaying);\n\n if (currentTime > 0) {\n this.player.seek(currentTime);\n await new Promise(r => setTimeout(r, 100));\n }\n if (wasPlaying) {\n await this.player.play();\n } else {\n this.player.pause();\n if (!shouldKeepPoster && this.player.hidePosterOverlay) {\n this.player.hidePosterOverlay();\n }\n }\n\n this.inMainView = true;\n this.player.state.signLanguageInMainView = true;\n if (this.player.videoWrapper) {\n this.player.videoWrapper.classList.add('vidply-sign-language-main-view-active');\n }\n this.player.emit('signlanguageinmainviewenabled');\n }\n\n /**\n * Disable sign language in main view: restore main video src.\n */\n async disableInMainView() {\n if (!this.inMainView) return;\n if (!this.mainViewOriginalSrc && !this.mainViewOriginalSources) {\n this.inMainView = false;\n this.player.state.signLanguageInMainView = false;\n if (this.player.videoWrapper) {\n this.player.videoWrapper.classList.remove('vidply-sign-language-main-view-active');\n }\n this.player.emit('signlanguageinmainviewdisabled');\n return;\n }\n\n const el = this.player.element as HTMLVideoElement;\n const currentTime = this.player.state.currentTime;\n const wasPlaying = this.player.state.playing;\n\n if (this._mainViewUsingSourceSwap && this.mainViewOriginalSources && this.mainViewOriginalSources.length > 0) {\n (Array.from(el.querySelectorAll('source')) as HTMLSourceElement[]).forEach((source: HTMLSourceElement) => source.remove());\n const trackNode = el.querySelector('track');\n this.mainViewOriginalSources.forEach((source: HTMLSourceElement) => {\n if (trackNode) {\n el.insertBefore(source, trackNode);\n } else {\n el.appendChild(source);\n }\n });\n this._mainViewUsingSourceSwap = false;\n } else if (this.mainViewOriginalSrc) {\n el.src = this.mainViewOriginalSrc;\n }\n el.muted = this._mainViewMutedBefore;\n this.player.currentSource = this.mainViewOriginalSrc || el.querySelector('source')?.src || '';\n if (typeof this.player.invalidateTrackCache === 'function') {\n this.player.invalidateTrackCache();\n }\n el.load();\n\n await this._waitForMediaReadyMainView(currentTime > 0 || wasPlaying);\n\n if (currentTime > 0) {\n this.player.seek(currentTime);\n }\n if (wasPlaying) {\n try {\n await this.player.play();\n } catch (e) {\n this.player.log?.('Sign language main view: play after restore failed', e, 'warn');\n }\n }\n\n this.mainViewOriginalSrc = null;\n this.mainViewOriginalSources = null;\n this.inMainView = false;\n this.player.state.signLanguageInMainView = false;\n if (this.player.videoWrapper) {\n this.player.videoWrapper.classList.remove('vidply-sign-language-main-view-active');\n }\n this.player.emit('signlanguageinmainviewdisabled');\n }\n\n /**\n * Wait for media ready (like AudioDescriptionManager).\n */\n async _waitForMediaReadyMainView(needSeek = false) {\n const el = this.player.element;\n const loadedMetaPromise = new Promise<void>((resolve) => {\n if (el.readyState >= 1) {\n resolve();\n return;\n }\n const onLoad = () => {\n el.removeEventListener('loadedmetadata', onLoad);\n el.removeEventListener('error', onError);\n resolve();\n };\n const onError = () => {\n el.removeEventListener('loadedmetadata', onLoad);\n el.removeEventListener('error', onError);\n resolve();\n };\n el.addEventListener('loadedmetadata', onLoad);\n el.addEventListener('error', onError, { once: true });\n });\n const timeoutPromise = new Promise(r => setTimeout(r, 10000));\n await Promise.race([loadedMetaPromise, timeoutPromise]);\n await new Promise(r => setTimeout(r, 300));\n if (needSeek) {\n await new Promise<void>((resolve) => {\n if (el.readyState >= 3) resolve();\n else {\n const onCanPlay = () => {\n el.removeEventListener('canplay', onCanPlay);\n el.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n };\n el.addEventListener('canplay', onCanPlay, { once: true });\n el.addEventListener('canplaythrough', onCanPlay, { once: true });\n setTimeout(() => {\n el.removeEventListener('canplay', onCanPlay);\n el.removeEventListener('canplaythrough', onCanPlay);\n resolve();\n }, 3000);\n }\n });\n }\n }\n\n /**\n * Toggle sign language in main view (src swap, like audio description).\n */\n toggleInMainView() {\n if (this.inMainView) {\n this.disableInMainView();\n } else {\n this.enableInMainView();\n }\n }\n\n /**\n * Switch to a different sign language\n */\n switchLanguage(langCode: string) {\n if (!this.sources[langCode]) return;\n\n this.currentLanguage = langCode;\n\n if (this.video) {\n const currentTime = this.video.currentTime;\n const wasPlaying = !this.video.paused;\n this.video.src = this.sources[langCode];\n this.video.currentTime = currentTime;\n if (wasPlaying) {\n // Autoplay can be rejected by browser policy; debug-log\n // unknown errors instead of silently swallowing.\n this.video.play().catch((e: unknown) => {\n if (typeof console !== 'undefined' && console.debug) {\n console.debug('[VidPly] sign-language play() rejected:', e);\n }\n });\n }\n }\n\n if (this.inMainView && this.player.element && this.player.element.tagName === 'VIDEO') {\n const currentTime = this.player.state.currentTime;\n const wasPlaying = this.player.state.playing;\n if (this._mainViewUsingSourceSwap) {\n const signSource = this.player.element.querySelector('source');\n if (signSource) {\n signSource.setAttribute('src', this.sources[langCode]);\n const type = this._inferVideoType(this.sources[langCode]);\n if (type) {\n signSource.setAttribute('type', type);\n }\n }\n } else {\n this.player.element.src = this.sources[langCode];\n }\n this.player.currentSource = this.sources[langCode];\n if (typeof this.player.invalidateTrackCache === 'function') {\n this.player.invalidateTrackCache();\n }\n this.player.element.load();\n this._waitForMediaReadyMainView(true).then(() => {\n if (currentTime > 0) this.player.seek(currentTime);\n if (wasPlaying) this.player.play();\n });\n }\n\n this.player.emit('signlanguagelanguagechanged', langCode);\n }\n\n _inferVideoType(url: string): string {\n if (!url) return '';\n const cleanUrl = (url.split('?')[0] ?? '').toLowerCase();\n if (cleanUrl.endsWith('.mp4')) return 'video/mp4';\n if (cleanUrl.endsWith('.webm')) return 'video/webm';\n if (cleanUrl.endsWith('.ogv') || cleanUrl.endsWith('.ogg')) return 'video/ogg';\n return '';\n }\n\n /**\n * Get language label\n */\n getLanguageLabel(langCode: string): string {\n const langNames: Record<string, string> = {\n 'en': 'English',\n 'de': 'Deutsch',\n 'es': 'Español',\n 'fr': 'Français',\n 'it': 'Italiano',\n 'ja': '日本語',\n 'pt': 'Português',\n 'ar': 'العربية',\n 'hi': 'हिन्दी'\n };\n return langNames[langCode] || langCode.toUpperCase();\n }\n\n /**\n * Determine initial sign language\n */\n _determineInitialLanguage(): string {\n // Try caption language\n if (this.player.captionManager && this.player.captionManager.currentTrack) {\n const captionLang = this.player.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.sources[captionLang]) {\n return captionLang;\n }\n }\n \n // Try player language\n if (this.player.options.language) {\n const playerLang = this.player.options.language.toLowerCase().split('-')[0];\n if (playerLang && this.sources[playerLang]) {\n return playerLang;\n }\n }\n \n // First available\n return Object.keys(this.sources)[0] ?? '';\n }\n\n /**\n * Create wrapper element\n */\n _createWrapper() {\n this.wrapper = document.createElement('div');\n this.wrapper.className = 'vidply-sign-language-wrapper';\n this.wrapper.setAttribute('tabindex', '0');\n this.wrapper.setAttribute('aria-label', i18n.t('player.signLanguageDragResize'));\n }\n\n /**\n * Create header element\n */\n _createHeader(hasMultipleSources: boolean, initialLang: string | null) {\n const classPrefix = this.player.options.classPrefix;\n \n this.header = DOMUtils.createElement('div', {\n className: `${classPrefix}-sign-language-header`,\n attributes: { 'tabindex': '0' }\n });\n\n const headerLeft = DOMUtils.createElement('div', {\n className: `${classPrefix}-sign-language-header-left`\n });\n\n const title = DOMUtils.createElement('h3', {\n textContent: i18n.t('player.signLanguageVideo')\n });\n\n // Settings button\n this._createSettingsButton(headerLeft);\n\n // Language selector\n if (hasMultipleSources) {\n this._createLanguageSelector(headerLeft, initialLang);\n }\n\n headerLeft.appendChild(title);\n \n // Close button\n const closeButton = this._createCloseButton();\n \n this.header.appendChild(headerLeft);\n this.header.appendChild(closeButton);\n }\n\n /**\n * Create settings button and wire it to a {@link DraggablePanel}\n * that owns the drag/resize settings menu and its lifecycle.\n */\n _createSettingsButton(container: HTMLElement) {\n const classPrefix = this.player.options.classPrefix;\n const ariaLabel = i18n.t('player.signLanguageSettings');\n \n this.settingsButton = DOMUtils.createElement('button', {\n className: `${classPrefix}-sign-language-settings`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel,\n 'aria-expanded': 'false'\n }\n }) as HTMLButtonElement;\n this.settingsButton.appendChild(createIconElement('settings'));\n DOMUtils.attachTooltip(this.settingsButton, ariaLabel, classPrefix);\n\n // The panel ties the settings-menu DOM, outside-click dismissal,\n // keyboard navigation, and drag/resize toggle items together\n // with the shared lifecycle signal. The manager still owns the\n // side effects that happen when a mode actually toggles (badge,\n // announcement, focus target), so the click callbacks below run\n // the manager's own toggle methods.\n this._panel = new DraggablePanel({\n player: this.player,\n namespace: 'sign-language',\n settingsButton: this.settingsButton,\n getDraggable: () => this.draggable,\n i18nKeys: {\n enableDrag: 'player.enableSignDragMode',\n disableDrag: 'player.disableSignDragMode',\n enableDragAria: 'player.enableSignDragModeAria',\n disableDragAria: 'player.disableSignDragModeAria',\n enableResize: 'player.enableSignResizeMode',\n disableResize: 'player.disableSignResizeMode',\n enableResizeAria: 'player.enableSignResizeModeAria',\n disableResizeAria: 'player.disableSignResizeModeAria',\n closeMenu: 'transcript.closeMenu',\n },\n menuAlign: 'center',\n getMenuParent: () => this.wrapper,\n getBadgeHost: () => this.wrapper,\n // Existing CSS uses `.vidply-sign-mode-badge` (shorter than\n // the namespace default) — pin the class so the styling\n // keeps applying without having to duplicate the rule.\n badgeClass: `${this.player.options.classPrefix}-sign-mode-badge`,\n onDragItemClick: (panel) => {\n this.toggleKeyboardDragMode();\n // Keep focus off the settings button so arrow keys go to\n // the draggable overlay.\n panel.hide({ focusButton: false });\n if (this.draggable?.keyboardDragMode) {\n setTimeout(() => {\n this.wrapper?.focus?.({ preventScroll: true });\n }, 20);\n }\n },\n onResizeItemClick: (panel) => {\n const enabled = this.toggleResizeMode({ focus: false });\n if (enabled) {\n panel.hide({ focusButton: false });\n setTimeout(() => {\n this.wrapper?.focus?.({ preventScroll: true });\n }, 20);\n } else {\n panel.hide({ focusButton: true });\n }\n },\n });\n\n this.settingsHandlers = {\n click: (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n this._panel?.markJustOpenedForClick();\n this._panel?.toggle();\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === 'd' || e.key === 'D') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleKeyboardDragMode();\n } else if (e.key === 'r' || e.key === 'R') {\n e.preventDefault();\n e.stopPropagation();\n this.toggleResizeMode();\n } else if (e.key === 'Escape' && this.settingsMenuVisible) {\n e.preventDefault();\n e.stopPropagation();\n this.hideSettingsMenu();\n }\n }\n };\n \n this.settingsButton.addEventListener('click', this.settingsHandlers.click);\n this.settingsButton.addEventListener('keydown', this.settingsHandlers.keydown);\n container.appendChild(this.settingsButton);\n }\n\n /**\n * Create language selector\n */\n _createLanguageSelector(container: HTMLElement, initialLang: string | null) {\n const classPrefix = this.player.options.classPrefix;\n const selectId = `${classPrefix}-sign-language-select-${Date.now()}`;\n \n const options = Object.keys(this.sources).map(langCode => ({\n value: langCode,\n text: this.getLanguageLabel(langCode),\n selected: langCode === initialLang\n }));\n \n const { label, select } = createLabeledSelect({\n classPrefix,\n labelClass: `${classPrefix}-sign-language-label`,\n selectClass: `${classPrefix}-sign-language-select`,\n labelText: 'settings.language',\n selectId,\n options,\n onChange: (e) => {\n e.stopPropagation();\n this.switchLanguage((e.target as HTMLSelectElement).value);\n }\n });\n \n this.selector = select as HTMLSelectElement;\n \n const selectorWrapper = DOMUtils.createElement('div', {\n className: `${classPrefix}-sign-language-selector-wrapper`\n });\n selectorWrapper.appendChild(label);\n selectorWrapper.appendChild(this.selector);\n \n preventDragOnElement(selectorWrapper);\n container.appendChild(selectorWrapper);\n }\n\n /**\n * Create close button\n */\n _createCloseButton() {\n const classPrefix = this.player.options.classPrefix;\n const ariaLabel = i18n.t('player.closeSignLanguage');\n \n const closeButton = DOMUtils.createElement('button', {\n className: `${classPrefix}-sign-language-close`,\n attributes: {\n 'type': 'button',\n 'aria-label': ariaLabel\n }\n });\n closeButton.appendChild(createIconElement('close'));\n DOMUtils.attachTooltip(closeButton, ariaLabel, classPrefix);\n \n // Bind to the player lifecycle so the listener is dropped on teardown\n // even if the button is detached without going through cleanup().\n closeButton.addEventListener('click', () => {\n this.disable();\n const signLanguageButton = this.player.controlBar?.controls?.signLanguage;\n if (signLanguageButton) {\n this.player.setManagedTimeout(() => {\n signLanguageButton.focus({ preventScroll: true });\n }, 0);\n }\n }, { signal: this.player.lifecycleSignal });\n \n return closeButton;\n }\n\n /**\n * Create video element\n */\n _createVideo(src: string | null) {\n this.video = document.createElement('video');\n this.video.className = 'vidply-sign-language-video';\n this.video.src = src ?? '';\n this.video.setAttribute('aria-label', i18n.t('player.signLanguage'));\n this.video.muted = true;\n this.video.setAttribute('playsinline', '');\n }\n\n /**\n * Create resize handles\n */\n _createResizeHandles() {\n const classPrefix = this.player.options.classPrefix;\n \n this.resizeHandles = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'].map(dir => {\n const handle = DOMUtils.createElement('div', {\n className: `${classPrefix}-sign-resize-handle ${classPrefix}-sign-resize-${dir}`,\n attributes: {\n 'data-direction': dir,\n 'data-vidply-managed-resize': 'true',\n 'aria-hidden': 'true'\n }\n });\n handle.style.display = 'none';\n return handle;\n });\n }\n\n /**\n * Apply initial size\n */\n _applyInitialSize() {\n const wrapper = this.wrapper;\n if (!wrapper) return;\n const saved = this.player.storage.getSignLanguagePreferences() as { size?: { width?: string } } | null;\n if (saved?.size?.width) {\n wrapper.style.width = saved.size.width;\n } else {\n wrapper.style.width = '280px';\n }\n wrapper.style.height = 'auto';\n }\n\n /**\n * Setup interaction (drag and resize)\n */\n _setupInteraction() {\n const isMobile = window.innerWidth < 768;\n const isFullscreen = this.player.state.fullscreen;\n\n // Historically, drag/resize was disabled on mobile unless fullscreen to avoid scroll conflicts.\n // Now that we support touch/pointer dragging with proper `touch-action` handling, enable it\n // by default on iOS/Android as well. Allow opting out via option.\n if (isMobile && !isFullscreen && this.player?.options?.signLanguageDragOnMobile === false) {\n if (this.draggable) {\n this.draggable.destroy();\n this.draggable = null;\n }\n return;\n }\n\n if (this.draggable) return;\n\n const wrapper = this.wrapper;\n if (!wrapper) return;\n\n const classPrefix = this.player.options.classPrefix;\n \n this.draggable = new DraggableResizable(wrapper, {\n // Allow dragging from anywhere on the sign-language window (better for touch).\n // We still block dragging when interacting with controls via `onDragStart` below.\n dragHandle: this.wrapper,\n resizeHandles: this.resizeHandles,\n constrainToViewport: true,\n maintainAspectRatio: true,\n minWidth: 150,\n minHeight: 100,\n classPrefix: `${classPrefix}-sign`,\n keyboardDragKey: 'd',\n keyboardResizeKey: 'r',\n keyboardStep: 10,\n keyboardStepLarge: 50,\n pointerResizeIndicatorText: i18n.t('player.signLanguageResizeActive'),\n onPointerResizeToggle: (enabled) => {\n this.resizeHandles.forEach(handle => {\n handle.style.display = enabled ? 'block' : 'none';\n });\n // Pair the resize-mode visual state with a translatable\n // badge and a live-region announcement. Fired for all\n // entry/exit paths (menu toggle, R key, Escape, Home).\n if (enabled) {\n this._showModeBadge(i18n.t('player.signResizeModeHint'));\n this.player.keyboardManager?.announce(i18n.t('player.signLanguageResizeActive'));\n } else {\n this._hideModeBadge();\n this.player.keyboardManager?.announce(i18n.t('player.signResizeModeDisabled'));\n }\n },\n onDragStart: (e) => {\n const target = e.target as HTMLElement;\n if (target.closest(`.${classPrefix}-sign-language-close`) ||\n target.closest(`.${classPrefix}-sign-language-settings`) ||\n target.closest(`.${classPrefix}-sign-language-select`) ||\n target.closest(`.${classPrefix}-sign-language-label`) ||\n target.closest(`.${classPrefix}-sign-language-settings-menu`)) {\n return false;\n }\n return true;\n }\n });\n\n this._setupCustomKeyHandler();\n \n this.interactionHandlers = {\n draggable: this.draggable,\n customKeyHandler: this.customKeyHandler\n };\n }\n\n /**\n * Setup custom keyboard handler\n */\n _setupCustomKeyHandler() {\n this.customKeyHandler = (e: KeyboardEvent) => {\n const key = e.key.toLowerCase();\n \n if (this.settingsMenuVisible) return;\n \n if (key === 'home') {\n e.preventDefault();\n e.stopPropagation();\n if (this.draggable) {\n if (this.draggable.pointerResizeMode) {\n this.draggable.disablePointerResizeMode();\n }\n this.draggable.manuallyPositioned = false;\n this.constrainPosition();\n }\n return;\n }\n \n if (key === 'r') {\n e.preventDefault();\n e.stopPropagation();\n if (this.toggleResizeMode()) {\n this.wrapper?.focus({ preventScroll: true });\n }\n return;\n }\n \n if (key === 'escape') {\n e.preventDefault();\n e.stopPropagation();\n if (this.draggable?.pointerResizeMode) {\n // disablePointerResizeMode() fires onPointerResizeToggle,\n // which hides the badge and announces the change.\n this.draggable.disablePointerResizeMode();\n return;\n }\n if (this.draggable?.keyboardDragMode) {\n // disableKeyboardDragMode on the draggable has no\n // callback, so mirror the cleanup that\n // toggleKeyboardDragMode() does when it turns the\n // mode off.\n this.draggable.disableKeyboardDragMode();\n this._hideModeBadge();\n this._updateDragOptionState();\n this.player.keyboardManager?.announce(i18n.t('player.signDragModeDisabled'));\n return;\n }\n this.disable();\n const signLanguageButton = this.player.controlBar?.controls?.signLanguage;\n if (signLanguageButton) {\n setTimeout(() => {\n signLanguageButton.focus({ preventScroll: true });\n }, 0);\n }\n }\n };\n \n this.wrapper?.addEventListener('keydown', this.customKeyHandler);\n }\n\n /**\n * Setup event handlers\n */\n _setupEventHandlers(hasMultipleSources: boolean) {\n this.handlers = {\n play: () => { if (this.video) this.video.play(); },\n pause: () => { if (this.video) this.video.pause(); },\n timeupdate: () => {\n if (this.video && Math.abs(this.video.currentTime - this.player.state.currentTime) > 0.5) {\n this.video.currentTime = this.player.state.currentTime;\n }\n },\n ratechange: () => {\n if (this.video) this.video.playbackRate = this.player.state.playbackSpeed;\n }\n };\n\n this.player.on('play', this.handlers.play);\n this.player.on('pause', this.handlers.pause);\n this.player.on('timeupdate', this.handlers.timeupdate);\n this.player.on('ratechange', this.handlers.ratechange);\n \n if (hasMultipleSources) {\n this.handlers.captionChange = () => {\n if (this.player.captionManager?.currentTrack && this.selector) {\n const captionLang = this.player.captionManager.currentTrack.language?.toLowerCase().split('-')[0];\n if (captionLang && this.sources[captionLang] && this.currentLanguage !== captionLang) {\n this.switchLanguage(captionLang);\n this.selector.value = captionLang;\n }\n }\n };\n this.player.on('captionsenabled', this.handlers.captionChange);\n }\n }\n\n /**\n * Constrain position within video wrapper\n */\n constrainPosition() {\n if (!this.wrapper || !this.player.videoWrapper) return;\n \n if (this.draggable?.manuallyPositioned) return;\n \n if (!this.wrapper.style.width) {\n this.wrapper.style.width = '280px';\n }\n \n const videoWrapperRect = this.player.videoWrapper.getBoundingClientRect();\n const containerRect = this.player.container.getBoundingClientRect();\n const wrapperRect = this.wrapper.getBoundingClientRect();\n \n const videoWrapperLeft = videoWrapperRect.left - containerRect.left;\n const videoWrapperTop = videoWrapperRect.top - containerRect.top;\n const videoWrapperWidth = videoWrapperRect.width;\n const videoWrapperHeight = videoWrapperRect.height;\n \n const wrapperWidth = wrapperRect.width || 280;\n const wrapperHeight = wrapperRect.height || ((280 * 9) / 16);\n \n let left, top;\n const margin = 16;\n const controlsHeight = 95;\n \n const position = this.desiredPosition || 'bottom-right';\n \n switch (position) {\n case 'bottom-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'bottom-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n break;\n case 'top-right':\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + margin;\n break;\n case 'top-left':\n left = videoWrapperLeft + margin;\n top = videoWrapperTop + margin;\n break;\n default:\n left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;\n top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;\n }\n \n left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));\n top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));\n \n this.wrapper.style.left = `${left}px`;\n this.wrapper.style.top = `${top}px`;\n this.wrapper.style.right = 'auto';\n this.wrapper.style.bottom = 'auto';\n }\n\n /**\n * Show the settings menu. Delegates to the shared {@link DraggablePanel},\n * which owns the DOM, outside-click dismissal, keyboard navigation and\n * positioning. Kept as a named method so external callers (other\n * managers, tests) that referenced the legacy API keep working.\n */\n showSettingsMenu() {\n this._panel?.show();\n }\n\n /** @see {@link showSettingsMenu} */\n hideSettingsMenu({ focusButton = true } = {}) {\n this._panel?.hide({ focusButton });\n }\n\n // Badge management moved into {@link DraggablePanel}; these\n // delegates keep the legacy names so internal call sites and\n // subclassers (if any) continue to work. Announcements for\n // assistive tech still go through the shared KeyboardManager\n // live region so AT doesn't read both the badge text and the\n // live-region copy.\n _showModeBadge(text: string) {\n this._panel?.showBadge(text);\n }\n\n _hideModeBadge() {\n this._panel?.hideBadge();\n }\n\n /**\n * Toggle keyboard drag mode\n */\n toggleKeyboardDragMode() {\n if (!this.draggable) return;\n\n const wasEnabled = this.draggable.keyboardDragMode;\n this.draggable.toggleKeyboardDragMode();\n const isEnabled = this.draggable.keyboardDragMode;\n\n if (!wasEnabled && isEnabled) {\n this._enableMoveMode();\n this._showModeBadge(i18n.t('player.signDragModeHint'));\n this.player.keyboardManager?.announce(i18n.t('player.signLanguageDragActive'));\n } else if (wasEnabled && !isEnabled) {\n this._hideModeBadge();\n this.player.keyboardManager?.announce(i18n.t('player.signDragModeDisabled'));\n }\n\n this._updateDragOptionState();\n }\n\n /**\n * Enable move mode visual feedback\n */\n _enableMoveMode() {\n this.wrapper?.classList.add(`${this.player.options.classPrefix}-sign-move-mode`);\n this._updateResizeOptionState();\n setTimeout(() => {\n this.wrapper?.classList.remove(`${this.player.options.classPrefix}-sign-move-mode`);\n }, 2000);\n }\n\n /**\n * Toggle resize mode\n */\n toggleResizeMode({ focus = true } = {}) {\n if (!this.draggable) return false;\n\n if (this.draggable.pointerResizeMode) {\n this.draggable.disablePointerResizeMode({ focus });\n this._updateResizeOptionState();\n return false;\n }\n\n this.draggable.enablePointerResizeMode({ focus });\n this._updateResizeOptionState();\n return true;\n }\n\n // Thin delegates to the panel's refreshState. Kept as named methods\n // so the existing internal call sites (e.g. `toggleKeyboardDragMode`)\n // read naturally without a double-dot chain to the panel.\n _updateDragOptionState() {\n this._panel?.refreshDragState();\n }\n\n _updateResizeOptionState() {\n this._panel?.refreshResizeState();\n }\n\n /**\n * Save preferences\n */\n savePreferences() {\n if (!this.wrapper) return;\n \n this.player.storage.saveSignLanguagePreferences({\n size: { width: this.wrapper.style.width }\n });\n }\n\n /**\n * Update sources (called when playlist changes)\n */\n updateSources(signLanguageSrc?: string | null, signLanguageSources?: Record<string, string> | null) {\n this.src = signLanguageSrc || null;\n this.sources = signLanguageSources || {};\n // Reset state for new playlist item (cleanup is called separately before this)\n this.currentLanguage = null;\n }\n\n /**\n * Cleanup\n */\n cleanup() {\n if (this.inMainView && this.player.element) {\n const el = this.player.element;\n if (this._mainViewUsingSourceSwap && this.mainViewOriginalSources && this.mainViewOriginalSources.length > 0) {\n (Array.from(el.querySelectorAll('source')) as HTMLSourceElement[]).forEach((source: HTMLSourceElement) => source.remove());\n const trackNode = el.querySelector('track');\n this.mainViewOriginalSources.forEach((source: HTMLSourceElement) => {\n if (trackNode) {\n el.insertBefore(source, trackNode);\n } else {\n el.appendChild(source);\n }\n });\n this._mainViewUsingSourceSwap = false;\n } else if (this.mainViewOriginalSrc) {\n el.src = this.mainViewOriginalSrc;\n }\n el.muted = this._mainViewMutedBefore;\n if (typeof this.player.invalidateTrackCache === 'function') {\n this.player.invalidateTrackCache();\n }\n el.load();\n this.mainViewOriginalSrc = null;\n this.mainViewOriginalSources = null;\n this.inMainView = false;\n this.player.state.signLanguageInMainView = false;\n if (this.player.videoWrapper) {\n this.player.videoWrapper.classList.remove('vidply-sign-language-main-view-active');\n }\n this.player.emit('signlanguageinmainviewdisabled');\n }\n if (this.settingsMenuVisible) {\n this.hideSettingsMenu({ focusButton: false });\n }\n\n // The panel owns its outside-click listener (bound to the\n // player's lifecycleSignal) and will drop that listener\n // automatically during player teardown. We still destroy the\n // panel here so its DOM is removed synchronously when the\n // wrapper goes away.\n if (this._panel) {\n this._panel.destroy();\n this._panel = null;\n }\n \n // Remove settings handlers\n if (this.settingsHandlers && this.settingsButton) {\n this.settingsButton.removeEventListener('click', this.settingsHandlers.click);\n this.settingsButton.removeEventListener('keydown', this.settingsHandlers.keydown);\n }\n this.settingsHandlers = null;\n \n // Remove event handlers\n if (this.handlers) {\n this.player.off('play', this.handlers.play);\n this.player.off('pause', this.handlers.pause);\n this.player.off('timeupdate', this.handlers.timeupdate);\n this.player.off('ratechange', this.handlers.ratechange);\n if (this.handlers.captionChange) {\n this.player.off('captionsenabled', this.handlers.captionChange);\n }\n this.handlers = null;\n }\n\n // Remove custom key handler\n if (this.wrapper && this.customKeyHandler) {\n this.wrapper.removeEventListener('keydown', this.customKeyHandler);\n }\n\n // Destroy draggable\n if (this.draggable) {\n if (this.draggable.pointerResizeMode) {\n this.draggable.disablePointerResizeMode();\n }\n this.draggable.destroy();\n this.draggable = null;\n }\n \n this.interactionHandlers = null;\n\n // Remove the mode badge before tearing down the wrapper, so the\n // reference doesn't outlive the DOM tree it belongs to.\n this._hideModeBadge();\n\n // Remove video and wrapper\n if (this.wrapper?.parentNode) {\n if (this.video) {\n this.video.pause();\n this.video.src = '';\n }\n this.wrapper.parentNode.removeChild(this.wrapper);\n }\n\n this.wrapper = null;\n this.video = null;\n this.settingsButton = null;\n }\n\n /**\n * Destroy\n */\n destroy() {\n this.cleanup();\n this.enabled = false;\n }\n}\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * VidPly v1.2.0 - Universal, Accessible Video Player
2
+ * VidPly v1.2.1 - Universal, Accessible Video Player
3
3
  * (c) 2026 Matthias Peltzer
4
4
  * Released under GPL-2.0-or-later License
5
5
  */
6
6
  import {
7
7
  loadScriptOnce
8
- } from "./vidply.chunk-DZSDO3B7.js";
8
+ } from "./vidply.chunk-HOYEMJSD.js";
9
9
 
10
10
  // src/renderers/SoundCloudRenderer.ts
11
11
  var SoundCloudRenderer = class {
@@ -337,4 +337,4 @@ export {
337
337
  SoundCloudRenderer,
338
338
  SoundCloudRenderer_default as default
339
339
  };
340
- //# sourceMappingURL=vidply.SoundCloudRenderer-RVSJZODO.js.map
340
+ //# sourceMappingURL=vidply.SoundCloudRenderer-OA7QQYGN.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/renderers/SoundCloudRenderer.ts"],
4
+ "sourcesContent": ["import type { Renderer } from '../types/renderer.js';\nimport type { Player } from '../core/Player.js';\nimport { loadScriptOnce } from '../utils/ScriptLoader.js';\n\n/**\n * Subset of the SoundCloud Widget event payloads we actually consume.\n * The Widget API is callback-shaped and does not export TS types, so we\n * narrow `unknown` arguments locally as they enter our handlers.\n */\ninterface SCSoundInfo {\n duration: number;\n title?: string;\n}\n\ninterface SCProgressData {\n currentPosition: number;\n loadedProgress?: number;\n}\n\ninterface SCWidgetError {\n message?: string;\n}\n\nexport class SoundCloudRenderer implements Renderer {\n player: Player;\n media: HTMLMediaElement;\n widget: SCWidget | null;\n trackUrl: string | null;\n isReady: boolean;\n iframe: HTMLIFrameElement | null;\n iframeId: string | null;\n _previousVolume: number;\n // Pending init timeout (rejects after 10s); cleared once READY fires or on\n // destroy so it can't reject / touch a torn-down player afterwards.\n private _initTimeoutId: ReturnType<typeof setTimeout> | null;\n // Detaches the iframe 'load' listener on destroy.\n private _initController: AbortController | null;\n\n constructor(player: Player) {\n this.player = player;\n this.media = player.element;\n this.widget = null;\n this.trackUrl = null;\n this.isReady = false;\n this.iframe = null;\n this.iframeId = null;\n this._previousVolume = 100;\n this._initTimeoutId = null;\n this._initController = null;\n }\n\n async init() {\n // Extract track URL - use currentSource which works for external renderers\n this.trackUrl = this.player.currentSource || this.player.element.src || this.player.element.querySelector('source')?.src || null;\n \n if (!this.trackUrl || !this.isValidSoundCloudUrl(this.trackUrl)) {\n throw new Error('Invalid SoundCloud URL');\n }\n\n // Load SoundCloud Widget API\n await this.loadSoundCloudAPI();\n\n // Create iframe\n this.createIframe();\n\n // Initialize widget\n await this.initializeWidget();\n }\n\n /**\n * Validate a SoundCloud URL by parsing it with the URL constructor and\n * checking the protocol + hostname against an explicit allow-list.\n * Substring checks like `url.includes('soundcloud.com')` accept things\n * like `https://evil.com/?leak=soundcloud.com` or\n * `https://soundcloud.com.attacker.example`.\n */\n isValidSoundCloudUrl(url: string): boolean {\n if (typeof url !== 'string' || !url) return false;\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return false;\n }\n if (parsed.protocol !== 'https:') return false;\n const allowedHosts = new Set([\n 'soundcloud.com',\n 'www.soundcloud.com',\n 'm.soundcloud.com',\n 'api.soundcloud.com',\n 'api-v2.soundcloud.com'\n ]);\n return allowedHosts.has(parsed.hostname.toLowerCase());\n }\n\n /**\n * Check if URL is a playlist/set\n */\n isPlaylist() {\n return this.trackUrl && this.trackUrl.includes('/sets/');\n }\n\n /**\n * Extract track/playlist info from URL for embed\n * SoundCloud URLs can be:\n * - https://soundcloud.com/artist/track\n * - https://soundcloud.com/artist/sets/playlist\n * - https://api.soundcloud.com/tracks/123456\n */\n getEmbedUrl() {\n const trackUrl = this.trackUrl;\n if (!trackUrl) {\n throw new Error('SoundCloudRenderer.getEmbedUrl(): trackUrl is not set');\n }\n \n // Build widget URL with parameters\n const params = new URLSearchParams({\n url: trackUrl,\n auto_play: this.player.options.autoplay ? 'true' : 'false',\n hide_related: 'true',\n show_comments: 'false',\n show_user: 'true',\n show_reposts: 'false',\n show_teaser: 'false',\n visual: 'false', // Use classic player for better control\n color: '%23007bff'\n });\n \n return `https://w.soundcloud.com/player/?${params.toString()}`;\n }\n\n async loadSoundCloudAPI() {\n // Check if API is already loaded\n if (typeof window.SC !== 'undefined') {\n return Promise.resolve();\n }\n\n // SC.Widget can become available a tick after the script's load event, so\n // resolve via the readiness predicate rather than load alone.\n return loadScriptOnce('https://w.soundcloud.com/player/api.js', {\n isReady: () => typeof window.SC !== 'undefined'\n });\n }\n\n createIframe() {\n // Hide original element and remove poster (SoundCloud has its own visual widget)\n this.player.element.style.display = 'none';\n this.player.element.removeAttribute('poster');\n \n // Remove poster overlay from video wrapper if present\n if (this.player.videoWrapper) {\n this.player.videoWrapper.classList.remove('vidply-forced-poster');\n this.player.videoWrapper.style.removeProperty('--vidply-poster-image');\n }\n\n // Generate unique ID for iframe\n this.iframeId = `soundcloud-player-${Math.random().toString(36).substr(2, 9)}`;\n\n // Create iframe for SoundCloud widget\n this.iframe = document.createElement('iframe');\n this.iframe.id = this.iframeId;\n this.iframe.scrolling = 'no';\n this.iframe.frameBorder = 'no';\n this.iframe.allow = 'autoplay';\n this.iframe.src = this.getEmbedUrl();\n this.iframe.style.width = '100%';\n this.iframe.style.display = 'block';\n \n // Use different aspect ratio for playlists vs single tracks\n // Playlists need more height to show the track list\n if (this.isPlaylist()) {\n this.iframe.classList.add('vidply-soundcloud-iframe', 'vidply-soundcloud-playlist');\n } else {\n this.iframe.classList.add('vidply-soundcloud-iframe');\n }\n this.iframe.style.maxHeight = '100%';\n \n this.player.element.parentNode?.insertBefore(this.iframe, this.player.element);\n }\n\n async initializeWidget() {\n return new Promise<void>((resolve, reject) => {\n const iframe = this.iframe;\n if (!iframe || typeof window.SC === 'undefined') {\n reject(new Error('SoundCloud widget cannot initialize'));\n return;\n }\n\n const SC = window.SC;\n if (!SC) {\n reject(new Error('SoundCloud widget cannot initialize'));\n return;\n }\n\n // Wait for iframe to load. Registered through an AbortController so\n // destroy() can detach it if init never completes.\n this._initController = new AbortController();\n iframe.addEventListener('load', () => {\n try {\n const widget = SC.Widget(iframe);\n this.widget = widget;\n\n widget.bind(SC.Widget.Events.READY, () => {\n this.isReady = true;\n // Init succeeded — cancel the pending timeout so it can't reject.\n if (this._initTimeoutId !== null) {\n clearTimeout(this._initTimeoutId);\n this._initTimeoutId = null;\n }\n this.attachEvents();\n\n // Hide VidPly controls - SoundCloud has its own\n if (this.player.container) {\n this.player.container.classList.add('vidply-external-controls');\n }\n\n // Get initial sound info\n widget.getCurrentSound((sound: unknown) => {\n const info = sound as SCSoundInfo | null;\n if (info) {\n this.player.state.duration = info.duration / 1000; // ms -> s\n this.player.emit('loadedmetadata');\n }\n });\n\n resolve();\n });\n\n widget.bind(SC.Widget.Events.ERROR, (...args: unknown[]) => {\n const error = args[0] as SCWidgetError | undefined;\n this.player.handleError(new Error(`SoundCloud error: ${error?.message || 'Unknown error'}`));\n });\n } catch (error) {\n reject(error);\n }\n }, { signal: this._initController.signal });\n \n // Timeout after 10 seconds\n this._initTimeoutId = setTimeout(() => {\n this._initTimeoutId = null;\n if (!this.isReady) {\n reject(new Error('SoundCloud widget initialization timeout'));\n }\n }, 10000);\n });\n }\n\n attachEvents() {\n const widget = this.widget;\n const SC = window.SC;\n if (!widget || !SC) return;\n\n const Events = SC.Widget.Events;\n\n widget.bind(Events.PLAY, () => {\n this.player.state.playing = true;\n this.player.state.paused = false;\n this.player.state.ended = false;\n this.player.emit('play');\n\n if (this.player.options.onPlay) {\n this.player.options.onPlay.call(this.player);\n }\n });\n\n widget.bind(Events.PAUSE, () => {\n this.player.state.playing = false;\n this.player.state.paused = true;\n this.player.emit('pause');\n\n if (this.player.options.onPause) {\n this.player.options.onPause.call(this.player);\n }\n });\n\n widget.bind(Events.FINISH, () => {\n this.player.state.playing = false;\n this.player.state.paused = true;\n this.player.state.ended = true;\n this.player.emit('ended');\n\n if (this.player.options.onEnded) {\n this.player.options.onEnded.call(this.player);\n }\n\n if (this.player.options.loop) {\n this.seek(0);\n this.play();\n }\n });\n\n widget.bind(Events.PLAY_PROGRESS, (...args: unknown[]) => {\n const data = args[0] as SCProgressData;\n // data.currentPosition is in milliseconds\n const currentTime = data.currentPosition / 1000;\n this.player.state.currentTime = currentTime;\n this.player.emit('timeupdate', currentTime);\n\n if (this.player.options.onTimeUpdate) {\n this.player.options.onTimeUpdate.call(this.player, currentTime);\n }\n });\n\n widget.bind(Events.SEEK, (...args: unknown[]) => {\n const data = args[0] as SCProgressData;\n this.player.state.currentTime = data.currentPosition / 1000;\n this.player.emit('seeked');\n });\n\n widget.bind(Events.LOAD_PROGRESS, (...args: unknown[]) => {\n const data = args[0] as SCProgressData;\n // data.loadedProgress is 0-1\n if (this.player.state.duration && data.loadedProgress !== undefined) {\n const buffered = data.loadedProgress * this.player.state.duration;\n this.player.emit('progress', buffered);\n }\n });\n }\n\n play() {\n if (this.isReady && this.widget) {\n // Save scroll position to prevent browser from scrolling\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n \n this.widget.play();\n \n // Restore scroll position\n window.scrollTo(scrollX, scrollY);\n }\n }\n\n pause() {\n if (this.isReady && this.widget) {\n this.widget.pause();\n }\n }\n\n seek(time: number) {\n if (this.isReady && this.widget) {\n // SoundCloud seekTo uses milliseconds\n this.widget.seekTo(time * 1000);\n this.player.state.currentTime = time;\n }\n }\n\n setVolume(volume: number) {\n if (this.isReady && this.widget) {\n // SoundCloud setVolume expects 0-100\n this.widget.setVolume(volume * 100);\n this.player.state.volume = volume;\n }\n }\n\n setMuted(muted: boolean) {\n const widget = this.widget;\n if (this.isReady && widget) {\n // SoundCloud doesn't have a native mute, use volume instead\n if (muted) {\n // Store current volume before muting\n widget.getVolume((vol: number) => {\n this._previousVolume = vol;\n widget.setVolume(0);\n });\n } else {\n widget.setVolume(this._previousVolume || 100);\n }\n this.player.state.muted = muted;\n }\n }\n\n setPlaybackSpeed(_speed: number) {\n // SoundCloud Widget API doesn't support playback speed\n this.player.log('SoundCloud does not support playback speed control', 'warn');\n }\n\n /**\n * Get current track info. Returns the raw sound payload from the\n * SoundCloud Widget API (shape is best described as `unknown` since\n * the API exposes many optional fields we don't formally type).\n */\n getCurrentSound(): Promise<unknown | null> {\n return new Promise<unknown | null>((resolve) => {\n if (this.isReady && this.widget) {\n this.widget.getCurrentSound((sound: unknown) => {\n resolve(sound);\n });\n } else {\n resolve(null);\n }\n });\n }\n\n destroy() {\n // Cancel any pending init timeout and detach the iframe 'load' listener.\n if (this._initTimeoutId !== null) {\n clearTimeout(this._initTimeoutId);\n this._initTimeoutId = null;\n }\n if (this._initController) {\n this._initController.abort();\n this._initController = null;\n }\n\n // Unbind all events\n if (this.widget && window.SC) {\n const Events = window.SC.Widget.Events;\n try {\n this.widget.unbind(Events.READY);\n this.widget.unbind(Events.PLAY);\n this.widget.unbind(Events.PAUSE);\n this.widget.unbind(Events.FINISH);\n this.widget.unbind(Events.PLAY_PROGRESS);\n this.widget.unbind(Events.SEEK);\n this.widget.unbind(Events.LOAD_PROGRESS);\n this.widget.unbind(Events.ERROR);\n } catch {\n // Ignore unbind errors\n }\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n }\n\n // Show original element\n if (this.player.element) {\n this.player.element.style.display = '';\n }\n\n this.widget = null;\n this.isReady = false;\n }\n}\n\nexport default SoundCloudRenderer;\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * VidPly v1.2.0 - Universal, Accessible Video Player
2
+ * VidPly v1.2.1 - Universal, Accessible Video Player
3
3
  * (c) 2026 Matthias Peltzer
4
4
  * Released under GPL-2.0-or-later License
5
5
  */
@@ -8,28 +8,28 @@ import {
8
8
  createLabeledSelect,
9
9
  createMenuItem,
10
10
  preventDragOnElement
11
- } from "./vidply.chunk-NQPURMQY.js";
11
+ } from "./vidply.chunk-W5BR65JY.js";
12
12
  import {
13
13
  DraggableResizable
14
- } from "./vidply.chunk-JJ47NO24.js";
14
+ } from "./vidply.chunk-C55OBT5H.js";
15
15
  import {
16
16
  TimeUtils
17
- } from "./vidply.chunk-SK4V2DAU.js";
17
+ } from "./vidply.chunk-YVCYQZJI.js";
18
18
  import {
19
19
  createIconElement
20
- } from "./vidply.chunk-KI7C3QVL.js";
20
+ } from "./vidply.chunk-RQG3MA7W.js";
21
21
  import {
22
22
  focusElement
23
- } from "./vidply.chunk-VMSQAZM7.js";
23
+ } from "./vidply.chunk-JAKZNGOR.js";
24
24
  import {
25
25
  StorageManager,
26
26
  deriveTrackLabel
27
- } from "./vidply.chunk-BNFIUL2Z.js";
28
- import "./vidply.chunk-6RQA4ROD.js";
27
+ } from "./vidply.chunk-UHMVDBDB.js";
28
+ import "./vidply.chunk-5IK3IC5V.js";
29
29
  import {
30
30
  DOMUtils,
31
31
  i18n
32
- } from "./vidply.chunk-RZWZGDV7.js";
32
+ } from "./vidply.chunk-NSMAZCMB.js";
33
33
 
34
34
  // src/controls/TranscriptManager.ts
35
35
  var TranscriptManager = class {
@@ -1891,4 +1891,4 @@ var TranscriptManager = class {
1891
1891
  export {
1892
1892
  TranscriptManager
1893
1893
  };
1894
- //# sourceMappingURL=vidply.TranscriptManager-5GXOQCLX.js.map
1894
+ //# sourceMappingURL=vidply.TranscriptManager-BPM3T23L.js.map