vidply 1.2.0 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/README.md +974 -946
  2. package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-JYYLK5KB.js} +275 -19
  3. package/dist/dev/vidply.AudioDescriptionManager-JYYLK5KB.js.map +7 -0
  4. package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-47RCKQF5.js} +4 -4
  5. package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-VEJ4HDHO.js} +3 -3
  6. package/dist/dev/vidply.DASHRenderer-VEJ4HDHO.js.map +7 -0
  7. package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-C2UVRPZY.js} +5 -5
  8. package/dist/dev/vidply.FloatingPlayerManager-C2UVRPZY.js.map +7 -0
  9. package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZVBK2TNQ.js} +4 -4
  10. package/dist/dev/vidply.HLSRenderer-ZVBK2TNQ.js.map +7 -0
  11. package/dist/dev/vidply.HTML5Renderer-HLRQUOCU.js +12 -0
  12. package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-FLUCBW5H.js} +8 -8
  13. package/dist/dev/vidply.SignLanguageManager-FLUCBW5H.js.map +7 -0
  14. package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-MGMAJ7NK.js} +3 -3
  15. package/dist/dev/vidply.SoundCloudRenderer-MGMAJ7NK.js.map +7 -0
  16. package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-Y2RYXHJW.js} +10 -10
  17. package/dist/dev/vidply.TranscriptManager-Y2RYXHJW.js.map +7 -0
  18. package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-RQFQD7OE.js} +3 -3
  19. package/dist/dev/vidply.VimeoRenderer-RQFQD7OE.js.map +7 -0
  20. package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-EU2BARZF.js} +3 -3
  21. package/dist/dev/vidply.YouTubeRenderer-EU2BARZF.js.map +7 -0
  22. package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-6LYZYI5G.js} +3 -3
  23. package/dist/dev/vidply.chunk-6LYZYI5G.js.map +7 -0
  24. package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-A4ESEOQ2.js} +6 -6
  25. package/dist/dev/vidply.chunk-A4ESEOQ2.js.map +7 -0
  26. package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-CGYIED2I.js} +2 -2
  27. package/dist/dev/vidply.chunk-CGYIED2I.js.map +7 -0
  28. package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-HZ7UOKOU.js} +3 -3
  29. package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-I6EDRYGJ.js} +33 -6
  30. package/dist/dev/vidply.chunk-I6EDRYGJ.js.map +7 -0
  31. package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-JKMQGLCJ.js} +5 -5
  32. package/dist/dev/vidply.chunk-JKMQGLCJ.js.map +7 -0
  33. package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-JZNZX32Z.js} +2 -2
  34. package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-P25MRJ6O.js} +2 -2
  35. package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-PRFNESYA.js} +2 -2
  36. package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-UI3RYCVF.js} +4 -3
  37. package/dist/dev/vidply.chunk-UI3RYCVF.js.map +7 -0
  38. package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-UNFGMABP.js} +2 -2
  39. package/dist/dev/vidply.chunk-UNFGMABP.js.map +7 -0
  40. package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-VAUVSQXC.js} +29 -2
  41. package/dist/dev/vidply.de-VAUVSQXC.js.map +7 -0
  42. package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-G65HFWO6.js} +29 -2
  43. package/dist/dev/vidply.es-G65HFWO6.js.map +7 -0
  44. package/dist/dev/vidply.esm.js +648 -35
  45. package/dist/dev/vidply.esm.js.map +3 -3
  46. package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-MJNOZELM.js} +29 -2
  47. package/dist/dev/vidply.fr-MJNOZELM.js.map +7 -0
  48. package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-INMDHIYJ.js} +29 -2
  49. package/dist/dev/vidply.ja-INMDHIYJ.js.map +7 -0
  50. package/dist/legacy/vidply.js +1062 -34
  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 +127 -55
  54. package/dist/prod/vidply.AudioDescriptionManager-EKWUNOPE.min.js +6 -0
  55. package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-JTWSNHRQ.min.js} +2 -2
  56. package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-CIDAHFWM.min.js} +2 -2
  57. package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-VZXHPCPM.min.js} +2 -2
  58. package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-Q6EFYKID.min.js} +2 -2
  59. package/dist/prod/vidply.HTML5Renderer-XRDJUTOO.min.js +6 -0
  60. package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-JUOSA5AM.min.js} +2 -2
  61. package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-7ODD46PO.min.js} +2 -2
  62. package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-4B2QKYGQ.min.js} +2 -2
  63. package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-MR3UYLY7.min.js} +2 -2
  64. package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-ITRTC7NR.min.js} +2 -2
  65. package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-3EEDXU4T.min.js} +2 -2
  66. package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-5HTX5QXW.min.js} +1 -1
  67. package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-6OGHHIYP.min.js} +2 -2
  68. package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-GUPGMFUZ.min.js} +2 -2
  69. package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-MWEBITCP.min.js} +1 -1
  70. package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-PL3P3JHR.min.js} +1 -1
  71. package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-QQZGV7TD.min.js} +2 -2
  72. package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-U5IRRYG5.min.js} +1 -1
  73. package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-VKHV4QHA.min.js} +2 -2
  74. package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-XA4M574A.min.js} +1 -1
  75. package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-ZPTV4JEP.min.js} +2 -2
  76. package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-UZHFCEZU.min.js} +2 -2
  77. package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-BOISUV2S.min.js} +2 -2
  78. package/dist/prod/vidply.esm.min.js +2 -2
  79. package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-ICSMKPFM.min.js} +2 -2
  80. package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-VQ2HKGAY.min.js} +2 -2
  81. package/dist/vidply.css +5852 -5796
  82. package/dist/vidply.esm.min.meta.json +204 -149
  83. package/dist/vidply.min.css +1 -1
  84. package/package.json +11 -11
  85. package/src/controls/CaptionManager.ts +598 -598
  86. package/src/controls/ControlBar.ts +4191 -4159
  87. package/src/controls/KeyboardHelp.ts +326 -0
  88. package/src/controls/KeyboardManager.ts +387 -383
  89. package/src/controls/SettingsDialog.ts +488 -488
  90. package/src/controls/TranscriptManager.ts +2426 -2426
  91. package/src/core/AudioDescriptionManager.ts +863 -774
  92. package/src/core/DescriptionSpeechManager.ts +232 -0
  93. package/src/core/FloatingPlayerManager.ts +674 -674
  94. package/src/core/LazyInit.ts +80 -80
  95. package/src/core/MediaSessionManager.ts +341 -0
  96. package/src/core/MetadataAlertsManager.ts +514 -514
  97. package/src/core/Player.ts +2973 -2872
  98. package/src/core/PosterManager.ts +169 -169
  99. package/src/core/PseudoFullscreen.ts +179 -179
  100. package/src/core/ResponsiveManager.ts +231 -231
  101. package/src/core/ResumeManager.ts +236 -236
  102. package/src/core/SignLanguageManager.ts +1308 -1308
  103. package/src/core/ThemeManager.ts +157 -157
  104. package/src/features/PlaylistManager.ts +1838 -1827
  105. package/src/i18n/i18n.ts +223 -223
  106. package/src/i18n/languages/de.ts +244 -217
  107. package/src/i18n/languages/en.ts +245 -218
  108. package/src/i18n/languages/es.ts +241 -214
  109. package/src/i18n/languages/fr.ts +241 -214
  110. package/src/i18n/languages/ja.ts +241 -214
  111. package/src/icons/Icons.ts +168 -167
  112. package/src/index.ts +196 -193
  113. package/src/renderers/DASHRenderer.ts +1077 -1077
  114. package/src/renderers/HLSRenderer.ts +944 -944
  115. package/src/renderers/HTML5Renderer.ts +389 -389
  116. package/src/renderers/SoundCloudRenderer.ts +437 -437
  117. package/src/renderers/VimeoRenderer.ts +298 -298
  118. package/src/renderers/YouTubeRenderer.ts +290 -290
  119. package/src/styles/vidply.css +5852 -5796
  120. package/src/types/events.ts +128 -122
  121. package/src/types/globals.d.ts +313 -313
  122. package/src/types/options.ts +199 -182
  123. package/src/types/renderer.ts +58 -58
  124. package/src/utils/DOMUtils.ts +281 -281
  125. package/src/utils/DownloadInfo.ts +171 -171
  126. package/src/utils/DraggablePanel.ts +539 -539
  127. package/src/utils/DraggablePanelMenu.ts +195 -195
  128. package/src/utils/DraggableResizable.ts +997 -997
  129. package/src/utils/EventEmitter.ts +59 -59
  130. package/src/utils/FormUtils.ts +95 -95
  131. package/src/utils/MenuFactory.ts +483 -483
  132. package/src/utils/Sanitize.ts +70 -70
  133. package/src/utils/SettingsMenuFactory.ts +289 -289
  134. package/src/utils/StorageManager.ts +287 -287
  135. package/src/utils/TrackLabelUtils.ts +52 -52
  136. package/src/utils/UrlSafe.ts +69 -69
  137. package/src/utils/VideoFrameCapture.ts +114 -114
  138. package/src/utils/WindowComponents.ts +250 -250
  139. package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
  140. package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
  141. package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
  142. package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
  143. package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
  144. package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
  145. package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
  146. package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
  147. package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
  148. package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
  149. package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
  150. package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
  151. package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
  152. package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
  153. package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
  154. package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
  155. package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
  156. package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
  157. package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
  158. package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
  159. package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
  160. package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
  161. package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
  162. /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-47RCKQF5.js.map} +0 -0
  163. /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-HLRQUOCU.js.map} +0 -0
  164. /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-HZ7UOKOU.js.map} +0 -0
  165. /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-JZNZX32Z.js.map} +0 -0
  166. /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-P25MRJ6O.js.map} +0 -0
  167. /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-PRFNESYA.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/renderers/DASHRenderer.ts"],
