@eluvio/elv-player-js 2.0.21 → 2.0.23
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/dist/.vite/manifest.json +17 -17
- package/dist/{Analytics-DdX0-7dQ.mjs → Analytics-B72tGTQx.mjs} +1 -1
- package/dist/{Analytics-B6MHUb3Q.js → Analytics-CDXMirgj.js} +1 -1
- package/dist/{dash.all.min-BgLUy4QY.js → dash.all.min-3hdqLcqd.js} +1 -1
- package/dist/{dash.all.min-DkmG-Qxu.mjs → dash.all.min-DlSRaJ_5.mjs} +1 -1
- package/dist/elv-player-js.cjs.js +1 -1
- package/dist/elv-player-js.css +1 -1
- package/dist/elv-player-js.es.js +1 -1
- package/dist/index-Be7Zq2Nh.js +378 -0
- package/dist/{index-BhYSs-gw.mjs → index-BrZn3sD8.mjs} +77 -79
- package/dist/{index-Clf0EQQK.mjs → index-BxTtC119.mjs} +19599 -19553
- package/dist/{index-MQ4UPeZq.js → index-CO76930D.js} +3 -3
- package/lib/player/Cast.js +280 -0
- package/lib/player/Controls.js +103 -5
- package/lib/player/Player.js +84 -20
- package/lib/static/icons/Icons.js +2 -0
- package/lib/static/icons/svgs/airplay.svg +1 -0
- package/lib/static/icons/svgs/cast.svg +1 -0
- package/lib/static/stylesheets/common.module.scss +65 -0
- package/lib/static/stylesheets/controls-tv.module.scss +1 -0
- package/lib/static/stylesheets/controls-web.module.scss +15 -0
- package/lib/static/stylesheets/player.module.scss +16 -0
- package/lib/ui/BuildIcons.cjs +2 -0
- package/lib/ui/Components.jsx +44 -5
- package/lib/ui/Observers.js +28 -18
- package/lib/ui/PlayerUI.jsx +10 -0
- package/lib/ui/TVControls.jsx +25 -11
- package/lib/ui/WebControls.jsx +30 -25
- package/package.json +3 -3
- package/dist/index-4uggw66b.js +0 -375
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
|
|
3
|
+
class Cast {
|
|
4
|
+
constructor({player, onReady, onUpdate}) {
|
|
5
|
+
this.player = player;
|
|
6
|
+
this.ready = false;
|
|
7
|
+
this.onReady = onReady;
|
|
8
|
+
this.connected = false;
|
|
9
|
+
this.playbackRate = 1;
|
|
10
|
+
|
|
11
|
+
window["__onGCastApiAvailable"] = isAvailable =>
|
|
12
|
+
isAvailable && this.Initialize();
|
|
13
|
+
|
|
14
|
+
window.CastController = this;
|
|
15
|
+
|
|
16
|
+
this.__listeners = [];
|
|
17
|
+
|
|
18
|
+
this.onUpdate = onUpdate;
|
|
19
|
+
|
|
20
|
+
this.LoadScript();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
LoadScript() {
|
|
24
|
+
const tag = document.createElement("script");
|
|
25
|
+
tag.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
|
|
26
|
+
document.querySelector("head").appendChild(tag);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Initialize() {
|
|
30
|
+
cast.framework.CastContext.getInstance().setOptions({
|
|
31
|
+
receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
|
|
32
|
+
//receiverApplicationId: "8E2BD113",
|
|
33
|
+
autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
this.remotePlayer = new cast.framework.RemotePlayer();
|
|
37
|
+
this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
|
|
38
|
+
|
|
39
|
+
this.remotePlayerController.addEventListener(
|
|
40
|
+
cast.framework.RemotePlayerEventType.ANY_CHANGE,
|
|
41
|
+
event => this.Update(event)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const context = cast.framework.CastContext.getInstance();
|
|
45
|
+
context.addEventListener(
|
|
46
|
+
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
|
47
|
+
event => {
|
|
48
|
+
switch (event.sessionState) {
|
|
49
|
+
case cast.framework.SessionState.SESSION_STARTED:
|
|
50
|
+
this.Start();
|
|
51
|
+
break;
|
|
52
|
+
case cast.framework.SessionState.SESSION_RESUMED:
|
|
53
|
+
break;
|
|
54
|
+
case cast.framework.SessionState.SESSION_ENDED:
|
|
55
|
+
this.Disconnect(true);
|
|
56
|
+
// Update locally as necessary
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.ready = true;
|
|
62
|
+
|
|
63
|
+
if(this.playoutUrl) {
|
|
64
|
+
this.onReady && this.onReady();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async SetMedia({playoutOptions, playoutParameters}) {
|
|
69
|
+
// Get dash options
|
|
70
|
+
let dashOptions = ((playoutOptions || {}).dash || {}).playoutMethods || {};
|
|
71
|
+
let options = dashOptions.clear || dashOptions.widevine;
|
|
72
|
+
|
|
73
|
+
if(!options) {
|
|
74
|
+
// Dash options might be available under the default_dash offering
|
|
75
|
+
try {
|
|
76
|
+
playoutOptions = await (await this.player.__Client()).PlayoutOptions({
|
|
77
|
+
...playoutParameters,
|
|
78
|
+
offering: "default_dash"
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
dashOptions = ((playoutOptions || {}).dash || {}).playoutMethods || {};
|
|
82
|
+
options = dashOptions.clear || dashOptions.widevine || {};
|
|
83
|
+
} catch(error) {
|
|
84
|
+
this.player.Log("Unable to find dash playout options for chromecast");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.playoutUrl = (options || {}).playoutUrl;
|
|
89
|
+
|
|
90
|
+
if(this.playoutUrl && this.ready) {
|
|
91
|
+
this.onReady && this.onReady();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async Start() {
|
|
96
|
+
this.player && this.player.__SetCasting(true);
|
|
97
|
+
|
|
98
|
+
window.addEventListener("beforeunload", () => this.Disconnect(true));
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
|
|
102
|
+
const mediaInfo = new chrome.cast.media.MediaInfo(this.playoutUrl, "application/dash+xml");
|
|
103
|
+
|
|
104
|
+
mediaInfo.contentUrl = this.playoutUrl;
|
|
105
|
+
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
|
|
106
|
+
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
|
|
107
|
+
mediaInfo.metadata.title = "Test Chromecast";
|
|
108
|
+
|
|
109
|
+
let { title, subtitle, image, headers } = (this.player.controls.GetContentInfo() || {});
|
|
110
|
+
mediaInfo.metadata.title = title || "Eluvio";
|
|
111
|
+
|
|
112
|
+
if(!subtitle && headers && headers.length > 0) {
|
|
113
|
+
subtitle = headers.join(" ");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
mediaInfo.metadata.subtitle = subtitle || "";
|
|
117
|
+
|
|
118
|
+
if(image) {
|
|
119
|
+
mediaInfo.metadata.images = [
|
|
120
|
+
new chrome.cast.Image(image)
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const request = new chrome.cast.media.LoadRequest(mediaInfo);
|
|
125
|
+
await castSession.loadMedia(request);
|
|
126
|
+
|
|
127
|
+
this.connected = true;
|
|
128
|
+
} catch(error) {
|
|
129
|
+
this.player.Log("Failed to start chromecast stream:", true);
|
|
130
|
+
this.player.Log(error, true);
|
|
131
|
+
this.Disconnect(true);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Controls */
|
|
136
|
+
IsPlaying() {
|
|
137
|
+
return !this.remotePlayer.isPaused;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
TogglePlay() {
|
|
141
|
+
this.remotePlayerController.playOrPause();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
GetCurrentTime() {
|
|
145
|
+
return this.remotePlayer.currentTime;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
GetDuration() {
|
|
149
|
+
return this.remotePlayer.duration || this.player.video.duration;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
Play() {
|
|
153
|
+
this.remotePlayer.isPaused && this.remotePlayerController.playOrPause();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Pause() {
|
|
157
|
+
!this.remotePlayer.isPaused && this.remotePlayerController.playOrPause();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Stop() {
|
|
161
|
+
this.remotePlayerController.stop();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
IsMuted() {
|
|
165
|
+
return this.remotePlayer.isMuted;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Mute() {
|
|
169
|
+
!this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Unmute() {
|
|
173
|
+
this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
ToggleMuted() {
|
|
177
|
+
this.remotePlayerController.muteOrUnmute();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
GetVolume() {
|
|
181
|
+
return this.remotePlayer.volumeLevel;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
SetVolume({fraction, relativeFraction}) {
|
|
185
|
+
let volume;
|
|
186
|
+
if(relativeFraction) {
|
|
187
|
+
volume = Math.min(1, Math.max(0, this.remotePlayer.volume + relativeFraction));
|
|
188
|
+
} else {
|
|
189
|
+
volume = fraction;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if(this.player.video.volume > 0) {
|
|
193
|
+
this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.remotePlayer.volumeLevel = volume;
|
|
197
|
+
this.remotePlayerController.setVolumeLevel();
|
|
198
|
+
|
|
199
|
+
return volume;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
Seek({fraction, time, relativeSeconds}) {
|
|
203
|
+
const originalTime = this.remotePlayer.currentTime;
|
|
204
|
+
|
|
205
|
+
if(relativeSeconds) {
|
|
206
|
+
time = Math.max(
|
|
207
|
+
0,
|
|
208
|
+
Math.min(
|
|
209
|
+
this.remotePlayer.duration,
|
|
210
|
+
this.remotePlayer.currentTime + relativeSeconds
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
} else if(typeof fraction !== "undefined") {
|
|
214
|
+
time = this.remotePlayer.duration * fraction;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.remotePlayer.currentTime = time;
|
|
218
|
+
this.remotePlayerController.seek();
|
|
219
|
+
|
|
220
|
+
return originalTime <= this.player.video.currentTime;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
GetPlaybackRate() {
|
|
224
|
+
return this.playbackRate || 1;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
SetPlaybackRate({index, rate}) {
|
|
228
|
+
if(typeof index !== "undefined") {
|
|
229
|
+
const option = this.player.controls.GetPlaybackRates().options[index];
|
|
230
|
+
|
|
231
|
+
if(option) {
|
|
232
|
+
rate = option.rate || 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
|
|
237
|
+
const media = castSession.getMediaSession();
|
|
238
|
+
castSession.sendMessage("urn:x-cast:com.google.cast.media",{
|
|
239
|
+
type: "SET_PLAYBACK_RATE",
|
|
240
|
+
playbackRate: rate,
|
|
241
|
+
mediaSessionId: media.mediaSessionId,
|
|
242
|
+
requestId: 2
|
|
243
|
+
})
|
|
244
|
+
.then(() => this.playbackRate = rate);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
Disconnect(force) {
|
|
248
|
+
(this.connected || force) && cast.framework.CastContext.getInstance().endCurrentSession();
|
|
249
|
+
this.connected = false;
|
|
250
|
+
this.player && this.player.__SetCasting(false);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Register a listener that will be called any time the video settings have changed
|
|
254
|
+
RegisterListener(listener) {
|
|
255
|
+
this.__listeners.push(listener);
|
|
256
|
+
|
|
257
|
+
return () => this.__listeners = this.__listeners.filter(l => l !== listener);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Indicate to controls that the settings have updated
|
|
261
|
+
Update(event) {
|
|
262
|
+
try {
|
|
263
|
+
this.onUpdate && this.onUpdate(event);
|
|
264
|
+
} catch(error) {
|
|
265
|
+
this.player.Log("Failed to call update listener", true);
|
|
266
|
+
this.player.Log(error, true);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.__listeners.forEach(listener => {
|
|
270
|
+
try {
|
|
271
|
+
listener(event);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
this.player.Log("Failed to call cast listener", true);
|
|
274
|
+
this.player.Log(error, true);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export default Cast;
|
package/lib/player/Controls.js
CHANGED
|
@@ -72,6 +72,8 @@ class PlayerControls {
|
|
|
72
72
|
* @returns {boolean} - Whether or not the video is currently playing
|
|
73
73
|
*/
|
|
74
74
|
IsPlaying() {
|
|
75
|
+
if(this.player.casting) { return this.player.castHandler.IsPlaying(); }
|
|
76
|
+
|
|
75
77
|
return !this.player.video.paused;
|
|
76
78
|
}
|
|
77
79
|
|
|
@@ -93,6 +95,8 @@ class PlayerControls {
|
|
|
93
95
|
* @returns {boolean} - Whether or not the video was able to start playing. Browser autoplay policies may block video from playing without user interaction.
|
|
94
96
|
*/
|
|
95
97
|
async Play() {
|
|
98
|
+
if(this.player.casting) { return this.player.castHandler.Play(); }
|
|
99
|
+
|
|
96
100
|
return await this.player.__Play();
|
|
97
101
|
}
|
|
98
102
|
|
|
@@ -102,6 +106,8 @@ class PlayerControls {
|
|
|
102
106
|
* @methodGroup Playback
|
|
103
107
|
*/
|
|
104
108
|
Pause() {
|
|
109
|
+
if(this.player.casting) { return this.player.castHandler.Pause(); }
|
|
110
|
+
|
|
105
111
|
this.player.video.pause();
|
|
106
112
|
}
|
|
107
113
|
|
|
@@ -112,6 +118,8 @@ class PlayerControls {
|
|
|
112
118
|
* @returns {boolean} - False if the video was paused, true if playback was started
|
|
113
119
|
*/
|
|
114
120
|
TogglePlay() {
|
|
121
|
+
if(this.player.casting) { return this.player.castHandler.TogglePlay(); }
|
|
122
|
+
|
|
115
123
|
if(this.player.video.paused) {
|
|
116
124
|
this.Play();
|
|
117
125
|
return true;
|
|
@@ -127,6 +135,8 @@ class PlayerControls {
|
|
|
127
135
|
* @methodGroup Playback
|
|
128
136
|
*/
|
|
129
137
|
Stop() {
|
|
138
|
+
if(this.player.casting) { return this.player.castHandler.Stop(); }
|
|
139
|
+
|
|
130
140
|
this.Pause();
|
|
131
141
|
this.Seek({time: 0});
|
|
132
142
|
this.player.playbackStarted = false;
|
|
@@ -142,6 +152,8 @@ class PlayerControls {
|
|
|
142
152
|
* @returns {number} - The current time of the video
|
|
143
153
|
*/
|
|
144
154
|
GetCurrentTime() {
|
|
155
|
+
if(this.player.casting) { return this.player.castHandler.GetCurrentTime(); }
|
|
156
|
+
|
|
145
157
|
return this.player.video.currentTime;
|
|
146
158
|
}
|
|
147
159
|
|
|
@@ -153,6 +165,8 @@ class PlayerControls {
|
|
|
153
165
|
* @returns {number} - The duration of the video. May be Infinity if content is live
|
|
154
166
|
*/
|
|
155
167
|
GetDuration() {
|
|
168
|
+
if(this.player.casting) { return this.player.castHandler.GetDuration(); }
|
|
169
|
+
|
|
156
170
|
return this.player.video.duration;
|
|
157
171
|
}
|
|
158
172
|
|
|
@@ -168,6 +182,8 @@ class PlayerControls {
|
|
|
168
182
|
* @returns {boolean} - False if the video was paused, true if playback was started
|
|
169
183
|
*/
|
|
170
184
|
Seek({fraction, time, relativeSeconds}) {
|
|
185
|
+
if(this.player.casting) { return this.player.castHandler.Seek({fraction, time, relativeSeconds}); }
|
|
186
|
+
|
|
171
187
|
if(!this.player.video || (fraction && !this.player.video.duration)) {
|
|
172
188
|
return;
|
|
173
189
|
}
|
|
@@ -199,6 +215,8 @@ class PlayerControls {
|
|
|
199
215
|
* @returns {number} - The current volume of the video
|
|
200
216
|
*/
|
|
201
217
|
GetVolume() {
|
|
218
|
+
if(this.player.casting) { return this.player.castHandler.GetVolume(); }
|
|
219
|
+
|
|
202
220
|
return this.player.video.volume;
|
|
203
221
|
}
|
|
204
222
|
|
|
@@ -213,6 +231,8 @@ class PlayerControls {
|
|
|
213
231
|
* @returns {boolean} - The resulting volume of the video
|
|
214
232
|
*/
|
|
215
233
|
SetVolume({fraction, relativeFraction}) {
|
|
234
|
+
if(this.player.casting) { return this.player.castHandler.SetVolume({fraction, relativeFraction}); }
|
|
235
|
+
|
|
216
236
|
if(relativeFraction) {
|
|
217
237
|
this.player.video.volume = Math.min(1, Math.max(0, this.GetVolume() + relativeFraction));
|
|
218
238
|
} else {
|
|
@@ -234,6 +254,8 @@ class PlayerControls {
|
|
|
234
254
|
* @returns {boolean} - Whether or not the video is currently muted
|
|
235
255
|
*/
|
|
236
256
|
IsMuted() {
|
|
257
|
+
if(this.player.casting) { return this.player.castHandler.IsMuted(); }
|
|
258
|
+
|
|
237
259
|
return this.player.video.muted;
|
|
238
260
|
}
|
|
239
261
|
|
|
@@ -243,6 +265,8 @@ class PlayerControls {
|
|
|
243
265
|
* @methodGroup Volume
|
|
244
266
|
*/
|
|
245
267
|
Mute() {
|
|
268
|
+
if(this.player.casting) { return this.player.castHandler.Mute(); }
|
|
269
|
+
|
|
246
270
|
this.player.video.muted = true;
|
|
247
271
|
}
|
|
248
272
|
|
|
@@ -252,6 +276,8 @@ class PlayerControls {
|
|
|
252
276
|
* @methodGroup Volume
|
|
253
277
|
*/
|
|
254
278
|
Unmute() {
|
|
279
|
+
if(this.player.casting) { return this.player.castHandler.Unmute(); }
|
|
280
|
+
|
|
255
281
|
this.player.video.muted = false;
|
|
256
282
|
}
|
|
257
283
|
|
|
@@ -263,6 +289,8 @@ class PlayerControls {
|
|
|
263
289
|
* @returns {boolean} - True if the video was muted, false if unmuted
|
|
264
290
|
*/
|
|
265
291
|
ToggleMuted() {
|
|
292
|
+
if(this.player.casting) { return this.player.castHandler.ToggleMuted(); }
|
|
293
|
+
|
|
266
294
|
this.player.video.muted = !this.player.video.muted;
|
|
267
295
|
return this.player.video.muted;
|
|
268
296
|
}
|
|
@@ -667,12 +695,14 @@ class PlayerControls {
|
|
|
667
695
|
tracks[index].mode = "showing";
|
|
668
696
|
}
|
|
669
697
|
} else if(this.player.dashPlayer) {
|
|
670
|
-
this.player.dashPlayer.setTextTrack(
|
|
698
|
+
this.player.dashPlayer.setTextTrack(index);
|
|
671
699
|
}
|
|
672
700
|
|
|
673
701
|
if(index >= 0) {
|
|
674
702
|
this.__lastTextTrackIndex = index;
|
|
675
703
|
}
|
|
704
|
+
|
|
705
|
+
setTimeout(() => this.player.__SettingsUpdate(), 500);
|
|
676
706
|
}
|
|
677
707
|
|
|
678
708
|
/**
|
|
@@ -715,6 +745,19 @@ class PlayerControls {
|
|
|
715
745
|
}
|
|
716
746
|
}
|
|
717
747
|
|
|
748
|
+
/**
|
|
749
|
+
* Retrieve the current playback rate
|
|
750
|
+
*
|
|
751
|
+
* @methodGroup Playback Rate
|
|
752
|
+
*
|
|
753
|
+
* @returns {number} - The current playback rate
|
|
754
|
+
*/
|
|
755
|
+
GetPlaybackRate() {
|
|
756
|
+
if(this.player.casting) { return this.player.castHandler.GetPlaybackRate(); }
|
|
757
|
+
|
|
758
|
+
return this.player.video.playbackRate || 1;
|
|
759
|
+
}
|
|
760
|
+
|
|
718
761
|
/**
|
|
719
762
|
* Retrieve the currently available playback rates
|
|
720
763
|
*
|
|
@@ -723,12 +766,20 @@ class PlayerControls {
|
|
|
723
766
|
* @returns {Object} - All options, as well as the active option.
|
|
724
767
|
*/
|
|
725
768
|
GetPlaybackRates() {
|
|
726
|
-
const
|
|
769
|
+
const currentPlaybackRate = this.GetPlaybackRate();
|
|
770
|
+
let options = ["0.25", "0.5", "0.75", "1", "1.25", "1.5", "1.75", "2"];
|
|
771
|
+
|
|
772
|
+
// Chromecast doesn't support < 0.5
|
|
773
|
+
if(this.player.casting) {
|
|
774
|
+
options = ["0.5", "0.75", "1", "1.25", "1.5", "1.75", "2"];
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
options = options
|
|
727
778
|
.map((speed, index) => ({
|
|
728
779
|
index,
|
|
729
780
|
rate: parseFloat(speed),
|
|
730
781
|
label: `${speed}x`,
|
|
731
|
-
active:
|
|
782
|
+
active: currentPlaybackRate.toFixed(2) === parseFloat(speed).toFixed(2)
|
|
732
783
|
}));
|
|
733
784
|
|
|
734
785
|
let active = options.find(option => option.active);
|
|
@@ -736,8 +787,8 @@ class PlayerControls {
|
|
|
736
787
|
if(!active) {
|
|
737
788
|
active = {
|
|
738
789
|
index: -1,
|
|
739
|
-
rate: this.
|
|
740
|
-
label: `${this.
|
|
790
|
+
rate: this.GetPlaybackRate(),
|
|
791
|
+
label: `${this.GetPlaybackRate()}x`,
|
|
741
792
|
active: true
|
|
742
793
|
};
|
|
743
794
|
}
|
|
@@ -759,6 +810,8 @@ class PlayerControls {
|
|
|
759
810
|
* @returns {Object} - The rate that was set, as well as whether the rate was increased or decreased
|
|
760
811
|
*/
|
|
761
812
|
SetPlaybackRate({index, rate}) {
|
|
813
|
+
if(this.player.casting) { return this.player.castHandler.SetPlaybackRate({index, rate}); }
|
|
814
|
+
|
|
762
815
|
const originalSpeed = this.player.video.playbackRate;
|
|
763
816
|
|
|
764
817
|
if(rate) {
|
|
@@ -780,6 +833,51 @@ class PlayerControls {
|
|
|
780
833
|
}
|
|
781
834
|
}
|
|
782
835
|
|
|
836
|
+
/**
|
|
837
|
+
* Retrieve whether or not DVR is available for the current content
|
|
838
|
+
*
|
|
839
|
+
* @methodGroup DVR
|
|
840
|
+
*
|
|
841
|
+
* @returns {boolean} - Whether or not DVR is available for the current content
|
|
842
|
+
*/
|
|
843
|
+
IsDVRAvailable() {
|
|
844
|
+
return this.player.dvrAvailable && !this.player.casting && isFinite(this.GetDuration());
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Retrieve whether or not DVR is active for the current content
|
|
849
|
+
*
|
|
850
|
+
* @methodGroup DVR
|
|
851
|
+
*
|
|
852
|
+
* @returns {boolean} - Whether or not DVR is active for the current content
|
|
853
|
+
*/
|
|
854
|
+
IsDVREnabled() {
|
|
855
|
+
return this.player.dvrEnabled;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Activate or deactivate DVR (if available)
|
|
860
|
+
*
|
|
861
|
+
* @methodGroup DVR
|
|
862
|
+
* @param {boolean} enabled - Whether or not DVR should be enabled
|
|
863
|
+
*
|
|
864
|
+
* @returns {boolean} - If DVR is enabled or disabled
|
|
865
|
+
*/
|
|
866
|
+
SetDVREnabled(enabled) {
|
|
867
|
+
const originallyEnabled = this.player.dvrEnabled;
|
|
868
|
+
|
|
869
|
+
this.player.dvrEnabled = this.IsDVRAvailable() && enabled;
|
|
870
|
+
|
|
871
|
+
this.player.__SettingsUpdate();
|
|
872
|
+
|
|
873
|
+
if(originallyEnabled && !this.player.dvrEnabled) {
|
|
874
|
+
// Seek to live edge if DVR was disabled
|
|
875
|
+
this.Seek({time: this.GetDuration() - 2});
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
return this.player.dvrEnabled;
|
|
879
|
+
}
|
|
880
|
+
|
|
783
881
|
/**
|
|
784
882
|
* Retrieve the currently available player profiles
|
|
785
883
|
*
|