@mattebox/player-cast 0.2.0 → 0.4.0

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.
package/README.md CHANGED
@@ -43,16 +43,35 @@ the session to the receiver, at the video's current time. When the session
43
43
  ends, the engine resumes and the video continues from the time where the
44
44
  receiver stopped.
45
45
 
46
- The receiver plays the URL by itself, so DRM and signed URLs are the page's
47
- to arrange, in the `castload` event. The event carries the load request
48
- before the button sends it:
46
+ The receiver plays the URL by itself. A signed URL goes as it is, since it
47
+ is the source's URL. The source's DRM servers go in `customData.mattebox`:
48
+ `licenseUrl`, `licenseUrls` and `certificateUrl`. `@mattebox/cast-receiver`
49
+ reads them.
50
+
51
+ The `castload` event carries the load request before the button sends it.
52
+ Add the license headers there:
49
53
 
50
54
  ```ts
51
- button.addEventListener('castload', (event) => {
52
- event.detail.customData = { licenseUrl: 'https://drm.example/widevine' };
55
+ player.addEventListener('castload', (event) => {
56
+ event.detail.customData.mattebox.licenseHeaders = { Authorization: `Bearer ${token}` };
53
57
  });
54
58
  ```
55
59
 
60
+ When the receiver's license server answers 401 or 403, the receiver asks
61
+ for a new token. The player dispatches `castunauthorized`. Reply with new
62
+ headers, or new servers:
63
+
64
+ ```ts
65
+ player.addEventListener('castunauthorized', (event) => {
66
+ event.detail.reply(fetchToken().then((token) => ({
67
+ licenseHeaders: { Authorization: `Bearer ${token}` },
68
+ })));
69
+ });
70
+ ```
71
+
72
+ The messages go on the `urn:x-cast:ch.mattebox.license` namespace
73
+ (`LICENSE_NAMESPACE`). The receiver waits 10 seconds for a reply.
74
+
56
75
  `receiver` on the button names the receiver application. Without it, the
57
76
  button uses the Default Media Receiver. With `sdk="none"`, the page loads
58
77
  the SDK instead of the button. The
@@ -4,7 +4,7 @@ import { icon } from "./icons.js";
4
4
  import { BUTTON_STYLE, SLIDER_STYLE, describe, el, fill, format, iconSlots, show, style } from "./shared.js";
5
5
  import { slider } from "./slider.js";
6
6
  //#region src/cast-screen.ts
7
- const STYLE_CSS = ":host{color:var(--mbx-text);font:400 15px / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:16px;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:420px;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:12px}[part~=title]{font-size:18px;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:12px}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:13px}[part~=stop]{height:36px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 16px;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}";
7
+ const STYLE_CSS = ":host{color:var(--mbx-text);font:400 .9375em / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:1.0667em;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:28em;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:.8em}[part~=title]{font-size:1.2em;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:.8em}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:.8667em}[part~=stop]{height:2.4em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 1.0667em;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}";
8
8
  const STATES = ["play", "pause"];
9
9
  const STEP = 5;
10
10
  const PAGE = 30;
package/dist/cast.d.ts CHANGED
@@ -1,23 +1,27 @@
1
- /**
2
- * Chromecast from the page, over Google's Cast sender framework. The SDK is
3
- * a script the page loads, never a dependency (rule 2): the helper puts it
4
- * on the page the first time a cast button connects, unless it is already
5
- * there or the button says `sdk="none"`. Its context is one per page by
6
- * Google's design, so the receiver id the first button gives is the one
7
- * the page keeps.
8
- *
9
- * One `Cast` per player. It owns the handoff and nothing on the video is
10
- * wrapped (rule 3): on start it pauses the video, freezes the engine, and
11
- * sends the session's source to the receiver at the video's time; on end
12
- * it thaws the engine, seeks the video to the receiver's last time, and
13
- * plays if the receiver was playing. The cast screen drives the receiver
14
- * through the SDK's remote player meanwhile.
15
- *
16
- * The receiver plays the URL by itself, so DRM and signed URLs are the
17
- * page's to arrange: the button dispatches `castload` with the request
18
- * before it goes out, and the page sets `customData` or cancels.
19
- */
20
1
  import type { PlayerHost } from './host.js';
2
+ /** The custom namespace a receiver asks the sender for a new license token on. */
3
+ export declare const LICENSE_NAMESPACE = "urn:x-cast:ch.mattebox.license";
4
+ /** What the page replies to `castunauthorized`: new license headers or servers for the receiver. */
5
+ export interface LicenseReply {
6
+ readonly licenseHeaders?: Readonly<Record<string, string>>;
7
+ readonly licenseUrl?: string;
8
+ readonly licenseUrls?: Readonly<Record<string, string>>;
9
+ }
10
+ /** `castunauthorized`'s `detail`: the receiver's license server answered 401 or 403. */
11
+ export interface UnauthorizedDetail {
12
+ readonly keySystem: string;
13
+ readonly status: number;
14
+ /** Sends the new token to the receiver. Call it once, with the reply or a promise of it. */
15
+ reply(reply: LicenseReply | Promise<LicenseReply>): void;
16
+ }
17
+ /** `customData.mattebox`: the source's DRM servers, as `@mattebox/cast-receiver` reads them. */
18
+ export interface MatteboxCustomData {
19
+ licenseUrl?: string;
20
+ licenseUrls?: Readonly<Record<string, string>>;
21
+ certificateUrl?: string;
22
+ /** Headers for the license requests. The player has none of its own; a `castload` listener adds them. */
23
+ licenseHeaders?: Record<string, string>;
24
+ }
21
25
  /** What the receiver plays. The page sees it as `castload`'s `detail`. */
