@amazon/vinyl 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/dist/index.cjs +11 -2
  2. package/dist/index.cjs.map +2 -2
  3. package/dist/index.js +15 -4
  4. package/dist/index.js.map +3 -3
  5. package/dist/test/integ.es5.js +43 -43
  6. package/dist/test/integ.js +70 -2
  7. package/dist/test/integ.js.map +2 -2
  8. package/dist/types/current/ad/AdBreakInfo.d.ts +160 -0
  9. package/dist/types/current/ad/AdBreakInfo.d.ts.map +1 -0
  10. package/dist/types/current/ad/AdBreakInfo.js +5 -0
  11. package/dist/types/current/ad/AdController.d.ts +229 -0
  12. package/dist/types/current/ad/AdController.d.ts.map +1 -0
  13. package/dist/types/current/ad/AdController.js +19 -0
  14. package/dist/types/current/ad/AdControllerImpl.d.ts +146 -0
  15. package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -0
  16. package/dist/types/current/ad/AdControllerImpl.js +705 -0
  17. package/dist/types/current/ad/AdError.d.ts +6 -0
  18. package/dist/types/current/ad/AdError.d.ts.map +1 -0
  19. package/dist/types/current/ad/AdError.js +14 -0
  20. package/dist/types/current/ad/AdsProvider.d.ts +28 -0
  21. package/dist/types/current/ad/AdsProvider.d.ts.map +1 -0
  22. package/dist/types/current/ad/AdsProvider.js +5 -0
  23. package/dist/types/current/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  24. package/dist/types/current/ad/defaultAdLoadOptionsResolver.d.ts.map +1 -0
  25. package/dist/types/current/ad/defaultAdLoadOptionsResolver.js +26 -0
  26. package/dist/types/current/ad/discoverHlsInterstitials.d.ts +22 -0
  27. package/dist/types/current/ad/discoverHlsInterstitials.d.ts.map +1 -0
  28. package/dist/types/current/ad/discoverHlsInterstitials.js +246 -0
  29. package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
  30. package/dist/types/current/drm/DrmControllerImpl.js +11 -1
  31. package/dist/types/current/playback/PlaybackControllerImpl.d.ts +1 -1
  32. package/dist/types/current/streaming/AudioOptions.d.ts +39 -0
  33. package/dist/types/current/streaming/AudioOptions.d.ts.map +1 -0
  34. package/dist/types/current/streaming/AudioOptions.js +15 -0
  35. package/dist/types/current/streaming/LoadMetric.d.ts +58 -0
  36. package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -0
  37. package/dist/types/current/streaming/LoadMetric.js +5 -0
  38. package/dist/types/current/streaming/ManifestControllerImpl.d.ts +43 -0
  39. package/dist/types/current/streaming/ManifestControllerImpl.d.ts.map +1 -0
  40. package/dist/types/current/streaming/ManifestControllerImpl.js +104 -0
  41. package/dist/types/current/streaming/buffering/codecDenylist.d.ts +23 -0
  42. package/dist/types/current/streaming/buffering/codecDenylist.d.ts.map +1 -0
  43. package/dist/types/current/streaming/buffering/codecDenylist.js +62 -0
  44. package/dist/types/current/streaming/createAllowedContentTypesValue.d.ts +30 -0
  45. package/dist/types/current/streaming/createAllowedContentTypesValue.d.ts.map +1 -0
  46. package/dist/types/current/streaming/createAllowedContentTypesValue.js +43 -0
  47. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  48. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.d.ts.map +1 -0
  49. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.js +75 -0
  50. package/dist/types/current/text/HtmlTextTrackRenderer.d.ts +60 -0
  51. package/dist/types/current/text/HtmlTextTrackRenderer.d.ts.map +1 -0
  52. package/dist/types/current/text/HtmlTextTrackRenderer.js +231 -0
  53. package/dist/types/current/text/SidecarTextTrackController.d.ts +103 -0
  54. package/dist/types/current/text/SidecarTextTrackController.d.ts.map +1 -0
  55. package/dist/types/current/text/SidecarTextTrackController.js +250 -0
  56. package/dist/types/current/text/SidecarTextTrackLoader.d.ts +65 -0
  57. package/dist/types/current/text/SidecarTextTrackLoader.d.ts.map +1 -0
  58. package/dist/types/current/text/SidecarTextTrackLoader.js +150 -0
  59. package/dist/types/current/text/TextTrack.d.ts +179 -0
  60. package/dist/types/current/text/TextTrack.d.ts.map +1 -0
  61. package/dist/types/current/text/TextTrack.js +29 -0
  62. package/dist/types/current/text/TextTrackRenderer.d.ts +24 -0
  63. package/dist/types/current/text/TextTrackRenderer.d.ts.map +1 -0
  64. package/dist/types/current/text/TextTrackRenderer.js +5 -0
  65. package/dist/types/current/text/VttCueStyle.d.ts +41 -0
  66. package/dist/types/current/text/VttCueStyle.d.ts.map +1 -0
  67. package/dist/types/current/text/VttCueStyle.js +45 -0
  68. package/dist/types/current/text/discoverDashTextTracks.d.ts +24 -0
  69. package/dist/types/current/text/discoverDashTextTracks.d.ts.map +1 -0
  70. package/dist/types/current/text/discoverDashTextTracks.js +109 -0
  71. package/dist/types/current/text/discoverHlsTextTracks.d.ts +19 -0
  72. package/dist/types/current/text/discoverHlsTextTracks.d.ts.map +1 -0
  73. package/dist/types/current/text/discoverHlsTextTracks.js +49 -0
  74. package/dist/types/current/text/mediaTextTrackProvider.d.ts +34 -0
  75. package/dist/types/current/text/mediaTextTrackProvider.d.ts.map +1 -0
  76. package/dist/types/current/text/mediaTextTrackProvider.js +42 -0
  77. package/dist/types/current/text/parseWebVtt.d.ts +60 -0
  78. package/dist/types/current/text/parseWebVtt.d.ts.map +1 -0
  79. package/dist/types/current/text/parseWebVtt.js +248 -0
  80. package/dist/types/current/text/pickPreferredTextTrack.d.ts +15 -0
  81. package/dist/types/current/text/pickPreferredTextTrack.d.ts.map +1 -0
  82. package/dist/types/current/text/pickPreferredTextTrack.js +71 -0
  83. package/dist/types/current/track/SeekRange.d.ts +9 -0
  84. package/dist/types/current/track/SeekRange.d.ts.map +1 -0
  85. package/dist/types/current/track/SeekRange.js +5 -0
  86. package/dist/types/current/track/hls/HlsManifestData.d.ts +19 -0
  87. package/dist/types/current/track/hls/HlsManifestData.d.ts.map +1 -0
  88. package/dist/types/current/track/hls/HlsManifestData.js +5 -0
  89. package/dist/types/current/track/hls/createHlsManifestProvider.d.ts +6 -0
  90. package/dist/types/current/track/hls/createHlsManifestProvider.d.ts.map +1 -0
  91. package/dist/types/current/track/hls/createHlsManifestProvider.js +9 -0
  92. package/dist/types/current/track/inferLoadOptionsFromUri.d.ts +15 -0
  93. package/dist/types/current/track/inferLoadOptionsFromUri.d.ts.map +1 -0
  94. package/dist/types/current/track/inferLoadOptionsFromUri.js +55 -0
  95. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  96. package/dist/types/current/util/media/codecOverrides.d.ts +33 -0
  97. package/dist/types/current/util/media/codecOverrides.d.ts.map +1 -0
  98. package/dist/types/current/util/media/codecOverrides.js +37 -0
  99. package/dist/types/current/util/media/codecSupport.d.ts +6 -0
  100. package/dist/types/current/util/media/codecSupport.d.ts.map +1 -0
  101. package/dist/types/current/util/media/codecSupport.js +17 -0
  102. package/dist/types/current/util/media/mimeType.d.ts +8 -0
  103. package/dist/types/current/util/media/mimeType.d.ts.map +1 -0
  104. package/dist/types/current/util/media/mimeType.js +13 -0
  105. package/dist/types/ts3.7/ad/AdBreakInfo.d.ts +160 -0
  106. package/dist/types/ts3.7/ad/AdController.d.ts +243 -0
  107. package/dist/types/ts3.7/ad/AdControllerImpl.d.ts +146 -0
  108. package/dist/types/ts3.7/ad/AdError.d.ts +6 -0
  109. package/dist/types/ts3.7/ad/AdsProvider.d.ts +28 -0
  110. package/dist/types/ts3.7/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  111. package/dist/types/ts3.7/ad/discoverHlsInterstitials.d.ts +22 -0
  112. package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +1 -1
  113. package/dist/types/ts3.7/streaming/AudioOptions.d.ts +39 -0
  114. package/dist/types/ts3.7/streaming/LoadMetric.d.ts +58 -0
  115. package/dist/types/ts3.7/streaming/ManifestControllerImpl.d.ts +40 -0
  116. package/dist/types/ts3.7/streaming/buffering/codecDenylist.d.ts +23 -0
  117. package/dist/types/ts3.7/streaming/createAllowedContentTypesValue.d.ts +30 -0
  118. package/dist/types/ts3.7/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  119. package/dist/types/ts3.7/text/HtmlTextTrackRenderer.d.ts +60 -0
  120. package/dist/types/ts3.7/text/SidecarTextTrackController.d.ts +103 -0
  121. package/dist/types/ts3.7/text/SidecarTextTrackLoader.d.ts +65 -0
  122. package/dist/types/ts3.7/text/TextTrack.d.ts +183 -0
  123. package/dist/types/ts3.7/text/TextTrackRenderer.d.ts +24 -0
  124. package/dist/types/ts3.7/text/VttCueStyle.d.ts +41 -0
  125. package/dist/types/ts3.7/text/discoverDashTextTracks.d.ts +24 -0
  126. package/dist/types/ts3.7/text/discoverHlsTextTracks.d.ts +19 -0
  127. package/dist/types/ts3.7/text/mediaTextTrackProvider.d.ts +34 -0
  128. package/dist/types/ts3.7/text/parseWebVtt.d.ts +60 -0
  129. package/dist/types/ts3.7/text/pickPreferredTextTrack.d.ts +15 -0
  130. package/dist/types/ts3.7/track/SeekRange.d.ts +9 -0
  131. package/dist/types/ts3.7/track/hls/HlsManifestData.d.ts +19 -0
  132. package/dist/types/ts3.7/track/hls/createHlsManifestProvider.d.ts +6 -0
  133. package/dist/types/ts3.7/track/inferLoadOptionsFromUri.d.ts +15 -0
  134. package/dist/types/ts3.7/util/media/codecOverrides.d.ts +33 -0
  135. package/dist/types/ts3.7/util/media/codecSupport.d.ts +6 -0
  136. package/dist/types/ts3.7/util/media/mimeType.d.ts +8 -0
  137. package/dist/types/ts4.1/ad/AdBreakInfo.d.ts +160 -0
  138. package/dist/types/ts4.1/ad/AdController.d.ts +243 -0
  139. package/dist/types/ts4.1/ad/AdControllerImpl.d.ts +146 -0
  140. package/dist/types/ts4.1/ad/AdError.d.ts +6 -0
  141. package/dist/types/ts4.1/ad/AdsProvider.d.ts +28 -0
  142. package/dist/types/ts4.1/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  143. package/dist/types/ts4.1/ad/discoverHlsInterstitials.d.ts +22 -0
  144. package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +1 -1
  145. package/dist/types/ts4.1/streaming/AudioOptions.d.ts +39 -0
  146. package/dist/types/ts4.1/streaming/LoadMetric.d.ts +58 -0
  147. package/dist/types/ts4.1/streaming/ManifestControllerImpl.d.ts +40 -0
  148. package/dist/types/ts4.1/streaming/buffering/codecDenylist.d.ts +23 -0
  149. package/dist/types/ts4.1/streaming/createAllowedContentTypesValue.d.ts +30 -0
  150. package/dist/types/ts4.1/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  151. package/dist/types/ts4.1/text/HtmlTextTrackRenderer.d.ts +60 -0
  152. package/dist/types/ts4.1/text/SidecarTextTrackController.d.ts +104 -0
  153. package/dist/types/ts4.1/text/SidecarTextTrackLoader.d.ts +65 -0
  154. package/dist/types/ts4.1/text/TextTrack.d.ts +183 -0
  155. package/dist/types/ts4.1/text/TextTrackRenderer.d.ts +24 -0
  156. package/dist/types/ts4.1/text/VttCueStyle.d.ts +41 -0
  157. package/dist/types/ts4.1/text/discoverDashTextTracks.d.ts +24 -0
  158. package/dist/types/ts4.1/text/discoverHlsTextTracks.d.ts +19 -0
  159. package/dist/types/ts4.1/text/mediaTextTrackProvider.d.ts +34 -0
  160. package/dist/types/ts4.1/text/parseWebVtt.d.ts +60 -0
  161. package/dist/types/ts4.1/text/pickPreferredTextTrack.d.ts +15 -0
  162. package/dist/types/ts4.1/track/SeekRange.d.ts +9 -0
  163. package/dist/types/ts4.1/track/hls/HlsManifestData.d.ts +19 -0
  164. package/dist/types/ts4.1/track/hls/createHlsManifestProvider.d.ts +6 -0
  165. package/dist/types/ts4.1/track/inferLoadOptionsFromUri.d.ts +15 -0
  166. package/dist/types/ts4.1/util/media/codecOverrides.d.ts +33 -0
  167. package/dist/types/ts4.1/util/media/codecSupport.d.ts +6 -0
  168. package/dist/types/ts4.1/util/media/mimeType.d.ts +8 -0
  169. package/dist/types/ts4.7/ad/AdBreakInfo.d.ts +160 -0
  170. package/dist/types/ts4.7/ad/AdController.d.ts +243 -0
  171. package/dist/types/ts4.7/ad/AdControllerImpl.d.ts +146 -0
  172. package/dist/types/ts4.7/ad/AdError.d.ts +6 -0
  173. package/dist/types/ts4.7/ad/AdsProvider.d.ts +28 -0
  174. package/dist/types/ts4.7/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  175. package/dist/types/ts4.7/ad/discoverHlsInterstitials.d.ts +22 -0
  176. package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +1 -1
  177. package/dist/types/ts4.7/streaming/AudioOptions.d.ts +39 -0
  178. package/dist/types/ts4.7/streaming/LoadMetric.d.ts +58 -0
  179. package/dist/types/ts4.7/streaming/ManifestControllerImpl.d.ts +43 -0
  180. package/dist/types/ts4.7/streaming/buffering/codecDenylist.d.ts +23 -0
  181. package/dist/types/ts4.7/streaming/createAllowedContentTypesValue.d.ts +30 -0
  182. package/dist/types/ts4.7/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  183. package/dist/types/ts4.7/text/HtmlTextTrackRenderer.d.ts +60 -0
  184. package/dist/types/ts4.7/text/SidecarTextTrackController.d.ts +103 -0
  185. package/dist/types/ts4.7/text/SidecarTextTrackLoader.d.ts +65 -0
  186. package/dist/types/ts4.7/text/TextTrack.d.ts +183 -0
  187. package/dist/types/ts4.7/text/TextTrackRenderer.d.ts +24 -0
  188. package/dist/types/ts4.7/text/VttCueStyle.d.ts +41 -0
  189. package/dist/types/ts4.7/text/discoverDashTextTracks.d.ts +24 -0
  190. package/dist/types/ts4.7/text/discoverHlsTextTracks.d.ts +19 -0
  191. package/dist/types/ts4.7/text/mediaTextTrackProvider.d.ts +34 -0
  192. package/dist/types/ts4.7/text/parseWebVtt.d.ts +60 -0
  193. package/dist/types/ts4.7/text/pickPreferredTextTrack.d.ts +15 -0
  194. package/dist/types/ts4.7/track/SeekRange.d.ts +9 -0
  195. package/dist/types/ts4.7/track/hls/HlsManifestData.d.ts +19 -0
  196. package/dist/types/ts4.7/track/hls/createHlsManifestProvider.d.ts +6 -0
  197. package/dist/types/ts4.7/track/inferLoadOptionsFromUri.d.ts +15 -0
  198. package/dist/types/ts4.7/util/media/codecOverrides.d.ts +33 -0
  199. package/dist/types/ts4.7/util/media/codecSupport.d.ts +6 -0
  200. package/dist/types/ts4.7/util/media/mimeType.d.ts +8 -0
  201. package/dist/unit/types/current/ad/AdController.test.d.ts +2 -0
  202. package/dist/unit/types/current/ad/AdController.test.d.ts.map +1 -0
  203. package/dist/unit/types/current/ad/AdController.test.js +10 -0
  204. package/dist/unit/types/current/ad/AdControllerImpl.test.d.ts +2 -0
  205. package/dist/unit/types/current/ad/AdControllerImpl.test.d.ts.map +1 -0
  206. package/dist/unit/types/current/ad/AdControllerImpl.test.js +1456 -0
  207. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.d.ts +2 -0
  208. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.d.ts.map +1 -0
  209. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.js +56 -0
  210. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.d.ts +2 -0
  211. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.d.ts.map +1 -0
  212. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.js +756 -0
  213. package/dist/unit/types/current/drm/DrmControllerImpl.test.js +66 -1
  214. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.d.ts +2 -0
  215. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.d.ts.map +1 -0
  216. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.js +197 -0
  217. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.d.ts +2 -0
  218. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.d.ts.map +1 -0
  219. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.js +56 -0
  220. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.d.ts +2 -0
  221. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.d.ts.map +1 -0
  222. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.js +77 -0
  223. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.d.ts +2 -0
  224. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.d.ts.map +1 -0
  225. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.js +99 -0
  226. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.d.ts +2 -0
  227. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.d.ts.map +1 -0
  228. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.js +231 -0
  229. package/dist/unit/types/current/text/SidecarTextTrackController.test.d.ts +2 -0
  230. package/dist/unit/types/current/text/SidecarTextTrackController.test.d.ts.map +1 -0
  231. package/dist/unit/types/current/text/SidecarTextTrackController.test.js +686 -0
  232. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.d.ts +2 -0
  233. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.d.ts.map +1 -0
  234. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.js +365 -0
  235. package/dist/unit/types/current/text/VttCueStyle.test.d.ts +2 -0
  236. package/dist/unit/types/current/text/VttCueStyle.test.d.ts.map +1 -0
  237. package/dist/unit/types/current/text/VttCueStyle.test.js +76 -0
  238. package/dist/unit/types/current/text/discoverDashTextTracks.test.d.ts +2 -0
  239. package/dist/unit/types/current/text/discoverDashTextTracks.test.d.ts.map +1 -0
  240. package/dist/unit/types/current/text/discoverDashTextTracks.test.js +199 -0
  241. package/dist/unit/types/current/text/discoverHlsTextTracks.test.d.ts +2 -0
  242. package/dist/unit/types/current/text/discoverHlsTextTracks.test.d.ts.map +1 -0
  243. package/dist/unit/types/current/text/discoverHlsTextTracks.test.js +177 -0
  244. package/dist/unit/types/current/text/mediaTextTrackProvider.test.d.ts +2 -0
  245. package/dist/unit/types/current/text/mediaTextTrackProvider.test.d.ts.map +1 -0
  246. package/dist/unit/types/current/text/mediaTextTrackProvider.test.js +86 -0
  247. package/dist/unit/types/current/text/parseWebVtt.test.d.ts +2 -0
  248. package/dist/unit/types/current/text/parseWebVtt.test.d.ts.map +1 -0
  249. package/dist/unit/types/current/text/parseWebVtt.test.js +393 -0
  250. package/dist/unit/types/current/text/pickPreferredTextTrack.test.d.ts +2 -0
  251. package/dist/unit/types/current/text/pickPreferredTextTrack.test.d.ts.map +1 -0
  252. package/dist/unit/types/current/text/pickPreferredTextTrack.test.js +78 -0
  253. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.d.ts +2 -0
  254. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.d.ts.map +1 -0
  255. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.js +165 -0
  256. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  257. package/dist/unit/types/current/util/media/codecOverrides.test.d.ts +2 -0
  258. package/dist/unit/types/current/util/media/codecOverrides.test.d.ts.map +1 -0
  259. package/dist/unit/types/current/util/media/codecOverrides.test.js +42 -0
  260. package/dist/unit/types/current/util/media/codecSupport.test.d.ts +2 -0
  261. package/dist/unit/types/current/util/media/codecSupport.test.d.ts.map +1 -0
  262. package/dist/unit/types/current/util/media/codecSupport.test.js +26 -0
  263. package/dist/unit/types/current/util/media/mimeType.test.d.ts +2 -0
  264. package/dist/unit/types/current/util/media/mimeType.test.d.ts.map +1 -0
  265. package/dist/unit/types/current/util/media/mimeType.test.js +22 -0
  266. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.d.ts +2 -0
  267. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.d.ts.map +1 -0
  268. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.js +142 -0
  269. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.d.ts +2 -0
  270. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.d.ts.map +1 -0
  271. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.js +188 -0
  272. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.d.ts +15 -0
  273. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.d.ts.map +1 -0
  274. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.js +26 -0
  275. package/dist/vinylTestUtil/types/current/mock/dash/mockDashManifest.d.ts +84 -84
  276. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.d.ts +10 -0
  277. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.d.ts.map +1 -0
  278. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.js +14 -0
  279. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  280. package/dist/vinylTestUtil/types/ts3.7/mock/ad/MockAdController.d.ts +15 -0
  281. package/dist/vinylTestUtil/types/ts3.7/mock/dash/mockDashManifest.d.ts +84 -84
  282. package/dist/vinylTestUtil/types/ts3.7/mock/text/MockTextTrackController.d.ts +10 -0
  283. package/dist/vinylTestUtil/types/ts4.1/mock/ad/MockAdController.d.ts +15 -0
  284. package/dist/vinylTestUtil/types/ts4.1/mock/dash/mockDashManifest.d.ts +84 -84
  285. package/dist/vinylTestUtil/types/ts4.1/mock/text/MockTextTrackController.d.ts +10 -0
  286. package/dist/vinylTestUtil/types/ts4.7/mock/ad/MockAdController.d.ts +15 -0
  287. package/dist/vinylTestUtil/types/ts4.7/mock/dash/mockDashManifest.d.ts +84 -84
  288. package/dist/vinylTestUtil/types/ts4.7/mock/text/MockTextTrackController.d.ts +10 -0
  289. package/package.json +10 -11
