@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,468 @@
1
+ import { listenEvent, effect, untrack, createScope, keysOf, onDispose, DOMEvent, peek } from '../chunks/vidstack-BGSTndAW.js';
2
+ import { TimeRange } from '../chunks/vidstack-ChQTHmIQ.js';
3
+ import { RAFLoop } from '../chunks/vidstack-DqAw8m9J.js';
4
+ import { ListSymbol } from '../chunks/vidstack-D5EzK014.js';
5
+ import { getCastSessionMedia, getCastContext, getCastSession, hasActiveCastSession, listenCastContextEvent, getCastErrorMessage } from '../chunks/vidstack-BQlOPwOu.js';
6
+
7
+ class GoogleCastMediaInfoBuilder {
8
+ #info;
9
+ constructor(src) {
10
+ this.#info = new chrome.cast.media.MediaInfo(src.src, src.type);
11
+ }
12
+ build() {
13
+ return this.#info;
14
+ }
15
+ setStreamType(streamType) {
16
+ if (streamType.includes("live")) {
17
+ this.#info.streamType = chrome.cast.media.StreamType.LIVE;
18
+ } else {
19
+ this.#info.streamType = chrome.cast.media.StreamType.BUFFERED;
20
+ }
21
+ return this;
22
+ }
23
+ setTracks(tracks) {
24
+ this.#info.tracks = tracks.map(this.#buildCastTrack);
25
+ return this;
26
+ }
27
+ setMetadata(title, poster) {
28
+ this.#info.metadata = new chrome.cast.media.GenericMediaMetadata();
29
+ this.#info.metadata.title = title;
30
+ this.#info.metadata.images = [{ url: poster }];
31
+ return this;
32
+ }
33
+ #buildCastTrack(track, trackId) {
34
+ const castTrack = new chrome.cast.media.Track(trackId, chrome.cast.media.TrackType.TEXT);
35
+ castTrack.name = track.label;
36
+ castTrack.trackContentId = track.src;
37
+ castTrack.trackContentType = "text/vtt";
38
+ castTrack.language = track.language;
39
+ castTrack.subtype = track.kind.toUpperCase();
40
+ return castTrack;
41
+ }
42
+ }
43
+
44
+ class GoogleCastTracksManager {
45
+ #cast;
46
+ #ctx;
47
+ #onNewLocalTracks;
48
+ constructor(cast, ctx, onNewLocalTracks) {
49
+ this.#cast = cast;
50
+ this.#ctx = ctx;
51
+ this.#onNewLocalTracks = onNewLocalTracks;
52
+ }
53
+ setup() {
54
+ const syncRemoteActiveIds = this.syncRemoteActiveIds.bind(this);
55
+ listenEvent(this.#ctx.audioTracks, "change", syncRemoteActiveIds);
56
+ listenEvent(this.#ctx.textTracks, "mode-change", syncRemoteActiveIds);
57
+ effect(this.#syncLocalTracks.bind(this));
58
+ }
59
+ getLocalTextTracks() {
60
+ return this.#ctx.$state.textTracks().filter((track) => track.src && track.type === "vtt");
61
+ }
62
+ #getLocalAudioTracks() {
63
+ return this.#ctx.$state.audioTracks();
64
+ }
65
+ #getRemoteTracks(type) {
66
+ const tracks = this.#cast.mediaInfo?.tracks ?? [];
67
+ return type ? tracks.filter((track) => track.type === type) : tracks;
68
+ }
69
+ #getRemoteActiveIds() {
70
+ const activeIds = [], activeLocalAudioTrack = this.#getLocalAudioTracks().find((track) => track.selected), activeLocalTextTracks = this.getLocalTextTracks().filter((track) => track.mode === "showing");
71
+ if (activeLocalAudioTrack) {
72
+ const remoteAudioTracks = this.#getRemoteTracks(chrome.cast.media.TrackType.AUDIO), remoteAudioTrack = this.#findRemoteTrack(remoteAudioTracks, activeLocalAudioTrack);
73
+ if (remoteAudioTrack) activeIds.push(remoteAudioTrack.trackId);
74
+ }
75
+ if (activeLocalTextTracks?.length) {
76
+ const remoteTextTracks = this.#getRemoteTracks(chrome.cast.media.TrackType.TEXT);
77
+ if (remoteTextTracks.length) {
78
+ for (const localTrack of activeLocalTextTracks) {
79
+ const remoteTextTrack = this.#findRemoteTrack(remoteTextTracks, localTrack);
80
+ if (remoteTextTrack) activeIds.push(remoteTextTrack.trackId);
81
+ }
82
+ }
83
+ }
84
+ return activeIds;
85
+ }
86
+ #syncLocalTracks() {
87
+ const localTextTracks = this.getLocalTextTracks();
88
+ if (!this.#cast.isMediaLoaded) return;
89
+ const remoteTextTracks = this.#getRemoteTracks(chrome.cast.media.TrackType.TEXT);
90
+ for (const localTrack of localTextTracks) {
91
+ const hasRemoteTrack = this.#findRemoteTrack(remoteTextTracks, localTrack);
92
+ if (!hasRemoteTrack) {
93
+ untrack(() => this.#onNewLocalTracks?.());
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ syncRemoteTracks(event) {
99
+ if (!this.#cast.isMediaLoaded) return;
100
+ const localAudioTracks = this.#getLocalAudioTracks(), localTextTracks = this.getLocalTextTracks(), remoteAudioTracks = this.#getRemoteTracks(chrome.cast.media.TrackType.AUDIO), remoteTextTracks = this.#getRemoteTracks(chrome.cast.media.TrackType.TEXT);
101
+ for (const remoteAudioTrack of remoteAudioTracks) {
102
+ const hasLocalTrack = this.#findLocalTrack(localAudioTracks, remoteAudioTrack);
103
+ if (hasLocalTrack) continue;
104
+ const localAudioTrack = {
105
+ id: remoteAudioTrack.trackId.toString(),
106
+ label: remoteAudioTrack.name,
107
+ language: remoteAudioTrack.language,
108
+ kind: remoteAudioTrack.subtype ?? "main",
109
+ selected: false
110
+ };
111
+ this.#ctx.audioTracks[ListSymbol.add](localAudioTrack, event);
112
+ }
113
+ for (const remoteTextTrack of remoteTextTracks) {
114
+ const hasLocalTrack = this.#findLocalTrack(localTextTracks, remoteTextTrack);
115
+ if (hasLocalTrack) continue;
116
+ const localTextTrack = {
117
+ id: remoteTextTrack.trackId.toString(),
118
+ src: remoteTextTrack.trackContentId,
119
+ label: remoteTextTrack.name,
120
+ language: remoteTextTrack.language,
121
+ kind: remoteTextTrack.subtype.toLowerCase()
122
+ };
123
+ this.#ctx.textTracks.add(localTextTrack, event);
124
+ }
125
+ }
126
+ syncRemoteActiveIds(event) {
127
+ if (!this.#cast.isMediaLoaded) return;
128
+ const activeIds = this.#getRemoteActiveIds(), editRequest = new chrome.cast.media.EditTracksInfoRequest(activeIds);
129
+ this.#editTracksInfo(editRequest).catch((error) => {
130
+ });
131
+ }
132
+ #editTracksInfo(request) {
133
+ const media = getCastSessionMedia();
134
+ return new Promise((resolve, reject) => media?.editTracksInfo(request, resolve, reject));
135
+ }
136
+ #findLocalTrack(localTracks, remoteTrack) {
137
+ return localTracks.find((localTrack) => this.#isMatch(localTrack, remoteTrack));
138
+ }
139
+ #findRemoteTrack(remoteTracks, localTrack) {
140
+ return remoteTracks.find((remoteTrack) => this.#isMatch(localTrack, remoteTrack));
141
+ }
142
+ // Note: we can't rely on id matching because they will differ between local/remote. A local
143
+ // track id might not even exist.
144
+ #isMatch(localTrack, remoteTrack) {
145
+ return remoteTrack.name === localTrack.label && remoteTrack.language === localTrack.language && remoteTrack.subtype.toLowerCase() === localTrack.kind.toLowerCase();
146
+ }
147
+ }
148
+
149
+ class GoogleCastProvider {
150
+ $$PROVIDER_TYPE = "GOOGLE_CAST";
151
+ scope = createScope();
152
+ #player;
153
+ #ctx;
154
+ #tracks;
155
+ #currentSrc = null;
156
+ #state = "disconnected";
157
+ #currentTime = 0;
158
+ #played = 0;
159
+ #seekableRange = new TimeRange(0, 0);
160
+ #timeRAF = new RAFLoop(this.#onAnimationFrame.bind(this));
161
+ #playerEventHandlers;
162
+ #reloadInfo = null;
163
+ #isIdle = false;
164
+ constructor(player, ctx) {
165
+ this.#player = player;
166
+ this.#ctx = ctx;
167
+ this.#tracks = new GoogleCastTracksManager(player, ctx, this.#onNewLocalTracks.bind(this));
168
+ }
169
+ get type() {
170
+ return "google-cast";
171
+ }
172
+ get currentSrc() {
173
+ return this.#currentSrc;
174
+ }
175
+ /**
176
+ * The Google Cast remote player.
177
+ *
178
+ * @see {@link https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayer}
179
+ */
180
+ get player() {
181
+ return this.#player;
182
+ }
183
+ /**
184
+ * @see {@link https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext}
185
+ */
186
+ get cast() {
187
+ return getCastContext();
188
+ }
189
+ /**
190
+ * @see {@link https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession}
191
+ */
192
+ get session() {
193
+ return getCastSession();
194
+ }
195
+ /**
196
+ * @see {@link https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.Media}
197
+ */
198
+ get media() {
199
+ return getCastSessionMedia();
200
+ }
201
+ /**
202
+ * Whether the current Google Cast session belongs to this provider.
203
+ */
204
+ get hasActiveSession() {
205
+ return hasActiveCastSession(this.#currentSrc);
206
+ }
207
+ setup() {
208
+ this.#attachCastContextEventListeners();
209
+ this.#attachCastPlayerEventListeners();
210
+ this.#tracks.setup();
211
+ this.#ctx.notify("provider-setup", this);
212
+ }
213
+ #attachCastContextEventListeners() {
214
+ listenCastContextEvent(
215
+ cast.framework.CastContextEventType.CAST_STATE_CHANGED,
216
+ this.#onCastStateChange.bind(this)
217
+ );
218
+ }
219
+ #attachCastPlayerEventListeners() {
220
+ const Event2 = cast.framework.RemotePlayerEventType, handlers = {
221
+ [Event2.IS_CONNECTED_CHANGED]: this.#onCastStateChange,
222
+ [Event2.IS_MEDIA_LOADED_CHANGED]: this.#onMediaLoadedChange,
223
+ [Event2.CAN_CONTROL_VOLUME_CHANGED]: this.#onCanControlVolumeChange,
224
+ [Event2.CAN_SEEK_CHANGED]: this.#onCanSeekChange,
225
+ [Event2.DURATION_CHANGED]: this.#onDurationChange,
226
+ [Event2.IS_MUTED_CHANGED]: this.#onVolumeChange,
227
+ [Event2.VOLUME_LEVEL_CHANGED]: this.#onVolumeChange,
228
+ [Event2.IS_PAUSED_CHANGED]: this.#onPausedChange,
229
+ [Event2.LIVE_SEEKABLE_RANGE_CHANGED]: this.#onProgress,
230
+ [Event2.PLAYER_STATE_CHANGED]: this.#onPlayerStateChange
231
+ };
232
+ this.#playerEventHandlers = handlers;
233
+ const handler = this.#onRemotePlayerEvent.bind(this);
234
+ for (const type of keysOf(handlers)) {
235
+ this.#player.controller.addEventListener(type, handler);
236
+ }
237
+ onDispose(() => {
238
+ for (const type of keysOf(handlers)) {
239
+ this.#player.controller.removeEventListener(type, handler);
240
+ }
241
+ });
242
+ }
243
+ async play() {
244
+ if (!this.#player.isPaused && !this.#isIdle) return;
245
+ if (this.#isIdle) {
246
+ await this.#reload(false, 0);
247
+ return;
248
+ }
249
+ this.#player.controller?.playOrPause();
250
+ }
251
+ async pause() {
252
+ if (this.#player.isPaused) return;
253
+ this.#player.controller?.playOrPause();
254
+ }
255
+ getMediaStatus(request) {
256
+ return new Promise((resolve, reject) => {
257
+ this.media?.getStatus(request, resolve, reject);
258
+ });
259
+ }
260
+ setMuted(muted) {
261
+ const hasChanged = muted && !this.#player.isMuted || !muted && this.#player.isMuted;
262
+ if (hasChanged) this.#player.controller?.muteOrUnmute();
263
+ }
264
+ setCurrentTime(time) {
265
+ this.#player.currentTime = time;
266
+ this.#ctx.notify("seeking", time);
267
+ this.#player.controller?.seek();
268
+ }
269
+ setVolume(volume) {
270
+ this.#player.volumeLevel = volume;
271
+ this.#player.controller?.setVolumeLevel();
272
+ }
273
+ async loadSource(src) {
274
+ if (this.#reloadInfo?.src !== src) this.#reloadInfo = null;
275
+ if (hasActiveCastSession(src)) {
276
+ this.#resumeSession();
277
+ this.#currentSrc = src;
278
+ return;
279
+ }
280
+ this.#ctx.notify("load-start");
281
+ const loadRequest = this.#buildLoadRequest(src), errorCode = await this.session.loadMedia(loadRequest);
282
+ if (errorCode) {
283
+ this.#currentSrc = null;
284
+ this.#ctx.notify("error", Error(getCastErrorMessage(errorCode)));
285
+ return;
286
+ }
287
+ this.#currentSrc = src;
288
+ }
289
+ destroy() {
290
+ this.#reset();
291
+ this.#endSession();
292
+ }
293
+ #reset() {
294
+ if (!this.#reloadInfo) {
295
+ this.#played = 0;
296
+ this.#seekableRange = new TimeRange(0, 0);
297
+ }
298
+ this.#timeRAF.stop();
299
+ this.#currentTime = 0;
300
+ this.#reloadInfo = null;
301
+ }
302
+ #resumeSession() {
303
+ const resumeSessionEvent = new DOMEvent("resume-session", { detail: this.session });
304
+ this.#onMediaLoadedChange(resumeSessionEvent);
305
+ const { muted, volume, savedState } = this.#ctx.$state, localState = savedState();
306
+ this.setCurrentTime(Math.max(this.#player.currentTime, localState?.currentTime ?? 0));
307
+ this.setMuted(muted());
308
+ this.setVolume(volume());
309
+ if (localState?.paused === false) this.play();
310
+ }
311
+ #endSession() {
312
+ this.cast.endCurrentSession(true);
313
+ const { remotePlaybackLoader } = this.#ctx.$state;
314
+ remotePlaybackLoader.set(null);
315
+ }
316
+ #disconnectFromReceiver() {
317
+ const { savedState } = this.#ctx.$state;
318
+ savedState.set({
319
+ paused: this.#player.isPaused,
320
+ currentTime: this.#player.currentTime
321
+ });
322
+ this.#endSession();
323
+ }
324
+ #onAnimationFrame() {
325
+ this.#onCurrentTimeChange();
326
+ }
327
+ #onRemotePlayerEvent(event) {
328
+ this.#playerEventHandlers[event.type].call(this, event);
329
+ }
330
+ #onCastStateChange(data) {
331
+ const castState = this.cast.getCastState(), state = castState === cast.framework.CastState.CONNECTED ? "connected" : castState === cast.framework.CastState.CONNECTING ? "connecting" : "disconnected";
332
+ if (this.#state === state) return;
333
+ const detail = { type: "google-cast", state }, trigger = this.#createEvent(data);
334
+ this.#state = state;
335
+ this.#ctx.notify("remote-playback-change", detail, trigger);
336
+ if (state === "disconnected") {
337
+ this.#disconnectFromReceiver();
338
+ }
339
+ }
340
+ #onMediaLoadedChange(event) {
341
+ const hasLoaded = !!this.#player.isMediaLoaded;
342
+ if (!hasLoaded) return;
343
+ const src = peek(this.#ctx.$state.source);
344
+ Promise.resolve().then(() => {
345
+ if (src !== peek(this.#ctx.$state.source) || !this.#player.isMediaLoaded) return;
346
+ this.#reset();
347
+ const duration = this.#player.duration;
348
+ this.#seekableRange = new TimeRange(0, duration);
349
+ const detail = {
350
+ provider: this,
351
+ duration,
352
+ buffered: new TimeRange(0, 0),
353
+ seekable: this.#getSeekableRange()
354
+ }, trigger = this.#createEvent(event);
355
+ this.#ctx.notify("loaded-metadata", void 0, trigger);
356
+ this.#ctx.notify("loaded-data", void 0, trigger);
357
+ this.#ctx.notify("can-play", detail, trigger);
358
+ this.#onCanControlVolumeChange();
359
+ this.#onCanSeekChange(event);
360
+ const { volume, muted } = this.#ctx.$state;
361
+ this.setVolume(volume());
362
+ this.setMuted(muted());
363
+ this.#timeRAF.start();
364
+ this.#tracks.syncRemoteTracks(trigger);
365
+ this.#tracks.syncRemoteActiveIds(trigger);
366
+ });
367
+ }
368
+ #onCanControlVolumeChange() {
369
+ this.#ctx.$state.canSetVolume.set(this.#player.canControlVolume);
370
+ }
371
+ #onCanSeekChange(event) {
372
+ const trigger = this.#createEvent(event);
373
+ this.#ctx.notify("stream-type-change", this.#getStreamType(), trigger);
374
+ }
375
+ #getStreamType() {
376
+ const streamType = this.#player.mediaInfo?.streamType;
377
+ return streamType === chrome.cast.media.StreamType.LIVE ? this.#player.canSeek ? "live:dvr" : "live" : "on-demand";
378
+ }
379
+ #onCurrentTimeChange() {
380
+ if (this.#reloadInfo) return;
381
+ const currentTime = this.#player.currentTime;
382
+ if (currentTime === this.#currentTime) return;
383
+ this.#ctx.notify("time-change", currentTime);
384
+ if (currentTime > this.#played) {
385
+ this.#played = currentTime;
386
+ this.#onProgress();
387
+ }
388
+ if (this.#ctx.$state.seeking()) {
389
+ this.#ctx.notify("seeked", currentTime);
390
+ }
391
+ this.#currentTime = currentTime;
392
+ }
393
+ #onDurationChange(event) {
394
+ if (!this.#player.isMediaLoaded || this.#reloadInfo) return;
395
+ const duration = this.#player.duration, trigger = this.#createEvent(event);
396
+ this.#seekableRange = new TimeRange(0, duration);
397
+ this.#ctx.notify("duration-change", duration, trigger);
398
+ }
399
+ #onVolumeChange(event) {
400
+ if (!this.#player.isMediaLoaded) return;
401
+ const detail = {
402
+ muted: this.#player.isMuted,
403
+ volume: this.#player.volumeLevel
404
+ }, trigger = this.#createEvent(event);
405
+ this.#ctx.notify("volume-change", detail, trigger);
406
+ }
407
+ #onPausedChange(event) {
408
+ const trigger = this.#createEvent(event);
409
+ if (this.#player.isPaused) {
410
+ this.#ctx.notify("pause", void 0, trigger);
411
+ } else {
412
+ this.#ctx.notify("play", void 0, trigger);
413
+ }
414
+ }
415
+ #onProgress(event) {
416
+ const detail = {
417
+ seekable: this.#getSeekableRange(),
418
+ buffered: new TimeRange(0, this.#played)
419
+ }, trigger = event ? this.#createEvent(event) : void 0;
420
+ this.#ctx.notify("progress", detail, trigger);
421
+ }
422
+ #onPlayerStateChange(event) {
423
+ const state = this.#player.playerState, PlayerState = chrome.cast.media.PlayerState;
424
+ this.#isIdle = state === PlayerState.IDLE;
425
+ if (state === PlayerState.PAUSED) return;
426
+ const trigger = this.#createEvent(event);
427
+ switch (state) {
428
+ case PlayerState.PLAYING:
429
+ this.#ctx.notify("playing", void 0, trigger);
430
+ break;
431
+ case PlayerState.BUFFERING:
432
+ this.#ctx.notify("waiting", void 0, trigger);
433
+ break;
434
+ case PlayerState.IDLE:
435
+ this.#timeRAF.stop();
436
+ this.#ctx.notify("pause");
437
+ this.#ctx.notify("end");
438
+ break;
439
+ }
440
+ }
441
+ #getSeekableRange() {
442
+ return this.#player.liveSeekableRange ? new TimeRange(this.#player.liveSeekableRange.start, this.#player.liveSeekableRange.end) : this.#seekableRange;
443
+ }
444
+ #createEvent(detail) {
445
+ return detail instanceof Event ? detail : new DOMEvent(detail.type, { detail });
446
+ }
447
+ #buildMediaInfo(src) {
448
+ const { streamType, title, poster } = this.#ctx.$state;
449
+ return new GoogleCastMediaInfoBuilder(src).setMetadata(title(), poster()).setStreamType(streamType()).setTracks(this.#tracks.getLocalTextTracks()).build();
450
+ }
451
+ #buildLoadRequest(src) {
452
+ const mediaInfo = this.#buildMediaInfo(src), request = new chrome.cast.media.LoadRequest(mediaInfo), savedState = this.#ctx.$state.savedState();
453
+ request.autoplay = (this.#reloadInfo?.paused ?? savedState?.paused) === false;
454
+ request.currentTime = this.#reloadInfo?.time ?? savedState?.currentTime ?? 0;
455
+ return request;
456
+ }
457
+ async #reload(paused, time) {
458
+ const src = peek(this.#ctx.$state.source);
459
+ this.#reloadInfo = { src, paused, time };
460
+ await this.loadSource(src);
461
+ }
462
+ #onNewLocalTracks() {
463
+ this.#reload(this.#player.isPaused, this.#player.currentTime).catch((error) => {
464
+ });
465
+ }
466
+ }
467
+
468
+ export { GoogleCastProvider };