@mattebox/player-cast 0.1.0 → 0.2.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 +22 -16
- package/dist/cast-button.js +58 -64
- package/dist/cast-button.js.map +1 -1
- package/dist/cast-screen.d.ts.map +1 -1
- package/dist/cast-screen.js +113 -145
- package/dist/cast-screen.js.map +1 -1
- package/dist/cast.js +258 -311
- package/dist/cast.js.map +1 -1
- package/dist/cdn/mattebox-player-cast.min.js +1 -91
- package/dist/component.js +85 -88
- package/dist/component.js.map +1 -1
- package/dist/es2015/cast-screen.js +2 -34
- package/dist/es2015/shared.js +4 -59
- package/dist/host.js +15 -13
- package/dist/host.js.map +1 -1
- package/dist/icons.js +19 -46
- package/dist/icons.js.map +1 -1
- package/dist/index.js +17 -19
- package/dist/index.js.map +1 -1
- package/dist/shared.d.ts +2 -10
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +54 -107
- package/dist/shared.js.map +1 -1
- package/dist/slider.js +151 -160
- package/dist/slider.js.map +1 -1
- package/package.json +5 -5
package/dist/cast.js
CHANGED
|
@@ -1,343 +1,290 @@
|
|
|
1
|
+
//#region src/cast.ts
|
|
1
2
|
/** Whether the session is live: the engine's `live` namespace, once it has an edge. */
|
|
2
3
|
function live(engine) {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
const api = engine?.live;
|
|
5
|
+
return api !== void 0 && api.edge !== null;
|
|
5
6
|
}
|
|
6
7
|
/** The Default Media Receiver: Google's player, which plays HLS and DASH by itself. */
|
|
7
|
-
const DEFAULT_RECEIVER =
|
|
8
|
-
const SDK_URL =
|
|
9
|
-
// The page-wide part: one SDK, one context, one remote player. Held in the
|
|
10
|
-
// module because the SDK holds them in the window.
|
|
8
|
+
const DEFAULT_RECEIVER = "CC1AD845";
|
|
9
|
+
const SDK_URL = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
|
|
11
10
|
let framework = null;
|
|
12
11
|
let configured = null;
|
|
13
12
|
let remotePlayer = null;
|
|
14
13
|
let remoteController = null;
|
|
15
|
-
const watchers = new Set();
|
|
14
|
+
const watchers = /* @__PURE__ */ new Set();
|
|
16
15
|
/** The player whose session this is, so two players on a page do not both take a session. */
|
|
17
16
|
let owner = null;
|
|
18
17
|
/** The receiver's last known playback, read while it reports and kept once it stops. */
|
|
19
|
-
const NOTHING = {
|
|
18
|
+
const NOTHING = {
|
|
19
|
+
loaded: false,
|
|
20
|
+
paused: true,
|
|
21
|
+
time: 0,
|
|
22
|
+
duration: NaN
|
|
23
|
+
};
|
|
20
24
|
let last = NOTHING;
|
|
21
25
|
function globals() {
|
|
22
|
-
|
|
26
|
+
return globalThis;
|
|
23
27
|
}
|
|
24
28
|
function notify() {
|
|
25
|
-
|
|
26
|
-
fn();
|
|
29
|
+
for (const fn of [...watchers]) fn();
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
* The framework, once the page has it. Resolves null where the SDK never
|
|
33
|
+
* arrives: a browser without Cast, a page whose CSP refused the script, or
|
|
34
|
+
* `sdk="none"` with no script of the page's own.
|
|
35
|
+
*/
|
|
33
36
|
function load(sdk) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
script.async = true;
|
|
59
|
-
script.addEventListener('error', () => resolve(null));
|
|
60
|
-
document.head.append(script);
|
|
61
|
-
});
|
|
62
|
-
return framework;
|
|
37
|
+
if (framework !== null) return framework;
|
|
38
|
+
const held = globals();
|
|
39
|
+
if (held.cast?.framework !== void 0) {
|
|
40
|
+
framework = Promise.resolve(held.cast.framework);
|
|
41
|
+
return framework;
|
|
42
|
+
}
|
|
43
|
+
if (!("chrome" in held)) {
|
|
44
|
+
framework = Promise.resolve(null);
|
|
45
|
+
return framework;
|
|
46
|
+
}
|
|
47
|
+
framework = new Promise((resolve) => {
|
|
48
|
+
const previous = held.__onGCastApiAvailable;
|
|
49
|
+
held.__onGCastApiAvailable = (available) => {
|
|
50
|
+
previous?.(available);
|
|
51
|
+
resolve(available ? globals().cast?.framework ?? null : null);
|
|
52
|
+
};
|
|
53
|
+
if (sdk === "none") return;
|
|
54
|
+
const script = document.createElement("script");
|
|
55
|
+
script.src = SDK_URL;
|
|
56
|
+
script.async = true;
|
|
57
|
+
script.addEventListener("error", () => resolve(null));
|
|
58
|
+
document.head.append(script);
|
|
59
|
+
});
|
|
60
|
+
return framework;
|
|
63
61
|
}
|
|
64
62
|
/** The context, set up once per page. */
|
|
65
63
|
function context(fw, receiver) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
return ctx;
|
|
64
|
+
const ctx = fw.CastContext.getInstance();
|
|
65
|
+
const wanted = receiver ?? DEFAULT_RECEIVER;
|
|
66
|
+
if (configured === null) {
|
|
67
|
+
const policy = globals().chrome?.cast?.AutoJoinPolicy.ORIGIN_SCOPED ?? "origin_scoped";
|
|
68
|
+
ctx.setOptions({
|
|
69
|
+
receiverApplicationId: wanted,
|
|
70
|
+
autoJoinPolicy: policy
|
|
71
|
+
});
|
|
72
|
+
configured = wanted;
|
|
73
|
+
ctx.addEventListener(fw.CastContextEventType.CAST_STATE_CHANGED, notify);
|
|
74
|
+
ctx.addEventListener(fw.CastContextEventType.SESSION_STATE_CHANGED, (event) => {
|
|
75
|
+
onSession(fw, ctx, event.sessionState ?? "");
|
|
76
|
+
});
|
|
77
|
+
remotePlayer = new fw.RemotePlayer();
|
|
78
|
+
remoteController = new fw.RemotePlayerController(remotePlayer);
|
|
79
|
+
remoteController.addEventListener(fw.RemotePlayerEventType.ANY_CHANGE, () => {
|
|
80
|
+
const remote = remotePlayer;
|
|
81
|
+
if (remote?.isConnected === true && remote.isMediaLoaded) last = {
|
|
82
|
+
loaded: true,
|
|
83
|
+
paused: remote.isPaused,
|
|
84
|
+
time: remote.currentTime,
|
|
85
|
+
duration: remote.duration > 0 ? remote.duration : Number.POSITIVE_INFINITY
|
|
86
|
+
};
|
|
87
|
+
notify();
|
|
88
|
+
});
|
|
89
|
+
} else if (receiver !== null && receiver !== configured) console.error(`mattebox-player: the Cast context already uses receiver ${configured}`);
|
|
90
|
+
return ctx;
|
|
95
91
|
}
|
|
96
92
|
function onSession(fw, ctx, state) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const ended = owner;
|
|
115
|
-
owner = null;
|
|
116
|
-
ended?.end(state === states.SESSION_ENDED);
|
|
117
|
-
}
|
|
118
|
-
notify();
|
|
93
|
+
const states = fw.SessionState;
|
|
94
|
+
if (state === states.SESSION_STARTED && owner !== null && owner.pending) {
|
|
95
|
+
last = NOTHING;
|
|
96
|
+
owner.begin(ctx);
|
|
97
|
+
} else if (state === states.SESSION_RESUMED) {
|
|
98
|
+
const playing = ctx.getCurrentSession()?.getMediaSession()?.media?.contentId;
|
|
99
|
+
const found = [...connected].find((cast) => cast.plays(playing));
|
|
100
|
+
if (found !== void 0 && owner === null) {
|
|
101
|
+
owner = found;
|
|
102
|
+
found.adopt();
|
|
103
|
+
}
|
|
104
|
+
} else if (state === states.SESSION_ENDED || state === states.SESSION_START_FAILED) {
|
|
105
|
+
const ended = owner;
|
|
106
|
+
owner = null;
|
|
107
|
+
ended?.end(state === states.SESSION_ENDED);
|
|
108
|
+
}
|
|
109
|
+
notify();
|
|
119
110
|
}
|
|
120
111
|
/** One per player, found again by its button and its screen. Weak, so a player that leaves is not held. */
|
|
121
|
-
const players = new WeakMap();
|
|
112
|
+
const players = /* @__PURE__ */ new WeakMap();
|
|
122
113
|
/** The players with a cast button attached, for a session Chrome rejoins on load. */
|
|
123
|
-
const connected = new Set();
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
/** The load request: the source, the time, the stream type, and the video's own text tracks. */
|
|
282
|
-
request(source, time, autoplay) {
|
|
283
|
-
const media = globals().chrome?.cast?.media;
|
|
284
|
-
if (media === undefined)
|
|
285
|
-
return null;
|
|
286
|
-
const engine = this.player.engine;
|
|
287
|
-
const type = source.type ?? '';
|
|
288
|
-
const info = new media.MediaInfo(source.url, type);
|
|
289
|
-
info.streamType = live(engine) ? media.StreamType.LIVE : media.StreamType.BUFFERED;
|
|
290
|
-
if (/mpegurl/i.test(type)) {
|
|
291
|
-
// The receiver assumes MPEG-TS segments for HLS unless told. The
|
|
292
|
-
// engine's presentation says which the stream has; a native session
|
|
293
|
-
// has none, and CMAF is the assumption there.
|
|
294
|
-
const ts = tsSegments(engine);
|
|
295
|
-
info.hlsSegmentFormat = ts ? 'ts' : 'fmp4';
|
|
296
|
-
info.hlsVideoSegmentFormat = ts ? 'mpeg2_ts' : 'fmp4';
|
|
297
|
-
}
|
|
298
|
-
const tracks = [];
|
|
299
|
-
for (const node of this.player.video.querySelectorAll('track[src]')) {
|
|
300
|
-
const track = node;
|
|
301
|
-
if (track.kind !== 'subtitles' && track.kind !== 'captions')
|
|
302
|
-
continue;
|
|
303
|
-
const out = new media.Track(tracks.length + 1, media.TrackType.TEXT);
|
|
304
|
-
out.trackContentId = track.src;
|
|
305
|
-
out.trackContentType = 'text/vtt';
|
|
306
|
-
out.subtype =
|
|
307
|
-
track.kind === 'captions' ? media.TextTrackType.CAPTIONS : media.TextTrackType.SUBTITLES;
|
|
308
|
-
out.name = track.label;
|
|
309
|
-
out.language = track.srclang;
|
|
310
|
-
tracks.push(out);
|
|
311
|
-
}
|
|
312
|
-
info.tracks = tracks.length > 0 ? tracks : null;
|
|
313
|
-
const request = new media.LoadRequest(info);
|
|
314
|
-
request.currentTime = time;
|
|
315
|
-
request.autoplay = autoplay;
|
|
316
|
-
return request;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
114
|
+
const connected = /* @__PURE__ */ new Set();
|
|
115
|
+
var CastOf = class {
|
|
116
|
+
constructor(player) {
|
|
117
|
+
this.player = player;
|
|
118
|
+
this.target = null;
|
|
119
|
+
this.ctx = null;
|
|
120
|
+
this.fw = null;
|
|
121
|
+
this.pending = false;
|
|
122
|
+
this.casting = false;
|
|
123
|
+
this.handoff = null;
|
|
124
|
+
}
|
|
125
|
+
connect(receiver, sdk) {
|
|
126
|
+
connected.add(this);
|
|
127
|
+
load(sdk).then((fw) => {
|
|
128
|
+
if (fw === null) return;
|
|
129
|
+
this.fw = fw;
|
|
130
|
+
this.ctx = context(fw, receiver);
|
|
131
|
+
notify();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
disconnect() {
|
|
135
|
+
connected.delete(this);
|
|
136
|
+
}
|
|
137
|
+
state() {
|
|
138
|
+
const ctx = this.ctx;
|
|
139
|
+
const fw = this.fw;
|
|
140
|
+
if (ctx === null || fw === null) return "unavailable";
|
|
141
|
+
if (this.casting) return "casting";
|
|
142
|
+
const cast = ctx.getCastState();
|
|
143
|
+
if (cast === fw.CastState.NO_DEVICES_AVAILABLE) return "unavailable";
|
|
144
|
+
if (cast === fw.CastState.CONNECTING || this.pending) return "connecting";
|
|
145
|
+
return "idle";
|
|
146
|
+
}
|
|
147
|
+
device() {
|
|
148
|
+
if (!this.casting) return null;
|
|
149
|
+
return this.ctx?.getCurrentSession()?.getCastDevice().friendlyName ?? null;
|
|
150
|
+
}
|
|
151
|
+
remote() {
|
|
152
|
+
return last;
|
|
153
|
+
}
|
|
154
|
+
start(target) {
|
|
155
|
+
const ctx = this.ctx;
|
|
156
|
+
if (ctx === null || this.casting) return;
|
|
157
|
+
if (owner !== null && owner !== this) {
|
|
158
|
+
ctx.endCurrentSession(true);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.target = target;
|
|
162
|
+
this.pending = true;
|
|
163
|
+
owner = this;
|
|
164
|
+
notify();
|
|
165
|
+
ctx.requestSession().catch(() => {
|
|
166
|
+
if (owner === this) owner = null;
|
|
167
|
+
this.pending = false;
|
|
168
|
+
notify();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
stop() {
|
|
172
|
+
if (this.casting) this.ctx?.endCurrentSession(true);
|
|
173
|
+
}
|
|
174
|
+
playPause() {
|
|
175
|
+
if (this.casting) remoteController?.playOrPause();
|
|
176
|
+
}
|
|
177
|
+
seek(time) {
|
|
178
|
+
if (!this.casting || remotePlayer === null) return;
|
|
179
|
+
remotePlayer.currentTime = time;
|
|
180
|
+
remoteController?.seek();
|
|
181
|
+
}
|
|
182
|
+
watch(fn) {
|
|
183
|
+
watchers.add(fn);
|
|
184
|
+
return () => {
|
|
185
|
+
watchers.delete(fn);
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** Whether this player's session plays `url`. */
|
|
189
|
+
plays(url) {
|
|
190
|
+
return url !== void 0 && this.player.player?.session?.source.url === url;
|
|
191
|
+
}
|
|
192
|
+
/** A session started for this player: freeze the picture and send the source. */
|
|
193
|
+
begin(ctx) {
|
|
194
|
+
this.pending = false;
|
|
195
|
+
const session = this.player.player?.session ?? null;
|
|
196
|
+
const video = this.player.video;
|
|
197
|
+
const time = video.currentTime;
|
|
198
|
+
const autoplay = !video.paused;
|
|
199
|
+
this.freeze();
|
|
200
|
+
if (session === null) return;
|
|
201
|
+
const request = this.request(session.source, time, autoplay);
|
|
202
|
+
if (request === null) return;
|
|
203
|
+
const event = new CustomEvent("castload", {
|
|
204
|
+
detail: request,
|
|
205
|
+
bubbles: true,
|
|
206
|
+
composed: true,
|
|
207
|
+
cancelable: true
|
|
208
|
+
});
|
|
209
|
+
if (this.target?.dispatchEvent(event) === false) return;
|
|
210
|
+
ctx.getCurrentSession()?.loadMedia(request).catch(() => {});
|
|
211
|
+
}
|
|
212
|
+
/** A session Chrome rejoined, already playing this player's source. */
|
|
213
|
+
adopt() {
|
|
214
|
+
this.freeze();
|
|
215
|
+
}
|
|
216
|
+
freeze() {
|
|
217
|
+
const engine = this.player.engine;
|
|
218
|
+
this.handoff = { live: live(engine) };
|
|
219
|
+
this.player.video.pause();
|
|
220
|
+
engine?.suspend();
|
|
221
|
+
this.casting = true;
|
|
222
|
+
this.player.toggleAttribute("casting", true);
|
|
223
|
+
notify();
|
|
224
|
+
}
|
|
225
|
+
/** The session ended: give the video back where the receiver left it. */
|
|
226
|
+
end(cleanly) {
|
|
227
|
+
this.pending = false;
|
|
228
|
+
if (!this.casting) return;
|
|
229
|
+
this.casting = false;
|
|
230
|
+
const handoff = this.handoff;
|
|
231
|
+
this.handoff = null;
|
|
232
|
+
const video = this.player.video;
|
|
233
|
+
this.player.engine?.resume();
|
|
234
|
+
this.player.removeAttribute("casting");
|
|
235
|
+
if (!cleanly || !last.loaded) return;
|
|
236
|
+
if (handoff?.live !== true && Number.isFinite(last.time)) video.currentTime = last.time;
|
|
237
|
+
if (!last.paused) video.play().catch(() => void 0);
|
|
238
|
+
}
|
|
239
|
+
/** The load request: the source, the time, the stream type, and the video's own text tracks. */
|
|
240
|
+
request(source, time, autoplay) {
|
|
241
|
+
const media = globals().chrome?.cast?.media;
|
|
242
|
+
if (media === void 0) return null;
|
|
243
|
+
const engine = this.player.engine;
|
|
244
|
+
const type = source.type ?? "";
|
|
245
|
+
const info = new media.MediaInfo(source.url, type);
|
|
246
|
+
info.streamType = live(engine) ? media.StreamType.LIVE : media.StreamType.BUFFERED;
|
|
247
|
+
if (/mpegurl/i.test(type)) {
|
|
248
|
+
const ts = tsSegments(engine);
|
|
249
|
+
info.hlsSegmentFormat = ts ? "ts" : "fmp4";
|
|
250
|
+
info.hlsVideoSegmentFormat = ts ? "mpeg2_ts" : "fmp4";
|
|
251
|
+
}
|
|
252
|
+
const tracks = [];
|
|
253
|
+
for (const node of this.player.video.querySelectorAll("track[src]")) {
|
|
254
|
+
const track = node;
|
|
255
|
+
if (track.kind !== "subtitles" && track.kind !== "captions") continue;
|
|
256
|
+
const out = new media.Track(tracks.length + 1, media.TrackType.TEXT);
|
|
257
|
+
out.trackContentId = track.src;
|
|
258
|
+
out.trackContentType = "text/vtt";
|
|
259
|
+
out.subtype = track.kind === "captions" ? media.TextTrackType.CAPTIONS : media.TextTrackType.SUBTITLES;
|
|
260
|
+
out.name = track.label;
|
|
261
|
+
out.language = track.srclang;
|
|
262
|
+
tracks.push(out);
|
|
263
|
+
}
|
|
264
|
+
info.tracks = tracks.length > 0 ? tracks : null;
|
|
265
|
+
const request = new media.LoadRequest(info);
|
|
266
|
+
request.currentTime = time;
|
|
267
|
+
request.autoplay = autoplay;
|
|
268
|
+
return request;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
319
271
|
/** Whether the engine's presentation carries MPEG-TS renditions. */
|
|
320
272
|
function tsSegments(engine) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
for (const track of period.tracks) {
|
|
326
|
-
for (const rendition of track.renditions) {
|
|
327
|
-
if (/mp2t/i.test(rendition.mimeType))
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return false;
|
|
273
|
+
const presentation = engine?.stats.snapshot().presentation;
|
|
274
|
+
if (presentation === null || presentation === void 0) return false;
|
|
275
|
+
for (const period of presentation.periods) for (const track of period.tracks) for (const rendition of track.renditions) if (/mp2t/i.test(rendition.mimeType)) return true;
|
|
276
|
+
return false;
|
|
333
277
|
}
|
|
334
278
|
/** The player's Cast, one per player, shared by its cast button and cast screen. */
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
279
|
+
function cast(player) {
|
|
280
|
+
let held = players.get(player);
|
|
281
|
+
if (held === void 0) {
|
|
282
|
+
held = new CastOf(player);
|
|
283
|
+
players.set(player, held);
|
|
284
|
+
}
|
|
285
|
+
return held;
|
|
342
286
|
}
|
|
287
|
+
//#endregion
|
|
288
|
+
export { cast };
|
|
289
|
+
|
|
343
290
|
//# sourceMappingURL=cast.js.map
|