@@ -0,0 +1,686 @@
1
+ /*
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { resolveSelectedTrack, SidecarTextTrackController, } from '@amazon/vinyl';
6
+ import { requesterWithRetryRef } from '@amazon/vinyl-util';
7
+ import { flushPromises } from '@amazon/vinyl-util/browserTestUtil';
8
+ import { MockRequester } from '@amazon/vinyl-util/testUtil';
9
+ import { data } from '@amazon/vinyl-observable';
10
+ /**
11
+ * Flushes the microtask/macrotask queue repeatedly until `predicate` holds or
12
+ * the attempt budget is exhausted. A single {@link flushPromises} is one
13
+ * macrotask, which is enough in Node but not always in a real browser: loading
14
+ * a sidecar VTT chains `fetch -> Response.text() -> parse -> onCues`, and the
15
+ * streamed body read can span several macrotasks. Polling avoids a flaky
16
+ * fixed-tick wait while still failing fast when the condition never becomes
17
+ * true.
18
+ */
19
+ async function flushUntil(predicate) {
20
+ for (let i = 0; i < 100 && !predicate(); i++)
21
+ await flushPromises();
22
+ }
23
+ /**
24
+ * A memoized fake provider mirroring {@link MediaTextTrackProvider}: one track
25
+ * per `(kind,label,language)` key, so the number of distinct tracks reveals
26
+ * whether the controller accumulates tracks or reuses them.
27
+ */
28
+ class FakeTextTrackProvider {
29
+ // Every distinct track created (one per rendition key).
30
+ created = [];
31
+ // The track handed out by the most recent getOrCreate (the active one).
32
+ lastTrack = null;
33
+ cache = new Map();
34
+ getOrCreate = jasmine
35
+ .createSpy('getOrCreate')
36
+ .and.callFake((kind, label, language) => {
37
+ const key = `${kind}-${label}-${language}`;
38
+ const existing = this.cache.get(key);
39
+ if (existing) {
40
+ this.lastTrack = existing.track;
41
+ return existing;
42
+ }
43
+ const storedCues = [];
44
+ const track = {
45
+ kind,
46
+ label: label ?? '',
47
+ language: language ?? '',
48
+ mode: 'disabled',
49
+ storedCues,
50
+ // Real TextTrack.cues returns null when mode is 'disabled'.
51
+ get cues() {
52
+ return this.mode === 'disabled' ? null : storedCues;
53
+ },
54
+ addCue(cue) {
55
+ storedCues.push(cue);
56
+ },
57
+ removeCue(cue) {
58
+ const i = storedCues.indexOf(cue);
59
+ if (i >= 0)
60
+ storedCues.splice(i, 1);
61
+ },
62
+ };
63
+ const ref = {
64
+ track: track,
65
+ clear() {
66
+ // Mirrors the real ref: cues only clear while not disabled.
67
+ if (track.mode === 'disabled')
68
+ return;
69
+ storedCues.length = 0;
70
+ },
71
+ };
72
+ this.created.push(track);
73
+ this.cache.set(key, ref);
74
+ this.lastTrack = track;
75
+ return ref;
76
+ });
77
+ /** Tracks currently rendering captions (showing with at least one cue). */
78
+ showingWithCues() {
79
+ return this.created.filter((t) => t.mode === 'showing' && (t.cues?.length ?? 0) > 0);
80
+ }
81
+ }
82
+ function makeTrack(overrides = {}) {
83
+ return {
84
+ id: 'a',
85
+ kind: 'subtitles',
86
+ language: 'en',
87
+ label: 'English',
88
+ default: false,
89
+ forced: false,
90
+ characteristics: [],
91
+ uri: 'https://x.test/a.vtt',
92
+ mimeType: 'text/vtt',
93
+ ...overrides,
94
+ };
95
+ }
96
+ describe('SidecarTextTrackController', () => {
97
+ let requester;
98
+ let originalCue;
99
+ const disposers = [];
100
+ function build(opts) {
101
+ const provider = new FakeTextTrackProvider();
102
+ const textTracks$ = data(Promise.resolve([]));
103
+ const options$ = data(opts?.options ?? { selection: {} });
104
+ const playback = { currentTime: 0 };
105
+ const controller = new SidecarTextTrackController({
106
+ textTrackProvider: provider,
107
+ textTracks: textTracks$,
108
+ options: options$,
109
+ playbackController: playback,
110
+ requestInit: opts?.requestInit,
111
+ textTrackRenderer: opts?.textTrackRenderer,
112
+ });
113
+ // The owning media track activates the controller once current; do the
114
+ // same so cues render (unless a test wants to control activation).
115
+ if (opts?.activate !== false)
116
+ controller.activate();
117
+ disposers.push(() => controller.dispose());
118
+ return {
119
+ controller,
120
+ provider,
121
+ options$,
122
+ textTracks$,
123
+ playback,
124
+ async setTracks(tracks) {
125
+ textTracks$.value = Promise.resolve(tracks);
126
+ await flushPromises();
127
+ },
128
+ select(selection) {
129
+ options$.value = { ...options$.value, selection };
130
+ },
131
+ };
132
+ }
133
+ beforeEach(() => {
134
+ requester = new MockRequester();
135
+ requesterWithRetryRef.set(() => requester);
136
+ originalCue = globalThis.VTTCue;
137
+ globalThis.VTTCue = function VTTCue(startTime, endTime, text) {
138
+ this.startTime = startTime;
139
+ this.endTime = endTime;
140
+ this.text = text;
141
+ this.id = '';
142
+ this.size = 100;
143
+ };
144
+ });
145
+ afterEach(() => {
146
+ for (const dispose of disposers.splice(0))
147
+ dispose();
148
+ globalThis.VTTCue = originalCue;
149
+ });
150
+ function respondVtt(body) {
151
+ requester.request.and.resolveTo(new Response(body));
152
+ }
153
+ it('starts with no tracks and no active selection', () => {
154
+ const { controller } = build();
155
+ expect(controller.textTracks).toEqual([]);
156
+ expect(controller.activeTextTrack).toBeNull();
157
+ });
158
+ describe('resolveSelectedTrack', () => {
159
+ const full = makeTrack({ id: 'full', language: 'en', forced: false });
160
+ const forced = makeTrack({ id: 'forced', language: 'en', forced: true });
161
+ const captions = makeTrack({
162
+ id: 'cc',
163
+ language: 'en',
164
+ forced: false,
165
+ kind: 'captions',
166
+ });
167
+ it("renders nothing when enabled is 'off' (even with an id)", () => {
168
+ expect(resolveSelectedTrack([full, forced], {
169
+ enabled: 'off',
170
+ selection: { id: 'full' },
171
+ })).toBeNull();
172
+ });
173
+ it("enabled 'on' selects the full track", () => {
174
+ expect(resolveSelectedTrack([full, forced], {
175
+ enabled: 'on',
176
+ selection: { language: 'en' },
177
+ })?.id).toBe('full');
178
+ });
179
+ it("enabled 'forced' selects the forced track", () => {
180
+ expect(resolveSelectedTrack([full, forced], {
181
+ enabled: 'forced',
182
+ selection: { language: 'en' },
183
+ })?.id).toBe('forced');
184
+ });
185
+ it('selection.forced overrides the enabled mode', () => {
186
+ expect(resolveSelectedTrack([full, forced], {
187
+ enabled: 'on',
188
+ selection: { language: 'en', forced: true },
189
+ })?.id).toBe('forced');
190
+ });
191
+ it('an explicit id wins over other criteria', () => {
192
+ expect(resolveSelectedTrack([full, forced], {
193
+ selection: { id: 'forced', language: 'en', forced: false },
194
+ })?.id).toBe('forced');
195
+ });
196
+ it('unknown id selects nothing', () => {
197
+ expect(resolveSelectedTrack([full], { selection: { id: 'nope' } })).toBeNull();
198
+ });
199
+ it('forced defaults to true (only forced tracks)', () => {
200
+ expect(resolveSelectedTrack([full, forced], {
201
+ selection: { language: 'en' },
202
+ })?.id).toBe('forced');
203
+ });
204
+ it('forced:false selects the full track', () => {
205
+ expect(resolveSelectedTrack([full, forced], {
206
+ selection: { language: 'en', forced: false },
207
+ })?.id).toBe('full');
208
+ });
209
+ it('kind restricts the candidate pool', () => {
210
+ expect(resolveSelectedTrack([full, captions], {
211
+ selection: {
212
+ language: 'en',
213
+ forced: false,
214
+ kind: 'captions',
215
+ },
216
+ })?.id).toBe('cc');
217
+ });
218
+ it('falls back to navigator.languages when no language is given', () => {
219
+ // Node exposes navigator.languages === ['en-US'], relating to 'en'.
220
+ expect(resolveSelectedTrack([full], { selection: { forced: false } })
221
+ ?.id).toBe('full');
222
+ });
223
+ it('an ordered language list prefers earlier entries', () => {
224
+ const es = makeTrack({ id: 'es', language: 'es', forced: false });
225
+ expect(resolveSelectedTrack([full, es], {
226
+ selection: { language: ['es', 'en'], forced: false },
227
+ })?.id).toBe('es');
228
+ });
229
+ });
230
+ it('selecting a known id loads cues and creates a TextTrack', async () => {
231
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nfirst`);
232
+ const h = build({ options: { selection: { id: 'a' } } });
233
+ const activeChange = jasmine.createSpy();
234
+ h.controller.on('activeTextTrackChange', activeChange);
235
+ await h.setTracks([makeTrack()]);
236
+ expect(h.controller.activeTextTrack?.id).toBe('a');
237
+ expect(activeChange).toHaveBeenCalledTimes(1);
238
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
239
+ expect(h.provider.getOrCreate).toHaveBeenCalledWith('subtitles', 'English', 'en');
240
+ expect(h.provider.lastTrack?.mode).toBe('showing');
241
+ expect(h.provider.lastTrack?.cues?.length).toBe(1);
242
+ });
243
+ describe('authored cue settings', () => {
244
+ it("applies the cue's own parsed settings to the VTTCue", async () => {
245
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000 align:left size:80%\nx`);
246
+ const h = build({ options: { selection: { id: 'a' } } });
247
+ await h.setTracks([makeTrack()]);
248
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
249
+ const cue = h.provider.lastTrack?.cues?.[0];
250
+ expect(cue.align).toBe('left');
251
+ expect(cue.size).toBe(80);
252
+ });
253
+ it('leaves the cue at defaults when it declares no settings', async () => {
254
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nx`);
255
+ const h = build({ options: { selection: { id: 'a' } } });
256
+ await h.setTracks([makeTrack()]);
257
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
258
+ // The VTTCue stub defaults size to 100; unset settings don't touch it.
259
+ const cue = h.provider.lastTrack?.cues?.[0];
260
+ expect(cue.size).toBe(100);
261
+ });
262
+ it('does not apply settings to non-VTTCue cues', async () => {
263
+ ;
264
+ globalThis.VTTCue = undefined;
265
+ globalThis.TextTrackCue = function TextTrackCue(start, end, text) {
266
+ this.startTime = start;
267
+ this.endTime = end;
268
+ this.text = text;
269
+ this.id = '';
270
+ this.size = 100;
271
+ };
272
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000 size:80%\nignored`);
273
+ const h = build({ options: { selection: { id: 'a' } } });
274
+ await h.setTracks([makeTrack()]);
275
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
276
+ const cue = h.provider.lastTrack?.cues?.[0];
277
+ expect(cue.size).toBe(100) // not a VTTCue → never styled
278
+ ;
279
+ globalThis.TextTrackCue = undefined;
280
+ });
281
+ });
282
+ describe('text track renderer', () => {
283
+ function fakeRenderer() {
284
+ return {
285
+ setTextTrack: jasmine.createSpy('setTextTrack'),
286
+ setStyles: jasmine.createSpy('setStyles'),
287
+ };
288
+ }
289
+ it("keeps the DOM track 'hidden' and hands it to the renderer", async () => {
290
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nx`);
291
+ const renderer = fakeRenderer();
292
+ const h = build({
293
+ options: { selection: { id: 'a' } },
294
+ textTrackRenderer: renderer,
295
+ });
296
+ await h.setTracks([makeTrack()]);
297
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
298
+ expect(h.provider.lastTrack?.mode).toBe('hidden');
299
+ expect(renderer.setTextTrack).toHaveBeenCalledWith(h.provider.lastTrack);
300
+ });
301
+ it('detaches the renderer when captions are turned off', async () => {
302
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nx`);
303
+ const renderer = fakeRenderer();
304
+ const h = build({
305
+ options: { selection: { id: 'a' } },
306
+ textTrackRenderer: renderer,
307
+ });
308
+ await h.setTracks([makeTrack()]);
309
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
310
+ renderer.setTextTrack.calls.reset();
311
+ h.options$.value = { enabled: 'off' };
312
+ expect(renderer.setTextTrack).toHaveBeenCalledWith(null);
313
+ });
314
+ it('forwards authored STYLE blocks to the renderer', async () => {
315
+ respondVtt(`WEBVTT\n\nSTYLE\n::cue { color: red }\n\n00:00:01.000 --> 00:00:02.000\nx`);
316
+ const renderer = fakeRenderer();
317
+ const h = build({
318
+ options: { selection: { id: 'a' } },
319
+ textTrackRenderer: renderer,
320
+ });
321
+ await h.setTracks([makeTrack()]);
322
+ await flushUntil(() => renderer.setStyles.calls.count() > 0);
323
+ expect(renderer.setStyles).toHaveBeenCalledWith([
324
+ '::cue { color: red }',
325
+ ]);
326
+ });
327
+ it('ignores styles that arrive after the load is cancelled', async () => {
328
+ let resolveFetch = () => { };
329
+ requester.request.and.returnValue(new Promise((res) => {
330
+ resolveFetch = res;
331
+ }));
332
+ const renderer = fakeRenderer();
333
+ const h = build({
334
+ options: { selection: { id: 'a' } },
335
+ textTrackRenderer: renderer,
336
+ });
337
+ await h.setTracks([makeTrack()]);
338
+ h.options$.value = { enabled: 'off' }; // cancels the load
339
+ renderer.setStyles.calls.reset();
340
+ resolveFetch(new Response(`WEBVTT\n\nSTYLE\n::cue { color: red }\n\n00:00:01.000 --> 00:00:02.000\nx`));
341
+ await flushPromises();
342
+ expect(renderer.setStyles).not.toHaveBeenCalled();
343
+ });
344
+ it('works with a renderer that cannot consume styles', async () => {
345
+ respondVtt(`WEBVTT\n\nSTYLE\n::cue { color: red }\n\n00:00:01.000 --> 00:00:02.000\nx`);
346
+ // A renderer implementing only setTextTrack (setStyles is optional).
347
+ const renderer = {
348
+ setTextTrack: jasmine.createSpy('setTextTrack'),
349
+ };
350
+ const h = build({
351
+ options: { selection: { id: 'a' } },
352
+ textTrackRenderer: renderer,
353
+ });
354
+ await h.setTracks([makeTrack()]);
355
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
356
+ expect(renderer.setTextTrack).toHaveBeenCalled();
357
+ });
358
+ it("renders natively ('showing') when no renderer is injected", async () => {
359
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nx`);
360
+ const h = build({ options: { selection: { id: 'a' } } });
361
+ await h.setTracks([makeTrack()]);
362
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
363
+ expect(h.provider.lastTrack?.mode).toBe('showing');
364
+ });
365
+ });
366
+ it('preserves cue id when present', async () => {
367
+ respondVtt(`WEBVTT\n\nidA\n00:00:01.000 --> 00:00:02.000\nfirst`);
368
+ const h = build({ options: { selection: { id: 'a' } } });
369
+ await h.setTracks([makeTrack()]);
370
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
371
+ const cue = h.provider.lastTrack?.cues?.[0];
372
+ expect(cue.id).toBe('idA');
373
+ });
374
+ it('dedupes cues that appear in more than one segment', async () => {
375
+ // HLS caption packagers commonly repeat a cue at the boundary of two
376
+ // adjacent segments. When the loader emits both, the controller must
377
+ // only add it to the DOM TextTrack once.
378
+ const playlistBody = `#EXTM3U
379
+ #EXT-X-TARGETDURATION:5
380
+ #EXTINF:5.0,
381
+ a.vtt
382
+ #EXTINF:5.0,
383
+ b.vtt
384
+ #EXT-X-ENDLIST
385
+ `;
386
+ // Both segments contain the boundary cue "shared" and their own.
387
+ const segA = `WEBVTT\n\n00:00:00.500 --> 00:00:01.500\nonly-a\n\n00:00:04.500 --> 00:00:05.500\nshared`;
388
+ const segB = `WEBVTT\n\n00:00:04.500 --> 00:00:05.500\nshared\n\n00:00:07.000 --> 00:00:08.000\nonly-b`;
389
+ let call = 0;
390
+ requester.request.and.callFake(() => {
391
+ call++;
392
+ if (call === 1)
393
+ return Promise.resolve(new Response(playlistBody));
394
+ if (call === 2)
395
+ return Promise.resolve(new Response(segA));
396
+ return Promise.resolve(new Response(segB));
397
+ });
398
+ const h = build({ options: { selection: { id: 'a' } } });
399
+ await h.setTracks([makeTrack({ uri: 'https://x.test/sub.m3u8' })]);
400
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) >= 3);
401
+ const texts = (h.provider.lastTrack?.cues ?? []).map((c) => c.text);
402
+ expect(texts).toEqual(['only-a', 'shared', 'only-b']);
403
+ });
404
+ it('selecting an unknown id renders nothing and stays inactive', async () => {
405
+ const handler = jasmine.createSpy();
406
+ const h = build({ options: { selection: { id: 'unknown' } } });
407
+ h.controller.on('activeTextTrackChange', handler);
408
+ await h.setTracks([makeTrack()]);
409
+ expect(handler).not.toHaveBeenCalled();
410
+ expect(h.controller.activeTextTrack).toBeNull();
411
+ expect(h.provider.getOrCreate).not.toHaveBeenCalled();
412
+ });
413
+ it('disabling clears the current active track', async () => {
414
+ respondVtt(`WEBVTT\n`);
415
+ const h = build({ options: { selection: { id: 'a' } } });
416
+ await h.setTracks([makeTrack()]);
417
+ expect(h.controller.activeTextTrack?.id).toBe('a');
418
+ h.options$.value = { enabled: 'off' };
419
+ expect(h.controller.activeTextTrack).toBeNull();
420
+ });
421
+ it('clears active selection when its track is removed', async () => {
422
+ respondVtt(`WEBVTT\n`);
423
+ const h = build({ options: { selection: { id: 'a' } } });
424
+ const t1 = makeTrack({ id: 'a' });
425
+ const t2 = makeTrack({ id: 'b', uri: 'https://x.test/b.vtt' });
426
+ await h.setTracks([t1, t2]);
427
+ expect(h.controller.activeTextTrack?.id).toBe('a');
428
+ await h.setTracks([t2]);
429
+ expect(h.controller.activeTextTrack).toBeNull();
430
+ });
431
+ it('keeps the active selection when the list updates with it still present', async () => {
432
+ respondVtt(`WEBVTT\n`);
433
+ const h = build({ options: { selection: { id: 'a' } } });
434
+ const t1 = makeTrack({ id: 'a' });
435
+ const t2 = makeTrack({ id: 'b' });
436
+ await h.setTracks([t1]);
437
+ expect(h.controller.activeTextTrack?.id).toBe('a');
438
+ await h.setTracks([t1, t2]);
439
+ expect(h.controller.activeTextTrack?.id).toBe('a');
440
+ });
441
+ it('emits textTrackError on fetch failure', async () => {
442
+ requester.request.and.rejectWith(new Error('boom'));
443
+ const h = build({ options: { selection: { id: 'a' } } });
444
+ const onError = jasmine.createSpy('textTrackError');
445
+ h.controller.on('textTrackError', onError);
446
+ const t = makeTrack();
447
+ await h.setTracks([t]);
448
+ await flushUntil(() => onError.calls.count() > 0);
449
+ expect(onError).toHaveBeenCalledTimes(1);
450
+ const arg = onError.calls.mostRecent().args[0];
451
+ expect(arg.track).toBe(t);
452
+ expect(arg.error.message).toBe('boom');
453
+ });
454
+ it('wraps non-Error rejections', async () => {
455
+ requester.request.and.rejectWith('plain');
456
+ const h = build({ options: { selection: { id: 'a' } } });
457
+ const onError = jasmine.createSpy();
458
+ h.controller.on('textTrackError', onError);
459
+ await h.setTracks([makeTrack()]);
460
+ await flushUntil(() => onError.calls.count() > 0);
461
+ expect(onError.calls.mostRecent().args[0].error.message).toBe('plain');
462
+ });
463
+ it('drops cues that arrive after the load has been cancelled', async () => {
464
+ // Delay the fetch by one macrotask so we can cancel between the
465
+ // network reply and the onCues delivery.
466
+ let resolveFetch = () => { };
467
+ requester.request.and.returnValue(new Promise((res) => {
468
+ resolveFetch = res;
469
+ }));
470
+ const h = build({ options: { selection: { id: 'a' } } });
471
+ await h.setTracks([makeTrack()]);
472
+ const track = h.provider.lastTrack;
473
+ // Turn captions off — aborts the in-flight load.
474
+ h.options$.value = { enabled: 'off' };
475
+ resolveFetch(new Response(`WEBVTT\n\n00:00:00.500 --> 00:00:01.500\npost`));
476
+ await flushPromises();
477
+ expect(track?.storedCues.length ?? 0).toBe(0);
478
+ });
479
+ it('does not emit textTrackError when a load is cancelled by switching', async () => {
480
+ let rejectFirst = () => { };
481
+ let callCount = 0;
482
+ requester.request.and.callFake(() => new Promise((_, rej) => {
483
+ callCount++;
484
+ if (callCount === 1)
485
+ rejectFirst = rej;
486
+ else
487
+ rej(new Error('unused'));
488
+ }));
489
+ const h = build({ options: { selection: { id: 'a' } } });
490
+ const onError = jasmine.createSpy('textTrackError');
491
+ h.controller.on('textTrackError', onError);
492
+ await h.setTracks([makeTrack()]);
493
+ h.options$.value = { enabled: 'off' };
494
+ rejectFirst(new Error('would-be error'));
495
+ await flushPromises();
496
+ expect(onError).not.toHaveBeenCalled();
497
+ });
498
+ it('switching language reuses the per-rendition track and swaps its cues', async () => {
499
+ let call = 0;
500
+ requester.request.and.callFake(() => {
501
+ call++;
502
+ return Promise.resolve(new Response(call === 1
503
+ ? `WEBVTT\n\n00:00:00.500 --> 00:00:01.500\none`
504
+ : `WEBVTT\n\n00:00:01.000 --> 00:00:02.000\ntwo`));
505
+ });
506
+ const en = makeTrack({ id: 'en', language: 'en', label: 'English' });
507
+ const es = makeTrack({
508
+ id: 'es',
509
+ language: 'es',
510
+ label: 'Espanol',
511
+ uri: 'https://x.test/es.vtt',
512
+ });
513
+ const h = build({ options: { selection: { id: 'en' } } });
514
+ await h.setTracks([en, es]);
515
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
516
+ const enTrack = h.provider.lastTrack;
517
+ h.select({ id: 'es' });
518
+ // The outgoing English track is hidden and cleared; a distinct Spanish
519
+ // track (its own rendition) renders instead.
520
+ expect(enTrack?.storedCues.length).toBe(0);
521
+ expect(enTrack?.mode).toBe('disabled');
522
+ await flushUntil(() => h.provider.lastTrack !== enTrack &&
523
+ (h.provider.lastTrack?.cues?.length ?? 0) > 0);
524
+ expect(h.provider.lastTrack).not.toBe(enTrack);
525
+ expect(h.provider.lastTrack?.language).toBe('es');
526
+ expect(h.provider.showingWithCues().length).toBe(1);
527
+ });
528
+ it('cycling languages never accumulates or double-shows cues', async () => {
529
+ requester.request.and.callFake(() => Promise.resolve(new Response(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\ncue`)));
530
+ const langs = ['en', 'es', 'ja'].map((language) => makeTrack({
531
+ id: language,
532
+ language,
533
+ uri: `https://x.test/${language}.vtt`,
534
+ }));
535
+ const h = build({ options: { selection: { id: 'en' } } });
536
+ await h.setTracks(langs);
537
+ for (const id of ['en', 'es', 'ja', 'en']) {
538
+ h.select({ id });
539
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
540
+ expect(h.provider.showingWithCues().length)
541
+ .withContext(`after selecting ${id}`)
542
+ .toBe(1);
543
+ }
544
+ // One track per distinct rendition (3), reused on the repeat of 'en' —
545
+ // never one per activation (which would be 4).
546
+ expect(h.provider.created.length).toBe(3);
547
+ });
548
+ it('deactivate hides the DOM track and activate rebuilds it, keeping the selection', async () => {
549
+ requester.request.and.callFake(() => Promise.resolve(new Response(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\none`)));
550
+ const h = build({ options: { selection: { id: 'a' } } });
551
+ await h.setTracks([makeTrack()]);
552
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
553
+ const track = h.provider.lastTrack;
554
+ expect(track?.mode).toBe('showing');
555
+ expect(h.controller.active).toBeTrue();
556
+ h.controller.deactivate();
557
+ expect(h.controller.active).toBeFalse();
558
+ expect(track?.storedCues.length).toBe(0);
559
+ expect(track?.mode).toBe('disabled');
560
+ expect(h.controller.activeTextTrack?.id).toBe('a');
561
+ h.controller.activate();
562
+ expect(h.controller.active).toBeTrue();
563
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
564
+ expect(h.provider.lastTrack?.mode).toBe('showing');
565
+ expect(h.provider.lastTrack?.cues?.length).toBe(1);
566
+ });
567
+ it('activate is a no-op when nothing is selected', () => {
568
+ const h = build();
569
+ h.controller.activate();
570
+ expect(h.provider.getOrCreate).not.toHaveBeenCalled();
571
+ });
572
+ it('activate is a no-op when already rendering', async () => {
573
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\none`);
574
+ const h = build({ options: { selection: { id: 'a' } } });
575
+ await h.setTracks([makeTrack()]);
576
+ await flushUntil(() => (h.provider.lastTrack?.cues?.length ?? 0) > 0);
577
+ h.provider.getOrCreate.calls.reset();
578
+ h.controller.activate();
579
+ expect(h.provider.getOrCreate).not.toHaveBeenCalled();
580
+ });
581
+ it('does not render while deactivated even as the selection resolves', async () => {
582
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\none`);
583
+ const h = build({
584
+ options: { selection: { id: 'a' } },
585
+ activate: false,
586
+ });
587
+ h.controller.deactivate();
588
+ await h.setTracks([makeTrack()]);
589
+ // Selection is tracked, but nothing is rendered until activate().
590
+ expect(h.controller.activeTextTrack?.id).toBe('a');
591
+ expect(h.provider.getOrCreate).not.toHaveBeenCalled();
592
+ });
593
+ it('skips DOM cue creation when no VTTCue ctor is available', async () => {
594
+ ;
595
+ globalThis.VTTCue = undefined;
596
+ respondVtt(`WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nignored`);
597
+ const h = build({ options: { selection: { id: 'a' } } });
598
+ await h.setTracks([makeTrack()]);
599
+ await flushPromises();
600
+ expect(h.provider.lastTrack?.cues?.length ?? 0).toBe(0);
601
+ });
602
+ it('forwards requestInit when configured', async () => {
603
+ respondVtt(`WEBVTT\n`);
604
+ const h = build({
605
+ options: { selection: { id: 'a' } },
606
+ requestInit: { credentials: 'include' },
607
+ });
608
+ const t = makeTrack();
609
+ await h.setTracks([t]);
610
+ await flushPromises();
611
+ expect(requester.request).toHaveBeenCalledWith(t.uri, jasmine.objectContaining({ credentials: 'include' }), jasmine.any(Object));
612
+ });
613
+ it('drives HLS caption segment order from the media playhead', async () => {
614
+ const playlistBody = `#EXTM3U
615
+ #EXT-X-TARGETDURATION:5
616
+ #EXTINF:5.0,
617
+ a.vtt
618
+ #EXTINF:5.0,
619
+ b.vtt
620
+ #EXTINF:5.0,
621
+ c.vtt
622
+ #EXTINF:5.0,
623
+ d.vtt
624
+ #EXT-X-ENDLIST
625
+ `;
626
+ const fetched = [];
627
+ let call = 0;
628
+ requester.request.and.callFake((url) => {
629
+ call++;
630
+ if (call === 1)
631
+ return Promise.resolve(new Response(playlistBody));
632
+ const path = String(url).split('/').pop();
633
+ fetched.push(path);
634
+ return Promise.resolve(new Response(`WEBVTT\n\n00:00:00.000 --> 00:00:01.000\n${path}`));
635
+ });
636
+ const h = build({ options: { selection: { id: 'a' } } });
637
+ // Media at t=12s should cause seg3 (10s..15s) to be fetched first.
638
+ h.playback.currentTime = 12;
639
+ await h.setTracks([makeTrack({ uri: 'https://x.test/sub.m3u8' })]);
640
+ await flushUntil(() => fetched.length > 0);
641
+ expect(fetched[0]).toBe('c.vtt');
642
+ });
643
+ it('dispose aborts in-flight loads and clears state', async () => {
644
+ let resolveResponse = () => { };
645
+ requester.request.and.callFake(() => new Promise((res) => {
646
+ resolveResponse = res;
647
+ }));
648
+ const h = build({ options: { selection: { id: 'a' } } });
649
+ await h.setTracks([makeTrack()]);
650
+ const track = h.provider.lastTrack;
651
+ expect(track).not.toBeNull();
652
+ h.controller.dispose();
653
+ // Resolving after dispose must not throw or push cues onto the track.
654
+ resolveResponse(new Response(`WEBVTT\n\n00:00:00.500 --> 00:00:01.500\npost`));
655
+ await flushPromises();
656
+ expect(track?.mode).toBe('disabled');
657
+ expect(track?.storedCues.length).toBe(0);
658
+ expect(h.controller.activeTextTrack).toBeNull();
659
+ expect(h.controller.textTracks).toEqual([]);
660
+ });
661
+ it('creates the DOM track with an undefined language for null-language tracks', async () => {
662
+ respondVtt(`WEBVTT\n`);
663
+ const h = build({ options: { selection: { id: 'a' } } });
664
+ await h.setTracks([makeTrack({ language: null })]);
665
+ await flushPromises();
666
+ expect(h.provider.getOrCreate).toHaveBeenCalledWith('subtitles', 'English', undefined);
667
+ });
668
+ it('setting the same resolved track list twice emits textTracksChange once', async () => {
669
+ const handler = jasmine.createSpy();
670
+ const h = build();
671
+ h.controller.on('textTracksChange', handler);
672
+ const list = [makeTrack()];
673
+ await h.setTracks(list);
674
+ await h.setTracks([makeTrack()]); // deep-equal contents
675
+ expect(handler).toHaveBeenCalledTimes(1);
676
+ });
677
+ it('re-selecting the same id is a no-op', async () => {
678
+ respondVtt(`WEBVTT\n`);
679
+ const h = build({ options: { selection: { id: 'a' } } });
680
+ await h.setTracks([makeTrack()]);
681
+ const handler = jasmine.createSpy();
682
+ h.controller.on('activeTextTrackChange', handler);
683
+ h.select({ id: 'a' });
684
+ expect(handler).not.toHaveBeenCalled();
685
+ });
686
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SidecarTextTrackLoader.test.d.ts.map