22
26
  export interface MediaInfo {
23
27
  contentId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"cast.d.ts","sourceRoot":"","sources":["../src/cast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAwD5C,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,KAAK;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB;AAuCD,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;AAE1E,kDAAkD;AAClD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,IAAI;IACnB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3D,2EAA2E;IAC3E,UAAU,IAAI,IAAI,CAAC;IACnB,KAAK,IAAI,SAAS,CAAC;IACnB,kDAAkD;IAClD,MAAM,IAAI,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,IAAI,MAAM,CAAC;IACjB,sFAAsF;IACtF,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,+CAA+C;IAC/C,IAAI,IAAI,IAAI,CAAC;IACb,SAAS,IAAI,IAAI,CAAC;IAClB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yGAAyG;IACzG,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CACnC;AAuVD,oFAAoF;AACpF,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAO7C"}
1
+ {"version":3,"file":"cast.d.ts","sourceRoot":"","sources":["../src/cast.ts"],"names":[],"mappings":"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"}
package/dist/cast.js CHANGED
@@ -4,6 +4,8 @@ function live(engine) {
4
4
  const api = engine?.live;
5
5
  return api !== void 0 && api.edge !== null;
6
6
  }
7
+ /** The custom namespace a receiver asks the sender for a new license token on. */
8
+ const LICENSE_NAMESPACE = "urn:x-cast:ch.mattebox.license";
7
9
  /** The Default Media Receiver: Google's player, which plays HLS and DASH by itself. */
8
10
  const DEFAULT_RECEIVER = "CC1AD845";
9
11
  const SDK_URL = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
@@ -99,7 +101,7 @@ function onSession(fw, ctx, state) {
99
101
  const found = [...connected].find((cast) => cast.plays(playing));
100
102
  if (found !== void 0 && owner === null) {
101
103
  owner = found;
102
- found.adopt();
104
+ found.adopt(ctx);
103
105
  }
104
106
  } else if (state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {
105
107
  const ended = owner;
@@ -121,6 +123,7 @@ var CastOf = class {
121
123
  this.pending = false;
122
124
  this.casting = false;
123
125
  this.handoff = null;
126
+ this.listening = null;
124
127
  }
125
128
  connect(receiver, sdk) {
126
129
  connected.add(this);
@@ -200,6 +203,7 @@ var CastOf = class {
200
203
  if (session === null) return;
201
204
  const request = this.request(session.source, time, autoplay);
202
205
  if (request === null) return;
206
+ this.listen(ctx.getCurrentSession());
203
207
  const event = new CustomEvent("castload", {
204
208
  detail: request,
205
209
  bubbles: true,
@@ -210,8 +214,55 @@ var CastOf = class {
210
214
  ctx.getCurrentSession()?.loadMedia(request).catch(() => {});
211
215
  }
212
216
  /** A session Chrome rejoined, already playing this player's source. */
213
- adopt() {
217
+ adopt(ctx) {
214
218
  this.freeze();
219
+ this.listen(ctx.getCurrentSession());
220
+ }
221
+ /**
222
+ * Answers the receiver's token requests for this session: a
223
+ * `castunauthorized` event on the player, and the page's reply sent back.
224
+ */
225
+ listen(session) {
226
+ this.unlisten();
227
+ if (session === null) return;
228
+ const fn = (_namespace, message) => {
229
+ let data;
230
+ try {
231
+ data = JSON.parse(message);
232
+ } catch {
233
+ return;
234
+ }
235
+ if (data.type !== "unauthorized") return;
236
+ const id = data.id;
237
+ let replied = false;
238
+ const detail = {
239
+ keySystem: typeof data.keySystem === "string" ? data.keySystem : "",
240
+ status: typeof data.status === "number" ? data.status : 0,
241
+ reply(reply) {
242
+ if (replied) return;
243
+ replied = true;
244
+ Promise.resolve(reply).then((answer) => session.sendMessage(LICENSE_NAMESPACE, {
245
+ type: "license",
246
+ id,
247
+ ...answer
248
+ })).catch(() => {});
249
+ }
250
+ };
251
+ this.player.dispatchEvent(new CustomEvent("castunauthorized", {
252
+ detail,
253
+ bubbles: true
254
+ }));
255
+ };
256
+ session.addMessageListener(LICENSE_NAMESPACE, fn);
257
+ this.listening = {
258
+ session,
259
+ fn
260
+ };
261
+ }
262
+ unlisten() {
263
+ const held = this.listening;
264
+ this.listening = null;
265
+ held?.session.removeMessageListener(LICENSE_NAMESPACE, held.fn);
215
266
  }
216
267
  freeze() {
217
268
  const engine = this.player.engine;
@@ -225,6 +276,7 @@ var CastOf = class {
225
276
  /** The session ended: give the video back where the receiver left it. */
226
277
  end(cleanly) {
227
278
  this.pending = false;
279
+ this.unlisten();
228
280
  if (!this.casting) return;
229
281
  this.casting = false;
230
282
  const handoff = this.handoff;
@@ -265,6 +317,12 @@ var CastOf = class {
265
317
  const request = new media.LoadRequest(info);
266
318
  request.currentTime = time;
267
319
  request.autoplay = autoplay;
320
+ const drm = source.drm;
321
+ if (drm !== void 0) request.customData = { mattebox: {
322
+ ...drm.licenseUrl === void 0 ? {} : { licenseUrl: drm.licenseUrl },
323
+ ...drm.licenseUrls === void 0 ? {} : { licenseUrls: drm.licenseUrls },
324
+ ...drm.certificateUrl === void 0 ? {} : { certificateUrl: drm.certificateUrl }
325
+ } };
268
326
  return request;
269
327
  }
270
328
  };
@@ -285,6 +343,6 @@ function cast(player) {
285
343
  return held;
286
344
  }
287
345
  //#endregion
288
- export { cast };
346
+ export { LICENSE_NAMESPACE, cast };
289
347
 
290
348
  //# sourceMappingURL=cast.js.map
package/dist/cast.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cast.js","names":[],"sources":["../src/cast.ts"],"sourcesContent":["/**\n * Chromecast from the page, over Google's Cast sender framework. The SDK is\n * a script the page loads, never a dependency (rule 2): the helper puts it\n * on the page the first time a cast button connects, unless it is already\n * there or the button says `sdk=\"none\"`. Its context is one per page by\n * Google's design, so the receiver id the first button gives is the one\n * the page keeps.\n *\n * One `Cast` per player. It owns the handoff and nothing on the video is\n * wrapped (rule 3): on start it pauses the video, freezes the engine, and\n * sends the session's source to the receiver at the video's time; on end\n * it thaws the engine, seeks the video to the receiver's last time, and\n * plays if the receiver was playing. The cast screen drives the receiver\n * through the SDK's remote player meanwhile.\n *\n * The receiver plays the URL by itself, so DRM and signed URLs are the\n * page's to arrange: the button dispatches `castload` with the request\n * before it goes out, and the page sets `customData` or cancels.\n */\nimport type { PlayerHost } from './host.js';\n\n/** Whether the session is live: the engine's `live` namespace, once it has an edge. */\nfunction live(engine: PlayerHost['engine']): boolean {\n const api = (engine as { live?: { edge: number | null } } | null)?.live;\n return api !== undefined && api.edge !== null;\n}\n\n// The slice of the sender SDK the helper reads. No `@types/chromecast`:\n// the SDK is not a dependency, and these names are what the page's script\n// puts on `window.cast.framework` and `window.chrome.cast`.\n\ninterface SdkEvent {\n readonly castState?: string;\n readonly sessionState?: string;\n}\n\ninterface SdkDevice {\n readonly friendlyName: string;\n}\n\ninterface SdkMediaSession {\n readonly media?: { readonly contentId?: string } | null;\n}\n\ninterface SdkSession {\n getCastDevice(): SdkDevice;\n getMediaSession(): SdkMediaSession | null;\n loadMedia(request: LoadRequest): Promise<unknown>;\n}\n\ninterface SdkContext {\n setOptions(options: { receiverApplicationId: string; autoJoinPolicy: string }): void;\n addEventListener(type: string, fn: (event: SdkEvent) => void): void;\n getCastState(): string;\n getCurrentSession(): SdkSession | null;\n requestSession(): Promise<unknown>;\n endCurrentSession(stopCasting: boolean): void;\n}\n\ninterface SdkRemotePlayer {\n isConnected: boolean;\n isMediaLoaded: boolean;\n isPaused: boolean;\n currentTime: number;\n duration: number;\n playerState: string | null;\n}\n\ninterface SdkRemoteController {\n addEventListener(type: string, fn: () => void): void;\n playOrPause(): void;\n seek(): void;\n stop(): void;\n}\n\n/** What the receiver plays. The page sees it as `castload`'s `detail`. */\nexport interface MediaInfo {\n contentId: string;\n contentType: string;\n streamType: string;\n tracks: Track[] | null;\n hlsSegmentFormat?: string;\n hlsVideoSegmentFormat?: string;\n}\n\nexport interface Track {\n trackContentId: string;\n trackContentType: string;\n subtype: string;\n name: string;\n language: string;\n}\n\nexport interface LoadRequest {\n media: MediaInfo;\n currentTime: number;\n autoplay: boolean;\n customData: unknown;\n}\n\ninterface Framework {\n CastContext: { getInstance(): SdkContext };\n RemotePlayer: new () => SdkRemotePlayer;\n RemotePlayerController: new (player: SdkRemotePlayer) => SdkRemoteController;\n CastContextEventType: { CAST_STATE_CHANGED: string; SESSION_STATE_CHANGED: string };\n CastState: { NO_DEVICES_AVAILABLE: string; CONNECTING: string; CONNECTED: string };\n SessionState: {\n SESSION_STARTED: string;\n SESSION_RESUMED: string;\n SESSION_ENDED: string;\n SESSION_START_FAILED: string;\n };\n RemotePlayerEventType: { ANY_CHANGE: string };\n}\n\ninterface ChromeCast {\n AutoJoinPolicy: { ORIGIN_SCOPED: string };\n media: {\n MediaInfo: new (contentId: string, contentType: string) => MediaInfo;\n LoadRequest: new (media: MediaInfo) => LoadRequest;\n Track: new (trackId: number, type: string) => Track;\n TrackType: { TEXT: string };\n TextTrackType: { SUBTITLES: string; CAPTIONS: string };\n StreamType: { BUFFERED: string; LIVE: string };\n };\n}\n\ninterface Globals {\n cast?: { framework?: Framework };\n chrome?: { cast?: ChromeCast };\n __onGCastApiAvailable?: (available: boolean) => void;\n}\n\n/** The Default Media Receiver: Google's player, which plays HLS and DASH by itself. */\nconst DEFAULT_RECEIVER = 'CC1AD845';\nconst SDK_URL = 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1';\n\nexport type CastState = 'unavailable' | 'idle' | 'connecting' | 'casting';\n\n/** What the cast screen shows of the receiver. */\nexport interface Remote {\n readonly loaded: boolean;\n readonly paused: boolean;\n readonly time: number;\n /** Infinity for a live stream, the way the video reports it. */\n readonly duration: number;\n}\n\nexport interface Cast {\n /**\n * Puts the SDK on the page unless `sdk` is `none` or it is already there,\n * and sets the context up with `receiver`, or the default receiver. The\n * first call on the page decides both; a later different receiver is an\n * error on the console, not a second context.\n */\n connect(receiver: string | null, sdk: string | null): void;\n /** The button left the player: a rejoined session no longer looks here. */\n disconnect(): void;\n state(): CastState;\n /** The receiver's name while casting, or null. */\n device(): string | null;\n remote(): Remote;\n /** Opens the device picker. `castload` goes out on `target` once a session starts. */\n start(target: HTMLElement): void;\n /** Ends the session and stops the receiver. */\n stop(): void;\n playPause(): void;\n seek(time: number): void;\n /** Runs `fn` on every change: devices, session, and the receiver's playback. Returns the unsubscribe. */\n watch(fn: () => void): () => void;\n}\n\n/** What the video is doing at the start of a cast, to give back at the end. */\ninterface Handoff {\n readonly live: boolean;\n}\n\n// The page-wide part: one SDK, one context, one remote player. Held in the\n// module because the SDK holds them in the window.\n\nlet framework: Promise<Framework | null> | null = null;\nlet configured: string | null = null;\nlet remotePlayer: SdkRemotePlayer | null = null;\nlet remoteController: SdkRemoteController | null = null;\nconst watchers = new Set<() => void>();\n/** The player whose session this is, so two players on a page do not both take a session. */\nlet owner: CastOf | null = null;\n/** The receiver's last known playback, read while it reports and kept once it stops. */\nconst NOTHING: Remote = { loaded: false, paused: true, time: 0, duration: Number.NaN };\nlet last: Remote = NOTHING;\n\nfunction globals(): Globals {\n return globalThis as Globals;\n}\n\nfunction notify(): void {\n for (const fn of [...watchers]) fn();\n}\n\n/**\n * The framework, once the page has it. Resolves null where the SDK never\n * arrives: a browser without Cast, a page whose CSP refused the script, or\n * `sdk=\"none\"` with no script of the page's own.\n */\nfunction load(sdk: string | null): Promise<Framework | null> {\n if (framework !== null) return framework;\n const held = globals();\n if (held.cast?.framework !== undefined) {\n framework = Promise.resolve(held.cast.framework);\n return framework;\n }\n // The SDK is Chromium's. Elsewhere the script only reports that it is\n // unavailable, so it is not fetched.\n if (!('chrome' in held)) {\n framework = Promise.resolve(null);\n return framework;\n }\n framework = new Promise((resolve) => {\n const previous = held.__onGCastApiAvailable;\n // The SDK calls this once it is in, on its own script or the page's.\n held.__onGCastApiAvailable = (available: boolean): void => {\n previous?.(available);\n resolve(available ? (globals().cast?.framework ?? null) : null);\n };\n if (sdk === 'none') return;\n const script = document.createElement('script');\n script.src = SDK_URL;\n script.async = true;\n script.addEventListener('error', () => resolve(null));\n document.head.append(script);\n });\n return framework;\n}\n\n/** The context, set up once per page. */\nfunction context(fw: Framework, receiver: string | null): SdkContext {\n const ctx = fw.CastContext.getInstance();\n const wanted = receiver ?? DEFAULT_RECEIVER;\n if (configured === null) {\n const policy = globals().chrome?.cast?.AutoJoinPolicy.ORIGIN_SCOPED ?? 'origin_scoped';\n ctx.setOptions({ receiverApplicationId: wanted, autoJoinPolicy: policy });\n configured = wanted;\n ctx.addEventListener(fw.CastContextEventType.CAST_STATE_CHANGED, notify);\n ctx.addEventListener(fw.CastContextEventType.SESSION_STATE_CHANGED, (event) => {\n onSession(fw, ctx, event.sessionState ?? '');\n });\n remotePlayer = new fw.RemotePlayer();\n remoteController = new fw.RemotePlayerController(remotePlayer);\n remoteController.addEventListener(fw.RemotePlayerEventType.ANY_CHANGE, () => {\n const remote = remotePlayer;\n if (remote?.isConnected === true && remote.isMediaLoaded) {\n last = {\n loaded: true,\n paused: remote.isPaused,\n time: remote.currentTime,\n duration: remote.duration > 0 ? remote.duration : Number.POSITIVE_INFINITY,\n };\n }\n notify();\n });\n } else if (receiver !== null && receiver !== configured) {\n console.error(`mattebox-player: the Cast context already uses receiver ${configured}`);\n }\n return ctx;\n}\n\nfunction onSession(fw: Framework, ctx: SdkContext, state: string): void {\n const states = fw.SessionState;\n if (state === states.SESSION_STARTED && owner !== null && owner.pending) {\n // A new session has loaded nothing yet, whatever the last one played.\n last = NOTHING;\n owner.begin(ctx);\n } else if (state === states.SESSION_RESUMED) {\n // Chrome rejoins a session of this origin on load. It is this player's\n // when the receiver plays what the player has.\n const playing = ctx.getCurrentSession()?.getMediaSession()?.media?.contentId;\n const found = [...connected].find((cast) => cast.plays(playing));\n if (found !== undefined && owner === null) {\n owner = found;\n found.adopt();\n }\n } else if (state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {\n const ended = owner;\n owner = null;\n ended?.end(state === states.SESSION_ENDED);\n }\n notify();\n}\n\n/** One per player, found again by its button and its screen. Weak, so a player that leaves is not held. */\nconst players = new WeakMap<PlayerHost, CastOf>();\n/** The players with a cast button attached, for a session Chrome rejoins on load. */\nconst connected = new Set<CastOf>();\n\nclass CastOf implements Cast {\n declare private readonly player: PlayerHost;\n declare private target: HTMLElement | null;\n declare private ctx: SdkContext | null;\n declare private fw: Framework | null;\n /** This player asked for a session and waits for it to start. */\n declare pending: boolean;\n declare private casting: boolean;\n declare private handoff: Handoff | null;\n\n constructor(player: PlayerHost) {\n this.player = player;\n this.target = null;\n this.ctx = null;\n this.fw = null;\n this.pending = false;\n this.casting = false;\n this.handoff = null;\n }\n\n connect(receiver: string | null, sdk: string | null): void {\n connected.add(this);\n void load(sdk).then((fw) => {\n if (fw === null) return;\n this.fw = fw;\n this.ctx = context(fw, receiver);\n notify();\n });\n }\n\n disconnect(): void {\n connected.delete(this);\n }\n\n state(): CastState {\n const ctx = this.ctx;\n const fw = this.fw;\n if (ctx === null || fw === null) return 'unavailable';\n if (this.casting) return 'casting';\n const cast = ctx.getCastState();\n if (cast === fw.CastState.NO_DEVICES_AVAILABLE) return 'unavailable';\n if (cast === fw.CastState.CONNECTING || this.pending) return 'connecting';\n return 'idle';\n }\n\n device(): string | null {\n if (!this.casting) return null;\n return this.ctx?.getCurrentSession()?.getCastDevice().friendlyName ?? null;\n }\n\n remote(): Remote {\n return last;\n }\n\n start(target: HTMLElement): void {\n const ctx = this.ctx;\n if (ctx === null || this.casting) return;\n // Another player on the page holds the session. The SDK has one, so\n // this click ends it, the way Chrome's own dialog offers to.\n if (owner !== null && owner !== this) {\n ctx.endCurrentSession(true);\n return;\n }\n this.target = target;\n this.pending = true;\n owner = this;\n notify();\n // Rejected when the viewer closes the picker; SESSION_START_FAILED\n // does not fire for that, so the wait ends here.\n ctx.requestSession().catch(() => {\n if (owner === this) owner = null;\n this.pending = false;\n notify();\n });\n }\n\n stop(): void {\n if (this.casting) this.ctx?.endCurrentSession(true);\n }\n\n playPause(): void {\n if (this.casting) remoteController?.playOrPause();\n }\n\n seek(time: number): void {\n if (!this.casting || remotePlayer === null) return;\n remotePlayer.currentTime = time;\n remoteController?.seek();\n }\n\n watch(fn: () => void): () => void {\n watchers.add(fn);\n return () => {\n watchers.delete(fn);\n };\n }\n\n /** Whether this player's session plays `url`. */\n plays(url: string | undefined): boolean {\n return url !== undefined && this.player.player?.session?.source.url === url;\n }\n\n /** A session started for this player: freeze the picture and send the source. */\n begin(ctx: SdkContext): void {\n this.pending = false;\n const session = this.player.player?.session ?? null;\n const video = this.player.video;\n const time = video.currentTime;\n const autoplay = !video.paused;\n this.freeze();\n if (session === null) return;\n const request = this.request(session.source, time, autoplay);\n if (request === null) return;\n const event = new CustomEvent<LoadRequest>('castload', {\n detail: request,\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n if (this.target?.dispatchEvent(event) === false) return;\n void ctx\n .getCurrentSession()\n ?.loadMedia(request)\n .catch(() => {\n // The receiver refused the media. The session stays, so the viewer\n // can stop it; the screen shows no time.\n });\n }\n\n /** A session Chrome rejoined, already playing this player's source. */\n adopt(): void {\n this.freeze();\n }\n\n private freeze(): void {\n const engine = this.player.engine;\n this.handoff = { live: live(engine) };\n this.player.video.pause();\n // The engine keeps its buffers and makes no request while the receiver\n // plays (engine guide 01, suspend and resume).\n engine?.suspend();\n this.casting = true;\n this.player.toggleAttribute('casting', true);\n notify();\n }\n\n /** The session ended: give the video back where the receiver left it. */\n end(cleanly: boolean): void {\n this.pending = false;\n if (!this.casting) return;\n this.casting = false;\n const handoff = this.handoff;\n this.handoff = null;\n const video = this.player.video;\n const engine = this.player.engine;\n engine?.resume();\n this.player.removeAttribute('casting');\n if (!cleanly || !last.loaded) return;\n // Live rejoins at the edge on its own; the receiver's time is on the\n // receiver's own timeline and means nothing here.\n if (handoff?.live !== true && Number.isFinite(last.time)) video.currentTime = last.time;\n if (!last.paused) video.play().catch(() => undefined);\n }\n\n /** The load request: the source, the time, the stream type, and the video's own text tracks. */\n private request(\n source: { readonly url: string; readonly type?: string },\n time: number,\n autoplay: boolean,\n ): LoadRequest | null {\n const media = globals().chrome?.cast?.media;\n if (media === undefined) return null;\n const engine = this.player.engine;\n const type = source.type ?? '';\n const info = new media.MediaInfo(source.url, type);\n info.streamType = live(engine) ? media.StreamType.LIVE : media.StreamType.BUFFERED;\n if (/mpegurl/i.test(type)) {\n // The receiver assumes MPEG-TS segments for HLS unless told. The\n // engine's presentation says which the stream has; a native session\n // has none, and CMAF is the assumption there.\n const ts = tsSegments(engine);\n info.hlsSegmentFormat = ts ? 'ts' : 'fmp4';\n info.hlsVideoSegmentFormat = ts ? 'mpeg2_ts' : 'fmp4';\n }\n const tracks: Track[] = [];\n for (const node of this.player.video.querySelectorAll('track[src]')) {\n const track = node as HTMLTrackElement;\n if (track.kind !== 'subtitles' && track.kind !== 'captions') continue;\n const out = new media.Track(tracks.length + 1, media.TrackType.TEXT);\n out.trackContentId = track.src;\n out.trackContentType = 'text/vtt';\n out.subtype =\n track.kind === 'captions' ? media.TextTrackType.CAPTIONS : media.TextTrackType.SUBTITLES;\n out.name = track.label;\n out.language = track.srclang;\n tracks.push(out);\n }\n info.tracks = tracks.length > 0 ? tracks : null;\n const request = new media.LoadRequest(info);\n request.currentTime = time;\n request.autoplay = autoplay;\n return request;\n }\n}\n\n/** Whether the engine's presentation carries MPEG-TS renditions. */\nfunction tsSegments(engine: PlayerHost['engine']): boolean {\n const presentation = engine?.stats.snapshot().presentation;\n if (presentation === null || presentation === undefined) return false;\n for (const period of presentation.periods) {\n for (const track of period.tracks) {\n for (const rendition of track.renditions) {\n if (/mp2t/i.test(rendition.mimeType)) return true;\n }\n }\n }\n return false;\n}\n\n/** The player's Cast, one per player, shared by its cast button and cast screen. */\nexport function cast(player: PlayerHost): Cast {\n let held = players.get(player);\n if (held === undefined) {\n held = new CastOf(player);\n players.set(player, held);\n }\n return held;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cast.js","names":[],"sources":["../src/cast.ts"],"sourcesContent":["/**\n * Chromecast from the page, over Google's Cast sender framework. The SDK is\n * a script the page loads, never a dependency (rule 2): the helper puts it\n * on the page the first time a cast button connects, unless it is already\n * there or the button says `sdk=\"none\"`. Its context is one per page by\n * Google's design, so the receiver id the first button gives is the one\n * the page keeps.\n *\n * One `Cast` per player. It owns the handoff and nothing on the video is\n * wrapped (rule 3): on start it pauses the video, freezes the engine, and\n * sends the session's source to the receiver at the video's time; on end\n * it thaws the engine, seeks the video to the receiver's last time, and\n * plays if the receiver was playing. The cast screen drives the receiver\n * through the SDK's remote player meanwhile.\n *\n * The receiver plays the URL by itself. The request's\n * `customData.mattebox` carries the source's DRM servers, the convention\n * `@mattebox/cast-receiver` reads. The button dispatches `castload` with the\n * request before it goes out, so the page adds license headers there, or\n * cancels. A receiver that gets a 401 or 403 from the license server asks\n * the sender for a new token on the `urn:x-cast:ch.mattebox.license`\n * namespace; the player dispatches `castunauthorized`, and the page replies.\n */\nimport type { Source } from '@mattebox/player-core';\nimport type { PlayerHost } from './host.js';\n\n/** Whether the session is live: the engine's `live` namespace, once it has an edge. */\nfunction live(engine: PlayerHost['engine']): boolean {\n const api = (engine as { live?: { edge: number | null } } | null)?.live;\n return api !== undefined && api.edge !== null;\n}\n\n// The slice of the sender SDK the helper reads. No `@types/chromecast`:\n// the SDK is not a dependency, and these names are what the page's script\n// puts on `window.cast.framework` and `window.chrome.cast`.\n\ninterface SdkEvent {\n readonly castState?: string;\n readonly sessionState?: string;\n}\n\ninterface SdkDevice {\n readonly friendlyName: string;\n}\n\ninterface SdkMediaSession {\n readonly media?: { readonly contentId?: string } | null;\n}\n\ninterface SdkSession {\n getCastDevice(): SdkDevice;\n getMediaSession(): SdkMediaSession | null;\n loadMedia(request: LoadRequest): Promise<unknown>;\n addMessageListener(namespace: string, fn: (namespace: string, message: string) => void): void;\n removeMessageListener(namespace: string, fn: (namespace: string, message: string) => void): void;\n sendMessage(namespace: string, message: unknown): Promise<unknown>;\n}\n\n/** The custom namespace a receiver asks the sender for a new license token on. */\nexport const LICENSE_NAMESPACE = 'urn:x-cast:ch.mattebox.license';\n\n/** What the page replies to `castunauthorized`: new license headers or servers for the receiver. */\nexport interface LicenseReply {\n readonly licenseHeaders?: Readonly<Record<string, string>>;\n readonly licenseUrl?: string;\n readonly licenseUrls?: Readonly<Record<string, string>>;\n}\n\n/** `castunauthorized`'s `detail`: the receiver's license server answered 401 or 403. */\nexport interface UnauthorizedDetail {\n readonly keySystem: string;\n readonly status: number;\n /** Sends the new token to the receiver. Call it once, with the reply or a promise of it. */\n reply(reply: LicenseReply | Promise<LicenseReply>): void;\n}\n\n/** `customData.mattebox`: the source's DRM servers, as `@mattebox/cast-receiver` reads them. */\nexport interface MatteboxCustomData {\n licenseUrl?: string;\n licenseUrls?: Readonly<Record<string, string>>;\n certificateUrl?: string;\n /** Headers for the license requests. The player has none of its own; a `castload` listener adds them. */\n licenseHeaders?: Record<string, string>;\n}\n\ninterface SdkContext {\n setOptions(options: { receiverApplicationId: string; autoJoinPolicy: string }): void;\n addEventListener(type: string, fn: (event: SdkEvent) => void): void;\n getCastState(): string;\n getCurrentSession(): SdkSession | null;\n requestSession(): Promise<unknown>;\n endCurrentSession(stopCasting: boolean): void;\n}\n\ninterface SdkRemotePlayer {\n isConnected: boolean;\n isMediaLoaded: boolean;\n isPaused: boolean;\n currentTime: number;\n duration: number;\n playerState: string | null;\n}\n\ninterface SdkRemoteController {\n addEventListener(type: string, fn: () => void): void;\n playOrPause(): void;\n seek(): void;\n stop(): void;\n}\n\n/** What the receiver plays. The page sees it as `castload`'s `detail`. */\nexport interface MediaInfo {\n contentId: string;\n contentType: string;\n streamType: string;\n tracks: Track[] | null;\n hlsSegmentFormat?: string;\n hlsVideoSegmentFormat?: string;\n}\n\nexport interface Track {\n trackContentId: string;\n trackContentType: string;\n subtype: string;\n name: string;\n language: string;\n}\n\nexport interface LoadRequest {\n media: MediaInfo;\n currentTime: number;\n autoplay: boolean;\n customData: unknown;\n}\n\ninterface Framework {\n CastContext: { getInstance(): SdkContext };\n RemotePlayer: new () => SdkRemotePlayer;\n RemotePlayerController: new (player: SdkRemotePlayer) => SdkRemoteController;\n CastContextEventType: { CAST_STATE_CHANGED: string; SESSION_STATE_CHANGED: string };\n CastState: { NO_DEVICES_AVAILABLE: string; CONNECTING: string; CONNECTED: string };\n SessionState: {\n SESSION_STARTED: string;\n SESSION_RESUMED: string;\n SESSION_ENDED: string;\n SESSION_START_FAILED: string;\n };\n RemotePlayerEventType: { ANY_CHANGE: string };\n}\n\ninterface ChromeCast {\n AutoJoinPolicy: { ORIGIN_SCOPED: string };\n media: {\n MediaInfo: new (contentId: string, contentType: string) => MediaInfo;\n LoadRequest: new (media: MediaInfo) => LoadRequest;\n Track: new (trackId: number, type: string) => Track;\n TrackType: { TEXT: string };\n TextTrackType: { SUBTITLES: string; CAPTIONS: string };\n StreamType: { BUFFERED: string; LIVE: string };\n };\n}\n\ninterface Globals {\n cast?: { framework?: Framework };\n chrome?: { cast?: ChromeCast };\n __onGCastApiAvailable?: (available: boolean) => void;\n}\n\n/** The Default Media Receiver: Google's player, which plays HLS and DASH by itself. */\nconst DEFAULT_RECEIVER = 'CC1AD845';\nconst SDK_URL = 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1';\n\nexport type CastState = 'unavailable' | 'idle' | 'connecting' | 'casting';\n\n/** What the cast screen shows of the receiver. */\nexport interface Remote {\n readonly loaded: boolean;\n readonly paused: boolean;\n readonly time: number;\n /** Infinity for a live stream, the way the video reports it. */\n readonly duration: number;\n}\n\nexport interface Cast {\n /**\n * Puts the SDK on the page unless `sdk` is `none` or it is already there,\n * and sets the context up with `receiver`, or the default receiver. The\n * first call on the page decides both; a later different receiver is an\n * error on the console, not a second context.\n */\n connect(receiver: string | null, sdk: string | null): void;\n /** The button left the player: a rejoined session no longer looks here. */\n disconnect(): void;\n state(): CastState;\n /** The receiver's name while casting, or null. */\n device(): string | null;\n remote(): Remote;\n /** Opens the device picker. `castload` goes out on `target` once a session starts. */\n start(target: HTMLElement): void;\n /** Ends the session and stops the receiver. */\n stop(): void;\n playPause(): void;\n seek(time: number): void;\n /** Runs `fn` on every change: devices, session, and the receiver's playback. Returns the unsubscribe. */\n watch(fn: () => void): () => void;\n}\n\n/** What the video is doing at the start of a cast, to give back at the end. */\ninterface Handoff {\n readonly live: boolean;\n}\n\n// The page-wide part: one SDK, one context, one remote player. Held in the\n// module because the SDK holds them in the window.\n\nlet framework: Promise<Framework | null> | null = null;\nlet configured: string | null = null;\nlet remotePlayer: SdkRemotePlayer | null = null;\nlet remoteController: SdkRemoteController | null = null;\nconst watchers = new Set<() => void>();\n/** The player whose session this is, so two players on a page do not both take a session. */\nlet owner: CastOf | null = null;\n/** The receiver's last known playback, read while it reports and kept once it stops. */\nconst NOTHING: Remote = { loaded: false, paused: true, time: 0, duration: Number.NaN };\nlet last: Remote = NOTHING;\n\nfunction globals(): Globals {\n return globalThis as Globals;\n}\n\nfunction notify(): void {\n for (const fn of [...watchers]) fn();\n}\n\n/**\n * The framework, once the page has it. Resolves null where the SDK never\n * arrives: a browser without Cast, a page whose CSP refused the script, or\n * `sdk=\"none\"` with no script of the page's own.\n */\nfunction load(sdk: string | null): Promise<Framework | null> {\n if (framework !== null) return framework;\n const held = globals();\n if (held.cast?.framework !== undefined) {\n framework = Promise.resolve(held.cast.framework);\n return framework;\n }\n // The SDK is Chromium's. Elsewhere the script only reports that it is\n // unavailable, so it is not fetched.\n if (!('chrome' in held)) {\n framework = Promise.resolve(null);\n return framework;\n }\n framework = new Promise((resolve) => {\n const previous = held.__onGCastApiAvailable;\n // The SDK calls this once it is in, on its own script or the page's.\n held.__onGCastApiAvailable = (available: boolean): void => {\n previous?.(available);\n resolve(available ? (globals().cast?.framework ?? null) : null);\n };\n if (sdk === 'none') return;\n const script = document.createElement('script');\n script.src = SDK_URL;\n script.async = true;\n script.addEventListener('error', () => resolve(null));\n document.head.append(script);\n });\n return framework;\n}\n\n/** The context, set up once per page. */\nfunction context(fw: Framework, receiver: string | null): SdkContext {\n const ctx = fw.CastContext.getInstance();\n const wanted = receiver ?? DEFAULT_RECEIVER;\n if (configured === null) {\n const policy = globals().chrome?.cast?.AutoJoinPolicy.ORIGIN_SCOPED ?? 'origin_scoped';\n ctx.setOptions({ receiverApplicationId: wanted, autoJoinPolicy: policy });\n configured = wanted;\n ctx.addEventListener(fw.CastContextEventType.CAST_STATE_CHANGED, notify);\n ctx.addEventListener(fw.CastContextEventType.SESSION_STATE_CHANGED, (event) => {\n onSession(fw, ctx, event.sessionState ?? '');\n });\n remotePlayer = new fw.RemotePlayer();\n remoteController = new fw.RemotePlayerController(remotePlayer);\n remoteController.addEventListener(fw.RemotePlayerEventType.ANY_CHANGE, () => {\n const remote = remotePlayer;\n if (remote?.isConnected === true && remote.isMediaLoaded) {\n last = {\n loaded: true,\n paused: remote.isPaused,\n time: remote.currentTime,\n duration: remote.duration > 0 ? remote.duration : Number.POSITIVE_INFINITY,\n };\n }\n notify();\n });\n } else if (receiver !== null && receiver !== configured) {\n console.error(`mattebox-player: the Cast context already uses receiver ${configured}`);\n }\n return ctx;\n}\n\nfunction onSession(fw: Framework, ctx: SdkContext, state: string): void {\n const states = fw.SessionState;\n if (state === states.SESSION_STARTED && owner !== null && owner.pending) {\n // A new session has loaded nothing yet, whatever the last one played.\n last = NOTHING;\n owner.begin(ctx);\n } else if (state === states.SESSION_RESUMED) {\n // Chrome rejoins a session of this origin on load. It is this player's\n // when the receiver plays what the player has.\n const playing = ctx.getCurrentSession()?.getMediaSession()?.media?.contentId;\n const found = [...connected].find((cast) => cast.plays(playing));\n if (found !== undefined && owner === null) {\n owner = found;\n found.adopt(ctx);\n }\n } else if (state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {\n const ended = owner;\n owner = null;\n ended?.end(state === states.SESSION_ENDED);\n }\n notify();\n}\n\n/** One per player, found again by its button and its screen. Weak, so a player that leaves is not held. */\nconst players = new WeakMap<PlayerHost, CastOf>();\n/** The players with a cast button attached, for a session Chrome rejoins on load. */\nconst connected = new Set<CastOf>();\n\nclass CastOf implements Cast {\n declare private readonly player: PlayerHost;\n declare private target: HTMLElement | null;\n declare private ctx: SdkContext | null;\n declare private fw: Framework | null;\n /** This player asked for a session and waits for it to start. */\n declare pending: boolean;\n declare private casting: boolean;\n declare private handoff: Handoff | null;\n /** The session this player listens on for license token requests, and its listener. */\n declare private listening: {\n readonly session: SdkSession;\n readonly fn: (namespace: string, message: string) => void;\n } | null;\n\n constructor(player: PlayerHost) {\n this.player = player;\n this.target = null;\n this.ctx = null;\n this.fw = null;\n this.pending = false;\n this.casting = false;\n this.handoff = null;\n this.listening = null;\n }\n\n connect(receiver: string | null, sdk: string | null): void {\n connected.add(this);\n void load(sdk).then((fw) => {\n if (fw === null) return;\n this.fw = fw;\n this.ctx = context(fw, receiver);\n notify();\n });\n }\n\n disconnect(): void {\n connected.delete(this);\n }\n\n state(): CastState {\n const ctx = this.ctx;\n const fw = this.fw;\n if (ctx === null || fw === null) return 'unavailable';\n if (this.casting) return 'casting';\n const cast = ctx.getCastState();\n if (cast === fw.CastState.NO_DEVICES_AVAILABLE) return 'unavailable';\n if (cast === fw.CastState.CONNECTING || this.pending) return 'connecting';\n return 'idle';\n }\n\n device(): string | null {\n if (!this.casting) return null;\n return this.ctx?.getCurrentSession()?.getCastDevice().friendlyName ?? null;\n }\n\n remote(): Remote {\n return last;\n }\n\n start(target: HTMLElement): void {\n const ctx = this.ctx;\n if (ctx === null || this.casting) return;\n // Another player on the page holds the session. The SDK has one, so\n // this click ends it, the way Chrome's own dialog offers to.\n if (owner !== null && owner !== this) {\n ctx.endCurrentSession(true);\n return;\n }\n this.target = target;\n this.pending = true;\n owner = this;\n notify();\n // Rejected when the viewer closes the picker; SESSION_START_FAILED\n // does not fire for that, so the wait ends here.\n ctx.requestSession().catch(() => {\n if (owner === this) owner = null;\n this.pending = false;\n notify();\n });\n }\n\n stop(): void {\n if (this.casting) this.ctx?.endCurrentSession(true);\n }\n\n playPause(): void {\n if (this.casting) remoteController?.playOrPause();\n }\n\n seek(time: number): void {\n if (!this.casting || remotePlayer === null) return;\n remotePlayer.currentTime = time;\n remoteController?.seek();\n }\n\n watch(fn: () => void): () => void {\n watchers.add(fn);\n return () => {\n watchers.delete(fn);\n };\n }\n\n /** Whether this player's session plays `url`. */\n plays(url: string | undefined): boolean {\n return url !== undefined && this.player.player?.session?.source.url === url;\n }\n\n /** A session started for this player: freeze the picture and send the source. */\n begin(ctx: SdkContext): void {\n this.pending = false;\n const session = this.player.player?.session ?? null;\n const video = this.player.video;\n const time = video.currentTime;\n const autoplay = !video.paused;\n this.freeze();\n if (session === null) return;\n const request = this.request(session.source, time, autoplay);\n if (request === null) return;\n this.listen(ctx.getCurrentSession());\n const event = new CustomEvent<LoadRequest>('castload', {\n detail: request,\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n if (this.target?.dispatchEvent(event) === false) return;\n void ctx\n .getCurrentSession()\n ?.loadMedia(request)\n .catch(() => {\n // The receiver refused the media. The session stays, so the viewer\n // can stop it; the screen shows no time.\n });\n }\n\n /** A session Chrome rejoined, already playing this player's source. */\n adopt(ctx: SdkContext): void {\n this.freeze();\n this.listen(ctx.getCurrentSession());\n }\n\n /**\n * Answers the receiver's token requests for this session: a\n * `castunauthorized` event on the player, and the page's reply sent back.\n */\n private listen(session: SdkSession | null): void {\n this.unlisten();\n if (session === null) return;\n const fn = (_namespace: string, message: string): void => {\n let data: { type?: unknown; id?: unknown; keySystem?: unknown; status?: unknown };\n try {\n data = JSON.parse(message) as typeof data;\n } catch {\n return;\n }\n if (data.type !== 'unauthorized') return;\n const id = data.id;\n let replied = false;\n const detail: UnauthorizedDetail = {\n keySystem: typeof data.keySystem === 'string' ? data.keySystem : '',\n status: typeof data.status === 'number' ? data.status : 0,\n reply(reply) {\n if (replied) return;\n replied = true;\n void Promise.resolve(reply)\n .then((answer) =>\n session.sendMessage(LICENSE_NAMESPACE, { type: 'license', id, ...answer }),\n )\n .catch(() => {\n // No reply reaches the receiver; it gives up after its own wait.\n });\n },\n };\n this.player.dispatchEvent(\n new CustomEvent<UnauthorizedDetail>('castunauthorized', { detail, bubbles: true }),\n );\n };\n session.addMessageListener(LICENSE_NAMESPACE, fn);\n this.listening = { session, fn };\n }\n\n private unlisten(): void {\n const held = this.listening;\n this.listening = null;\n held?.session.removeMessageListener(LICENSE_NAMESPACE, held.fn);\n }\n\n private freeze(): void {\n const engine = this.player.engine;\n this.handoff = { live: live(engine) };\n this.player.video.pause();\n // The engine keeps its buffers and makes no request while the receiver\n // plays (engine guide 01, suspend and resume).\n engine?.suspend();\n this.casting = true;\n this.player.toggleAttribute('casting', true);\n notify();\n }\n\n /** The session ended: give the video back where the receiver left it. */\n end(cleanly: boolean): void {\n this.pending = false;\n this.unlisten();\n if (!this.casting) return;\n this.casting = false;\n const handoff = this.handoff;\n this.handoff = null;\n const video = this.player.video;\n const engine = this.player.engine;\n engine?.resume();\n this.player.removeAttribute('casting');\n if (!cleanly || !last.loaded) return;\n // Live rejoins at the edge on its own; the receiver's time is on the\n // receiver's own timeline and means nothing here.\n if (handoff?.live !== true && Number.isFinite(last.time)) video.currentTime = last.time;\n if (!last.paused) video.play().catch(() => undefined);\n }\n\n /** The load request: the source, the time, the stream type, and the video's own text tracks. */\n private request(source: Source, time: number, autoplay: boolean): LoadRequest | null {\n const media = globals().chrome?.cast?.media;\n if (media === undefined) return null;\n const engine = this.player.engine;\n const type = source.type ?? '';\n const info = new media.MediaInfo(source.url, type);\n info.streamType = live(engine) ? media.StreamType.LIVE : media.StreamType.BUFFERED;\n if (/mpegurl/i.test(type)) {\n // The receiver assumes MPEG-TS segments for HLS unless told. The\n // engine's presentation says which the stream has; a native session\n // has none, and CMAF is the assumption there.\n const ts = tsSegments(engine);\n info.hlsSegmentFormat = ts ? 'ts' : 'fmp4';\n info.hlsVideoSegmentFormat = ts ? 'mpeg2_ts' : 'fmp4';\n }\n const tracks: Track[] = [];\n for (const node of this.player.video.querySelectorAll('track[src]')) {\n const track = node as HTMLTrackElement;\n if (track.kind !== 'subtitles' && track.kind !== 'captions') continue;\n const out = new media.Track(tracks.length + 1, media.TrackType.TEXT);\n out.trackContentId = track.src;\n out.trackContentType = 'text/vtt';\n out.subtype =\n track.kind === 'captions' ? media.TextTrackType.CAPTIONS : media.TextTrackType.SUBTITLES;\n out.name = track.label;\n out.language = track.srclang;\n tracks.push(out);\n }\n info.tracks = tracks.length > 0 ? tracks : null;\n const request = new media.LoadRequest(info);\n request.currentTime = time;\n request.autoplay = autoplay;\n const drm = source.drm;\n if (drm !== undefined) {\n const mattebox: MatteboxCustomData = {\n ...(drm.licenseUrl === undefined ? {} : { licenseUrl: drm.licenseUrl }),\n ...(drm.licenseUrls === undefined ? {} : { licenseUrls: drm.licenseUrls }),\n ...(drm.certificateUrl === undefined ? {} : { certificateUrl: drm.certificateUrl }),\n };\n request.customData = { mattebox };\n }\n return request;\n }\n}\n\n/** Whether the engine's presentation carries MPEG-TS renditions. */\nfunction tsSegments(engine: PlayerHost['engine']): boolean {\n const presentation = engine?.stats.snapshot().presentation;\n if (presentation === null || presentation === undefined) return false;\n for (const period of presentation.periods) {\n for (const track of period.tracks) {\n for (const rendition of track.renditions) {\n if (/mp2t/i.test(rendition.mimeType)) return true;\n }\n }\n }\n return false;\n}\n\n/** The player's Cast, one per player, shared by its cast button and cast screen. */\nexport function cast(player: PlayerHost): Cast {\n let held = players.get(player);\n if (held === undefined) {\n held = new CastOf(player);\n players.set(player, held);\n }\n return held;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- var matteboxPlayerCast=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){let t=e==null?void 0:e.live;return t!==void 0&&t.edge!==null}let n=null,r=null,i=null,a=null,o=/* @__PURE__ */ new Set,s=null,c={loaded:!1,paused:!0,time:0,duration:NaN},l=c;function u(){return globalThis}function d(){for(let e of[...o])e()}function f(e){var t;if(n!==null)return n;let r=u();return((t=r.cast)==null?void 0:t.framework)===void 0?`chrome`in r?(n=new Promise(t=>{let n=r.__onGCastApiAvailable;if(r.__onGCastApiAvailable=e=>{var r,i;n==null||n(e),t(e?(r=(i=u().cast)==null?void 0:i.framework)==null?null:r:null)},e===`none`)return;let i=document.createElement(`script`);i.src=`https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1`,i.async=!0,i.addEventListener(`error`,()=>t(null)),document.head.append(i)}),n):(n=Promise.resolve(null),n):(n=Promise.resolve(r.cast.framework),n)}function p(e,t){let n=e.CastContext.getInstance(),o=t==null?`CC1AD845`:t;if(r===null){var s,c;let t=(s=(c=u().chrome)==null||(c=c.cast)==null?void 0:c.AutoJoinPolicy.ORIGIN_SCOPED)==null?`origin_scoped`:s;n.setOptions({receiverApplicationId:o,autoJoinPolicy:t}),r=o,n.addEventListener(e.CastContextEventType.CAST_STATE_CHANGED,d),n.addEventListener(e.CastContextEventType.SESSION_STATE_CHANGED,t=>{var r;m(e,n,(r=t.sessionState)==null?``:r)}),i=new e.RemotePlayer,a=new e.RemotePlayerController(i),a.addEventListener(e.RemotePlayerEventType.ANY_CHANGE,()=>{let e=i;(e==null?void 0:e.isConnected)===!0&&e.isMediaLoaded&&(l={loaded:!0,paused:e.isPaused,time:e.currentTime,duration:e.duration>0?e.duration:1/0}),d()})}else t!==null&&t!==r&&console.error(`mattebox-player: the Cast context already uses receiver ${r}`);return n}function m(e,t,n){let r=e.SessionState;if(n===r.SESSION_STARTED&&s!==null&&s.pending)l=c,s.begin(t);else if(n===r.SESSION_RESUMED){var i;let e=(i=t.getCurrentSession())==null||(i=i.getMediaSession())==null||(i=i.media)==null?void 0:i.contentId,n=[...g].find(t=>t.plays(e));n!==void 0&&s===null&&(s=n,n.adopt())}else if(n===r.SESSION_ENDED||n===r.SESSION_START_FAILED){let e=s;s=null,e==null||e.end(n===r.SESSION_ENDED)}d()}let h=/* @__PURE__ */ new WeakMap,g=/* @__PURE__ */ new Set;var _=class{constructor(e){this.player=e,this.target=null,this.ctx=null,this.fw=null,this.pending=!1,this.casting=!1,this.handoff=null}connect(e,t){g.add(this),f(t).then(t=>{t!==null&&(this.fw=t,this.ctx=p(t,e),d())})}disconnect(){g.delete(this)}state(){let e=this.ctx,t=this.fw;if(e===null||t===null)return`unavailable`;if(this.casting)return`casting`;let n=e.getCastState();return n===t.CastState.NO_DEVICES_AVAILABLE?`unavailable`:n===t.CastState.CONNECTING||this.pending?`connecting`:`idle`}device(){var e,t;return this.casting?(e=(t=this.ctx)==null||(t=t.getCurrentSession())==null?void 0:t.getCastDevice().friendlyName)==null?null:e:null}remote(){return l}start(e){let t=this.ctx;if(!(t===null||this.casting)){if(s!==null&&s!==this){t.endCurrentSession(!0);return}this.target=e,this.pending=!0,s=this,d(),t.requestSession().catch(()=>{s===this&&(s=null),this.pending=!1,d()})}}stop(){var e;this.casting&&((e=this.ctx)==null||e.endCurrentSession(!0))}playPause(){this.casting&&(a==null||a.playOrPause())}seek(e){this.casting&&i!==null&&(i.currentTime=e,a==null||a.seek())}watch(e){return o.add(e),()=>{o.delete(e)}}plays(e){var t;return e!==void 0&&((t=this.player.player)==null||(t=t.session)==null?void 0:t.source.url)===e}begin(e){var t,n,r,i;this.pending=!1;let a=(t=(n=this.player.player)==null?void 0:n.session)==null?null:t,o=this.player.video,s=o.currentTime,c=!o.paused;if(this.freeze(),a===null)return;let l=this.request(a.source,s,c);if(l===null)return;let u=new CustomEvent(`castload`,{detail:l,bubbles:!0,composed:!0,cancelable:!0});((r=this.target)==null?void 0:r.dispatchEvent(u))!==!1&&((i=e.getCurrentSession())==null||i.loadMedia(l).catch(()=>{}))}adopt(){this.freeze()}freeze(){let e=this.player.engine;this.handoff={live:t(e)},this.player.video.pause(),e==null||e.suspend(),this.casting=!0,this.player.toggleAttribute(`casting`,!0),d()}end(e){if(this.pending=!1,!this.casting)return;this.casting=!1;let t=this.handoff;this.handoff=null;let n=this.player.video,r=this.player.engine;r==null||r.resume(),this.player.removeAttribute(`casting`),e&&l.loaded&&((t==null?void 0:t.live)!==!0&&Number.isFinite(l.time)&&(n.currentTime=l.time),l.paused||n.play().catch(()=>void 0))}request(e,n,r){var i,a;let o=(i=u().chrome)==null||(i=i.cast)==null?void 0:i.media;if(o===void 0)return null;let s=this.player.engine,c=(a=e.type)==null?``:a,l=new o.MediaInfo(e.url,c);if(l.streamType=t(s)?o.StreamType.LIVE:o.StreamType.BUFFERED,/mpegurl/i.test(c)){let e=v(s);l.hlsSegmentFormat=e?`ts`:`fmp4`,l.hlsVideoSegmentFormat=e?`mpeg2_ts`:`fmp4`}let d=[];for(let e of this.player.video.querySelectorAll(`track[src]`)){let t=e;if(t.kind!==`subtitles`&&t.kind!==`captions`)continue;let n=new o.Track(d.length+1,o.TrackType.TEXT);n.trackContentId=t.src,n.trackContentType=`text/vtt`,n.subtype=t.kind===`captions`?o.TextTrackType.CAPTIONS:o.TextTrackType.SUBTITLES,n.name=t.label,n.language=t.srclang,d.push(n)}l.tracks=d.length>0?d:null;let f=new o.LoadRequest(l);return f.currentTime=n,f.autoplay=r,f}};function v(e){let t=e==null?void 0:e.stats.snapshot().presentation;if(t==null)return!1;for(let e of t.periods)for(let t of e.tracks)for(let e of t.renditions)if(/mp2t/i.test(e.mimeType))return!0;return!1}function y(e){let t=h.get(e);return t===void 0&&(t=new _(e),h.set(e,t)),t}function b(e){let t=e.parentNode;return t===null?e instanceof ShadowRoot?e.host:null:t}function x(e){let t=e;for(;t!==null;){if(t instanceof HTMLElement&&t.localName===`mattebox-player`)return t;t=b(t)}return null}var S=class extends HTMLElement{constructor(){super(),this.player=null,this.offs=[],this.epoch=0}connectedCallback(){let e=x(this);if(e===null)return;this.epoch+=1;let t=this.epoch,n=()=>{t===this.epoch&&this.isConnected&&(customElements.upgrade(e),`video`in e&&(this.player=e,this.attach(this.player)))};`video`in e?n():customElements.whenDefined(`mattebox-player`).then(n)}disconnectedCallback(){this.epoch+=1;for(let e of this.offs)e();this.offs=[];let e=this.player;e!==null&&(this.player=null,this.detach(e))}attributeChangedCallback(){this.player!==null&&this.render()}listen(e,t,n){for(let r of t)e.addEventListener(r,n);this.offs.push(()=>{for(let r of t)e.removeEventListener(r,n)})}keep(e){this.offs.push(e)}follow(e,t){let n,r=()=>{n==null||n(),n=t(e.engine)};this.listen(e,[`sourcechange`],r),this.offs.push(()=>{n==null||n(),n=void 0}),r()}observe(e,t,n,r=!1){let i=new MutationObserver(n);i.observe(e,{attributes:!0,attributeFilter:[...t],subtree:r}),this.offs.push(()=>{i.disconnect()})}detach(e){}render(){}};let C={play:`M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z`,pause:`M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z`,cast:`M4 6h24v18H20v-2h6V8H6v1H4V6zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z`,"cast-active":`M4 6h24v18H20A16 16 0 0 0 4 8zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z`},w=`http://www.w3.org/2000/svg`;function T(e){let t=document.createElementNS(w,`svg`);t.setAttribute(`viewBox`,`0 0 32 32`),t.setAttribute(`aria-hidden`,`true`),t.setAttribute(`part`,`icon`);let n=document.createElementNS(w,`path`);return n.setAttribute(`fill-rule`,`evenodd`),n.setAttribute(`d`,C[e]),t.append(n),t}function E(e){let t=document.createElement(`style`);return t.textContent=e,t}function D(e,t){let n={};for(let r of e){let e=document.createElement(`slot`);e.name=`icon-${r}`,e.append(t(r)),e.hidden=!0,n[r]=e}return n}function O(e,t){for(let n of Object.keys(e))e[n].hidden=n!==t}function k(e,t,n){let r=document.createElement(e);return r.setAttribute(`part`,t),n!==void 0&&(r.textContent=n),r}function A(e,t){return e.replace(/\{(\w+)\}/g,(e,n)=>{let r=t[n];return r===void 0?e:String(r)})}function j(e){return e<10?`0${e}`:`${e}`}function M(e){let t=Number.isFinite(e)&&e>0?Math.floor(e):0,n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}:${j(r)}:${j(i)}`:`${r}:${j(i)}`}function N(e,t){return Number.isFinite(t)?`${M(e)} of ${M(t)}`:M(e)}let P=[`default`,`active`];var F=class extends S{static get observedAttributes(){return[`label-start`,`label-stop`]}constructor(){super(),this.api=null;let e=this.attachShadow({mode:`open`});this.button=document.createElement(`button`),this.button.type=`button`,this.button.setAttribute(`part`,`button`),this.slots=D(P,e=>T(e===`active`?`cast-active`:`cast`));for(let e of P)this.button.append(this.slots[e]);this.button.addEventListener(`click`,()=>{let e=this.api;e!==null&&(e.state()===`casting`?e.stop():e.start(this))}),e.append(E(`:host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:40px;height:40px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}`),this.button)}attach(e){let t=y(e);this.api=t,t.connect(this.getAttribute(`receiver`),this.getAttribute(`sdk`)),this.keep(t.watch(()=>{this.render()})),this.follow(e,()=>{this.render()})}detach(){var e;(e=this.api)==null||e.disconnect(),this.api=null}render(){var e,t,n;let r=this.player,i=this.api;if(r===null||i===null)return;let a=i.state(),o=a===`casting`;this.hidden=a===`unavailable`,this.button.disabled=!o&&((e=r.player)==null?void 0:e.session)==null,this.button.toggleAttribute(`aria-busy`,a===`connecting`),O(this.slots,o?`active`:`default`),this.button.setAttribute(`aria-label`,o?(t=this.getAttribute(`label-stop`))==null?`Stop casting`:t:(n=this.getAttribute(`label-start`))==null?`Cast`:n)}};function I(e,t,n){return Math.min(n,Math.max(t,e))}function L(e){let{onInput:t}=e,n=k(`div`,`slider`);n.setAttribute(`role`,`slider`),n.tabIndex=0;let r=k(`div`,`rail`),i=k(`div`,`track`),a=k(`div`,`fill`),o=k(`div`,`thumb`);i.append(a),r.append(i,o),n.append(r);let s=0,c=1,l=0,u=!1;function d(){let e=`${(c>s?(l-s)/(c-s):0)*100}%`;a.style.width=e,o.style.left=e}function f(e){let t=r.getBoundingClientRect();return t.width===0?s:s+I((e-t.left)/t.width,0,1)*(c-s)}function p(t){u=t,e.onDrag(t)}function m(e){if(e.button===0){e.preventDefault(),p(!0);try{n.setPointerCapture(e.pointerId)}catch(e){}t(f(e.clientX))}}function h(e){if(u){if(e.buttons===0){g(e);return}t(f(e.clientX))}}function g(e){u&&(p(!1),t(f(e.clientX)))}function _(){u&&p(!1)}function v(n){let r;switch(n.key){case`ArrowRight`:case`ArrowUp`:r=l+e.step();break;case`ArrowLeft`:case`ArrowDown`:r=l-e.step();break;case`PageUp`:r=l+e.page();break;case`PageDown`:r=l-e.page();break;case`Home`:r=s;break;case`End`:r=c;break;default:return}n.preventDefault(),t(I(r,s,c))}return n.addEventListener(`pointerdown`,m),n.addEventListener(`pointermove`,h),n.addEventListener(`pointerup`,g),n.addEventListener(`pointercancel`,_),n.addEventListener(`lostpointercapture`,_),n.addEventListener(`keydown`,v),{root:n,track:i,rail:r,label(e){n.setAttribute(`aria-label`,e)},dragging(){return u},range(e,t){s=e,c=t,n.setAttribute(`aria-valuemin`,String(e)),n.setAttribute(`aria-valuemax`,String(t)),d()},set(e,t){l=I(e,s,c),n.setAttribute(`aria-valuenow`,String(l)),n.setAttribute(`aria-valuetext`,t),d()},dispose(){n.removeEventListener(`pointerdown`,m),n.removeEventListener(`pointermove`,h),n.removeEventListener(`pointerup`,g),n.removeEventListener(`pointercancel`,_),n.removeEventListener(`lostpointercapture`,_),n.removeEventListener(`keydown`,v)}}}let R=[`play`,`pause`];var z=class extends S{static get observedAttributes(){return[`label`,`label-stop`,`label-play`,`label-pause`,`label-seek`]}constructor(){super(),this.api=null,this.held=null;let e=this.attachShadow({mode:`open`}),t=k(`div`,`box`);this.title_=k(`div`,`title`),this.play=document.createElement(`button`),this.play.type=`button`,this.play.setAttribute(`part`,`button play`),this.slots=D(R,T);for(let e of R)this.play.append(this.slots[e]);this.play.addEventListener(`click`,()=>{var e;(e=this.api)==null||e.playPause()}),this.seek=L({step:()=>5,page:()=>30,onInput:e=>{var t;if(this.seek.dragging()){this.held=e,this.paint();return}this.held=null,(t=this.api)==null||t.seek(e)},onDrag:e=>{this.toggleAttribute(`dragging`,e),e||(this.held=null)}}),this.time=k(`span`,`time`),this.row=k(`div`,`row`),this.row.append(this.play,this.seek.root,this.time),this.stop=k(`button`,`stop`),this.stop.type=`button`,this.stop.addEventListener(`click`,()=>{var e;(e=this.api)==null||e.stop()}),t.append(this.title_,this.row,this.stop),e.append(E(`:host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:40px;height:40px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}:host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:40px;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:8px;right:8px}[part~=track]{background:#ffffff59;border-radius:2px;height:4px;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:12px;height:12px;margin:-6px 0 0 -6px;position:absolute;top:50%}:host{color:var(--mbx-text);font:400 15px / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:16px;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:420px;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:12px}[part~=title]{font-size:18px;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:12px}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:13px}[part~=stop]{height:36px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 16px;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}`),t)}connectedCallback(){this.player===null&&(this.hidden=!0),super.connectedCallback()}attach(e){let t=y(e);this.api=t,this.keep(t.watch(()=>{this.render()})),this.render()}detach(){this.api=null,this.hidden=!0}paint(){var e;let t=this.api;if(t===null)return;let n=t.remote(),r=n.loaded&&Number.isFinite(n.duration);if(this.seek.root.hidden=!r,this.time.hidden=!r,!r)return;let i=(e=this.held)==null?n.time:e;this.seek.range(0,n.duration),this.seek.set(i,N(i,n.duration)),this.time.textContent=`${M(i)} / ${M(n.duration)}`}render(){var e,t,n,r,i;let a=this.api;if(a===null)return;let o=a.remote(),s=o.loaded&&!o.paused?`pause`:`play`;O(this.slots,s),this.play.setAttribute(`aria-label`,(e=this.getAttribute(`label-${s}`))==null?s===`play`?`Play`:`Pause`:e),this.seek.label((t=this.getAttribute(`label-seek`))==null?`Seek`:t),this.stop.textContent=(n=this.getAttribute(`label-stop`))==null?`Stop casting`:n;let c=a.state()===`casting`;this.hidden=!c,c&&(this.title_.textContent=A((r=this.getAttribute(`label`))==null?`Casting to {device}`:r,{device:(i=a.device())==null?``:i}),this.play.disabled=!o.loaded,this.paint())}};let B=`mbx-cast-button`,V=`mbx-cast-screen`;return customElements.get(`mbx-cast-button`)===void 0&&customElements.define(B,F),customElements.get(`mbx-cast-screen`)===void 0&&customElements.define(V,z),e.CAST_BUTTON=B,e.CAST_SCREEN=V,e.MbxCastButton=F,e.MbxCastScreen=z,e})({});
1
+ var matteboxPlayerCast=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){"@babel/helpers - typeof";return t=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},t(e)}function n(e,n){if(t(e)!=`object`||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var i=r.call(e,n||`default`);if(t(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(n===`string`?String:Number)(e)}function r(e){var r=n(e,`string`);return t(r)==`symbol`?r:r+``}function i(e,t,n){return(t=r(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?a(Object(n),!0).forEach(function(t){i(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function s(e){let t=e==null?void 0:e.live;return t!==void 0&&t.edge!==null}let c=`urn:x-cast:ch.mattebox.license`,l=null,u=null,d=null,f=null,p=/* @__PURE__ */ new Set,m=null,h={loaded:!1,paused:!0,time:0,duration:NaN},g=h;function _(){return globalThis}function v(){for(let e of[...p])e()}function y(e){var t;if(l!==null)return l;let n=_();return((t=n.cast)==null?void 0:t.framework)===void 0?`chrome`in n?(l=new Promise(t=>{let r=n.__onGCastApiAvailable;if(n.__onGCastApiAvailable=e=>{var n,i;r==null||r(e),t(e?(n=(i=_().cast)==null?void 0:i.framework)==null?null:n:null)},e===`none`)return;let i=document.createElement(`script`);i.src=`https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1`,i.async=!0,i.addEventListener(`error`,()=>t(null)),document.head.append(i)}),l):(l=Promise.resolve(null),l):(l=Promise.resolve(n.cast.framework),l)}function b(e,t){let n=e.CastContext.getInstance(),r=t==null?`CC1AD845`:t;if(u===null){var i,a;let t=(i=(a=_().chrome)==null||(a=a.cast)==null?void 0:a.AutoJoinPolicy.ORIGIN_SCOPED)==null?`origin_scoped`:i;n.setOptions({receiverApplicationId:r,autoJoinPolicy:t}),u=r,n.addEventListener(e.CastContextEventType.CAST_STATE_CHANGED,v),n.addEventListener(e.CastContextEventType.SESSION_STATE_CHANGED,t=>{var r;x(e,n,(r=t.sessionState)==null?``:r)}),d=new e.RemotePlayer,f=new e.RemotePlayerController(d),f.addEventListener(e.RemotePlayerEventType.ANY_CHANGE,()=>{let e=d;(e==null?void 0:e.isConnected)===!0&&e.isMediaLoaded&&(g={loaded:!0,paused:e.isPaused,time:e.currentTime,duration:e.duration>0?e.duration:1/0}),v()})}else t!==null&&t!==u&&console.error(`mattebox-player: the Cast context already uses receiver ${u}`);return n}function x(e,t,n){let r=e.SessionState;if(n===r.SESSION_STARTED&&m!==null&&m.pending)g=h,m.begin(t);else if(n===r.SESSION_RESUMED){var i;let e=(i=t.getCurrentSession())==null||(i=i.getMediaSession())==null||(i=i.media)==null?void 0:i.contentId,n=[...C].find(t=>t.plays(e));n!==void 0&&m===null&&(m=n,n.adopt(t))}else if(n===r.SESSION_ENDED||n===r.SESSION_START_FAILED){let e=m;m=null,e==null||e.end(n===r.SESSION_ENDED)}v()}let S=/* @__PURE__ */ new WeakMap,C=/* @__PURE__ */ new Set;var w=class{constructor(e){this.player=e,this.target=null,this.ctx=null,this.fw=null,this.pending=!1,this.casting=!1,this.handoff=null,this.listening=null}connect(e,t){C.add(this),y(t).then(t=>{t!==null&&(this.fw=t,this.ctx=b(t,e),v())})}disconnect(){C.delete(this)}state(){let e=this.ctx,t=this.fw;if(e===null||t===null)return`unavailable`;if(this.casting)return`casting`;let n=e.getCastState();return n===t.CastState.NO_DEVICES_AVAILABLE?`unavailable`:n===t.CastState.CONNECTING||this.pending?`connecting`:`idle`}device(){var e,t;return this.casting?(e=(t=this.ctx)==null||(t=t.getCurrentSession())==null?void 0:t.getCastDevice().friendlyName)==null?null:e:null}remote(){return g}start(e){let t=this.ctx;t===null||this.casting||(m!==null&&m!==this?t.endCurrentSession(!0):(this.target=e,this.pending=!0,m=this,v(),t.requestSession().catch(()=>{m===this&&(m=null),this.pending=!1,v()})))}stop(){var e;this.casting&&((e=this.ctx)==null||e.endCurrentSession(!0))}playPause(){this.casting&&(f==null||f.playOrPause())}seek(e){this.casting&&d!==null&&(d.currentTime=e,f==null||f.seek())}watch(e){return p.add(e),()=>{p.delete(e)}}plays(e){var t;return e!==void 0&&((t=this.player.player)==null||(t=t.session)==null?void 0:t.source.url)===e}begin(e){var t,n,r,i;this.pending=!1;let a=(t=(n=this.player.player)==null?void 0:n.session)==null?null:t,o=this.player.video,s=o.currentTime,c=!o.paused;if(this.freeze(),a===null)return;let l=this.request(a.source,s,c);if(l===null)return;this.listen(e.getCurrentSession());let u=new CustomEvent(`castload`,{detail:l,bubbles:!0,composed:!0,cancelable:!0});((r=this.target)==null?void 0:r.dispatchEvent(u))!==!1&&((i=e.getCurrentSession())==null||i.loadMedia(l).catch(()=>{}))}adopt(e){this.freeze(),this.listen(e.getCurrentSession())}listen(e){if(this.unlisten(),e===null)return;let t=(t,n)=>{let r;try{r=JSON.parse(n)}catch(e){return}if(r.type!==`unauthorized`)return;let i=r.id,a=!1,s={keySystem:typeof r.keySystem==`string`?r.keySystem:``,status:typeof r.status==`number`?r.status:0,reply(t){a||(a=!0,Promise.resolve(t).then(t=>e.sendMessage(c,o({type:`license`,id:i},t))).catch(()=>{}))}};this.player.dispatchEvent(new CustomEvent(`castunauthorized`,{detail:s,bubbles:!0}))};e.addMessageListener(c,t),this.listening={session:e,fn:t}}unlisten(){let e=this.listening;this.listening=null,e==null||e.session.removeMessageListener(`urn:x-cast:ch.mattebox.license`,e.fn)}freeze(){let e=this.player.engine;this.handoff={live:s(e)},this.player.video.pause(),e==null||e.suspend(),this.casting=!0,this.player.toggleAttribute(`casting`,!0),v()}end(e){if(this.pending=!1,this.unlisten(),!this.casting)return;this.casting=!1;let t=this.handoff;this.handoff=null;let n=this.player.video,r=this.player.engine;r==null||r.resume(),this.player.removeAttribute(`casting`),e&&g.loaded&&((t==null?void 0:t.live)!==!0&&Number.isFinite(g.time)&&(n.currentTime=g.time),g.paused||n.play().catch(()=>void 0))}request(e,t,n){var r,i;let a=(r=_().chrome)==null||(r=r.cast)==null?void 0:r.media;if(a===void 0)return null;let c=this.player.engine,l=(i=e.type)==null?``:i,u=new a.MediaInfo(e.url,l);if(u.streamType=s(c)?a.StreamType.LIVE:a.StreamType.BUFFERED,/mpegurl/i.test(l)){let e=T(c);u.hlsSegmentFormat=e?`ts`:`fmp4`,u.hlsVideoSegmentFormat=e?`mpeg2_ts`:`fmp4`}let d=[];for(let e of this.player.video.querySelectorAll(`track[src]`)){let t=e;if(t.kind!==`subtitles`&&t.kind!==`captions`)continue;let n=new a.Track(d.length+1,a.TrackType.TEXT);n.trackContentId=t.src,n.trackContentType=`text/vtt`,n.subtype=t.kind===`captions`?a.TextTrackType.CAPTIONS:a.TextTrackType.SUBTITLES,n.name=t.label,n.language=t.srclang,d.push(n)}u.tracks=d.length>0?d:null;let f=new a.LoadRequest(u);f.currentTime=t,f.autoplay=n;let p=e.drm;return p!==void 0&&(f.customData={mattebox:o(o(o({},p.licenseUrl===void 0?{}:{licenseUrl:p.licenseUrl}),p.licenseUrls===void 0?{}:{licenseUrls:p.licenseUrls}),p.certificateUrl===void 0?{}:{certificateUrl:p.certificateUrl})}),f}};function T(e){let t=e==null?void 0:e.stats.snapshot().presentation;if(t==null)return!1;for(let e of t.periods)for(let t of e.tracks)for(let e of t.renditions)if(/mp2t/i.test(e.mimeType))return!0;return!1}function E(e){let t=S.get(e);return t===void 0&&(t=new w(e),S.set(e,t)),t}function D(e){let t=e.parentNode;return t===null?e instanceof ShadowRoot?e.host:null:t}function O(e){let t=e;for(;t!==null;){if(t instanceof HTMLElement&&t.localName===`mattebox-player`)return t;t=D(t)}return null}var k=class extends HTMLElement{constructor(){super(),this.player=null,this.offs=[],this.epoch=0}connectedCallback(){let e=O(this);if(e===null)return;this.epoch+=1;let t=this.epoch,n=()=>{t===this.epoch&&this.isConnected&&(customElements.upgrade(e),`video`in e&&(this.player=e,this.attach(this.player)))};`video`in e?n():customElements.whenDefined(`mattebox-player`).then(n)}disconnectedCallback(){this.epoch+=1;for(let e of this.offs)e();this.offs=[];let e=this.player;e!==null&&(this.player=null,this.detach(e))}attributeChangedCallback(){this.player!==null&&this.render()}listen(e,t,n){for(let r of t)e.addEventListener(r,n);this.offs.push(()=>{for(let r of t)e.removeEventListener(r,n)})}keep(e){this.offs.push(e)}follow(e,t){let n,r=()=>{n==null||n(),n=t(e.engine)};this.listen(e,[`sourcechange`],r),this.offs.push(()=>{n==null||n(),n=void 0}),r()}observe(e,t,n,r=!1){let i=new MutationObserver(n);i.observe(e,{attributes:!0,attributeFilter:[...t],subtree:r}),this.offs.push(()=>{i.disconnect()})}detach(e){}render(){}};let A={play:`M9 5L26 16L9 27z`,pause:`M8 6h5.5v20h-5.5zM18.5 6h5.5v20h-5.5z`,cast:`M4 6H28V26H20V23.5H25.5V8.5H6.5V11H4zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z`,"cast-active":`M4 6H28V26H20A16 16 0 0 0 4 10zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z`},j=`http://www.w3.org/2000/svg`;function M(e){let t=document.createElementNS(j,`svg`);t.setAttribute(`viewBox`,`0 0 32 32`),t.setAttribute(`aria-hidden`,`true`),t.setAttribute(`part`,`icon`);let n=document.createElementNS(j,`path`);return n.setAttribute(`fill-rule`,`evenodd`),n.setAttribute(`d`,A[e]),t.append(n),t}function N(e){let t=document.createElement(`style`);return t.textContent=e,t}function P(e,t){let n={};for(let r of e){let e=document.createElement(`slot`);e.name=`icon-${r}`,e.append(t(r)),e.hidden=!0,n[r]=e}return n}function F(e,t){for(let n of Object.keys(e))e[n].hidden=n!==t}function I(e,t,n){let r=document.createElement(e);return r.setAttribute(`part`,t),n!==void 0&&(r.textContent=n),r}function L(e,t){return e.replace(/\{(\w+)\}/g,(e,n)=>{let r=t[n];return r===void 0?e:String(r)})}function R(e){return e<10?`0${e}`:`${e}`}function z(e){let t=Number.isFinite(e)&&e>0?Math.floor(e):0,n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}:${R(r)}:${R(i)}`:`${r}:${R(i)}`}function B(e,t){return Number.isFinite(t)?`${z(e)} of ${z(t)}`:z(e)}let V=[`default`,`active`];var H=class extends k{static get observedAttributes(){return[`label-start`,`label-stop`]}constructor(){super(),this.api=null;let e=this.attachShadow({mode:`open`});this.button=document.createElement(`button`),this.button.type=`button`,this.button.setAttribute(`part`,`button`),this.slots=P(V,e=>M(e===`active`?`cast-active`:`cast`));for(let e of V)this.button.append(this.slots[e]);this.button.addEventListener(`click`,()=>{let e=this.api;e!==null&&(e.state()===`casting`?e.stop():e.start(this))}),e.append(N(`:host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:2.5em;height:2.5em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}`),this.button)}attach(e){let t=E(e);this.api=t,t.connect(this.getAttribute(`receiver`),this.getAttribute(`sdk`)),this.keep(t.watch(()=>{this.render()})),this.follow(e,()=>{this.render()})}detach(){var e;(e=this.api)==null||e.disconnect(),this.api=null}render(){var e,t,n;let r=this.player,i=this.api;if(r===null||i===null)return;let a=i.state(),o=a===`casting`;this.hidden=a===`unavailable`,this.button.disabled=!o&&((e=r.player)==null?void 0:e.session)==null,this.button.toggleAttribute(`aria-busy`,a===`connecting`),F(this.slots,o?`active`:`default`),this.button.setAttribute(`aria-label`,o?(t=this.getAttribute(`label-stop`))==null?`Stop casting`:t:(n=this.getAttribute(`label-start`))==null?`Cast`:n)}};function U(e,t,n){return Math.min(n,Math.max(t,e))}function W(e){let{onInput:t}=e,n=I(`div`,`slider`);n.setAttribute(`role`,`slider`),n.tabIndex=0;let r=I(`div`,`rail`),i=I(`div`,`track`),a=I(`div`,`fill`),o=I(`div`,`thumb`);i.append(a),r.append(i,o),n.append(r);let s=0,c=1,l=0,u=!1;function d(){let e=`${(c>s?(l-s)/(c-s):0)*100}%`;a.style.width=e,o.style.left=e}function f(e){let t=r.getBoundingClientRect();return t.width===0?s:s+U((e-t.left)/t.width,0,1)*(c-s)}function p(t){u=t,e.onDrag(t)}function m(e){if(e.button===0){e.preventDefault(),p(!0);try{n.setPointerCapture(e.pointerId)}catch(e){}t(f(e.clientX))}}function h(e){u&&(e.buttons===0?g(e):t(f(e.clientX)))}function g(e){u&&(p(!1),t(f(e.clientX)))}function _(){u&&p(!1)}function v(n){let r;switch(n.key){case`ArrowRight`:case`ArrowUp`:r=l+e.step();break;case`ArrowLeft`:case`ArrowDown`:r=l-e.step();break;case`PageUp`:r=l+e.page();break;case`PageDown`:r=l-e.page();break;case`Home`:r=s;break;case`End`:r=c;break;default:return}n.preventDefault(),t(U(r,s,c))}return n.addEventListener(`pointerdown`,m),n.addEventListener(`pointermove`,h),n.addEventListener(`pointerup`,g),n.addEventListener(`pointercancel`,_),n.addEventListener(`lostpointercapture`,_),n.addEventListener(`keydown`,v),{root:n,track:i,rail:r,label(e){n.setAttribute(`aria-label`,e)},dragging(){return u},range(e,t){s=e,c=t,n.setAttribute(`aria-valuemin`,String(e)),n.setAttribute(`aria-valuemax`,String(t)),d()},set(e,t){l=U(e,s,c),n.setAttribute(`aria-valuenow`,String(l)),n.setAttribute(`aria-valuetext`,t),d()},dispose(){n.removeEventListener(`pointerdown`,m),n.removeEventListener(`pointermove`,h),n.removeEventListener(`pointerup`,g),n.removeEventListener(`pointercancel`,_),n.removeEventListener(`lostpointercapture`,_),n.removeEventListener(`keydown`,v)}}}let G=[`play`,`pause`];var K=class extends k{static get observedAttributes(){return[`label`,`label-stop`,`label-play`,`label-pause`,`label-seek`]}constructor(){super(),this.api=null,this.held=null;let e=this.attachShadow({mode:`open`}),t=I(`div`,`box`);this.title_=I(`div`,`title`),this.play=document.createElement(`button`),this.play.type=`button`,this.play.setAttribute(`part`,`button play`),this.slots=P(G,M);for(let e of G)this.play.append(this.slots[e]);this.play.addEventListener(`click`,()=>{var e;(e=this.api)==null||e.playPause()}),this.seek=W({step:()=>5,page:()=>30,onInput:e=>{var t;this.seek.dragging()?(this.held=e,this.paint()):(this.held=null,(t=this.api)==null||t.seek(e))},onDrag:e=>{this.toggleAttribute(`dragging`,e),e||(this.held=null)}}),this.time=I(`span`,`time`),this.row=I(`div`,`row`),this.row.append(this.play,this.seek.root,this.time),this.stop=I(`button`,`stop`),this.stop.type=`button`,this.stop.addEventListener(`click`,()=>{var e;(e=this.api)==null||e.stop()}),t.append(this.title_,this.row,this.stop),e.append(N(`:host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:2.5em;height:2.5em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}:host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:2.6667em;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:.5333em;right:.5333em}[part~=track]{background:#ffffff59;border-radius:2px;height:.2667em;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:.8em;height:.8em;margin:-.4em 0 0 -.4em;position:absolute;top:50%}:host{color:var(--mbx-text);font:400 .9375em / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:1.0667em;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:28em;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:.8em}[part~=title]{font-size:1.2em;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:.8em}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:.8667em}[part~=stop]{height:2.4em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 1.0667em;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}`),t)}connectedCallback(){this.player===null&&(this.hidden=!0),super.connectedCallback()}attach(e){let t=E(e);this.api=t,this.keep(t.watch(()=>{this.render()})),this.render()}detach(){this.api=null,this.hidden=!0}paint(){var e;let t=this.api;if(t===null)return;let n=t.remote(),r=n.loaded&&Number.isFinite(n.duration);if(this.seek.root.hidden=!r,this.time.hidden=!r,!r)return;let i=(e=this.held)==null?n.time:e;this.seek.range(0,n.duration),this.seek.set(i,B(i,n.duration)),this.time.textContent=`${z(i)} / ${z(n.duration)}`}render(){var e,t,n,r,i;let a=this.api;if(a===null)return;let o=a.remote(),s=o.loaded&&!o.paused?`pause`:`play`;F(this.slots,s),this.play.setAttribute(`aria-label`,(e=this.getAttribute(`label-${s}`))==null?s===`play`?`Play`:`Pause`:e),this.seek.label((t=this.getAttribute(`label-seek`))==null?`Seek`:t),this.stop.textContent=(n=this.getAttribute(`label-stop`))==null?`Stop casting`:n;let c=a.state()===`casting`;this.hidden=!c,c&&(this.title_.textContent=L((r=this.getAttribute(`label`))==null?`Casting to {device}`:r,{device:(i=a.device())==null?``:i}),this.play.disabled=!o.loaded,this.paint())}};let q=`mbx-cast-button`,J=`mbx-cast-screen`;return customElements.get(`mbx-cast-button`)===void 0&&customElements.define(q,H),customElements.get(`mbx-cast-screen`)===void 0&&customElements.define(J,K),e.CAST_BUTTON=q,e.CAST_SCREEN=J,e.LICENSE_NAMESPACE=c,e.MbxCastButton=H,e.MbxCastScreen=K,e})({});
@@ -0,0 +1,12 @@
1
+ import toPropertyKey from "./toPropertyKey.js";
2
+ //#region \0@oxc-project+runtime@0.154.0/helpers/esm/defineProperty.js
3
+ function _defineProperty(e, r, t) {
4
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
5
+ value: t,
6
+ enumerable: !0,
7
+ configurable: !0,
8
+ writable: !0
9
+ }) : e[r] = t, e;
10
+ }
11
+ //#endregion
12
+ export { _defineProperty as default };
@@ -0,0 +1,25 @@
1
+ import _defineProperty from "./defineProperty.js";
2
+ //#region \0@oxc-project+runtime@0.154.0/helpers/esm/objectSpread2.js
3
+ function ownKeys(e, r) {
4
+ var t = Object.keys(e);
5
+ if (Object.getOwnPropertySymbols) {
6
+ var o = Object.getOwnPropertySymbols(e);
7
+ r && (o = o.filter(function(r) {
8
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
9
+ })), t.push.apply(t, o);
10
+ }
11
+ return t;
12
+ }
13
+ function _objectSpread2(e) {
14
+ for (var r = 1; r < arguments.length; r++) {
15
+ var t = null != arguments[r] ? arguments[r] : {};
16
+ r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
17
+ _defineProperty(e, r, t[r]);
18
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
19
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
20
+ });
21
+ }
22
+ return e;
23
+ }
24
+ //#endregion
25
+ export { _objectSpread2 as default };
@@ -0,0 +1,14 @@
1
+ import _typeof from "./typeof.js";
2
+ //#region \0@oxc-project+runtime@0.154.0/helpers/esm/toPrimitive.js
3
+ function toPrimitive(t, r) {
4
+ if ("object" != _typeof(t) || !t) return t;
5
+ var e = t[Symbol.toPrimitive];
6
+ if (void 0 !== e) {
7
+ var i = e.call(t, r || "default");
8
+ if ("object" != _typeof(i)) return i;
9
+ throw new TypeError("@@toPrimitive must return a primitive value.");
10
+ }
11
+ return ("string" === r ? String : Number)(t);
12
+ }
13
+ //#endregion
14
+ export { toPrimitive as default };
@@ -0,0 +1,9 @@
1
+ import _typeof from "./typeof.js";
2
+ import toPrimitive from "./toPrimitive.js";
3
+ //#region \0@oxc-project+runtime@0.154.0/helpers/esm/toPropertyKey.js
4
+ function toPropertyKey(t) {
5
+ var i = toPrimitive(t, "string");
6
+ return "symbol" == _typeof(i) ? i : i + "";
7
+ }
8
+ //#endregion
9
+ export { toPropertyKey as default };
@@ -0,0 +1,11 @@
1
+ //#region \0@oxc-project+runtime@0.154.0/helpers/esm/typeof.js
2
+ function _typeof(o) {
3
+ "@babel/helpers - typeof";
4
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
5
+ return typeof o;
6
+ } : function(o) {
7
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
8
+ }, _typeof(o);
9
+ }
10
+ //#endregion
11
+ export { _typeof as default };
@@ -4,7 +4,7 @@ import { icon } from "./icons.js";
4
4
  import { BUTTON_STYLE, SLIDER_STYLE, describe, el, fill, format, iconSlots, show, style } from "./shared.js";
5
5
  import { slider } from "./slider.js";
6
6
  //#region src/cast-screen.ts
7
- const STYLE_CSS = ":host{color:var(--mbx-text);font:400 15px / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:16px;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:420px;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:12px}[part~=title]{font-size:18px;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:12px}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:13px}[part~=stop]{height:36px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 16px;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}";
7
+ const STYLE_CSS = ":host{color:var(--mbx-text);font:400 .9375em / 1.4 var(--mbx-font);text-align:center;background:#000000d9;justify-content:center;align-items:center;padding:1.0667em;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}:host([hidden]){display:none}[part~=box]{flex-direction:column;align-items:center;width:100%;max-width:28em;display:flex}[part~=box]>:not([hidden])~:not([hidden]){margin-top:.8em}[part~=title]{font-size:1.2em;font-weight:600}[part~=row]{justify-content:center;align-items:center;width:100%;display:flex}[part~=row]>:not([hidden])~:not([hidden]){margin-left:.8em}[part~=slider]{flex:1}[part~=time]{font-variant-numeric:tabular-nums;color:var(--mbx-muted);font-size:.8667em}[part~=stop]{height:2.4em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;background:0 0;border:1px solid;padding:0 1.0667em;font-weight:600}[part~=stop]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=stop]:focus:not(:focus-visible){outline:none}[hidden]{display:none}";
8
8
  const STATES = ["play", "pause"];
9
9
  const STEP = 5;
10
10
  const PAGE = 30;
@@ -1,9 +1,12 @@
1
+ import _objectSpread2 from "./_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/objectSpread2.js";
1
2
  //#region src/cast.ts
2
3
  /** Whether the session is live: the engine's `live` namespace, once it has an edge. */
3
4
  function live(engine) {
4
5
  const api = engine === null || engine === void 0 ? void 0 : engine.live;
5
6
  return api !== void 0 && api.edge !== null;
6
7
  }
8
+ /** The custom namespace a receiver asks the sender for a new license token on. */
9
+ const LICENSE_NAMESPACE = "urn:x-cast:ch.mattebox.license";
7
10
  /** The Default Media Receiver: Google's player, which plays HLS and DASH by itself. */
8
11
  const DEFAULT_RECEIVER = "CC1AD845";
9
12
  const SDK_URL = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
@@ -104,7 +107,7 @@ function onSession(fw, ctx, state) {
104
107
  const found = [...connected].find((cast) => cast.plays(playing));
105
108
  if (found !== void 0 && owner === null) {
106
109
  owner = found;
107
- found.adopt();
110
+ found.adopt(ctx);
108
111
  }
109
112
  } else if (state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {
110
113
  const ended = owner;
@@ -126,6 +129,7 @@ var CastOf = class {
126
129
  this.pending = false;
127
130
  this.casting = false;
128
131
  this.handoff = null;
132
+ this.listening = null;
129
133
  }
130
134
  connect(receiver, sdk) {
131
135
  connected.add(this);
@@ -209,6 +213,7 @@ var CastOf = class {
209
213
  if (session === null) return;
210
214
  const request = this.request(session.source, time, autoplay);
211
215
  if (request === null) return;
216
+ this.listen(ctx.getCurrentSession());
212
217
  const event = new CustomEvent("castload", {
213
218
  detail: request,
214
219
  bubbles: true,
@@ -219,8 +224,54 @@ var CastOf = class {
219
224
  (_ctx$getCurrentSessio2 = ctx.getCurrentSession()) === null || _ctx$getCurrentSessio2 === void 0 || _ctx$getCurrentSessio2.loadMedia(request).catch(() => {});
220
225
  }
221
226
  /** A session Chrome rejoined, already playing this player's source. */
222
- adopt() {
227
+ adopt(ctx) {
223
228
  this.freeze();
229
+ this.listen(ctx.getCurrentSession());
230
+ }
231
+ /**
232
+ * Answers the receiver's token requests for this session: a
233
+ * `castunauthorized` event on the player, and the page's reply sent back.
234
+ */
235
+ listen(session) {
236
+ this.unlisten();
237
+ if (session === null) return;
238
+ const fn = (_namespace, message) => {
239
+ let data;
240
+ try {
241
+ data = JSON.parse(message);
242
+ } catch (_unused) {
243
+ return;
244
+ }
245
+ if (data.type !== "unauthorized") return;
246
+ const id = data.id;
247
+ let replied = false;
248
+ const detail = {
249
+ keySystem: typeof data.keySystem === "string" ? data.keySystem : "",
250
+ status: typeof data.status === "number" ? data.status : 0,
251
+ reply(reply) {
252
+ if (replied) return;
253
+ replied = true;
254
+ Promise.resolve(reply).then((answer) => session.sendMessage(LICENSE_NAMESPACE, _objectSpread2({
255
+ type: "license",
256
+ id
257
+ }, answer))).catch(() => {});
258
+ }
259
+ };
260
+ this.player.dispatchEvent(new CustomEvent("castunauthorized", {
261
+ detail,
262
+ bubbles: true
263
+ }));
264
+ };
265
+ session.addMessageListener(LICENSE_NAMESPACE, fn);
266
+ this.listening = {
267
+ session,
268
+ fn
269
+ };
270
+ }
271
+ unlisten() {
272
+ const held = this.listening;
273
+ this.listening = null;
274
+ held === null || held === void 0 || held.session.removeMessageListener("urn:x-cast:ch.mattebox.license", held.fn);
224
275
  }
225
276
  freeze() {
226
277
  const engine = this.player.engine;
@@ -234,6 +285,7 @@ var CastOf = class {
234
285
  /** The session ended: give the video back where the receiver left it. */
235
286
  end(cleanly) {
236
287
  this.pending = false;
288
+ this.unlisten();
237
289
  if (!this.casting) return;
238
290
  this.casting = false;
239
291
  const handoff = this.handoff;
@@ -276,6 +328,8 @@ var CastOf = class {
276
328
  const request = new media.LoadRequest(info);
277
329
  request.currentTime = time;
278
330
  request.autoplay = autoplay;
331
+ const drm = source.drm;
332
+ if (drm !== void 0) request.customData = { mattebox: _objectSpread2(_objectSpread2(_objectSpread2({}, drm.licenseUrl === void 0 ? {} : { licenseUrl: drm.licenseUrl }), drm.licenseUrls === void 0 ? {} : { licenseUrls: drm.licenseUrls }), drm.certificateUrl === void 0 ? {} : { certificateUrl: drm.certificateUrl }) };
279
333
  return request;
280
334
  }
281
335
  };
@@ -296,4 +350,4 @@ function cast(player) {
296
350
  return held;
297
351
  }
298
352
  //#endregion
299
- export { cast };
353
+ export { LICENSE_NAMESPACE, cast };
@@ -1,10 +1,10 @@
1
1
  //#region src/icons.ts
2
2
  /** Each glyph's subpaths joined into one `d`, drawn even-odd like the player's. */
3
3
  const PATHS = {
4
- play: "M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z",
5
- pause: "M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z",
6
- cast: "M4 6h24v18H20v-2h6V8H6v1H4V6zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z",
7
- "cast-active": "M4 6h24v18H20A16 16 0 0 0 4 8zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z"
4
+ play: "M9 5L26 16L9 27z",
5
+ pause: "M8 6h5.5v20h-5.5zM18.5 6h5.5v20h-5.5z",
6
+ cast: "M4 6H28V26H20V23.5H25.5V8.5H6.5V11H4zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z",
7
+ "cast-active": "M4 6H28V26H20A16 16 0 0 0 4 10zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z"
8
8
  };
9
9
  const SVG = "http://www.w3.org/2000/svg";
10
10
  /** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */
@@ -1,3 +1,4 @@
1
+ import { LICENSE_NAMESPACE } from "./cast.js";
1
2
  import { MbxCastButton } from "./cast-button.js";
2
3
  import { MbxCastScreen } from "./cast-screen.js";
3
4
  //#region src/index.ts
@@ -14,4 +15,4 @@ const CAST_SCREEN = "mbx-cast-screen";
14
15
  if (customElements.get("mbx-cast-button") === void 0) customElements.define(CAST_BUTTON, MbxCastButton);
15
16
  if (customElements.get("mbx-cast-screen") === void 0) customElements.define(CAST_SCREEN, MbxCastScreen);
16
17
  //#endregion
17
- export { CAST_BUTTON, CAST_SCREEN, MbxCastButton, MbxCastScreen };
18
+ export { CAST_BUTTON, CAST_SCREEN, LICENSE_NAMESPACE, MbxCastButton, MbxCastScreen };
@@ -7,8 +7,8 @@
7
7
  * package. The tokens come through the `--mbx-*` custom properties the
8
8
  * player sets, which inherit into every control.
9
9
  */
10
- const BUTTON_STYLE_CSS = ":host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:40px;height:40px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}";
11
- const SLIDER_STYLE_CSS = ":host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:40px;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:8px;right:8px}[part~=track]{background:#ffffff59;border-radius:2px;height:4px;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:12px;height:12px;margin:-6px 0 0 -6px;position:absolute;top:50%}";
10
+ const BUTTON_STYLE_CSS = ":host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:2.5em;height:2.5em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}";
11
+ const SLIDER_STYLE_CSS = ":host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:2.6667em;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:.5333em;right:.5333em}[part~=track]{background:#ffffff59;border-radius:2px;height:.2667em;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:.8em;height:.8em;margin:-.4em 0 0 -.4em;position:absolute;top:50%}";
12
12
  const BUTTON_STYLE = BUTTON_STYLE_CSS;
13
13
  /** The style of a slider: the rail, the track with its fill, and the thumb. */
14
14
  /** The style of a slider: the rail, the track with its fill, and the thumb. */
package/dist/icons.d.ts CHANGED
@@ -1,31 +1,7 @@
1
1
  /**
2
- * The play and pause glyphs, copied from Vidstack's media-icons 0.10.0
3
- * (https://github.com/vidstack/media-icons): filled paths on a 32-unit
4
- * viewBox, drawn for a control bar, one visual weight across the set.
5
- * Copied, not depended on. The notice below is the license's one condition,
6
- * and packages/player/NOTICE repeats it for the published tarball.
7
- *
8
- * MIT License
9
- *
10
- * Copyright (c) 2023 Rahim Alwer
11
- *
12
- * Permission is hereby granted, free of charge, to any person obtaining a copy
13
- * of this software and associated documentation files (the "Software"), to deal
14
- * in the Software without restriction, including without limitation the rights
15
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- * copies of the Software, and to permit persons to whom the Software is
17
- * furnished to do so, subject to the following conditions:
18
- *
19
- * The above copyright notice and this permission notice shall be included in all
20
- * copies or substantial portions of the Software.
21
- *
22
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
- * SOFTWARE.
2
+ * The play, pause and cast glyphs, Mattebox's own drawings and the same
3
+ * ones the player draws: filled paths on a 32-unit viewBox. The cast glyph
4
+ * is a screen with a corner open for three arcs, filled while casting.
29
5
  */
30
6
  export type IconName = 'play' | 'pause' | 'cast' | 'cast-active';
31
7
  /** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAgBjE,2FAA2F;AAC3F,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAUlD"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAajE,2FAA2F;AAC3F,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAUlD"}
package/dist/icons.js CHANGED
@@ -1,10 +1,10 @@
1
1
  //#region src/icons.ts
2
2
  /** Each glyph's subpaths joined into one `d`, drawn even-odd like the player's. */
3
3
  const PATHS = {
4
- play: "M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z",
5
- pause: "M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z",
6
- cast: "M4 6h24v18H20v-2h6V8H6v1H4V6zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z",
7
- "cast-active": "M4 6h24v18H20A16 16 0 0 0 4 8zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z"
4
+ play: "M9 5L26 16L9 27z",
5
+ pause: "M8 6h5.5v20h-5.5zM18.5 6h5.5v20h-5.5z",
6
+ cast: "M4 6H28V26H20V23.5H25.5V8.5H6.5V11H4zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z",
7
+ "cast-active": "M4 6H28V26H20A16 16 0 0 0 4 10zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z"
8
8
  };
9
9
  const SVG = "http://www.w3.org/2000/svg";
10
10
  /** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */
package/dist/icons.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"icons.js","names":[],"sources":["../src/icons.ts"],"sourcesContent":["/**\n * The play and pause glyphs, copied from Vidstack's media-icons 0.10.0\n * (https://github.com/vidstack/media-icons): filled paths on a 32-unit\n * viewBox, drawn for a control bar, one visual weight across the set.\n * Copied, not depended on. The notice below is the license's one condition,\n * and packages/player/NOTICE repeats it for the published tarball.\n *\n * MIT License\n *\n * Copyright (c) 2023 Rahim Alwer\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nexport type IconName = 'play' | 'pause' | 'cast' | 'cast-active';\n\n/** Each glyph's subpaths joined into one `d`, drawn even-odd like the player's. */\nconst PATHS: Readonly<Record<IconName, string>> = {\n play: 'M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z',\n pause:\n 'M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z',\n // The cast glyphs are this package's own drawing, not media-icons: a\n // screen with the corner open for three arcs, filled while casting.\n cast: 'M4 6h24v18H20v-2h6V8H6v1H4V6zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z',\n 'cast-active':\n 'M4 6h24v18H20A16 16 0 0 0 4 8zM4 21a3 3 0 0 1 3 3H4zM4 15a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7zM4 10a14 14 0 0 1 14 14h-2A12 12 0 0 0 4 12z',\n};\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\n/** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */\nexport function icon(name: IconName): SVGSVGElement {\n const svg = document.createElementNS(SVG, 'svg');\n svg.setAttribute('viewBox', '0 0 32 32');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('part', 'icon');\n const path = document.createElementNS(SVG, 'path');\n path.setAttribute('fill-rule', 'evenodd');\n path.setAttribute('d', PATHS[name]);\n svg.append(path);\n return svg;\n}\n"],"mappings":";;AAiCA,MAAM,QAA4C;CAChD,MAAM;CACN,OACE;CAGF,MAAM;CACN,eACE;AACJ;AAEA,MAAM,MAAM;;AAGZ,SAAgB,KAAK,MAA+B;CAClD,MAAM,MAAM,SAAS,gBAAgB,KAAK,KAAK;CAC/C,IAAI,aAAa,WAAW,WAAW;CACvC,IAAI,aAAa,eAAe,MAAM;CACtC,IAAI,aAAa,QAAQ,MAAM;CAC/B,MAAM,OAAO,SAAS,gBAAgB,KAAK,MAAM;CACjD,KAAK,aAAa,aAAa,SAAS;CACxC,KAAK,aAAa,KAAK,MAAM,KAAK;CAClC,IAAI,OAAO,IAAI;CACf,OAAO;AACT"}
1
+ {"version":3,"file":"icons.js","names":[],"sources":["../src/icons.ts"],"sourcesContent":["/**\n * The play, pause and cast glyphs, Mattebox's own drawings and the same\n * ones the player draws: filled paths on a 32-unit viewBox. The cast glyph\n * is a screen with a corner open for three arcs, filled while casting.\n */\n\nexport type IconName = 'play' | 'pause' | 'cast' | 'cast-active';\n\n/** Each glyph's subpaths joined into one `d`, drawn even-odd like the player's. */\nconst PATHS: Readonly<Record<IconName, string>> = {\n play: 'M9 5L26 16L9 27z',\n pause: 'M8 6h5.5v20h-5.5zM18.5 6h5.5v20h-5.5z',\n cast: 'M4 6H28V26H20V23.5H25.5V8.5H6.5V11H4zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z',\n 'cast-active':\n 'M4 6H28V26H20A16 16 0 0 0 4 10zM4 23h3v3h-3zM4 17.5A8.5 8.5 0 0 1 12.5 26L10 26A6 6 0 0 0 4 20zM4 12A14 14 0 0 1 18 26L15.5 26A11.5 11.5 0 0 0 4 14.5z',\n};\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\n/** A glyph, hidden from the accessibility tree: the button it sits in carries the name. */\nexport function icon(name: IconName): SVGSVGElement {\n const svg = document.createElementNS(SVG, 'svg');\n svg.setAttribute('viewBox', '0 0 32 32');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('part', 'icon');\n const path = document.createElementNS(SVG, 'path');\n path.setAttribute('fill-rule', 'evenodd');\n path.setAttribute('d', PATHS[name]);\n svg.append(path);\n return svg;\n}\n"],"mappings":";;AASA,MAAM,QAA4C;CAChD,MAAM;CACN,OAAO;CACP,MAAM;CACN,eACE;AACJ;AAEA,MAAM,MAAM;;AAGZ,SAAgB,KAAK,MAA+B;CAClD,MAAM,MAAM,SAAS,gBAAgB,KAAK,KAAK;CAC/C,IAAI,aAAa,WAAW,WAAW;CACvC,IAAI,aAAa,eAAe,MAAM;CACtC,IAAI,aAAa,QAAQ,MAAM;CAC/B,MAAM,OAAO,SAAS,gBAAgB,KAAK,MAAM;CACjD,KAAK,aAAa,aAAa,SAAS;CACxC,KAAK,aAAa,KAAK,MAAM,KAAK;CAClC,IAAI,OAAO,IAAI;CACf,OAAO;AACT"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,8 @@
8
8
  */
9
9
  import { MbxCastButton } from './cast-button.js';
10
10
  import { MbxCastScreen } from './cast-screen.js';
11
- export type { CastState, LoadRequest as CastLoadRequest, MediaInfo, Track } from './cast.js';
11
+ export type { CastState, LicenseReply, LoadRequest as CastLoadRequest, MatteboxCustomData, MediaInfo, Track, UnauthorizedDetail, } from './cast.js';
12
+ export { LICENSE_NAMESPACE } from './cast.js';
12
13
  export { MbxCastButton } from './cast-button.js';
13
14
  export { MbxCastScreen } from './cast-screen.js';
14
15
  export declare const CAST_BUTTON = "mbx-cast-button";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,YAAY,EAAE,SAAS,EAAE,WAAW,IAAI,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAC7C,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAS7C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;QACjC,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,IAAI,eAAe,EAC9B,kBAAkB,EAClB,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAC7C,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAS7C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;QACjC,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { LICENSE_NAMESPACE } from "./cast.js";
1
2
  import { MbxCastButton } from "./cast-button.js";
2
3
  import { MbxCastScreen } from "./cast-screen.js";
3
4
  //#region src/index.ts
@@ -14,6 +15,6 @@ const CAST_SCREEN = "mbx-cast-screen";
14
15
  if (customElements.get("mbx-cast-button") === void 0) customElements.define(CAST_BUTTON, MbxCastButton);
15
16
  if (customElements.get("mbx-cast-screen") === void 0) customElements.define(CAST_SCREEN, MbxCastScreen);
16
17
  //#endregion
17
- export { CAST_BUTTON, CAST_SCREEN, MbxCastButton, MbxCastScreen };
18
+ export { CAST_BUTTON, CAST_SCREEN, LICENSE_NAMESPACE, MbxCastButton, MbxCastScreen };
18
19
 
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @mattebox/player-cast: <mbx-cast-button> and <mbx-cast-screen>, Chromecast\n * from the player over Google's sender SDK. Importing this module registers\n * both elements; that is the package's one side effect. It is a package of\n * its own because the button loads Google's script onto the page, which the\n * player never does on an integrator's behalf: the AirPlay button, over\n * Safari's own API, ships with the player.\n */\nimport { MbxCastButton } from './cast-button.js';\nimport { MbxCastScreen } from './cast-screen.js';\n\nexport type { CastState, LoadRequest as CastLoadRequest, MediaInfo, Track } from './cast.js';\nexport { MbxCastButton } from './cast-button.js';\nexport { MbxCastScreen } from './cast-screen.js';\n\nexport const CAST_BUTTON = 'mbx-cast-button';\nexport const CAST_SCREEN = 'mbx-cast-screen';\n\nif (customElements.get(CAST_BUTTON) === undefined) {\n customElements.define(CAST_BUTTON, MbxCastButton);\n}\nif (customElements.get(CAST_SCREEN) === undefined) {\n customElements.define(CAST_SCREEN, MbxCastScreen);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mbx-cast-button': MbxCastButton;\n 'mbx-cast-screen': MbxCastScreen;\n }\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAE3B,IAAI,eAAe,IAAA,iBAAe,MAAM,KAAA,GACtC,eAAe,OAAO,aAAa,aAAa;AAElD,IAAI,eAAe,IAAA,iBAAe,MAAM,KAAA,GACtC,eAAe,OAAO,aAAa,aAAa"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @mattebox/player-cast: <mbx-cast-button> and <mbx-cast-screen>, Chromecast\n * from the player over Google's sender SDK. Importing this module registers\n * both elements; that is the package's one side effect. It is a package of\n * its own because the button loads Google's script onto the page, which the\n * player never does on an integrator's behalf: the AirPlay button, over\n * Safari's own API, ships with the player.\n */\nimport { MbxCastButton } from './cast-button.js';\nimport { MbxCastScreen } from './cast-screen.js';\n\nexport type {\n CastState,\n LicenseReply,\n LoadRequest as CastLoadRequest,\n MatteboxCustomData,\n MediaInfo,\n Track,\n UnauthorizedDetail,\n} from './cast.js';\nexport { LICENSE_NAMESPACE } from './cast.js';\nexport { MbxCastButton } from './cast-button.js';\nexport { MbxCastScreen } from './cast-screen.js';\n\nexport const CAST_BUTTON = 'mbx-cast-button';\nexport const CAST_SCREEN = 'mbx-cast-screen';\n\nif (customElements.get(CAST_BUTTON) === undefined) {\n customElements.define(CAST_BUTTON, MbxCastButton);\n}\nif (customElements.get(CAST_SCREEN) === undefined) {\n customElements.define(CAST_SCREEN, MbxCastScreen);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mbx-cast-button': MbxCastButton;\n 'mbx-cast-screen': MbxCastScreen;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAwBA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAE3B,IAAI,eAAe,IAAA,iBAAe,MAAM,KAAA,GACtC,eAAe,OAAO,aAAa,aAAa;AAElD,IAAI,eAAe,IAAA,iBAAe,MAAM,KAAA,GACtC,eAAe,OAAO,aAAa,aAAa"}
package/dist/shared.js CHANGED
@@ -7,8 +7,8 @@
7
7
  * package. The tokens come through the `--mbx-*` custom properties the
8
8
  * player sets, which inherit into every control.
9
9
  */
10
- const BUTTON_STYLE_CSS = ":host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:40px;height:40px;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}";
11
- const SLIDER_STYLE_CSS = ":host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:40px;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:8px;right:8px}[part~=track]{background:#ffffff59;border-radius:2px;height:4px;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:12px;height:12px;margin:-6px 0 0 -6px;position:absolute;top:50%}";
10
+ const BUTTON_STYLE_CSS = ":host{display:inline-flex}:host([hidden]){display:none}[part~=button]{width:2.5em;height:2.5em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}slot[hidden]{display:none}";
11
+ const SLIDER_STYLE_CSS = ":host{display:block}:host([hidden]){display:none}[part~=slider]{border-radius:var(--mbx-radius);cursor:pointer;touch-action:none;height:2.6667em;position:relative}[part~=slider]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=slider]:focus:not(:focus-visible){outline:none}[part~=rail]{position:absolute;top:0;bottom:0;left:.5333em;right:.5333em}[part~=track]{background:#ffffff59;border-radius:2px;height:.2667em;position:absolute;top:50%;left:0;right:0;overflow:hidden;transform:translateY(-50%)}[part~=fill]{background:var(--mbx-accent);position:absolute;top:0;bottom:0;left:0}[part~=thumb]{background:var(--mbx-text);pointer-events:none;border-radius:50%;width:.8em;height:.8em;margin:-.4em 0 0 -.4em;position:absolute;top:50%}";
12
12
  const BUTTON_STYLE = BUTTON_STYLE_CSS;
13
13
  /** The style of a slider: the rail, the track with its fill, and the thumb. */
14
14
  /** The style of a slider: the rail, the track with its fill, and the thumb. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mattebox/player-cast",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "<mbx-cast-button> and <mbx-cast-screen>: Chromecast from <mattebox-player>, over Google's sender SDK.",
5
5
  "author": "Josep Boix Requesens",
6
6
  "repository": {
@@ -37,8 +37,7 @@
37
37
  "./package.json": "./package.json"
38
38
  },
39
39
  "files": [
40
- "dist",
41
- "NOTICE"
40
+ "dist"
42
41
  ],
43
42
  "scripts": {
44
43
  "clean": "rm -rf dist",
@@ -50,10 +49,10 @@
50
49
  "release:ci": "semantic-release"
51
50
  },
52
51
  "devDependencies": {
53
- "@mattebox/player-core": "^0.4.0"
52
+ "@mattebox/player-core": "^0.6.1"
54
53
  },
55
54
  "peerDependencies": {
56
- "@mattebox/player": ">=0.7.0",
57
- "mattebox": "^0.8.2"
55
+ "@mattebox/player": ">=0.10.0",
56
+ "mattebox": "^0.15.0"
58
57
  }
59
58
  }
package/NOTICE DELETED
@@ -1,24 +0,0 @@
1
- @mattebox/player-cast carries two glyphs copied from media-icons
2
- (https://github.com/vidstack/media-icons), used under the MIT License:
3
-
4
- MIT License
5
-
6
- Copyright (c) 2023 Rahim Alwer
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy
9
- of this software and associated documentation files (the "Software"), to deal
10
- in the Software without restriction, including without limitation the rights
11
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- copies of the Software, and to permit persons to whom the Software is
13
- furnished to do so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.