@locpd/vidstack 1.12.14

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 (242) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -0
  3. package/analyze.json.d.ts +8 -0
  4. package/bundle.d.ts +1 -0
  5. package/cdn/chunks/vidstack-2f5gzOW6.js +1 -0
  6. package/cdn/chunks/vidstack-BYgY9wmd.js +1 -0
  7. package/cdn/chunks/vidstack-BfBBPhXV.js +1 -0
  8. package/cdn/chunks/vidstack-Bjo5esRp.js +1 -0
  9. package/cdn/chunks/vidstack-BuL67v3q.js +1 -0
  10. package/cdn/chunks/vidstack-C0msPRTd.js +3 -0
  11. package/cdn/chunks/vidstack-CJNLoJPa.js +1 -0
  12. package/cdn/chunks/vidstack-CQSpZ7X8.js +16 -0
  13. package/cdn/chunks/vidstack-C_AxqLKV.js +1 -0
  14. package/cdn/chunks/vidstack-CioT3Yw2.js +1 -0
  15. package/cdn/chunks/vidstack-CrqkytHl.js +1 -0
  16. package/cdn/chunks/vidstack-D0M8R0ZU.js +1 -0
  17. package/cdn/chunks/vidstack-D40FSa5B.js +3 -0
  18. package/cdn/chunks/vidstack-DD2JwFVU.js +1 -0
  19. package/cdn/chunks/vidstack-DRH_1tFW.js +1 -0
  20. package/cdn/chunks/vidstack-DfDZuHNP.js +1 -0
  21. package/cdn/chunks/vidstack-DiNS2Vx5.js +1 -0
  22. package/cdn/chunks/vidstack-xjJ-ui_l.js +1 -0
  23. package/cdn/providers/vidstack-audio-2Dt_Ivbp.js +1 -0
  24. package/cdn/providers/vidstack-dash-CUtD4e6q.js +1 -0
  25. package/cdn/providers/vidstack-google-cast-BdORATUX.js +1 -0
  26. package/cdn/providers/vidstack-hls-R25Kb6DP.js +1 -0
  27. package/cdn/providers/vidstack-html-DaAUJYsD.js +1 -0
  28. package/cdn/providers/vidstack-video-Csvox7SO.js +1 -0
  29. package/cdn/providers/vidstack-vimeo-D4Z96kg2.js +1 -0
  30. package/cdn/providers/vidstack-youtube-DiND6h3s.js +1 -0
  31. package/cdn/vidstack.js +1 -0
  32. package/cdn/with-layouts/chunks/vidstack-2f5gzOW6.js +1 -0
  33. package/cdn/with-layouts/chunks/vidstack-45yH5los.js +1 -0
  34. package/cdn/with-layouts/chunks/vidstack-BBVMdOnf.js +1 -0
  35. package/cdn/with-layouts/chunks/vidstack-BB_ulI_T.js +1 -0
  36. package/cdn/with-layouts/chunks/vidstack-BcAewM33.js +1 -0
  37. package/cdn/with-layouts/chunks/vidstack-BfBBPhXV.js +1 -0
  38. package/cdn/with-layouts/chunks/vidstack-Bxv1Qnxe.js +1 -0
  39. package/cdn/with-layouts/chunks/vidstack-C2ZbG62f.js +3 -0
  40. package/cdn/with-layouts/chunks/vidstack-CCYIOKgL.js +1 -0
  41. package/cdn/with-layouts/chunks/vidstack-CL6PeIO1.js +1 -0
  42. package/cdn/with-layouts/chunks/vidstack-C_AxqLKV.js +1 -0
  43. package/cdn/with-layouts/chunks/vidstack-CifDkwDH.js +795 -0
  44. package/cdn/with-layouts/chunks/vidstack-Cry7aD59.js +3 -0
  45. package/cdn/with-layouts/chunks/vidstack-D065okCn.js +1 -0
  46. package/cdn/with-layouts/chunks/vidstack-DGuMoXmI.js +1 -0
  47. package/cdn/with-layouts/chunks/vidstack-DRH_1tFW.js +1 -0
  48. package/cdn/with-layouts/chunks/vidstack-DVBs1XoQ.js +1 -0
  49. package/cdn/with-layouts/chunks/vidstack-Dge3KT8k.js +1 -0
  50. package/cdn/with-layouts/chunks/vidstack-DiNS2Vx5.js +1 -0
  51. package/cdn/with-layouts/chunks/vidstack-HvYfJoen.js +1 -0
  52. package/cdn/with-layouts/providers/vidstack-audio-DE5vKIzW.js +1 -0
  53. package/cdn/with-layouts/providers/vidstack-dash-CA2agUuZ.js +1 -0
  54. package/cdn/with-layouts/providers/vidstack-google-cast-CGs-t8HM.js +1 -0
  55. package/cdn/with-layouts/providers/vidstack-hls-BHMbMFFR.js +1 -0
  56. package/cdn/with-layouts/providers/vidstack-html-Dm9gmNk6.js +1 -0
  57. package/cdn/with-layouts/providers/vidstack-video-C5it_Lbl.js +1 -0
  58. package/cdn/with-layouts/providers/vidstack-vimeo-BabLn9sy.js +1 -0
  59. package/cdn/with-layouts/providers/vidstack-youtube-D8UlccUL.js +1 -0
  60. package/cdn/with-layouts/vidstack.js +1 -0
  61. package/dev/chunks/vidstack-B7Zi3v_O.js +104 -0
  62. package/dev/chunks/vidstack-BFg1ZqiG.js +91 -0
  63. package/dev/chunks/vidstack-BGB2pa9s.js +58 -0
  64. package/dev/chunks/vidstack-BaIbHZE3.js +1519 -0
  65. package/dev/chunks/vidstack-Bb2rASIc.js +5188 -0
  66. package/dev/chunks/vidstack-Bcmx8pmK.js +224 -0
  67. package/dev/chunks/vidstack-Bl4b0Nen.js +29 -0
  68. package/dev/chunks/vidstack-Bo5OTJ06.js +58 -0
  69. package/dev/chunks/vidstack-BoAGnlRt.js +58 -0
  70. package/dev/chunks/vidstack-Bpr4fI4n.js +7 -0
  71. package/dev/chunks/vidstack-Bt8MP2DK.js +204 -0
  72. package/dev/chunks/vidstack-Bu2kfzUd.js +1637 -0
  73. package/dev/chunks/vidstack-C-ffXlSV.js +2995 -0
  74. package/dev/chunks/vidstack-C-ztJq-f.js +109 -0
  75. package/dev/chunks/vidstack-CFNlaVTR.js +55 -0
  76. package/dev/chunks/vidstack-C_l97D5j.js +254 -0
  77. package/dev/chunks/vidstack-CjhKISI0.js +114 -0
  78. package/dev/chunks/vidstack-CofXIJAy.js +57 -0
  79. package/dev/chunks/vidstack-CwTj4H1w.js +18 -0
  80. package/dev/chunks/vidstack-DDwbYVHV.js +66 -0
  81. package/dev/chunks/vidstack-DFImIcIL.js +11 -0
  82. package/dev/chunks/vidstack-DGDvUbvO.js +33 -0
  83. package/dev/chunks/vidstack-DO0kqA99.js +107 -0
  84. package/dev/chunks/vidstack-DXxIKXmd.js +50 -0
  85. package/dev/chunks/vidstack-DajrMUR0.js +297 -0
  86. package/dev/chunks/vidstack-DbBJlz7I.js +10 -0
  87. package/dev/chunks/vidstack-Dihypf8P.js +11 -0
  88. package/dev/chunks/vidstack-DlAhl87f.js +1193 -0
  89. package/dev/chunks/vidstack-Dm1xEU9Q.js +34 -0
  90. package/dev/chunks/vidstack-Dv_LIPFu.js +14 -0
  91. package/dev/chunks/vidstack-igYn0Apa.js +254 -0
  92. package/dev/chunks/vidstack-krOAtKMi.js +32 -0
  93. package/dev/chunks/vidstack-qh1N5_f_.js +26 -0
  94. package/dev/chunks/vidstack-rB-wqXw1.js +107 -0
  95. package/dev/chunks/vidstack-zG6PIeGg.js +66 -0
  96. package/dev/define/plyr-layout.js +51 -0
  97. package/dev/define/templates/plyr-layout.js +571 -0
  98. package/dev/define/templates/vidstack-audio-layout.js +167 -0
  99. package/dev/define/templates/vidstack-video-layout.js +390 -0
  100. package/dev/define/vidstack-icons.js +1 -0
  101. package/dev/define/vidstack-player-default-layout.js +21 -0
  102. package/dev/define/vidstack-player-layouts.js +25 -0
  103. package/dev/define/vidstack-player-ui.js +70 -0
  104. package/dev/define/vidstack-player.js +19 -0
  105. package/dev/global/plyr.js +501 -0
  106. package/dev/global/vidstack-player.js +129 -0
  107. package/dev/providers/vidstack-audio.js +35 -0
  108. package/dev/providers/vidstack-dash.js +516 -0
  109. package/dev/providers/vidstack-google-cast.js +474 -0
  110. package/dev/providers/vidstack-hls.js +408 -0
  111. package/dev/providers/vidstack-html.js +567 -0
  112. package/dev/providers/vidstack-video.js +207 -0
  113. package/dev/providers/vidstack-vimeo.js +554 -0
  114. package/dev/providers/vidstack-youtube.js +286 -0
  115. package/dev/vidstack-elements.js +36 -0
  116. package/dev/vidstack.js +91 -0
  117. package/dom.d.ts +91 -0
  118. package/elements.d.ts +1433 -0
  119. package/empty.vtt +1 -0
  120. package/global/player.d.ts +52 -0
  121. package/global/plyr.d.ts +343 -0
  122. package/google-cast.d.ts +1422 -0
  123. package/icons.d.ts +1 -0
  124. package/index.d.ts +402 -0
  125. package/package.json +199 -0
  126. package/player/index.d.ts +3 -0
  127. package/player/layouts/default.d.ts +3 -0
  128. package/player/layouts/index.d.ts +3 -0
  129. package/player/layouts/plyr.d.ts +3 -0
  130. package/player/styles/base.css +153 -0
  131. package/player/styles/default/buffering.css +55 -0
  132. package/player/styles/default/buttons.css +175 -0
  133. package/player/styles/default/captions.css +181 -0
  134. package/player/styles/default/chapter-title.css +26 -0
  135. package/player/styles/default/controls.css +56 -0
  136. package/player/styles/default/gestures.css +19 -0
  137. package/player/styles/default/icons.css +6 -0
  138. package/player/styles/default/keyboard.css +148 -0
  139. package/player/styles/default/layouts/audio.css +417 -0
  140. package/player/styles/default/layouts/video.css +590 -0
  141. package/player/styles/default/menus.css +959 -0
  142. package/player/styles/default/poster.css +52 -0
  143. package/player/styles/default/sliders.css +391 -0
  144. package/player/styles/default/theme.css +2461 -0
  145. package/player/styles/default/thumbnail.css +40 -0
  146. package/player/styles/default/time.css +45 -0
  147. package/player/styles/default/tooltips.css +141 -0
  148. package/player/styles/plyr/theme.css +1237 -0
  149. package/player/ui.d.ts +3 -0
  150. package/plugins.d.ts +19 -0
  151. package/plugins.js +13 -0
  152. package/prod/chunks/vidstack-B01xzxC4.js +7 -0
  153. package/prod/chunks/vidstack-BCeb7ryV.js +201 -0
  154. package/prod/chunks/vidstack-BGSTndAW.js +1590 -0
  155. package/prod/chunks/vidstack-BPitBBjh.js +1519 -0
  156. package/prod/chunks/vidstack-BQlOPwOu.js +45 -0
  157. package/prod/chunks/vidstack-BSDzlwxO.js +4778 -0
  158. package/prod/chunks/vidstack-BT0m6zEi.js +109 -0
  159. package/prod/chunks/vidstack-BTigPj2h.js +55 -0
  160. package/prod/chunks/vidstack-BiyXcJ_M.js +107 -0
  161. package/prod/chunks/vidstack-BoVf5n1M.js +2985 -0
  162. package/prod/chunks/vidstack-Bq6c3Bam.js +58 -0
  163. package/prod/chunks/vidstack-ByLCIBtB.js +297 -0
  164. package/prod/chunks/vidstack-C2US-gSO.js +248 -0
  165. package/prod/chunks/vidstack-C9vIqaYT.js +10 -0
  166. package/prod/chunks/vidstack-CF6fixCQ.js +1193 -0
  167. package/prod/chunks/vidstack-CTojmhKq.js +66 -0
  168. package/prod/chunks/vidstack-ChQTHmIQ.js +77 -0
  169. package/prod/chunks/vidstack-Cm6_unwd.js +246 -0
  170. package/prod/chunks/vidstack-CwTj4H1w.js +18 -0
  171. package/prod/chunks/vidstack-D3ltXc3a.js +33 -0
  172. package/prod/chunks/vidstack-D5EzK014.js +14 -0
  173. package/prod/chunks/vidstack-DDXt6fpN.js +58 -0
  174. package/prod/chunks/vidstack-DJDnh4xT.js +11 -0
  175. package/prod/chunks/vidstack-DXxIKXmd.js +50 -0
  176. package/prod/chunks/vidstack-D_-9AA6_.js +29 -0
  177. package/prod/chunks/vidstack-DbkZGjSn.js +107 -0
  178. package/prod/chunks/vidstack-Dihypf8P.js +11 -0
  179. package/prod/chunks/vidstack-Dm1xEU9Q.js +34 -0
  180. package/prod/chunks/vidstack-Dq5Yu0Vr.js +205 -0
  181. package/prod/chunks/vidstack-DqAw8m9J.js +26 -0
  182. package/prod/chunks/vidstack-DsPOyKtl.js +57 -0
  183. package/prod/chunks/vidstack-krOAtKMi.js +32 -0
  184. package/prod/chunks/vidstack-nLyr4NEP.js +58 -0
  185. package/prod/chunks/vidstack-xMS8dnYq.js +114 -0
  186. package/prod/chunks/vidstack-yEGTpgeA.js +104 -0
  187. package/prod/define/plyr-layout.js +51 -0
  188. package/prod/define/templates/plyr-layout.js +571 -0
  189. package/prod/define/templates/vidstack-audio-layout.js +167 -0
  190. package/prod/define/templates/vidstack-video-layout.js +390 -0
  191. package/prod/define/vidstack-icons.js +1 -0
  192. package/prod/define/vidstack-player-default-layout.js +21 -0
  193. package/prod/define/vidstack-player-layouts.js +25 -0
  194. package/prod/define/vidstack-player-ui.js +70 -0
  195. package/prod/define/vidstack-player.js +19 -0
  196. package/prod/global/plyr.js +493 -0
  197. package/prod/global/vidstack-player.js +129 -0
  198. package/prod/providers/vidstack-audio.js +35 -0
  199. package/prod/providers/vidstack-dash.js +501 -0
  200. package/prod/providers/vidstack-google-cast.js +468 -0
  201. package/prod/providers/vidstack-hls.js +393 -0
  202. package/prod/providers/vidstack-html.js +555 -0
  203. package/prod/providers/vidstack-video.js +204 -0
  204. package/prod/providers/vidstack-vimeo.js +548 -0
  205. package/prod/providers/vidstack-youtube.js +286 -0
  206. package/prod/vidstack-elements.js +36 -0
  207. package/prod/vidstack.js +158 -0
  208. package/server/chunks/vidstack-6juFdkKy.js +29 -0
  209. package/server/chunks/vidstack-B7iHmv7_.js +307 -0
  210. package/server/chunks/vidstack-BmxyML9v.js +1619 -0
  211. package/server/chunks/vidstack-BskfxwD3.js +566 -0
  212. package/server/chunks/vidstack-BvLV0SMz.js +4642 -0
  213. package/server/chunks/vidstack-BvWwluXZ.js +205 -0
  214. package/server/chunks/vidstack-C-413dj2.js +8 -0
  215. package/server/chunks/vidstack-C26K8z_-.js +55 -0
  216. package/server/chunks/vidstack-CJJiksDz.js +107 -0
  217. package/server/chunks/vidstack-CUNv52x1.js +141 -0
  218. package/server/chunks/vidstack-CqyBCODe.js +295 -0
  219. package/server/chunks/vidstack-CwTj4H1w.js +18 -0
  220. package/server/chunks/vidstack-DHAyGSOl.js +1502 -0
  221. package/server/chunks/vidstack-DLU3cjcp.js +381 -0
  222. package/server/chunks/vidstack-DXxIKXmd.js +50 -0
  223. package/server/chunks/vidstack-DbtDXDS2.js +104 -0
  224. package/server/chunks/vidstack-Dm1xEU9Q.js +34 -0
  225. package/server/chunks/vidstack-DzTHw_bw.js +207 -0
  226. package/server/chunks/vidstack-Wn3NH5Sg.js +1566 -0
  227. package/server/chunks/vidstack-krOAtKMi.js +32 -0
  228. package/server/chunks/vidstack-wNViAkr4.js +3045 -0
  229. package/server/define/plyr-layout.js +16 -0
  230. package/server/define/vidstack-icons.js +1 -0
  231. package/server/define/vidstack-player-default-layout.js +13 -0
  232. package/server/define/vidstack-player-layouts.js +16 -0
  233. package/server/define/vidstack-player-ui.js +11 -0
  234. package/server/define/vidstack-player.js +6 -0
  235. package/server/global/plyr.js +322 -0
  236. package/server/global/vidstack-player.js +58 -0
  237. package/server/vidstack-elements.js +46 -0
  238. package/server/vidstack.js +148 -0
  239. package/tailwind.cjs +101 -0
  240. package/tailwind.d.cts +15 -0
  241. package/types/vidstack-BOvzfZjK.d.ts +1269 -0
  242. package/types/vidstack-Cttpg6GU.d.ts +7474 -0