4
+ "sourcesContent": ["import type { Renderer } from '../types/renderer.js';\nimport type { Player } from '../core/Player.js';\nimport { loadScriptOnce } from '../utils/ScriptLoader.js';\n\ninterface DashTextTrack {\n lang?: string;\n language?: string;\n srclang?: string;\n kind?: string;\n label?: string;\n labels?: string;\n isTTML?: boolean;\n codec?: string;\n mimeType?: string;\n [key: string]: unknown;\n}\n\n/**\n * Shape of payloads emitted by VidPly's `captionsenabled` event when\n * routed into a DASH renderer. These come from CaptionManager and carry\n * both the language and the underlying TextTrack reference.\n */\ninterface CaptionTrackSelection {\n language?: string;\n label?: string;\n track?: TextTrack;\n}\n\ntype CaptionEnabledHandler = (track: CaptionTrackSelection) => void;\ntype CaptionDisabledHandler = () => void;\n\nexport class DASHRenderer implements Renderer {\n player: Player;\n media: HTMLMediaElement;\n dash: DashMediaPlayerInstance | null;\n readonly isStreaming = true;\n _dashSourceLoaded: boolean;\n _pendingSrc: string | null;\n _dashSubtitleTracksCount: number | undefined;\n _dashTextTracks: DashTextTrack[];\n _cueUpdateTimer: ReturnType<typeof setInterval> | null;\n _captionEnabledHandler: CaptionEnabledHandler | null;\n _captionDisabledHandler: CaptionDisabledHandler | null;\n _lastKnownCueCount: number;\n _dashTextIsTtml: boolean;\n _pendingTimeouts: ReturnType<typeof setTimeout>[];\n _ttmlDiv: HTMLElement | null;\n _manifestUrl: string | null;\n // Detaches all media listeners (attachMediaEvents) in destroy().\n private _listenerController: AbortController;\n // Deferred 'ready' handler from updateCaptionButtonsForStreaming, removed on\n // destroy if it never fired.\n private _pendingReadyHandler: (() => void) | null;\n\n constructor(player: Player) {\n this.player = player;\n this.media = player.element;\n this.dash = null;\n this._dashSourceLoaded = false;\n this._pendingSrc = null;\n this._dashSubtitleTracksCount = undefined;\n this._dashTextTracks = [];\n this._cueUpdateTimer = null;\n this._captionEnabledHandler = null;\n this._captionDisabledHandler = null;\n this._lastKnownCueCount = 0;\n this._dashTextIsTtml = false;\n this._pendingTimeouts = [];\n this._ttmlDiv = null;\n this._manifestUrl = null;\n this._listenerController = new AbortController();\n this._pendingReadyHandler = null;\n }\n\n async init() {\n this.player.log('Using dash.js for DASH support');\n await this.initDashJs();\n }\n\n async initDashJs() {\n this.media.controls = false;\n this.media.removeAttribute('controls');\n\n if (!window.dashjs) {\n await this.loadDashJs();\n }\n\n // Remove <source> children — dash.js manages the src via MSE\n const sourceElements = Array.from(this.media.querySelectorAll('source'));\n let originalSrc = null;\n if (sourceElements.length > 0) {\n originalSrc = sourceElements[0]?.getAttribute('src') ?? null;\n sourceElements.forEach(source => source.remove());\n this.player.log('Removed <source> elements for HTML5 validity (dash.js uses MSE)');\n }\n\n const dashjs = window.dashjs;\n if (!dashjs) {\n throw new Error('dash.js not available');\n }\n this.dash = dashjs.MediaPlayer().create();\n\n this.dash.updateSettings({\n debug: {\n logLevel: this.player.options.debug ? 4 : 0\n },\n streaming: {\n // Override dash.js default of 'lowestStartupDelay'. For audio\n // AdaptationSets that tie on selectionPriority and role=main (e.g.\n // Axinom's three en/en-low/en-high tracks), 'lowestStartupDelay'\n // falls through to 'highestEfficiency' which, for audio, has no\n // meaningful pixels-per-bit metric and collapses to \"highest\n // bitrate\". 'firstTrack' respects manifest order instead, which is\n // both predictable and closer to the MPD author's intent.\n selectionModeForInitialTrack: 'firstTrack',\n // NOTE on pre-play preload: we deliberately do NOT set\n // streaming.scheduling.scheduleWhilePaused = false here. While that\n // is the documented dash.js way to suppress segment downloads while\n // paused / before the first play, in our setup (dash.js 5.2.0 +\n // dash.initialize(media, null, false) + attachSource at init) it\n // tears down the SourceBuffers mid-init with\n // \"SourceBuffer has been removed from the parent media source\"\n // exceptions, which leaves the player unable to seek or play. The\n // PR #3785 fix that was supposed to handle the initial-playback /\n // autoPlay=false case is fragile against our usage pattern.\n // Instead we keep dash.js's default scheduling (scheduleWhilePaused\n // stays at its default `true`) and let the buffer caps below limit\n // how much is fetched before play. With a single ~6s segment size,\n // the visible network preload is one init segment per track plus\n // 1–2 media segments — the same \"first two chunks\" behavior the\n // user previously confirmed as acceptable for DASH.\n buffer: {\n bufferTimeAtTopQuality: 30,\n bufferTimeAtTopQualityLongForm: 60,\n // dash.js 5.x: use bufferTimeDefault (replaces removed stableBufferTime).\n // Keep at 12s — going lower (0 / 1) was tested but dash.js still\n // loads the first segment regardless because it's needed to make\n // the MediaSource playable, so the savings are negligible while\n // hurting mid-playback resilience on slow networks.\n bufferTimeDefault: 12,\n bufferToKeep: 20,\n bufferPruningInterval: 10\n },\n retryAttempts: {\n MPD: 4,\n MediaSegment: 6,\n InitializationSegment: 4,\n BitstreamSwitchingSegment: 4\n },\n retryIntervals: {\n MPD: 1000,\n MediaSegment: 1000,\n InitializationSegment: 1000,\n BitstreamSwitchingSegment: 1000\n },\n abr: {\n autoSwitchBitrate: { video: true, audio: true }\n },\n text: {\n defaultEnabled: true\n }\n }\n });\n\n // Create the TTML rendering div before initialize() so the DOM element\n // exists, but attach it to dash.js after initialize() because\n // attachTTMLRenderingDiv() requires attachView() which initialize() calls.\n this._ttmlDiv = document.createElement('div');\n this._ttmlDiv.className = 'vidply-dash-ttml';\n this._ttmlDiv.style.visibility = 'hidden';\n const wrapper = this.player.videoWrapper || this.media.parentElement;\n if (wrapper) {\n wrapper.appendChild(this._ttmlDiv);\n }\n\n this.dash.initialize(this.media, null, false);\n this.dash.attachTTMLRenderingDiv(this._ttmlDiv);\n\n // Resolve source URL\n let src = this.player.currentSource;\n\n if (!src && originalSrc) {\n src = originalSrc;\n }\n\n if (!src) {\n src = this.player.element.getAttribute('data-vidply-src');\n }\n\n if (!src) {\n const elementSrc = this.player.element.getAttribute('src') || this.player.element.src;\n if (elementSrc && !elementSrc.startsWith('blob:')) {\n src = elementSrc;\n }\n }\n\n this.player.log(`Loading DASH source: ${src}`, 'log');\n\n if (!src) {\n throw new Error('No DASH source found');\n }\n\n // Always attach the source at init so the manifest is fetched and the\n // seekbar / duration / quality list are available before the first play.\n // We deliberately don't honor `deferLoad` here: deferring attachSource\n // would leave duration unknown and seek requests unserviceable. The\n // small preload (init segments + ~1 segment of media data) that dash.js\n // does up to bufferTimeDefault is acceptable; in exchange the seekbar\n // becomes functional immediately.\n this._pendingSrc = src;\n this._manifestUrl = src;\n this.dash.attachSource(src);\n this._dashSourceLoaded = true;\n\n // Force the vidply poster overlay even though dash.js will paint the\n // first decoded frame into the <video> element. With MSE attached and\n // init/startup segments appended, the browser ignores the native\n // `poster` attribute and shows the first frame instead. We instead use\n // the `vidply-forced-poster` CSS class, which sets `<video>` to\n // opacity:0 and renders the poster image as a wrapper background — the\n // user sees the artwork until they press play, just like on a fully\n // native HTML5 video. The 'play' handler in Player.ts already calls\n // hidePosterOverlay() on first playback, so we don't need to remove it\n // manually here.\n this.player.showPosterOverlay();\n\n this.attachDashEvents();\n this.attachMediaEvents();\n this._setupCaptionSync();\n }\n\n /**\n * Load dash.js. Pinned to an exact version (the previous default\n * `5.2.0` is preserved) and overridable via `options.dashScriptUrl`\n * (URL) / `options.dashScriptIntegrity` (SRI hash). See\n * HLSRenderer.loadHlsJs() for the SRI computation command.\n */\n async loadDashJs(): Promise<void> {\n const defaultUrl = 'https://cdn.jsdelivr.net/npm/dashjs@5.2.0/dist/modern/umd/dash.all.min.js';\n const url: string = (this.player.options.dashScriptUrl as string | undefined) || defaultUrl;\n const integrity = this.player.options.dashScriptIntegrity as string | undefined;\n\n return loadScriptOnce(url, { integrity });\n }\n\n _setTimeout(fn: () => void, delay: number) {\n const id = setTimeout(() => {\n this._pendingTimeouts = this._pendingTimeouts.filter(t => t !== id);\n fn();\n }, delay);\n this._pendingTimeouts.push(id);\n return id;\n }\n\n attachDashEvents() {\n const dashjs = window.dashjs;\n const dash = this.dash;\n if (!dashjs || !dash) return;\n const dashEvents = dashjs.MediaPlayer.events;\n\n dash.on(dashEvents.MANIFEST_LOADED, (...args: unknown[]) => {\n const e = args[0] as { data?: unknown } | undefined;\n const data = e?.data ?? e;\n this.player.log('DASH manifest loaded');\n this.player.emit('dashmanifestloaded', data);\n\n if (this.player.container) {\n this.player.container.classList.remove('vidply-external-controls');\n }\n\n this._setTimeout(() => {\n this._checkSubtitleTracks();\n }, 500);\n });\n\n dash.on(dashEvents.QUALITY_CHANGE_RENDERED, (...args: unknown[]) => {\n const e = args[0] as { mediaType?: string; newQuality?: number };\n if (e.mediaType === 'video') {\n this.player.log('DASH quality changed to index ' + e.newQuality);\n this.player.emit('dashqualitychanged', e);\n }\n });\n\n dash.on(dashEvents.TEXT_TRACKS_ADDED, (...args: unknown[]) => {\n const e = args[0] as { tracks?: DashTextTrack[] } | undefined;\n const tracks = e?.tracks ?? [];\n this._dashTextTracks = tracks;\n this._dashTextIsTtml = tracks.some((t) =>\n t.isTTML || /stpp|ttml/i.test(t.codec || '') || /ttml/i.test(t.mimeType || '')\n );\n this.player.log(`DASH text tracks added: ${tracks.length} tracks, format: ${this._dashTextIsTtml ? 'TTML' : 'WebVTT'}`);\n this._dashSubtitleTracksCount = tracks.length;\n this.player.emit('dashsubtitletracksupdated', { tracks });\n this.updateCaptionButtonsForDash();\n\n if (tracks.length > 0) {\n try {\n dash.setTextTrack(0);\n } catch {\n // ignore if not ready yet\n }\n if (!this._dashTextIsTtml) {\n this._startCueUpdatePolling();\n }\n }\n });\n\n dash.on(dashEvents.STREAM_INITIALIZED, () => {\n this.player.log('DASH stream initialized');\n this.player.emit('dashstreaminitialized');\n\n this._setTimeout(() => {\n const qualities = this.getQualities();\n if (qualities.length > 0) {\n this.player.emit('dashmanifestparsed', { qualities });\n }\n }, 300);\n });\n\n dash.on(dashEvents.ERROR, (...args: unknown[]) => {\n this.handleDashError(args[0]);\n });\n\n dash.on(dashEvents.FRAGMENT_LOADING_COMPLETED, (...args: unknown[]) => {\n const e = args[0] as { request?: { mediaType?: string } } | undefined;\n this.player.state.buffering = false;\n if (e?.request?.mediaType === 'text' && !this._dashTextIsTtml) {\n this._setTimeout(() => {\n const count = this._getTotalCueCount();\n if (count > this._lastKnownCueCount) {\n this._lastKnownCueCount = count;\n this.player.emit('textcuesupdate');\n }\n }, 100);\n }\n });\n }\n\n /**\n * Count total cues across all subtitle/caption tracks (for WebVTT DASH).\n */\n _getTotalCueCount() {\n const textTracks = this.media.textTracks;\n let total = 0;\n if (!textTracks) return total;\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n if (track && (track.kind === 'subtitles' || track.kind === 'captions') && !track._vidplyStale && track.cues) {\n total += track.cues.length;\n }\n }\n return total;\n }\n\n /**\n * Return true if `time` falls inside any TimeRange the SourceBuffer already\n * holds, with a small tolerance to absorb GOP boundaries. Used by the\n * seeking handler to decide whether to surface a 'waiting' event for the\n * spinner UI when the user scrubs while paused.\n */\n _isTimeBuffered(time: number): boolean {\n const buffered = this.media.buffered;\n if (!buffered || buffered.length === 0) return false;\n const tolerance = 0.25;\n for (let i = 0; i < buffered.length; i++) {\n if (time >= buffered.start(i) - tolerance && time <= buffered.end(i) + tolerance) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Sync VidPly caption track switches with dash.js so it loads\n * subtitle segments for the selected language.\n */\n _setupCaptionSync() {\n this._captionEnabledHandler = (selectedTrack) => {\n if (this._dashTextIsTtml) {\n // dash.js only renders TTML content to the rendering div when the\n // TextTrack mode is 'showing'. CaptionManager sets it to 'hidden',\n // so we override it here. VidPly's own caption overlay is skipped\n // via handlesOwnCaptions().\n if (selectedTrack.track) {\n selectedTrack.track.mode = 'showing';\n }\n if (this._ttmlDiv) {\n this._ttmlDiv.style.visibility = 'visible';\n }\n }\n this._syncDashTextTrack(selectedTrack);\n };\n this._captionDisabledHandler = () => {\n if (this._dashTextIsTtml && this._ttmlDiv) {\n this._ttmlDiv.style.visibility = 'hidden';\n }\n if (this.dash) {\n try { this.dash.setTextTrack(-1); } catch { /* ignore */ }\n }\n };\n this.player.on('captionsenabled', this._captionEnabledHandler);\n this.player.on('captionsdisabled', this._captionDisabledHandler);\n }\n\n /**\n * Map a VidPly caption track to the corresponding dash.js track index\n * and switch dash.js to load segments for that language.\n */\n _syncDashTextTrack(selectedTrack: CaptionTrackSelection) {\n if (!this.dash || !this._dashTextTracks.length) return;\n\n const lang = selectedTrack.language;\n if (!lang) return;\n\n const dashIndex = this._dashTextTracks.findIndex(dt => {\n const dtLang = dt.lang || dt.language || dt.srclang || '';\n if (!dtLang) return false;\n return dtLang === lang || dtLang.startsWith(lang) || lang.startsWith(dtLang);\n });\n\n if (dashIndex >= 0) {\n this.player.log(`Syncing DASH text track to index ${dashIndex} (${lang})`);\n try {\n this.dash.setTextTrack(dashIndex);\n } catch { /* ignore */ }\n if (!this._dashTextIsTtml) {\n this._lastKnownCueCount = 0;\n this._startCueUpdatePolling();\n }\n }\n }\n\n /**\n * Poll for new WebVTT cues being added by dash.js as subtitle segments load.\n * Emits events for transcript refresh when new cues arrive.\n */\n _startCueUpdatePolling() {\n this._stopCueUpdatePolling();\n let prevCueCount = 0;\n let stableRounds = 0;\n\n this._cueUpdateTimer = setInterval(() => {\n const count = this._getTotalCueCount();\n\n if (count > prevCueCount) {\n prevCueCount = count;\n stableRounds = 0;\n this.player.emit('textcuesupdate');\n } else {\n stableRounds++;\n if (stableRounds >= 8) {\n this._stopCueUpdatePolling();\n if (count > 0) {\n this.player.emit('textcuesupdate');\n }\n }\n }\n }, 500);\n }\n\n _stopCueUpdatePolling() {\n if (this._cueUpdateTimer) {\n clearInterval(this._cueUpdateTimer);\n this._cueUpdateTimer = null;\n }\n }\n\n _checkSubtitleTracks() {\n if (this._dashSubtitleTracksCount !== undefined && this._dashSubtitleTracksCount > 0) {\n return;\n }\n const tracks = this.media.textTracks;\n let count = 0;\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n if (track && (track.kind === 'subtitles' || track.kind === 'captions') && !track._vidplyStale) {\n count++;\n }\n }\n this._dashSubtitleTracksCount = count;\n this.updateCaptionButtonsForDash();\n }\n\n updateCaptionButtonsForDash(retryCount = 0) {\n const tracksCount = this._dashSubtitleTracksCount || 0;\n\n const doUpdate = () => {\n this.player.invalidateTrackCache();\n\n if (tracksCount > 0) {\n if (this.player.captionManager) {\n const found = this.player.captionManager.refreshTracks();\n\n // dash.js fires TEXT_TRACKS_ADDED when it knows about the\n // tracks, but the browser TextTrackList may not yet enumerate\n // the new TextTrack objects synchronously. If refreshTracks\n // found nothing, retry a few times with increasing delays.\n if (found === 0 && retryCount < 5) {\n const delay = (retryCount + 1) * 200;\n this.player.log(`DASH caption tracks not yet on video element, retrying in ${delay}ms (attempt ${retryCount + 1})`, 'info');\n this._setTimeout(() => {\n this.updateCaptionButtonsForDash(retryCount + 1);\n }, delay);\n return;\n }\n }\n\n if (!this._dashTextIsTtml && this.player.transcriptManager?.isVisible) {\n this.player.transcriptManager.loadTranscriptData();\n this.player.transcriptManager.updateLanguageSelector();\n }\n\n if (this.player.controlBar) {\n this.player.controlBar.ensureCaptionsButton();\n if (!this._dashTextIsTtml) {\n this.player.controlBar.ensureCaptionStyleButton();\n this.player.controlBar.ensureTranscriptButton();\n }\n }\n } else {\n if (this.player.captionManager) {\n this.player.captionManager.refreshTracks();\n }\n\n if (this.player.transcriptManager?.isVisible) {\n this.player.transcriptManager.hideTranscript();\n }\n\n if (this.player.controlBar) {\n this.player.controlBar.removeHlsCaptionButtons(true);\n }\n }\n };\n\n if (this.player.controlBar) {\n doUpdate();\n return;\n }\n\n const onReady = () => {\n this.player.off('ready', onReady);\n this._pendingReadyHandler = null;\n doUpdate();\n };\n // Track so destroy() can detach it if 'ready' never fires.\n this._pendingReadyHandler = onReady;\n this.player.on('ready', onReady);\n }\n\n attachMediaEvents() {\n const { signal } = this._listenerController;\n\n this.media.addEventListener('loadedmetadata', () => {\n this.player.state.duration = this.media.duration;\n this.player.emit('loadedmetadata');\n }, { signal });\n\n this.media.addEventListener('durationchange', () => {\n const duration = this.media.duration;\n if (duration && isFinite(duration) && duration > 0) {\n this.player.state.duration = duration;\n this.player.emit('durationchange', duration);\n }\n }, { signal });\n\n this.media.addEventListener('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 }, { signal });\n\n this.media.addEventListener('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 }, { signal });\n\n this.media.addEventListener('ended', () => {\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.player.seek(0);\n this.player.play();\n }\n }, { signal });\n\n this.media.addEventListener('timeupdate', () => {\n this.player.state.currentTime = this.media.currentTime;\n this.player.emit('timeupdate', this.media.currentTime);\n\n if (this.player.options.onTimeUpdate) {\n this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);\n }\n }, { signal });\n\n this.media.addEventListener('volumechange', () => {\n this.player.state.volume = this.media.volume;\n this.player.state.muted = this.media.muted;\n this.player.emit('volumechange', this.media.volume);\n }, { signal });\n\n this.media.addEventListener('seeking', () => {\n this.player.state.seeking = true;\n this.player.emit('seeking');\n\n // Browsers do not fire `waiting` when seeking on a paused media element\n // — there is nothing to \"wait\" for since playback isn't requested. With\n // dash.js + MSE, scrubbing while paused (or before the first play)\n // still triggers a real fragment download, but the spinner stays hidden\n // because no `waiting` event reaches the buffering UI. Detect a seek\n // into an unbuffered range here and surface it as 'waiting' so the\n // spinner appears. Cleared again by the existing `canplay` /\n // `seeked` paths.\n if (!this._isTimeBuffered(this.media.currentTime)) {\n this.player.state.buffering = true;\n this.player.emit('waiting');\n }\n }, { signal });\n\n this.media.addEventListener('seeked', () => {\n this.player.state.seeking = false;\n this.player.emit('seeked');\n }, { signal });\n\n this.media.addEventListener('waiting', () => {\n this.player.state.buffering = true;\n this.player.emit('waiting');\n }, { signal });\n\n this.media.addEventListener('canplay', () => {\n this.player.state.buffering = false;\n this.player.emit('canplay');\n }, { signal });\n\n this.media.addEventListener('error', () => {\n this.player.handleError(this.media.error);\n }, { signal });\n }\n\n handleDashError(e: unknown) {\n const wrapped = e as { error?: { code?: number; message?: string }; code?: number; message?: string } | undefined;\n const error = wrapped?.error ?? wrapped;\n if (!error) return;\n const code = error.code ?? '';\n const message = error.message || '';\n this.player.log(`DASH Error - Code: ${code}, Message: ${message}`, 'warn');\n\n if (typeof code === 'number' && code >= 100) {\n this.player.log('Fatal DASH error', 'error');\n this.player.handleError(new Error(`DASH Error: ${code} - ${message}`));\n } else {\n this.player.log('Non-fatal DASH error: ' + (message || String(error)), 'warn');\n }\n }\n\n ensureLoaded() {\n if (!this.player.options.deferLoad) {\n return;\n }\n\n if (!this.dash) {\n return;\n }\n\n if (this._dashSourceLoaded) {\n return;\n }\n\n const src = this._pendingSrc || this.player._pendingSource || this.player.currentSource;\n if (!src) {\n return;\n }\n\n try {\n this.dash.attachSource(src);\n this._dashSourceLoaded = true;\n } catch {\n // ignore\n }\n }\n\n play() {\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n // Defer-load (legacy code path, kept for completeness): the source is\n // normally attached at init and dash.js is configured with\n // scheduling.scheduleWhilePaused: false to keep prefetch at zero until\n // play. If for any reason the source is still pending here, attach it\n // now. Note that media.play() is called immediately afterwards; on\n // modern dash.js this races cleanly because attachSource() is sync\n // enough for the MediaSource to be ready by the time the play promise\n // resolves, and the configured zero-prefetch settings make the race\n // window very short. The general \"no preload\" UX no longer relies on\n // this branch.\n if (this.player.options.deferLoad && this.dash && !this._dashSourceLoaded) {\n const src = this._pendingSrc || this.player.currentSource;\n if (src) {\n try {\n this.dash.attachSource(src);\n this._dashSourceLoaded = true;\n } catch {\n // ignore and let media.play() surface errors if any\n }\n }\n }\n\n const promise = this.media.play();\n\n window.scrollTo(scrollX, scrollY);\n\n if (promise !== undefined) {\n promise.catch(error => {\n this.player.log('Play failed:', error, 'warn');\n });\n }\n }\n\n pause() {\n // dash.js stops scheduling new fragment downloads once `paused` is true,\n // because we configured `streaming.scheduling.scheduleWhilePaused: false`\n // at init. Already-buffered data stays in the SourceBuffer, so a\n // subsequent play() resumes near-instantly while pause saves bandwidth.\n this.media.pause();\n }\n\n seek(time: number) {\n this.media.currentTime = time;\n }\n\n setVolume(volume: number) {\n this.media.volume = volume;\n }\n\n setMuted(muted: boolean) {\n this.media.muted = muted;\n }\n\n setPlaybackSpeed(speed: number) {\n this.media.playbackRate = speed;\n }\n\n switchQuality(qualityIndex: number) {\n if (!this.dash) return;\n\n if (qualityIndex === -1) {\n // Re-enable ABR auto-switching\n if (typeof this.dash.setAutoSwitchQualityFor === 'function') {\n this.dash.setAutoSwitchQualityFor('video', true);\n } else {\n this.dash.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: true } } }\n });\n }\n } else {\n // Disable ABR and lock to the chosen quality\n if (typeof this.dash.setAutoSwitchQualityFor === 'function') {\n this.dash.setAutoSwitchQualityFor('video', false);\n } else {\n this.dash.updateSettings({\n streaming: { abr: { autoSwitchBitrate: { video: false } } }\n });\n }\n\n if (typeof this.dash.setRepresentationForTypeByIndex === 'function') {\n this.dash.setRepresentationForTypeByIndex('video', qualityIndex);\n } else if (typeof this.dash.setQualityFor === 'function') {\n this.dash.setQualityFor('video', qualityIndex, true);\n }\n }\n }\n\n getQualities() {\n if (!this.dash) return [];\n\n try {\n // dash.js v5+: getRepresentationsByType\n let reps = null;\n if (typeof this.dash.getRepresentationsByType === 'function') {\n reps = this.dash.getRepresentationsByType('video');\n }\n\n if (reps && reps.length > 0) {\n const heightCounts: Record<number, number> = {};\n reps.forEach((r: DashRepresentation) => {\n const h = Number(r.height) || 0;\n heightCounts[h] = (heightCounts[h] || 0) + 1;\n });\n\n return reps.map((rep: DashRepresentation, index: number) => {\n const height = Number(rep.height) || 0;\n const bitrate = Number(rep.bandwidth || rep.bitrate) || 0;\n const kb = bitrate > 0 ? Math.round(bitrate / 1000) : 0;\n let name;\n if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {\n name = `${height}p (${kb} kbps)`;\n } else if (height > 0) {\n name = `${height}p`;\n } else {\n name = kb > 0 ? `${kb} kbps` : 'Auto';\n }\n return {\n index,\n id: rep.id,\n height: rep.height,\n width: rep.width,\n bitrate,\n name\n };\n });\n }\n\n // Fallback: dash.js v4 and earlier\n const bitrateList = this.dash.getBitrateInfoListFor('video');\n if (!bitrateList || bitrateList.length === 0) return [];\n\n const heightCounts: Record<number, number> = {};\n bitrateList.forEach((info: DashBitrateInfo) => {\n const h = Number(info.height) || 0;\n heightCounts[h] = (heightCounts[h] || 0) + 1;\n });\n\n return bitrateList.map((info: DashBitrateInfo, index: number) => {\n const height = Number(info.height) || 0;\n const bitrate = Number(info.bitrate) || 0;\n const kb = bitrate > 0 ? Math.round(bitrate / 1000) : 0;\n let name;\n if (height > 0 && (heightCounts[height] ?? 0) > 1 && kb > 0) {\n name = `${height}p (${kb} kbps)`;\n } else if (height > 0) {\n name = `${height}p`;\n } else {\n name = kb > 0 ? `${kb} kbps` : 'Auto';\n }\n return {\n index,\n height: info.height,\n width: info.width,\n bitrate: info.bitrate,\n name\n };\n });\n } catch {\n return [];\n }\n }\n\n getCurrentQuality() {\n if (!this.dash) return -1;\n try {\n if (typeof this.dash.getRepresentationsByType === 'function') {\n const reps = this.dash.getRepresentationsByType('video');\n const current = this.dash.getCurrentRepresentationForType?.('video');\n if (current && reps) {\n const idx = reps.findIndex((r: DashRepresentation) => r.id === current.id);\n if (idx >= 0) return idx;\n }\n }\n return this.dash.getQualityFor('video');\n } catch {\n return -1;\n }\n }\n\n handlesOwnCaptions() {\n return this._dashTextIsTtml;\n }\n\n /**\n * Tell dash.js to activate the text track for `lang` so it begins\n * downloading subtitle segments and populating cues for that language.\n */\n activateTextTrackForLanguage(lang: string): boolean {\n if (!this.dash || !this._dashTextTracks.length || !lang) return false;\n\n let dashIndex = this._dashTextTracks.findIndex(dt => {\n const dtLang = dt.lang || dt.language || dt.srclang || '';\n if (!dtLang) return false;\n return dtLang === lang || dtLang.startsWith(lang) || lang.startsWith(dtLang);\n });\n\n if (dashIndex < 0) {\n dashIndex = this._dashTextTracks.findIndex(dt => {\n const dtLabel = (dt.label || dt.labels || '').toString().toLowerCase();\n return dtLabel.includes(lang.toLowerCase());\n });\n }\n\n if (dashIndex < 0) return false;\n\n this.player.log(`Activating DASH text track index ${dashIndex} for transcript language \"${lang}\"`);\n try {\n this.dash.setTextTrack(dashIndex);\n } catch { /* ignore */ }\n\n // dash.js's text scheduler only fetches segments while the video is\n // playing. When paused, a brief play–pause cycle forces the scheduler\n // to buffer text data for the newly selected track.\n if (this.media.paused) {\n const pos = this.media.currentTime;\n const wasMuted = this.media.muted;\n this.media.muted = true;\n const playPromise = this.media.play();\n const doPause = () => {\n if (this.media && !this.media.paused) {\n this.media.pause();\n this.media.muted = wasMuted;\n // Restore position in case it drifted\n if (Math.abs(this.media.currentTime - pos) > 0.5) {\n this.media.currentTime = pos;\n }\n }\n };\n if (playPromise && typeof playPromise.then === 'function') {\n playPromise.then(() => {\n this._setTimeout(doPause, 250);\n }).catch(() => {\n this.media.muted = wasMuted;\n });\n } else {\n this._setTimeout(doPause, 250);\n }\n }\n\n if (!this._dashTextIsTtml) {\n this._lastKnownCueCount = 0;\n this._startCueUpdatePolling();\n }\n return true;\n }\n\n getTextTrackURLs(): { lang: string; url: string }[] {\n if (!this.dash || !this._manifestUrl) return [];\n try {\n // dash.js manifest objects are loosely shaped (XML-derived), so we\n // walk them through index-keyed records and narrow as we go.\n type ManifestNode = Record<string, unknown>;\n const manifest = this.dash.getManifest?.() as ManifestNode | undefined;\n if (!manifest) return [];\n\n const baseUrl = this._manifestUrl.substring(0, this._manifestUrl.lastIndexOf('/') + 1);\n const results: { lang: string; url: string }[] = [];\n\n const rawPeriods = manifest.Period || manifest.period || manifest.periods || manifest;\n const periods = (Array.isArray(rawPeriods) ? rawPeriods : [rawPeriods]) as ManifestNode[];\n for (const period of periods) {\n const rawAdaptSets = period.AdaptationSet || period.adaptationSet || period.AdaptationSet_asArray || [];\n const adaptSets = (Array.isArray(rawAdaptSets) ? rawAdaptSets : [rawAdaptSets]) as ManifestNode[];\n for (const as of adaptSets) {\n const ct = String(as.contentType || as.ContentType || '');\n const mime = String(as.mimeType || as.MimeType || '');\n if (ct !== 'text' && !/text\\/vtt|application\\/ttml/i.test(mime)) continue;\n\n const lang = String(as.lang || as.language || '');\n const rawReps = as.Representation || as.representation || as.Representation_asArray || [];\n const reps = (Array.isArray(rawReps) ? rawReps : [rawReps]) as ManifestNode[];\n for (const rep of reps) {\n const bu = (rep.BaseURL || rep.baseURL || rep.BaseURL_asArray) as\n | string\n | { __text?: string }\n | Array<string | { __text?: string }>\n | undefined;\n let rawUrl: string | undefined;\n if (Array.isArray(bu)) {\n const first = bu[0];\n rawUrl = typeof first === 'string' ? first : first?.__text;\n } else if (typeof bu === 'string') {\n rawUrl = bu;\n } else {\n rawUrl = bu?.__text;\n }\n if (!rawUrl) continue;\n const url = rawUrl.startsWith('http') ? rawUrl : new URL(rawUrl, baseUrl).href;\n results.push({ lang, url });\n break;\n }\n }\n }\n return results;\n } catch {\n return [];\n }\n }\n\n supportsAutoQuality() {\n return true;\n }\n\n isAutoQuality() {\n if (!this.dash) return true;\n try {\n if (typeof this.dash.getAutoSwitchQualityFor === 'function') {\n return this.dash.getAutoSwitchQualityFor('video');\n }\n const settings = this.dash.getSettings?.();\n return settings?.streaming?.abr?.autoSwitchBitrate?.video !== false;\n } catch {\n return true;\n }\n }\n\n destroy() {\n this._pendingTimeouts.forEach(id => clearTimeout(id));\n this._pendingTimeouts = [];\n this._stopCueUpdatePolling();\n this._lastKnownCueCount = 0;\n // Detach media listeners registered in attachMediaEvents().\n this._listenerController.abort();\n // Remove the deferred 'ready' listener if it never fired.\n if (this._pendingReadyHandler) {\n this.player.off('ready', this._pendingReadyHandler);\n this._pendingReadyHandler = null;\n }\n\n if (this._captionEnabledHandler) {\n this.player.off('captionsenabled', this._captionEnabledHandler);\n this._captionEnabledHandler = null;\n }\n if (this._captionDisabledHandler) {\n this.player.off('captionsdisabled', this._captionDisabledHandler);\n this._captionDisabledHandler = null;\n }\n\n if (this._ttmlDiv && this._ttmlDiv.parentNode) {\n this._ttmlDiv.parentNode.removeChild(this._ttmlDiv);\n this._ttmlDiv = null;\n }\n\n // Mark all subtitle/caption text tracks as stale. dash.js creates\n // programmatic TextTrack objects that persist on the <video> element\n // after destroy() and cannot be removed via standard APIs. The stale\n // flag prevents _checkSubtitleTracks() in a new renderer instance from\n // treating them as tracks belonging to the current stream.\n const textTracks = this.media.textTracks;\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n if (track && (track.kind === 'subtitles' || track.kind === 'captions')) {\n track._vidplyStale = true;\n track.mode = 'disabled';\n }\n }\n\n if (this.dash) {\n try {\n // Silence dash.js logging during teardown to suppress harmless\n // SourceBuffer errors from in-flight async operations.\n this.dash.updateSettings({ debug: { logLevel: 0 } });\n // reset() cleanly detaches from MediaSource and cancels pending\n // buffer operations before destroy() releases all resources.\n this.dash.reset();\n } catch { /* ignore teardown errors */ }\n try {\n this.dash.destroy();\n } catch { /* ignore teardown errors */ }\n this.dash = null;\n }\n this._dashTextTracks = [];\n this._dashTextIsTtml = false;\n this._manifestUrl = null;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["heightCounts"]
7
+ }
@@ -1,18 +1,18 @@
1
1
  /*!
2
- * VidPly v1.2.0 - Universal, Accessible Video Player
2
+ * VidPly v1.2.3 - Universal, Accessible Video Player
3
3
  * (c) 2026 Matthias Peltzer
4
4
  * Released under GPL-2.0-or-later License
5
5
  */