@@ -0,0 +1,567 @@
1
+ import { IS_SAFARI, IS_IOS, isHLSSrc, isMediaStream } from '../chunks/vidstack-CjhKISI0.js';
2
+ import { signal, EventsController, effect, onDispose, peek, isNil, listenEvent, DOMEvent, createScope, setAttribute, isString } from '../chunks/vidstack-Bu2kfzUd.js';
3
+ import { RAFLoop } from '../chunks/vidstack-qh1N5_f_.js';
4
+ import { getNumberOfDecimalPlaces } from '../chunks/vidstack-Dihypf8P.js';
5
+ import { ListSymbol } from '../chunks/vidstack-Dv_LIPFu.js';
6
+
7
+ let audioContext = null, gainNodes = [], elAudioSources = [];
8
+ function getOrCreateAudioCtx() {
9
+ return audioContext ??= new AudioContext();
10
+ }
11
+ function createGainNode() {
12
+ const audioCtx = getOrCreateAudioCtx(), gainNode = audioCtx.createGain();
13
+ gainNode.connect(audioCtx.destination);
14
+ gainNodes.push(gainNode);
15
+ return gainNode;
16
+ }
17
+ function createElementSource(el, gainNode) {
18
+ const audioCtx = getOrCreateAudioCtx(), src = audioCtx.createMediaElementSource(el);
19
+ if (gainNode) {
20
+ src.connect(gainNode);
21
+ }
22
+ elAudioSources.push(src);
23
+ return src;
24
+ }
25
+ function destroyGainNode(node) {
26
+ const idx = gainNodes.indexOf(node);
27
+ if (idx !== -1) {
28
+ gainNodes.splice(idx, 1);
29
+ node.disconnect();
30
+ freeAudioCtxWhenAllResourcesFreed();
31
+ }
32
+ }
33
+ function destroyElementSource(src) {
34
+ const idx = elAudioSources.indexOf(src);
35
+ if (idx !== -1) {
36
+ elAudioSources.splice(idx, 1);
37
+ src.disconnect();
38
+ freeAudioCtxWhenAllResourcesFreed();
39
+ }
40
+ }
41
+ function freeAudioCtxWhenAllResourcesFreed() {
42
+ if (audioContext && gainNodes.length === 0 && elAudioSources.length === 0) {
43
+ audioContext.close().then(() => {
44
+ audioContext = null;
45
+ });
46
+ }
47
+ }
48
+
49
+ class AudioGain {
50
+ #media;
51
+ #onChange;
52
+ #gainNode = null;
53
+ #srcAudioNode = null;
54
+ get currentGain() {
55
+ return this.#gainNode?.gain?.value ?? null;
56
+ }
57
+ get supported() {
58
+ return true;
59
+ }
60
+ constructor(media, onChange) {
61
+ this.#media = media;
62
+ this.#onChange = onChange;
63
+ }
64
+ setGain(gain) {
65
+ const currGain = this.currentGain;
66
+ if (gain === this.currentGain) {
67
+ return;
68
+ }
69
+ if (gain === 1 && currGain !== 1) {
70
+ this.removeGain();
71
+ return;
72
+ }
73
+ if (!this.#gainNode) {
74
+ this.#gainNode = createGainNode();
75
+ if (this.#srcAudioNode) {
76
+ this.#srcAudioNode.connect(this.#gainNode);
77
+ }
78
+ }
79
+ if (!this.#srcAudioNode) {
80
+ this.#srcAudioNode = createElementSource(this.#media, this.#gainNode);
81
+ }
82
+ this.#gainNode.gain.value = gain;
83
+ this.#onChange(gain);
84
+ }
85
+ removeGain() {
86
+ if (!this.#gainNode) return;
87
+ if (this.#srcAudioNode) {
88
+ this.#srcAudioNode.connect(getOrCreateAudioCtx().destination);
89
+ }
90
+ this.#destroyGainNode();
91
+ this.#onChange(null);
92
+ }
93
+ destroy() {
94
+ this.#destroySrcNode();
95
+ this.#destroyGainNode();
96
+ }
97
+ #destroySrcNode() {
98
+ if (!this.#srcAudioNode) return;
99
+ try {
100
+ destroyElementSource(this.#srcAudioNode);
101
+ } catch (e) {
102
+ } finally {
103
+ this.#srcAudioNode = null;
104
+ }
105
+ }
106
+ #destroyGainNode() {
107
+ if (!this.#gainNode) return;
108
+ try {
109
+ destroyGainNode(this.#gainNode);
110
+ } catch (e) {
111
+ } finally {
112
+ this.#gainNode = null;
113
+ }
114
+ }
115
+ }
116
+
117
+ const PAGE_EVENTS = ["focus", "blur", "visibilitychange", "pageshow", "pagehide"];
118
+ class PageVisibility {
119
+ #state = signal(determinePageState());
120
+ #visibility = signal(document.visibilityState);
121
+ #safariBeforeUnloadTimeout;
122
+ connect() {
123
+ const events = new EventsController(window), handlePageEvent = this.#handlePageEvent.bind(this);
124
+ for (const eventType of PAGE_EVENTS) {
125
+ events.add(eventType, handlePageEvent);
126
+ }
127
+ if (IS_SAFARI) {
128
+ events.add("beforeunload", (event) => {
129
+ this.#safariBeforeUnloadTimeout = setTimeout(() => {
130
+ if (!(event.defaultPrevented || event.returnValue.length > 0)) {
131
+ this.#state.set("hidden");
132
+ this.#visibility.set("hidden");
133
+ }
134
+ }, 0);
135
+ });
136
+ }
137
+ }
138
+ /**
139
+ * The current page state. Important to note we only account for a subset of page states, as
140
+ * the rest aren't valuable to the player at the moment.
141
+ *
142
+ * - **active:** A page is in the active state if it is visible and has input focus.
143
+ * - **passive:** A page is in the passive state if it is visible and does not have input focus.
144
+ * - **hidden:** A page is in the hidden state if it is not visible.
145
+ *
146
+ * @see https://developers.google.com/web/updates/2018/07/page-lifecycle-api#states
147
+ */
148
+ get pageState() {
149
+ return this.#state();
150
+ }
151
+ /**
152
+ * The current document visibility state.
153
+ *
154
+ * - **visible:** The page content may be at least partially visible. In practice, this means that
155
+ * the page is the foreground tab of a non-minimized window.
156
+ * - **hidden:** The page content is not visible to the user. In practice this means that the
157
+ * document is either a background tab or part of a minimized window, or the OS screen lock is
158
+ * active.
159
+ *
160
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState
161
+ */
162
+ get visibility() {
163
+ return this.#visibility();
164
+ }
165
+ #handlePageEvent(event) {
166
+ if (IS_SAFARI) window.clearTimeout(this.#safariBeforeUnloadTimeout);
167
+ if (event.type !== "blur" || this.#state() === "active") {
168
+ this.#state.set(determinePageState(event));
169
+ this.#visibility.set(document.visibilityState == "hidden" ? "hidden" : "visible");
170
+ }
171
+ }
172
+ }
173
+ function determinePageState(event) {
174
+ if (event?.type === "blur" || document.visibilityState === "hidden") return "hidden";
175
+ if (document.hasFocus()) return "active";
176
+ return "passive";
177
+ }
178
+
179
+ class HTMLMediaEvents {
180
+ #provider;
181
+ #ctx;
182
+ #waiting = false;
183
+ #attachedLoadStart = false;
184
+ #attachedCanPlay = false;
185
+ #timeRAF = new RAFLoop(this.#onAnimationFrame.bind(this));
186
+ #pageVisibility = new PageVisibility();
187
+ #events;
188
+ get #media() {
189
+ return this.#provider.media;
190
+ }
191
+ constructor(provider, ctx) {
192
+ this.#provider = provider;
193
+ this.#ctx = ctx;
194
+ this.#events = new EventsController(provider.media);
195
+ this.#attachInitialListeners();
196
+ this.#pageVisibility.connect();
197
+ effect(this.#attachTimeUpdate.bind(this));
198
+ onDispose(this.#onDispose.bind(this));
199
+ }
200
+ #onDispose() {
201
+ this.#attachedLoadStart = false;
202
+ this.#attachedCanPlay = false;
203
+ this.#timeRAF.stop();
204
+ this.#events.abort();
205
+ this.#devHandlers?.clear();
206
+ }
207
+ /**
208
+ * The `timeupdate` event fires surprisingly infrequently during playback, meaning your progress
209
+ * bar (or whatever else is synced to the currentTime) moves in a choppy fashion. This helps
210
+ * resolve that by retrieving time updates in a request animation frame loop.
211
+ */
212
+ #lastSeenTime = 0;
213
+ #seekedTo = -1;
214
+ #onAnimationFrame() {
215
+ const newTime = this.#media.currentTime;
216
+ const didStutter = IS_SAFARI && newTime - this.#seekedTo < 0.35;
217
+ if (!didStutter && this.#lastSeenTime !== newTime) {
218
+ this.#updateCurrentTime(newTime);
219
+ this.#lastSeenTime = newTime;
220
+ }
221
+ }
222
+ #attachInitialListeners() {
223
+ {
224
+ this.#ctx.logger?.info("attaching initial listeners");
225
+ }
226
+ this.#attachEventListener("loadstart", this.#onLoadStart);
227
+ this.#attachEventListener("abort", this.#onAbort);
228
+ this.#attachEventListener("emptied", this.#onEmptied);
229
+ this.#attachEventListener("error", this.#onError);
230
+ this.#attachEventListener("volumechange", this.#onVolumeChange);
231
+ this.#ctx.logger?.debug("attached initial media event listeners");
232
+ }
233
+ #attachLoadStartListeners() {
234
+ if (this.#attachedLoadStart) return;
235
+ {
236
+ this.#ctx.logger?.info("attaching load start listeners");
237
+ }
238
+ this.#attachEventListener("loadeddata", this.#onLoadedData);
239
+ this.#attachEventListener("loadedmetadata", this.#onLoadedMetadata);
240
+ this.#attachEventListener("canplay", this.#onCanPlay);
241
+ this.#attachEventListener("canplaythrough", this.#onCanPlayThrough);
242
+ this.#attachEventListener("durationchange", this.#onDurationChange);
243
+ this.#attachEventListener("play", this.#onPlay);
244
+ this.#attachEventListener("progress", this.#onProgress);
245
+ this.#attachEventListener("stalled", this.#onStalled);
246
+ this.#attachEventListener("suspend", this.#onSuspend);
247
+ this.#attachEventListener("ratechange", this.#onRateChange);
248
+ this.#attachedLoadStart = true;
249
+ }
250
+ #attachCanPlayListeners() {
251
+ if (this.#attachedCanPlay) return;
252
+ {
253
+ this.#ctx.logger?.info("attaching can play listeners");
254
+ }
255
+ this.#attachEventListener("pause", this.#onPause);
256
+ this.#attachEventListener("playing", this.#onPlaying);
257
+ this.#attachEventListener("seeked", this.#onSeeked);
258
+ this.#attachEventListener("seeking", this.#onSeeking);
259
+ this.#attachEventListener("ended", this.#onEnded);
260
+ this.#attachEventListener("waiting", this.#onWaiting);
261
+ this.#attachedCanPlay = true;
262
+ }
263
+ #devHandlers = /* @__PURE__ */ new Map() ;
264
+ #handleDevEvent = this.#onDevEvent.bind(this) ;
265
+ #attachEventListener(eventType, handler) {
266
+ this.#devHandlers.set(eventType, handler);
267
+ this.#events.add(eventType, this.#handleDevEvent );
268
+ }
269
+ #onDevEvent(event2) {
270
+ this.#ctx.logger?.debugGroup(`\u{1F4FA} provider fired \`${event2.type}\``).labelledLog("Provider", this.#provider).labelledLog("Event", event2).labelledLog("Media Store", { ...this.#ctx.$state }).dispatch();
271
+ this.#devHandlers.get(event2.type)?.call(this, event2);
272
+ }
273
+ #updateCurrentTime(time, trigger) {
274
+ const newTime = Math.min(time, this.#ctx.$state.seekableEnd());
275
+ this.#ctx.notify("time-change", newTime, trigger);
276
+ }
277
+ #onLoadStart(event2) {
278
+ if (this.#media.networkState === 3) {
279
+ this.#onAbort(event2);
280
+ return;
281
+ }
282
+ this.#attachLoadStartListeners();
283
+ this.#ctx.notify("load-start", void 0, event2);
284
+ }
285
+ #onAbort(event2) {
286
+ this.#ctx.notify("abort", void 0, event2);
287
+ }
288
+ #onEmptied() {
289
+ this.#ctx.notify("emptied", void 0, event);
290
+ }
291
+ #onLoadedData(event2) {
292
+ this.#ctx.notify("loaded-data", void 0, event2);
293
+ }
294
+ #onLoadedMetadata(event2) {
295
+ this.#lastSeenTime = 0;
296
+ this.#seekedTo = -1;
297
+ this.#attachCanPlayListeners();
298
+ this.#ctx.notify("loaded-metadata", void 0, event2);
299
+ if (IS_IOS || IS_SAFARI && isHLSSrc(this.#ctx.$state.source())) {
300
+ this.#ctx.delegate.ready(this.#getCanPlayDetail(), event2);
301
+ }
302
+ }
303
+ #getCanPlayDetail() {
304
+ return {
305
+ provider: peek(this.#ctx.$provider),
306
+ duration: this.#media.duration,
307
+ buffered: this.#media.buffered,
308
+ seekable: this.#media.seekable
309
+ };
310
+ }
311
+ #onPlay(event2) {
312
+ if (!this.#ctx.$state.canPlay) return;
313
+ this.#ctx.notify("play", void 0, event2);
314
+ }
315
+ #onPause(event2) {
316
+ if (this.#media.readyState === 1 && !this.#waiting) return;
317
+ this.#waiting = false;
318
+ this.#timeRAF.stop();
319
+ this.#ctx.notify("pause", void 0, event2);
320
+ }
321
+ #onCanPlay(event2) {
322
+ this.#ctx.delegate.ready(this.#getCanPlayDetail(), event2);
323
+ }
324
+ #onCanPlayThrough(event2) {
325
+ if (this.#ctx.$state.started()) return;
326
+ this.#ctx.notify("can-play-through", this.#getCanPlayDetail(), event2);
327
+ }
328
+ #onPlaying(event2) {
329
+ if (this.#media.paused) return;
330
+ this.#waiting = false;
331
+ this.#ctx.notify("playing", void 0, event2);
332
+ this.#timeRAF.start();
333
+ }
334
+ #onStalled(event2) {
335
+ this.#ctx.notify("stalled", void 0, event2);
336
+ if (this.#media.readyState < 3) {
337
+ this.#waiting = true;
338
+ this.#ctx.notify("waiting", void 0, event2);
339
+ }
340
+ }
341
+ #onWaiting(event2) {
342
+ if (this.#media.readyState < 3) {
343
+ this.#waiting = true;
344
+ this.#ctx.notify("waiting", void 0, event2);
345
+ }
346
+ }
347
+ #onEnded(event2) {
348
+ this.#timeRAF.stop();
349
+ this.#updateCurrentTime(this.#media.duration, event2);
350
+ this.#ctx.notify("end", void 0, event2);
351
+ if (this.#ctx.$state.loop()) {
352
+ const hasCustomControls = isNil(this.#media.controls);
353
+ if (hasCustomControls) this.#media.controls = false;
354
+ }
355
+ }
356
+ #attachTimeUpdate() {
357
+ const isPaused = this.#ctx.$state.paused(), isPageHidden = this.#pageVisibility.visibility === "hidden", shouldListenToTimeUpdates = isPaused || isPageHidden;
358
+ if (shouldListenToTimeUpdates) {
359
+ listenEvent(this.#media, "timeupdate", this.#onTimeUpdate.bind(this));
360
+ }
361
+ }
362
+ #onTimeUpdate(event2) {
363
+ this.#updateCurrentTime(this.#media.currentTime, event2);
364
+ }
365
+ #onDurationChange(event2) {
366
+ if (this.#ctx.$state.ended()) {
367
+ this.#updateCurrentTime(this.#media.duration, event2);
368
+ }
369
+ this.#ctx.notify("duration-change", this.#media.duration, event2);
370
+ }
371
+ #onVolumeChange(event2) {
372
+ const detail = {
373
+ volume: this.#media.volume,
374
+ muted: this.#media.muted
375
+ };
376
+ this.#ctx.notify("volume-change", detail, event2);
377
+ }
378
+ #onSeeked(event2) {
379
+ this.#seekedTo = this.#media.currentTime;
380
+ this.#updateCurrentTime(this.#media.currentTime, event2);
381
+ this.#ctx.notify("seeked", this.#media.currentTime, event2);
382
+ if (Math.trunc(this.#media.currentTime) === Math.trunc(this.#media.duration) && getNumberOfDecimalPlaces(this.#media.duration) > getNumberOfDecimalPlaces(this.#media.currentTime)) {
383
+ this.#updateCurrentTime(this.#media.duration, event2);
384
+ if (!this.#media.ended) {
385
+ this.#ctx.player.dispatch(
386
+ new DOMEvent("media-play-request", {
387
+ trigger: event2
388
+ })
389
+ );
390
+ }
391
+ }
392
+ }
393
+ #onSeeking(event2) {
394
+ this.#ctx.notify("seeking", this.#media.currentTime, event2);
395
+ }
396
+ #onProgress(event2) {
397
+ const detail = {
398
+ buffered: this.#media.buffered,
399
+ seekable: this.#media.seekable
400
+ };
401
+ this.#ctx.notify("progress", detail, event2);
402
+ }
403
+ #onSuspend(event2) {
404
+ this.#ctx.notify("suspend", void 0, event2);
405
+ }
406
+ #onRateChange(event2) {
407
+ this.#ctx.notify("rate-change", this.#media.playbackRate, event2);
408
+ }
409
+ #onError(event2) {
410
+ const error = this.#media.error;
411
+ if (!error) return;
412
+ const detail = {
413
+ message: error.message,
414
+ code: error.code,
415
+ mediaError: error
416
+ };
417
+ this.#ctx.notify("error", detail, event2);
418
+ }
419
+ }
420
+
421
+ class NativeAudioTracks {
422
+ #provider;
423
+ #ctx;
424
+ get #nativeTracks() {
425
+ return this.#provider.media.audioTracks;
426
+ }
427
+ constructor(provider, ctx) {
428
+ this.#provider = provider;
429
+ this.#ctx = ctx;
430
+ this.#nativeTracks.onaddtrack = this.#onAddNativeTrack.bind(this);
431
+ this.#nativeTracks.onremovetrack = this.#onRemoveNativeTrack.bind(this);
432
+ this.#nativeTracks.onchange = this.#onChangeNativeTrack.bind(this);
433
+ listenEvent(this.#ctx.audioTracks, "change", this.#onChangeTrack.bind(this));
434
+ }
435
+ #onAddNativeTrack(event) {
436
+ const nativeTrack = event.track;
437
+ if (nativeTrack.label === "") return;
438
+ const id = nativeTrack.id.toString() || `native-audio-${this.#ctx.audioTracks.length}`, audioTrack = {
439
+ id,
440
+ label: nativeTrack.label,
441
+ language: nativeTrack.language,
442
+ kind: nativeTrack.kind,
443
+ selected: false
444
+ };
445
+ this.#ctx.audioTracks[ListSymbol.add](audioTrack, event);
446
+ if (nativeTrack.enabled) audioTrack.selected = true;
447
+ }
448
+ #onRemoveNativeTrack(event) {
449
+ const track = this.#ctx.audioTracks.getById(event.track.id);
450
+ if (track) this.#ctx.audioTracks[ListSymbol.remove](track, event);
451
+ }
452
+ #onChangeNativeTrack(event) {
453
+ let enabledTrack = this.#getEnabledNativeTrack();
454
+ if (!enabledTrack) return;
455
+ const track = this.#ctx.audioTracks.getById(enabledTrack.id);
456
+ if (track) this.#ctx.audioTracks[ListSymbol.select](track, true, event);
457
+ }
458
+ #getEnabledNativeTrack() {
459
+ return Array.from(this.#nativeTracks).find((track) => track.enabled);
460
+ }
461
+ #onChangeTrack(event) {
462
+ const { current } = event.detail;
463
+ if (!current) return;
464
+ const track = this.#nativeTracks.getTrackById(current.id);
465
+ if (track) {
466
+ const prev = this.#getEnabledNativeTrack();
467
+ if (prev) prev.enabled = false;
468
+ track.enabled = true;
469
+ }
470
+ }
471
+ }
472
+
473
+ class HTMLMediaProvider {
474
+ constructor(media, ctx) {
475
+ this.media = media;
476
+ this.ctx = ctx;
477
+ this.audioGain = new AudioGain(media, (gain) => {
478
+ this.ctx.notify("audio-gain-change", gain);
479
+ });
480
+ }
481
+ scope = createScope();
482
+ currentSrc = null;
483
+ audioGain;
484
+ setup() {
485
+ new HTMLMediaEvents(this, this.ctx);
486
+ if ("audioTracks" in this.media) new NativeAudioTracks(this, this.ctx);
487
+ onDispose(() => {
488
+ this.audioGain.destroy();
489
+ this.media.srcObject = null;
490
+ this.media.removeAttribute("src");
491
+ for (const source of this.media.querySelectorAll("source")) source.remove();
492
+ this.media.load();
493
+ });
494
+ }
495
+ get type() {
496
+ return "";
497
+ }
498
+ setPlaybackRate(rate) {
499
+ this.media.playbackRate = rate;
500
+ }
501
+ async play() {
502
+ return this.media.play();
503
+ }
504
+ async pause() {
505
+ return this.media.pause();
506
+ }
507
+ setMuted(muted) {
508
+ this.media.muted = muted;
509
+ }
510
+ setVolume(volume) {
511
+ this.media.volume = volume;
512
+ }
513
+ setCurrentTime(time) {
514
+ this.media.currentTime = time;
515
+ }
516
+ setPlaysInline(inline) {
517
+ setAttribute(this.media, "playsinline", inline);
518
+ }
519
+ async loadSource({ src, type }, preload) {
520
+ this.media.preload = preload || "";
521
+ if (isMediaStream(src)) {
522
+ this.removeSource();
523
+ this.media.srcObject = src;
524
+ } else {
525
+ this.media.srcObject = null;
526
+ if (isString(src)) {
527
+ if (type !== "?") {
528
+ this.appendSource({ src, type });
529
+ } else {
530
+ this.removeSource();
531
+ this.media.src = this.#appendMediaFragment(src);
532
+ }
533
+ } else {
534
+ this.removeSource();
535
+ this.media.src = window.URL.createObjectURL(src);
536
+ }
537
+ }
538
+ this.media.load();
539
+ this.currentSrc = { src, type };
540
+ }
541
+ /**
542
+ * Append source so it works when requesting AirPlay since hls.js will remove it.
543
+ */
544
+ appendSource(src, defaultType) {
545
+ const prevSource = this.media.querySelector("source[data-vds]"), source = prevSource ?? document.createElement("source");
546
+ setAttribute(source, "src", this.#appendMediaFragment(src.src));
547
+ setAttribute(source, "type", src.type !== "?" ? src.type : defaultType);
548
+ setAttribute(source, "data-vds", "");
549
+ if (!prevSource) this.media.append(source);
550
+ }
551
+ removeSource() {
552
+ this.media.querySelector("source[data-vds]")?.remove();
553
+ }
554
+ #appendMediaFragment(src) {
555
+ const { clipStartTime, clipEndTime } = this.ctx.$state, startTime = clipStartTime(), endTime = clipEndTime();
556
+ if (startTime > 0 && endTime > 0) {
557
+ return `${src}#t=${startTime},${endTime}`;
558
+ } else if (startTime > 0) {
559
+ return `${src}#t=${startTime}`;
560
+ } else if (endTime > 0) {
561
+ return `${src}#t=0,${endTime}`;
562
+ }
563
+ return src;
564
+ }
565
+ }
566
+
567
+ export { HTMLMediaProvider };