6
6
  import {
7
7
  DraggableResizable
8
- } from "./vidply.chunk-JJ47NO24.js";
8
+ } from "./vidply.chunk-UNFGMABP.js";
9
9
  import {
10
10
  createIconElement
11
- } from "./vidply.chunk-KI7C3QVL.js";
11
+ } from "./vidply.chunk-UI3RYCVF.js";
12
12
  import {
13
13
  DOMUtils,
14
14
  i18n
15
- } from "./vidply.chunk-RZWZGDV7.js";
15
+ } from "./vidply.chunk-I6EDRYGJ.js";
16
16
 
17
17
  // src/core/FloatingPlayerManager.ts
18
18
  var FLOATING_CLAIM_EVENT = "vidply:floating-claim";
@@ -534,4 +534,4 @@ var FloatingPlayerManager = class {
534
534
  export {
535
535
  FloatingPlayerManager
536
536
  };
537
- //# sourceMappingURL=vidply.FloatingPlayerManager-PKNNNAS2.js.map
537
+ //# sourceMappingURL=vidply.FloatingPlayerManager-C2UVRPZY.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/FloatingPlayerManager.ts"],
4
+ "sourcesContent": ["/**\n * Floating Player Manager\n *\n * Custom in-page Picture-in-Picture. Moves the entire player.container\n * into a position:fixed, draggable and resizable shell that lives outside\n * the document flow (appended to document.body). A transparent placeholder\n * preserves layout and, while floating, serves as the IntersectionObserver\n * sentinel so scroll-based auto-float/redock decisions stay anchored to\n * the original slot.\n *\n * Triggers:\n * - pinned: the user clicks the control-bar PiP button (only when\n * options.floating is true; otherwise the button uses native PiP).\n * Pinned floating ignores scroll-based docking.\n * - auto: the video is playing and the original slot has scrolled out\n * of the viewport. Auto-float redocks automatically when the slot\n * scrolls back in.\n *\n * Close button: pauses playback, exits the floating shell and marks the\n * current play session as dismissed so auto-float will not re-trigger\n * until the user presses play again (matches YouTube miniplayer UX).\n *\n * Only one player is allowed to float at a time across a page; enter()\n * broadcasts a 'vidply:floating-claim' CustomEvent that other managers\n * listen for and auto-exit on.\n */\n\nimport { DOMUtils } from '../utils/DOMUtils.js';\nimport { DraggableResizable } from '../utils/DraggableResizable.js';\nimport { createIconElement } from '../icons/Icons.js';\nimport { i18n } from '../i18n/i18n.js';\nimport type { Player } from './Player.js';\n\ntype FloatingState = 'pinned' | 'auto';\ntype ExitReason = 'manual' | 'auto' | 'dismiss' | 'claim' | 'destroy';\n\nconst FLOATING_CLAIM_EVENT = 'vidply:floating-claim';\nconst DEFAULT_WIDTH = 400;\nconst MIN_WIDTH = 240;\nconst EDGE_MARGIN = 16;\n\ninterface FloatingPrefs {\n width?: number;\n height?: number;\n left?: number;\n top?: number;\n}\n\nexport class FloatingPlayerManager {\n player: Player;\n classPrefix: string;\n\n shell: HTMLElement | null;\n dragHandle: HTMLElement | null;\n closeButton: HTMLButtonElement | null;\n resizeHandles: HTMLElement[];\n placeholder: HTMLElement | null;\n draggable: DraggableResizable | null;\n\n originalParent: HTMLElement | null;\n originalNextSibling: Node | null;\n\n intersectionObserver: IntersectionObserver | null;\n observerTarget: HTMLElement | null;\n lastRatio: number;\n\n _autoDismissedThisPlay: boolean;\n _playListenerAttached: boolean;\n _onPlayAfterDismiss: (() => void) | null;\n _onClaim: ((event: Event) => void) | null;\n _onResize: (() => void) | null;\n _onKeyDown: ((event: KeyboardEvent) => void) | null;\n _onEnterFullscreen: (() => void) | null;\n _destroyed: boolean;\n _triggerFocusEl: HTMLElement | null;\n _claimId: string;\n _lastAutoExitTime: number;\n\n constructor(player: Player) {\n this.player = player;\n this.classPrefix = player.options.classPrefix || 'vidply';\n\n this.shell = null;\n this.dragHandle = null;\n this.closeButton = null;\n this.resizeHandles = [];\n this.placeholder = null;\n this.draggable = null;\n\n this.originalParent = null;\n this.originalNextSibling = null;\n\n this.intersectionObserver = null;\n this.observerTarget = null;\n this.lastRatio = 1;\n\n this._autoDismissedThisPlay = false;\n this._playListenerAttached = false;\n this._onPlayAfterDismiss = null;\n this._onClaim = null;\n this._onResize = null;\n this._onKeyDown = null;\n this._onEnterFullscreen = null;\n this._destroyed = false;\n this._triggerFocusEl = null;\n this._claimId = `floating-${player.instanceId}-${Date.now()}`;\n this._lastAutoExitTime = 0;\n\n this._setupClaimListener();\n this._setupFullscreenGuard();\n this._startObserving();\n }\n\n // ---------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------\n\n togglePinned(triggerEl?: HTMLElement | null) {\n if (this._destroyed) return;\n if (this.player.state.floating === 'pinned') {\n // Manual unpin: suppress auto-float for the remainder of the\n // current play session so scrolling doesn't immediately re-pop\n // the floating shell. A fresh 'play' event clears the flag.\n this._autoDismissedThisPlay = true;\n this._armPlayListenerToClearDismiss();\n this.exit('manual');\n return;\n }\n // If the user pins while in 'auto' mode, that's an explicit request\n // to float; any previous auto-dismiss flag should be cleared so the\n // pinned state behaves naturally.\n this._autoDismissedThisPlay = false;\n this._triggerFocusEl = triggerEl || this._activeElement();\n this.enter('pinned');\n }\n\n enter(reason: FloatingState) {\n if (this._destroyed) return;\n if (this.player.state.floating === reason) return;\n\n if (!this._canFloat(reason)) {\n return;\n }\n\n // Upgrade 'auto' -> 'pinned' without rebuilding the shell\n if (this.player.state.floating && this.player.state.floating !== reason) {\n this.player.state.floating = reason;\n this.player.emit('floatingchange', reason);\n return;\n }\n\n this._claimSingleton();\n\n this._ensureShell();\n this._mountIntoShell();\n this._applyInitialGeometry();\n\n this.player.state.floating = reason;\n this.player.emit('floatingchange', reason);\n\n // Focus the close button after a microtask so screen readers announce\n // the dialog opening.\n queueMicrotask(() => {\n if (this.closeButton && this.player.state.floating) {\n try { this.closeButton.focus({ preventScroll: true }); } catch { /* ignore */ }\n }\n });\n }\n\n exit(reason: ExitReason = 'manual') {\n if (this._destroyed && reason !== 'destroy') return;\n if (!this.player.state.floating) return;\n\n if (reason === 'auto') {\n // Record when an auto-exit occurred so the IntersectionObserver\n // callback can apply a cooldown before re-entering auto-float.\n this._lastAutoExitTime = Date.now();\n }\n\n this._unmountFromShell();\n this._teardownShell();\n\n const priorTrigger = this._triggerFocusEl;\n this._triggerFocusEl = null;\n\n this.player.state.floating = null;\n this.player.emit('floatingchange', null);\n\n // Restore focus to the element that triggered floating (pinned flow).\n // For scroll-based exits we leave focus untouched.\n if ((reason === 'manual' || reason === 'dismiss') && priorTrigger) {\n try { priorTrigger.focus({ preventScroll: true }); } catch { /* ignore */ }\n }\n }\n\n /**\n * Close button: pause, dismiss, and prevent auto-float until the next\n * user-initiated play event.\n */\n dismiss() {\n if (this._destroyed) return;\n this._autoDismissedThisPlay = true;\n this._armPlayListenerToClearDismiss();\n\n try {\n this.player.pause();\n } catch { /* ignore */ }\n\n this.exit('dismiss');\n }\n\n destroy() {\n if (this._destroyed) return;\n this._destroyed = true;\n\n if (this.player.state && this.player.state.floating) {\n try { this.exit('destroy'); } catch { /* ignore */ }\n }\n\n if (this.intersectionObserver) {\n try { this.intersectionObserver.disconnect(); } catch { /* ignore */ }\n this.intersectionObserver = null;\n }\n this.observerTarget = null;\n\n if (this._onClaim) {\n window.removeEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener);\n this._onClaim = null;\n }\n if (this._onResize) {\n window.removeEventListener('resize', this._onResize);\n this._onResize = null;\n }\n const enterFs = this._onEnterFullscreen;\n if (enterFs) {\n this.player.off('enterfullscreen', enterFs);\n this._onEnterFullscreen = null;\n }\n const playAfterDismiss = this._onPlayAfterDismiss;\n if (playAfterDismiss && this._playListenerAttached) {\n this.player.off('play', playAfterDismiss);\n this._playListenerAttached = false;\n this._onPlayAfterDismiss = null;\n }\n }\n\n // ---------------------------------------------------------------\n // Internal: guards\n // ---------------------------------------------------------------\n\n _canFloat(reason: FloatingState): boolean {\n if (!this.player.options.floating) return false;\n if (!this.player.container) return false;\n if (!this.player.element || this.player.element.tagName !== 'VIDEO') return false;\n if (this.player.state.fullscreen) return false;\n\n // Playlist players move through multiple tracks and manage their own\n // UI; floating support for playlists is out of scope for this v1.\n if (this.player.playlistManager) return false;\n\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\n if (window.innerWidth < minWidth) return false;\n\n // Auto-float only engages when the user is actively watching.\n if (reason === 'auto') {\n if (this._autoDismissedThisPlay) return false;\n if (this.player.state.paused) return false;\n // Never auto-float before the user has started playback; stops\n // auto-entry from firing while the page is still below the fold\n // on initial load.\n if (!this.player.state.hasStartedPlayback) return false;\n }\n\n return true;\n }\n\n _claimSingleton() {\n try {\n window.dispatchEvent(new CustomEvent(FLOATING_CLAIM_EVENT, {\n detail: { claimId: this._claimId }\n }));\n } catch { /* ignore (older browsers) */ }\n }\n\n _setupClaimListener() {\n this._onClaim = (event: Event) => {\n const detail = (event as CustomEvent).detail;\n if (!detail || detail.claimId === this._claimId) return;\n if (this.player.state.floating) {\n this.exit('claim');\n }\n };\n const signal = this.player.lifecycleSignal;\n window.addEventListener(FLOATING_CLAIM_EVENT, this._onClaim as EventListener, { signal });\n\n this._onResize = () => {\n const minWidth = this.player.options.floatingMinViewportWidth ?? 768;\n if (this.player.state.floating && window.innerWidth < minWidth) {\n this.exit('auto');\n }\n };\n window.addEventListener('resize', this._onResize, { signal });\n }\n\n _setupFullscreenGuard() {\n const onEnterFullscreen = () => {\n if (this.player.state.floating) {\n this.exit('manual');\n }\n };\n this._onEnterFullscreen = onEnterFullscreen;\n this.player.on('enterfullscreen', onEnterFullscreen);\n }\n\n _armPlayListenerToClearDismiss() {\n if (this._playListenerAttached) return;\n const onPlayAfterDismiss = () => {\n this._autoDismissedThisPlay = false;\n const handler = this._onPlayAfterDismiss;\n if (handler) {\n this.player.off('play', handler);\n }\n this._playListenerAttached = false;\n this._onPlayAfterDismiss = null;\n };\n this._onPlayAfterDismiss = onPlayAfterDismiss;\n this.player.on('play', onPlayAfterDismiss);\n this._playListenerAttached = true;\n }\n\n // ---------------------------------------------------------------\n // Internal: IntersectionObserver for scroll-triggered auto-float\n // ---------------------------------------------------------------\n\n _startObserving() {\n if (!('IntersectionObserver' in window)) return;\n if (!this.player.container) return;\n\n this.observerTarget = this.player.container;\n this.intersectionObserver = new IntersectionObserver((entries) => {\n const entry = entries[entries.length - 1];\n if (!entry) return;\n this.lastRatio = entry.intersectionRatio;\n\n if (this.player.options.debug) {\n try {\n console.log('[vidply:floating] intersection', {\n ratio: Number(entry.intersectionRatio.toFixed(3)),\n state: this.player.state.floating,\n paused: this.player.state.paused,\n hasStartedPlayback: this.player.state.hasStartedPlayback,\n dismissed: this._autoDismissedThisPlay\n });\n } catch { /* ignore */ }\n }\n\n if (this.player.state.floating === 'auto') {\n if (entry.intersectionRatio >= 0.5) {\n this.exit('auto');\n }\n return;\n }\n\n // Pinned state: scroll is a no-op, the user has taken control.\n if (this.player.state.floating === 'pinned') {\n return;\n }\n\n if (entry.intersectionRatio < 0.1 && this._canFloat('auto')) {\n // Brief cooldown after an auto-exit prevents the layout reflow that\n // accompanies the placeholder→container swap from immediately\n // re-triggering auto-float (oscillation guard).\n const AUTO_EXIT_COOLDOWN_MS = 500;\n if (Date.now() - this._lastAutoExitTime < AUTO_EXIT_COOLDOWN_MS) return;\n this.enter('auto');\n }\n }, { threshold: [0, 0.1, 0.5, 0.9] });\n\n this.intersectionObserver.observe(this.observerTarget);\n }\n\n _retargetObserver(target: HTMLElement) {\n if (!this.intersectionObserver) return;\n if (this.observerTarget) {\n try { this.intersectionObserver.unobserve(this.observerTarget); } catch { /* ignore */ }\n }\n this.observerTarget = target;\n try { this.intersectionObserver.observe(target); } catch { /* ignore */ }\n }\n\n // ---------------------------------------------------------------\n // Internal: shell DOM\n // ---------------------------------------------------------------\n\n _ensureShell() {\n if (this.shell) return;\n\n this.shell = DOMUtils.createElement('div', {\n className: `${this.classPrefix}-floating-shell`,\n attributes: {\n 'role': 'dialog',\n 'aria-modal': 'false',\n 'aria-label': i18n.t('player.floatingPlayer'),\n 'data-vidply-floating': 'true',\n 'tabindex': '-1'\n }\n });\n\n this.dragHandle = DOMUtils.createElement('div', {\n className: `${this.classPrefix}-floating-drag-handle`,\n attributes: { 'aria-hidden': 'true' }\n });\n this.shell.appendChild(this.dragHandle);\n\n this.closeButton = DOMUtils.createElement('button', {\n className: `${this.classPrefix}-floating-close`,\n attributes: {\n 'type': 'button',\n 'aria-label': i18n.t('player.floatingPlayerClose'),\n 'title': i18n.t('player.floatingPlayerClose')\n }\n }) as HTMLButtonElement;\n this.closeButton.appendChild(createIconElement('close'));\n this.closeButton.addEventListener('click', (event) => {\n event.stopPropagation();\n this.dismiss();\n });\n this.shell.appendChild(this.closeButton);\n\n this._createResizeHandles();\n const shell = this.shell;\n this.resizeHandles.forEach(handle => shell.appendChild(handle));\n\n this._onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n // If the user is in keyboard drag / resize (or pointer-resize)\n // mode, Escape must exit that mode first — not dismiss the\n // whole floating player. This listener is registered before the\n // DraggableResizable one, so we let the event fall through to\n // it (no dismiss, no stopPropagation) while a mode is active\n // (WCAG 2.1.1). Only a \"neutral\" Escape dismisses.\n const d = this.draggable;\n const inEditMode = !!d && (d.keyboardDragMode || d.keyboardResizeMode || d.pointerResizeMode);\n if (inEditMode) {\n return;\n }\n event.stopPropagation();\n this.dismiss();\n }\n };\n this.shell.addEventListener('keydown', this._onKeyDown as EventListener);\n }\n\n _createResizeHandles() {\n // Resize handles are always-on for the floating shell. Do NOT set\n // `data-vidply-managed-resize=\"true\"`: that flag is used by the\n // transcript / sign-language overlays to gate the handles behind\n // an \"R\" keypress, and DraggableResizable hides managed handles\n // during init() — which would leave the shell with no visible or\n // hittable edges/corners.\n const dirs = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];\n this.resizeHandles = dirs.map(dir => DOMUtils.createElement('div', {\n className: `${this.classPrefix}-floating-resize-handle ${this.classPrefix}-floating-resize-${dir}`,\n attributes: {\n 'data-direction': dir,\n 'aria-hidden': 'true'\n }\n }));\n }\n\n _teardownShell() {\n if (this.draggable) {\n try { this.draggable.destroy(); } catch { /* ignore */ }\n this.draggable = null;\n }\n if (this.shell) {\n if (this._onKeyDown) {\n this.shell.removeEventListener('keydown', this._onKeyDown as EventListener);\n this._onKeyDown = null;\n }\n if (this.shell.parentNode) {\n this.shell.parentNode.removeChild(this.shell);\n }\n }\n this.shell = null;\n this.dragHandle = null;\n this.closeButton = null;\n this.resizeHandles = [];\n }\n\n // ---------------------------------------------------------------\n // Internal: mount / unmount the player.container\n // ---------------------------------------------------------------\n\n _mountIntoShell() {\n const container = this.player.container;\n if (!container || !container.parentNode) return;\n if (!this.shell) return;\n\n const rect = container.getBoundingClientRect();\n this.originalParent = container.parentNode as HTMLElement;\n this.originalNextSibling = container.nextSibling;\n\n this.placeholder = DOMUtils.createElement('div', {\n className: `${this.classPrefix}-floating-placeholder`,\n attributes: { 'aria-hidden': 'true' }\n });\n this.placeholder.style.width = `${Math.max(1, rect.width)}px`;\n this.placeholder.style.height = `${Math.max(1, rect.height)}px`;\n\n // Centred PiP glyph that signals \"video popped out\" in the slot the\n // player used to occupy. Lives as a regular child so it can inherit\n // currentColor and scale with the placeholder; both the icon and\n // the placeholder itself are removed wholesale on _unmountFromShell().\n const placeholderIcon = createIconElement('pip', `${this.classPrefix}-floating-placeholder-icon`);\n this.placeholder.appendChild(placeholderIcon);\n\n this.originalParent.insertBefore(this.placeholder, container);\n\n this.shell.appendChild(container);\n document.body.appendChild(this.shell);\n\n container.classList.add(`${this.classPrefix}-is-floating`);\n\n // Observe the placeholder while floating so scroll-back decisions are\n // anchored to the original slot instead of the moved container.\n this._retargetObserver(this.placeholder);\n }\n\n _unmountFromShell() {\n const container = this.player.container;\n\n if (container) {\n container.classList.remove(`${this.classPrefix}-is-floating`);\n // Clear inline sizes applied while floating\n container.style.removeProperty('width');\n container.style.removeProperty('height');\n }\n\n if (this.placeholder && this.placeholder.parentNode) {\n if (container) {\n this.placeholder.parentNode.insertBefore(container, this.placeholder);\n }\n this.placeholder.parentNode.removeChild(this.placeholder);\n } else if (container && this.originalParent) {\n if (this.originalNextSibling && this.originalNextSibling.parentNode === this.originalParent) {\n this.originalParent.insertBefore(container, this.originalNextSibling);\n } else {\n this.originalParent.appendChild(container);\n }\n }\n\n this.placeholder = null;\n this.originalParent = null;\n this.originalNextSibling = null;\n\n // Retarget the observer to the docked container\n if (container) {\n this._retargetObserver(container);\n }\n }\n\n // ---------------------------------------------------------------\n // Internal: initial geometry + drag/resize wiring\n // ---------------------------------------------------------------\n\n _applyInitialGeometry() {\n if (!this.shell) return;\n\n const prefs = (this.player.storage?.getFloatingPreferences?.() || {}) as FloatingPrefs;\n\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n let width = prefs.width && prefs.width >= MIN_WIDTH ? prefs.width : DEFAULT_WIDTH;\n width = Math.min(width, Math.max(MIN_WIDTH, vw - EDGE_MARGIN * 2));\n\n // If we know the source container's aspect ratio, match it by default.\n const containerRect = this.player.container?.getBoundingClientRect();\n const aspect = containerRect && containerRect.height > 0\n ? containerRect.width / containerRect.height\n : 16 / 9;\n const defaultHeight = Math.round(width / aspect);\n let height = prefs.height && prefs.height >= 100 ? prefs.height : defaultHeight;\n height = Math.min(height, Math.max(100, vh - EDGE_MARGIN * 2));\n\n let left: number;\n let top: number;\n\n if (typeof prefs.left === 'number' && typeof prefs.top === 'number') {\n left = Math.max(EDGE_MARGIN, Math.min(prefs.left, vw - width - EDGE_MARGIN));\n top = Math.max(EDGE_MARGIN, Math.min(prefs.top, vh - height - EDGE_MARGIN));\n } else {\n const pos = this.player.options.floatingPosition || 'bottom-right';\n switch (pos) {\n case 'bottom-left':\n left = EDGE_MARGIN;\n top = vh - height - EDGE_MARGIN;\n break;\n case 'top-right':\n left = vw - width - EDGE_MARGIN;\n top = EDGE_MARGIN;\n break;\n case 'top-left':\n left = EDGE_MARGIN;\n top = EDGE_MARGIN;\n break;\n case 'bottom-right':\n default:\n left = vw - width - EDGE_MARGIN;\n top = vh - height - EDGE_MARGIN;\n break;\n }\n }\n\n this.shell.style.width = `${width}px`;\n this.shell.style.height = `${height}px`;\n this.shell.style.left = `${left}px`;\n this.shell.style.top = `${top}px`;\n\n this._initDraggable();\n }\n\n _initDraggable() {\n if (!this.shell) return;\n if (this.draggable) return;\n\n this.draggable = new DraggableResizable(this.shell, {\n dragHandle: this.dragHandle,\n resizeHandles: this.resizeHandles,\n constrainToViewport: true,\n maintainAspectRatio: true,\n minWidth: MIN_WIDTH,\n minHeight: 100,\n maxWidth: () => Math.max(MIN_WIDTH, window.innerWidth - EDGE_MARGIN * 2),\n maxHeight: () => Math.max(100, window.innerHeight - EDGE_MARGIN * 2),\n classPrefix: `${this.classPrefix}-floating`,\n keyboardDragKey: 'd',\n keyboardResizeKey: 'r',\n keyboardStep: 10,\n keyboardStepLarge: 50,\n pointerResizeIndicatorText: i18n.t('player.floatingPlayerDialog'),\n onDragEnd: () => this._savePrefs(),\n onResizeEnd: () => this._savePrefs(),\n onDragStart: (event: Event) => {\n const target = event.target as HTMLElement;\n if (!target) return true;\n // Don't start drag when interacting with the close button or\n // with any control inside the embedded player (play/pause,\n // captions menu, etc.).\n if (target.closest(`.${this.classPrefix}-floating-close`)) return false;\n if (target.closest(`.${this.classPrefix}-controls`)) return false;\n if (target.closest(`.${this.classPrefix}-floating-resize-handle`)) return false;\n return true;\n }\n });\n }\n\n _savePrefs() {\n if (!this.shell || !this.player.storage?.saveFloatingPreferences) return;\n const rect = this.shell.getBoundingClientRect();\n this.player.storage.saveFloatingPreferences({\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n left: Math.round(rect.left),\n top: Math.round(rect.top)\n });\n }\n\n _activeElement(): HTMLElement | null {\n const active = document.activeElement;\n return active && active instanceof HTMLElement ? active : null;\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.3 - 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-JZNZX32Z.js";
9
9
 
10
10
  // src/renderers/HLSRenderer.ts
11
11
  var HLSRenderer = class {
@@ -94,7 +94,7 @@ var HLSRenderer = class {
94
94
  return video.canPlayType("application/vnd.apple.mpegurl") !== "";
95
95
  }
96
96
  async initNative() {
97
- const { HTML5Renderer } = await import("./vidply.HTML5Renderer-BU4QJJJY.js");
97
+ const { HTML5Renderer } = await import("./vidply.HTML5Renderer-HLRQUOCU.js");
98
98
  const native = new HTML5Renderer(this.player);
99
99
  await native.init();
100
100
  this.play = () => native.play();
@@ -701,4 +701,4 @@ var HLSRenderer = class {
701
701
  export {
702
702
  HLSRenderer
703
703
  };
704
- //# sourceMappingURL=vidply.HLSRenderer-E7RQ74HI.js.map
704
+ //# sourceMappingURL=vidply.HLSRenderer-ZVBK2TNQ.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/renderers/HLSRenderer.ts"],
4
+ "sourcesContent": ["import type { Renderer, QualityLevel } from '../types/renderer.js';\nimport type { Player } from '../core/Player.js';\nimport { loadScriptOnce } from '../utils/ScriptLoader.js';\n\n/** Subset of payloads emitted by hls.js events that we actually consume. */\ninterface HlsManifestParsedData {\n levels: HlsLevel[];\n}\n\ninterface HlsLevelSwitchedData {\n level: number;\n}\n\ninterface HlsSubtitleTracksUpdatedData {\n subtitleTracks: HlsSubtitleTrack[];\n}\n\ninterface HlsSubtitleTrackSwitchData {\n id: number;\n}\n\ninterface HlsSubtitleFragProcessedData {\n success?: boolean;\n}\n\nexport class HLSRenderer implements Renderer {\n player: Player;\n media: HTMLMediaElement;\n hls: HlsInstance | null;\n\n // True once hls.js is driving playback via MSE. Native HLS playback on\n // iOS / iPadOS keeps a real HTTP URL on the <video> and does not need the\n // streaming path to be forced.\n get isStreaming(): boolean {\n return this.hls !== null && this.hls !== undefined;\n }\n\n _hlsSourceLoaded: boolean;\n _pendingSrc: string | null;\n _hlsSubtitleTracksCount: number | undefined;\n _cueUpdateTimer: ReturnType<typeof setInterval> | null;\n _lastKnownCueCount: number;\n _nativeTrackListenersDestroyed?: boolean;\n _didDeferredLoad?: boolean;\n _manifestUrl: string | null;\n /**\n * True when the most recent startLoad() call was triggered by a seek on a\n * paused media element (not by play()). The FRAG_BUFFERED handler uses this\n * to call stopLoad() once the seek target is buffered, so hls.js does not\n * keep pre-fetching subsequent segments while the user is still paused.\n */\n _loadingForSeekOnly?: boolean;\n _cleanupNativeTextTrackListeners: () => void;\n // Detaches all hls.js-path media listeners (attachMediaEvents) in destroy().\n private _listenerController: AbortController;\n // Pending setTimeout ids so destroy() can cancel retries that would\n // otherwise fire (and touch a torn-down player) after teardown.\n private _timers: Set<ReturnType<typeof setTimeout>>;\n // Tracked 'ready' listener registered by updateCaptionButtonsForHls when the\n // control bar isn't built yet; removed on destroy if it never fired.\n private _pendingReadyHandler: (() => void) | null;\n\n constructor(player: Player) {\n this.player = player;\n this.media = player.element;\n this.hls = null;\n this._hlsSourceLoaded = false;\n this._pendingSrc = null;\n this._hlsSubtitleTracksCount = undefined;\n this._cueUpdateTimer = null;\n this._lastKnownCueCount = 0;\n this._manifestUrl = null;\n this._cleanupNativeTextTrackListeners = () => {};\n this._listenerController = new AbortController();\n this._timers = new Set();\n this._pendingReadyHandler = null;\n }\n\n /**\n * Schedule a timeout that is automatically cancelled by destroy(). Prevents\n * caption-retry / error-recovery callbacks from running after teardown.\n */\n private _setTimeout(handler: () => void, ms: number): void {\n const id = setTimeout(() => {\n this._timers.delete(id);\n handler();\n }, ms);\n this._timers.add(id);\n }\n\n private _clearTimers(): void {\n for (const id of this._timers) {\n clearTimeout(id);\n }\n this._timers.clear();\n }\n\n async init() {\n // Check if browser natively supports HLS (Safari)\n if (this.canPlayNatively()) {\n this.player.log('Using native HLS support');\n await this.initNative();\n } else {\n this.player.log('Using hls.js for HLS support');\n await this.initHlsJs();\n }\n }\n\n canPlayNatively() {\n // Use native HLS only on iOS/iPadOS (MSE unavailable); desktop macOS Safari uses hls.js\n // for quality switching and parity with Chrome/Firefox.\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n // iPad in desktop mode reports MacIntel but has touch\n const isIPadDesktopMode = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;\n\n if (!isIOS && !isIPadDesktopMode) {\n return false;\n }\n\n const video = document.createElement('video');\n return video.canPlayType('application/vnd.apple.mpegurl') !== '';\n }\n\n async initNative() {\n // Native HLS (iOS / iPadOS): the <video> element plays the HLS URL\n // directly, so we delegate the playback surface to an HTML5Renderer via\n // composition rather than grafting its prototype methods onto this\n // instance. hls.js is never created on this path (this.hls stays null),\n // and this.media already references the same player.element the delegate\n // drives, so quality/caption inspection keeps working.\n const { HTML5Renderer } = await import('./HTML5Renderer.js');\n const native = new HTML5Renderer(this.player);\n await native.init();\n\n // Forward the externally-invoked Renderer surface to the delegate. The\n // delegate's own internal helpers (attachEvents, pauseOtherPlayers, …)\n // run via these calls, so they don't need explicit forwarding. HLS-only\n // methods (attachHlsEvents, handleHlsError, supportsAutoQuality, …) keep\n // their HLSRenderer implementations.\n this.play = () => native.play();\n this.pause = () => native.pause();\n this.seek = (time: number) => native.seek(time);\n this.setVolume = (volume: number) => native.setVolume(volume);\n this.setMuted = (muted: boolean) => native.setMuted(muted);\n this.setPlaybackSpeed = (speed: number) => native.setPlaybackSpeed(speed);\n this.ensureLoaded = () => native.ensureLoaded?.();\n this.getQualities = () => native.getQualities?.() ?? [];\n this.switchQuality = (index: number) => native.switchQuality?.(index);\n this.getCurrentQuality = () => native.getCurrentQuality?.() ?? 0;\n\n this._attachNativeTextTrackListeners();\n\n // destroy() delegates to the native renderer but also tears down the\n // native text-track listeners, caption-retry timers and any deferred\n // 'ready' handler scheduled by updateCaptionButtonsForHls.\n this.destroy = () => {\n this._cleanupNativeTextTrackListeners();\n this._clearTimers();\n if (this._pendingReadyHandler) {\n this.player.off('ready', this._pendingReadyHandler);\n this._pendingReadyHandler = null;\n }\n native.destroy();\n };\n }\n\n /**\n * Listen for HLS-exposed text tracks so captions/transcript buttons appear on native HLS.\n * Debounces rapid addtrack bursts (one per subtitle rendition in the manifest).\n */\n _attachNativeTextTrackListeners() {\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const checkTracks = () => {\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (this._nativeTrackListenersDestroyed) return;\n const tracks = this.media.textTracks;\n let count = 0;\n for (let i = 0; i < tracks.length; i++) {\n const k = tracks[i]?.kind;\n if (k === 'subtitles' || k === 'captions') {\n count++;\n }\n }\n this._hlsSubtitleTracksCount = count;\n this.updateCaptionButtonsForHls();\n }, 150);\n };\n\n this.media.textTracks.addEventListener('addtrack', checkTracks);\n this.media.textTracks.addEventListener('removetrack', checkTracks);\n this.media.addEventListener('loadedmetadata', checkTracks);\n\n this._cleanupNativeTextTrackListeners = () => {\n this._nativeTrackListenersDestroyed = true;\n clearTimeout(debounceTimer);\n this.media.textTracks.removeEventListener('addtrack', checkTracks);\n this.media.textTracks.removeEventListener('removetrack', checkTracks);\n this.media.removeEventListener('loadedmetadata', checkTracks);\n };\n }\n\n async initHlsJs() {\n // Hide native controls\n this.media.controls = false;\n this.media.removeAttribute('controls');\n \n // Load hls.js if not already loaded\n if (!window.Hls) {\n await this.loadHlsJs();\n }\n\n const HlsCtor = window.Hls;\n if (!HlsCtor?.isSupported()) {\n throw new Error('HLS is not supported in this browser');\n }\n\n // HTML5 spec: If video has src attribute, <source> children are not allowed.\n // hls.js sets a blob: URL on the src attribute, so we must remove any <source> elements\n // to maintain valid HTML. Store the original source URL first.\n const sourceElements = Array.from(this.media.querySelectorAll('source'));\n let originalSrc = null;\n if (sourceElements.length > 0) {\n originalSrc = sourceElements[0]?.getAttribute('src') ?? null;\n sourceElements.forEach(source => source.remove());\n this.player.log('Removed <source> elements for HTML5 validity (hls.js uses src attribute)');\n }\n\n // Create hls.js instance with better error recovery\n this.hls = new HlsCtor({\n debug: this.player.options.debug,\n // Never let hls.js auto-start segment loading. loadSource() alone fetches\n // the manifest (needed for duration, quality levels, subtitle tracks) but\n // startLoad() is what kicks off media fragment downloads. We defer that\n // to the first play() (or ensureLoaded() for playlists) so paused HLS\n // players don't pre-download the entire stream the way hls.js does by\n // default. This matches dash.js behavior where initialize(media, null, false)\n // only loads the init segment + minimal startup buffer.\n autoStartLoad: false,\n enableWorker: true,\n lowLatencyMode: false,\n backBufferLength: 90,\n // Buffer ceilings tuned to roughly match dash.js defaults so HLS and DASH\n // behave similarly in terms of pre-fetched data:\n // - maxBufferLength (12s) ≈ dash.js bufferTimeDefault: 12\n // - maxMaxBufferLength (60s) ≈ dash.js bufferTimeAtTopQualityLongForm: 60\n // - maxBufferSize (30 MB) — byte cap, hit first on high-bitrate streams.\n // For typical 6s segments this keeps ~2 segments buffered ahead during\n // playback. Combined with stopLoad() on pause(), zero segments are\n // pre-fetched when paused.\n maxBufferLength: 12,\n maxMaxBufferLength: 60,\n maxBufferSize: 30 * 1000 * 1000,\n maxBufferHole: 0.5,\n // Network retry settings\n manifestLoadingTimeOut: 10000,\n manifestLoadingMaxRetry: 4,\n manifestLoadingRetryDelay: 1000,\n manifestLoadingMaxRetryTimeout: 64000,\n levelLoadingTimeOut: 10000,\n levelLoadingMaxRetry: 4,\n levelLoadingRetryDelay: 1000,\n levelLoadingMaxRetryTimeout: 64000,\n fragLoadingTimeOut: 20000,\n fragLoadingMaxRetry: 6,\n fragLoadingRetryDelay: 1000,\n fragLoadingMaxRetryTimeout: 64000\n });\n\n // Attach media element\n this.hls.attachMedia(this.media);\n\n // Load source - use currentSource for external renderers, or get from attribute\n // Priority: currentSource > originalSrc (from removed <source>) > data-vidply-src > src attribute\n let src = this.player.currentSource;\n \n if (!src && originalSrc) {\n src = originalSrc;\n }\n \n if (!src) {\n // Try data-vidply-src attribute (used by TYPO3 integration)\n src = this.player.element.getAttribute('data-vidply-src');\n }\n \n if (!src) {\n // Fallback to element's src attribute (but not blob: URLs)\n const elementSrc = this.player.element.getAttribute('src') || this.player.element.src;\n if (elementSrc && !elementSrc.startsWith('blob:')) {\n src = elementSrc;\n }\n }\n \n this.player.log(`Loading HLS source: ${src}`, 'log');\n \n if (!src) {\n throw new Error('No HLS source found');\n }\n \n // Always load the manifest immediately so duration/quality levels/subtitle\n // tracks are available in the UI before playback. Because autoStartLoad is\n // false, this does NOT trigger media fragment downloads; startLoad() in\n // play() / ensureLoaded() does.\n this._pendingSrc = src;\n this._manifestUrl = src;\n this.hls.loadSource(src);\n this._hlsSourceLoaded = true;\n\n // Attach events\n this.attachHlsEvents();\n this.attachMediaEvents();\n }\n\n /**\n * Load hls.js. Pinned to an exact version by default (no more `@latest`).\n * Embedders who self-host or who want SRI protection can override via:\n * - `options.hlsScriptUrl` (URL to load from)\n * - `options.hlsScriptIntegrity` (Subresource Integrity hash, e.g.\n * `sha384-XXXX`)\n *\n * Generate the SRI hash with:\n * curl -sSL <url> | openssl dgst -sha384 -binary | openssl base64 -A\n * and prefix with `sha384-`. SRI is opt-in because hash drift would\n * silently break playback for consumers who upgrade hls.js.\n */\n async loadHlsJs(): Promise<void> {\n const defaultUrl = 'https://cdn.jsdelivr.net/npm/hls.js@1.6.16/dist/hls.min.js';\n const url: string = (this.player.options.hlsScriptUrl as string | undefined) || defaultUrl;\n const integrity = this.player.options.hlsScriptIntegrity as string | undefined;\n\n return loadScriptOnce(url, { integrity });\n }\n\n attachHlsEvents() {\n const hls = this.hls;\n const Hls = window.Hls;\n if (!hls || !Hls) return;\n\n hls.on(Hls.Events.MANIFEST_PARSED, (...args: unknown[]) => {\n const data = args[1] as HlsManifestParsedData;\n this.player.log('HLS manifest loaded, found ' + data.levels.length + ' quality levels');\n this.player.emit('hlsmanifestparsed', data);\n\n // Show VidPly controls (remove external controls class if present)\n if (this.player.container) {\n this.player.container.classList.remove('vidply-external-controls');\n }\n\n // Check for subtitle tracks after manifest parse\n // This handles streams without subtitles (SUBTITLE_TRACKS_UPDATED won't fire for them)\n this._setTimeout(() => {\n if (this._hlsSubtitleTracksCount === undefined || this._hlsSubtitleTracksCount === 0) {\n const currentCount = this.hls?.subtitleTracks?.length || 0;\n if (currentCount === 0) {\n this._hlsSubtitleTracksCount = 0;\n this.updateCaptionButtonsForHls();\n }\n }\n }, 500);\n });\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (...args: unknown[]) => {\n const data = args[1] as HlsLevelSwitchedData;\n this.player.log('HLS level switched to ' + data.level);\n this.player.emit('hlslevelswitched', data);\n });\n\n // Handle HLS subtitle tracks\n hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, (...args: unknown[]) => {\n const data = args[1] as HlsSubtitleTracksUpdatedData;\n this.player.log('HLS subtitle tracks updated, found ' + data.subtitleTracks.length + ' tracks');\n this.player.emit('hlssubtitletracksupdated', data);\n this._hlsSubtitleTracksCount = data.subtitleTracks.length;\n this.updateCaptionButtonsForHls();\n if (data.subtitleTracks.length > 0) {\n this._startCueUpdatePolling();\n }\n });\n\n hls.on(Hls.Events.SUBTITLE_TRACK_SWITCH, (...args: unknown[]) => {\n const data = args[1] as HlsSubtitleTrackSwitchData;\n this.player.log('HLS subtitle track switched to ' + data.id);\n this.player.emit('hlssubtitletrackswitch', data);\n this._lastKnownCueCount = 0;\n this._startCueUpdatePolling();\n });\n\n hls.on(Hls.Events.ERROR, (...args: unknown[]) => {\n this.handleHlsError(args[1] as HlsErrorData);\n });\n\n hls.on(Hls.Events.FRAG_BUFFERED, () => {\n this.player.state.buffering = false;\n\n // Seek-only loading: the user scrubbed the seekbar on a paused (or\n // never-played) media element. We only want hls.js to fetch enough\n // fragments to render the seek target frame and then stop, instead of\n // continuing to pre-fetch upcoming segments.\n //\n // FRAG_BUFFERED fires per track (audio and video have separate\n // SourceBuffers in hls.js), so the first event may fire after just the\n // audio fragment is appended — at which point media.buffered does not\n // yet cover the seek position because the video track is still loading.\n // Stopping there would abort the video fetch and leave the player on a\n // frozen frame. Checking _isTimeBuffered(currentTime) makes sure both\n // tracks actually cover the playhead before we call stopLoad.\n //\n // Playback resuming before this fires clears the flag so a later\n // mid-playback fragment doesn't accidentally stop the loader.\n if (!this.media.paused) {\n this._loadingForSeekOnly = false;\n } else if (this._loadingForSeekOnly && this._isTimeBuffered(this.media.currentTime)) {\n this._loadingForSeekOnly = false;\n try {\n hls.stopLoad();\n } catch {\n // ignore\n }\n }\n });\n\n // Subtitle fragments do NOT go through the media source buffer, so\n // FRAG_BUFFERED is unreliable for them. SUBTITLE_FRAG_PROCESSED fires\n // immediately after hls.js has parsed the WebVTT and appended cues to\n // the TextTrack via `addCueToTrack`, which is exactly when we need to\n // refresh captions/transcript UIs.\n hls.on(Hls.Events.SUBTITLE_FRAG_PROCESSED, (...args: unknown[]) => {\n const data = args[1] as HlsSubtitleFragProcessedData | undefined;\n if (!data || !data.success) return;\n const count = this._getTotalCueCount();\n if (count > this._lastKnownCueCount) {\n this._lastKnownCueCount = count;\n this.player.emit('textcuesupdate');\n }\n });\n\n // Some streams (e.g. IMSC1/TTML rendered externally by hls.js) deliver\n // their cues via CUES_PARSED instead of through a native TextTrack. Echo\n // that through to the transcript so it can refresh regardless of the\n // underlying subtitle format.\n hls.on(Hls.Events.CUES_PARSED, () => {\n this.player.emit('textcuesupdate');\n });\n }\n\n _getTotalCueCount() {\n const textTracks = this.media.textTracks;\n let total = 0;\n if (!textTracks) return total;\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n if (track && (track.kind === 'subtitles' || track.kind === 'captions') && track.cues) {\n total += track.cues.length;\n }\n }\n return total;\n }\n\n /**\n * Return true if `time` falls inside any TimeRange the SourceBuffer already\n * holds, with a small tolerance to absorb GOP boundaries. Used by the\n * seeking handler to decide whether to surface a 'waiting' event for the\n * spinner UI.\n */\n _isTimeBuffered(time: number): boolean {\n const buffered = this.media.buffered;\n if (!buffered || buffered.length === 0) return false;\n const tolerance = 0.25;\n for (let i = 0; i < buffered.length; i++) {\n if (time >= buffered.start(i) - tolerance && time <= buffered.end(i) + tolerance) {\n return true;\n }\n }\n return false;\n }\n\n _startCueUpdatePolling() {\n this._stopCueUpdatePolling();\n let prevCueCount = 0;\n let stableRounds = 0;\n\n this._cueUpdateTimer = setInterval(() => {\n const count = this._getTotalCueCount();\n\n if (count > prevCueCount) {\n prevCueCount = count;\n stableRounds = 0;\n this.player.emit('textcuesupdate');\n } else {\n stableRounds++;\n if (stableRounds >= 8) {\n this._stopCueUpdatePolling();\n if (count > 0) {\n this.player.emit('textcuesupdate');\n }\n }\n }\n }, 500);\n }\n\n _stopCueUpdatePolling() {\n if (this._cueUpdateTimer) {\n clearInterval(this._cueUpdateTimer);\n this._cueUpdateTimer = null;\n }\n }\n\n /**\n * Update caption buttons based on HLS subtitle tracks\n * Handles the case where control bar may not exist yet\n */\n updateCaptionButtonsForHls(retryCount = 0) {\n const tracksCount = this._hlsSubtitleTracksCount || 0;\n \n const doUpdate = () => {\n this.player.invalidateTrackCache();\n \n if (tracksCount > 0) {\n if (this.player.captionManager) {\n const found = this.player.captionManager.refreshTracks();\n\n // hls.js fires SUBTITLE_TRACKS_UPDATED when it knows about the\n // tracks, but the browser TextTrackList may not yet enumerate\n // the new TextTrack objects synchronously. Retry with increasing\n // delays until the tracks appear.\n if (found === 0 && retryCount < 5) {\n const delay = (retryCount + 1) * 200;\n this.player.log(`HLS caption tracks not yet on video element, retrying in ${delay}ms (attempt ${retryCount + 1})`, 'info');\n this._setTimeout(() => {\n this.updateCaptionButtonsForHls(retryCount + 1);\n }, delay);\n return;\n }\n }\n \n if (this.player.transcriptManager?.isVisible) {\n this.player.transcriptManager.loadTranscriptData();\n this.player.transcriptManager.updateLanguageSelector();\n }\n \n if (this.player.controlBar) {\n this.player.controlBar.ensureCaptionsButton();\n this.player.controlBar.ensureCaptionStyleButton();\n this.player.controlBar.ensureTranscriptButton();\n }\n } else {\n if (this.player.captionManager) {\n this.player.captionManager.refreshTracks();\n }\n \n if (this.player.transcriptManager?.isVisible) {\n this.player.transcriptManager.hideTranscript();\n }\n \n if (this.player.controlBar) {\n this.player.controlBar.removeHlsCaptionButtons(true);\n }\n }\n };\n \n if (this.player.controlBar) {\n doUpdate();\n return;\n }\n \n const onReady = () => {\n this.player.off('ready', onReady);\n this._pendingReadyHandler = null;\n doUpdate();\n };\n // Track so destroy() can detach it if 'ready' never fires.\n this._pendingReadyHandler = onReady;\n this.player.on('ready', onReady);\n }\n\n attachMediaEvents() {\n const { signal } = this._listenerController;\n\n // Use same events as HTML5 renderer\n this.media.addEventListener('loadedmetadata', () => {\n this.player.state.duration = this.media.duration;\n this.player.emit('loadedmetadata');\n }, { signal });\n\n this.media.addEventListener('durationchange', () => {\n const duration = this.media.duration;\n if (duration && isFinite(duration) && duration > 0) {\n this.player.state.duration = duration;\n this.player.emit('durationchange', duration);\n }\n }, { signal });\n\n this.media.addEventListener('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 }, { signal });\n\n this.media.addEventListener('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 }, { signal });\n\n this.media.addEventListener('ended', () => {\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.player.seek(0);\n this.player.play();\n }\n }, { signal });\n\n this.media.addEventListener('timeupdate', () => {\n this.player.state.currentTime = this.media.currentTime;\n this.player.emit('timeupdate', this.media.currentTime);\n \n if (this.player.options.onTimeUpdate) {\n this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);\n }\n }, { signal });\n\n this.media.addEventListener('volumechange', () => {\n this.player.state.volume = this.media.volume;\n this.player.state.muted = this.media.muted;\n this.player.emit('volumechange', this.media.volume);\n }, { signal });\n\n this.media.addEventListener('waiting', () => {\n this.player.state.buffering = true;\n this.player.emit('waiting');\n }, { signal });\n\n this.media.addEventListener('seeking', () => {\n this.player.state.seeking = true;\n this.player.emit('seeking');\n\n // Browsers fire `waiting` when playback can't continue due to missing\n // data, but they DO NOT fire it when seeking on a paused element. With\n // hls.js + stopLoad-on-pause, scrubbing while paused triggers a real\n // segment download, but the spinner stays hidden because no `waiting`\n // event reaches the buffering UI. Detect a seek into an unbuffered\n // range here and surface it as 'waiting' so the spinner appears. The\n // spinner is cleared again by the existing `canplay` / `seeked` paths.\n if (!this._isTimeBuffered(this.media.currentTime)) {\n this.player.state.buffering = true;\n this.player.emit('waiting');\n }\n }, { signal });\n\n this.media.addEventListener('seeked', () => {\n this.player.state.seeking = false;\n this.player.emit('seeked');\n\n // After a seek finishes while paused, hls.js otherwise keeps fetching\n // subsequent segments to fill maxBufferLength. The user explicitly chose\n // not to play, so calling stopLoad() halts the loader once the segment(s)\n // required to render the new playhead frame are buffered. play() and\n // future seeks re-arm via startLoad(-1).\n if (this.media.paused && this.hls) {\n try {\n this.hls.stopLoad();\n } catch {\n // ignore\n }\n }\n }, { signal });\n\n this.media.addEventListener('canplay', () => {\n this.player.state.buffering = false;\n this.player.emit('canplay');\n }, { signal });\n\n this.media.addEventListener('error', () => {\n this.player.handleError(this.media.error);\n }, { signal });\n }\n\n handleHlsError(data: HlsErrorData) {\n // Log detailed error info\n this.player.log(`HLS Error - Type: ${data.type}, Details: ${data.details}, Fatal: ${data.fatal}`, 'warn');\n if (data.response) {\n this.player.log(`Response code: ${data.response.code}, URL: ${data.response.url}`, 'warn');\n }\n\n if (data.fatal) {\n const ErrorTypes = window.Hls?.ErrorTypes;\n switch (data.type) {\n case ErrorTypes?.NETWORK_ERROR:\n this.player.log('Fatal network error, trying to recover...', 'error');\n this.player.log(`Network error details: ${data.details}`, 'error');\n this._setTimeout(() => {\n this.hls?.startLoad();\n }, 1000);\n break;\n\n case ErrorTypes?.MEDIA_ERROR:\n this.player.log('Fatal media error, trying to recover...', 'error');\n this.hls?.recoverMediaError();\n break;\n\n default:\n this.player.log('Fatal error, cannot recover', 'error');\n this.player.handleError(new Error(`HLS Error: ${data.type} - ${data.details}`));\n this.hls?.destroy();\n break;\n }\n } else {\n this.player.log('Non-fatal HLS error: ' + data.details, 'warn');\n }\n }\n\n /**\n * Begin fetching media fragments without starting playback. Used by the\n * playlist manager when a track is selected so playback can start quickly\n * once the user hits play. The manifest was already loaded in initHlsJs();\n * this call is just the equivalent of \"press play without playing\".\n */\n ensureLoaded() {\n // Native HLS path delegates to HTML5Renderer; if we got here and have no\n // hls.js instance, there is nothing to do.\n if (!this.hls) {\n return;\n }\n\n if (this._didDeferredLoad) {\n return;\n }\n\n try {\n this.hls.startLoad(-1);\n } catch {\n // ignore\n }\n this._didDeferredLoad = true;\n }\n\n play() {\n // Save scroll position to prevent browser from scrolling to video\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n // (Re)start segment loading on every play. Cheap when already loading\n // (hls.js no-ops); needed after pause() called stopLoad() so the buffer\n // resumes filling. Passing -1 lets hls.js pick the starting position from\n // the current playhead instead of forcing one. Clearing the seek-only\n // flag here ensures FRAG_BUFFERED does not stop the loader mid-playback.\n if (this.hls) {\n this._loadingForSeekOnly = false;\n try {\n this.hls.startLoad(-1);\n } catch {\n // ignore and let media.play() surface errors if any\n }\n this._didDeferredLoad = true;\n }\n\n const promise = this.media.play();\n \n // Restore scroll position immediately to prevent auto-scroll\n window.scrollTo(scrollX, scrollY);\n \n if (promise !== undefined) {\n promise.catch(error => {\n this.player.log('Play failed:', error, 'warn');\n });\n }\n }\n\n pause() {\n this.media.pause();\n // Stop downloading further segments while paused. Already buffered data\n // stays in the SourceBuffer so resume is instant for short pauses; longer\n // pauses (or stop() = pause() + seek(0)) save bandwidth by not pre-fetching\n // content the user may never watch. play() / seek() re-arm via startLoad().\n if (this.hls) {\n try {\n this.hls.stopLoad();\n } catch {\n // ignore\n }\n }\n }\n\n seek(time: number) {\n this.media.currentTime = time;\n // If we're paused with the loader stopped and the user seeks outside the\n // currently buffered range, hls.js needs to fetch new fragments to render\n // the target frame. Calling startLoad(-1) here is safe regardless: when\n // already loading, hls.js no-ops; when stopped, it resumes from the new\n // currentTime so the seek shows a real frame instead of a frozen one.\n // The _loadingForSeekOnly flag tells FRAG_BUFFERED to stop the loader\n // again once the target segment is buffered, so paused/never-played\n // players don't keep pre-fetching beyond the seek point.\n if (this.hls) {\n if (this.media.paused) {\n this._loadingForSeekOnly = true;\n }\n try {\n this.hls.startLoad(-1);\n } catch {\n // ignore\n }\n }\n }\n\n setVolume(volume: number) {\n this.media.volume = volume;\n }\n\n setMuted(muted: boolean) {\n this.media.muted = muted;\n }\n\n setPlaybackSpeed(speed: number) {\n this.media.playbackRate = speed;\n }\n\n switchQuality(levelIndex: number) {\n if (this.hls) {\n this.hls.currentLevel = levelIndex;\n }\n }\n\n getQualities(): QualityLevel[] {\n if (this.hls && this.hls.levels) {\n // hls.js creates separate levels for each video+audio-group combination,\n // producing duplicates (e.g. three \"720p\" entries). Deduplicate by\n // resolution height, keeping the entry with the highest bitrate per height.\n type LevelEntry = { index: number; height: number; width: number; bitrate: number; level: HlsLevel };\n const byHeight = new Map<string | number, LevelEntry>();\n\n this.hls.levels.forEach((level: HlsLevel, index: number) => {\n const height = Number(level.height) || 0;\n const bitrate = Number(level.bitrate) || 0;\n const key: string | number = height > 0 ? height : `br_${bitrate}`;\n const existing = byHeight.get(key);\n\n if (!existing || bitrate > (existing.bitrate || 0)) {\n byHeight.set(key, { index, height: level.height, width: level.width, bitrate, level });\n }\n });\n\n return Array.from(byHeight.values()).map((entry) => {\n const height = Number(entry.height) || 0;\n const kb = entry.bitrate > 0 ? Math.round(entry.bitrate / 1000) : 0;\n const name = height > 0 ? `${height}p` : (kb > 0 ? `${kb} kb` : 'Auto');\n return { index: entry.index, height: entry.height, width: entry.width, bitrate: entry.bitrate, name };\n });\n }\n return [];\n }\n\n getCurrentQuality() {\n if (this.hls) {\n return this.hls.currentLevel;\n }\n return -1;\n }\n\n activateTextTrackForLanguage(lang: string): boolean {\n if (!this.hls || !lang) return false;\n\n const tracks = this.hls.subtitleTracks;\n if (!tracks || tracks.length === 0) return false;\n\n const idx = tracks.findIndex((t: HlsSubtitleTrack) => {\n const tLang = t.lang || t.language || '';\n return tLang === lang || tLang.startsWith(lang) || lang.startsWith(tLang);\n });\n\n if (idx < 0) return false;\n\n this.player.log(`Activating HLS subtitle track index ${idx} for language \"${lang}\"`);\n this.hls.subtitleTrack = idx;\n\n this._lastKnownCueCount = 0;\n this._startCueUpdatePolling();\n return true;\n }\n\n getTextTrackURLs(): { lang: string; url: string }[] {\n if (!this.hls || !this._manifestUrl) return [];\n try {\n const tracks = this.hls.subtitleTracks;\n if (!tracks || tracks.length === 0) return [];\n\n const results: { lang: string; url: string }[] = [];\n for (const track of tracks) {\n const lang = track.lang || track.language || '';\n const playlistUrl = track.url;\n if (!lang || !playlistUrl) continue;\n results.push({ lang, url: playlistUrl });\n }\n return results;\n } catch {\n return [];\n }\n }\n\n supportsAutoQuality() {\n return true;\n }\n\n isAutoQuality() {\n return this.hls?.currentLevel === -1;\n }\n\n destroy() {\n this._stopCueUpdatePolling();\n this._clearTimers();\n // Detach the media listeners registered in attachMediaEvents().\n this._listenerController.abort();\n // Remove the deferred 'ready' listener if it never fired.\n if (this._pendingReadyHandler) {\n this.player.off('ready', this._pendingReadyHandler);\n this._pendingReadyHandler = null;\n }\n this._lastKnownCueCount = 0;\n this._manifestUrl = null;\n if (this.hls) {\n this.hls.destroy();\n this.hls = null;\n }\n }\n}\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,12 @@
1
+ /*!
2
+ * VidPly v1.2.3 - Universal, Accessible Video Player
3
+ * (c) 2026 Matthias Peltzer
4
+ * Released under GPL-2.0-or-later License
5
+ */
6
+ import {
7
+ HTML5Renderer
8
+ } from "./vidply.chunk-CGYIED2I.js";
9
+ export {
10
+ HTML5Renderer
11
+ };
12
+ //# sourceMappingURL=vidply.HTML5Renderer-HLRQUOCU.js.map
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * VidPly v1.2.0 - Universal, Accessible Video Player
2
+ * VidPly v1.2.3 - Universal, Accessible Video Player
3
3
  * (c) 2026 Matthias Peltzer
4
4
  * Released under GPL-2.0-or-later License
5
5
  */
@@ -7,19 +7,19 @@ import {
7
7
  DraggablePanel,
8
8
  createLabeledSelect,
9
9
  preventDragOnElement
10
- } from "./vidply.chunk-NQPURMQY.js";
10
+ } from "./vidply.chunk-A4ESEOQ2.js";
11
11
  import {
12
12
  DraggableResizable
13
- } from "./vidply.chunk-JJ47NO24.js";
13
+ } from "./vidply.chunk-UNFGMABP.js";
14
14
  import {
15
15
  createIconElement
16
- } from "./vidply.chunk-KI7C3QVL.js";
17
- import "./vidply.chunk-VMSQAZM7.js";
18
- import "./vidply.chunk-6RQA4ROD.js";
16
+ } from "./vidply.chunk-UI3RYCVF.js";
17
+ import "./vidply.chunk-P25MRJ6O.js";
18
+ import "./vidply.chunk-PRFNESYA.js";
19
19
  import {
20
20
  DOMUtils,
21
21
  i18n
22
- } from "./vidply.chunk-RZWZGDV7.js";
22
+ } from "./vidply.chunk-I6EDRYGJ.js";
23
23
 
24
24
  // src/core/SignLanguageManager.ts
25
25
  var SignLanguageManager = class {
@@ -1083,4 +1083,4 @@ var SignLanguageManager = class {
1083
1083
  export {
1084
1084
  SignLanguageManager
1085
1085
  };
1086
- //# sourceMappingURL=vidply.SignLanguageManager-FET5FQZ7.js.map
1086
+ //# sourceMappingURL=vidply.SignLanguageManager-FLUCBW5H.js.map