@eluvio/elv-player-js 2.0.22 → 2.0.24
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-B5-vVweo.js → Analytics-B0y2dvhs.js} +1 -1
- package/dist/{Analytics-DMv5C4jR.mjs → Analytics-DJ_v0bIw.mjs} +1 -1
- package/dist/{dash.all.min-DdJwXkcr.js → dash.all.min-BFqp01gO.js} +1 -1
- package/dist/{dash.all.min-D6KUBLpO.mjs → dash.all.min-Bsq3_rAF.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-M64Z5q4j.js → index-CWpTu79Y.js} +3 -3
- package/dist/{index-CD_eflzW.mjs → index-TLjW30UD.mjs} +77 -79
- package/dist/{index-BAQHi25X.mjs → index-icVCF-A6.mjs} +19146 -19096
- package/dist/index-yaG_tNvS.js +378 -0
- package/lib/player/Cast.js +286 -0
- package/lib/player/Controls.js +100 -4
- package/lib/player/Player.js +84 -12
- 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-Bw8z3Iax.js +0 -375
|
@@ -0,0 +1,286 @@
|
|
|
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
|
+
this.__listeners = [];
|
|
11
|
+
this.onUpdate = onUpdate;
|
|
12
|
+
|
|
13
|
+
if(window.__chromecastAvailable || (window.chrome && window.chrome.cast)) {
|
|
14
|
+
// Chromecast already initialized
|
|
15
|
+
this.Initialize();
|
|
16
|
+
} else {
|
|
17
|
+
// Initialize chromecast script
|
|
18
|
+
window["__onGCastApiAvailable"] = isAvailable => {
|
|
19
|
+
if(isAvailable) {
|
|
20
|
+
window.__chromecastAvailable = true;
|
|
21
|
+
this.Initialize();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
this.LoadScript();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
LoadScript() {
|
|
30
|
+
const tag = document.createElement("script");
|
|
31
|
+
tag.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
|
|
32
|
+
document.querySelector("head").appendChild(tag);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Initialize() {
|
|
36
|
+
cast.framework.CastContext.getInstance().setOptions({
|
|
37
|
+
receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
|
|
38
|
+
//receiverApplicationId: "8E2BD113",
|
|
39
|
+
autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.remotePlayer = new cast.framework.RemotePlayer();
|
|
43
|
+
this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
|
|
44
|
+
|
|
45
|
+
this.remotePlayerController.addEventListener(
|
|
46
|
+
cast.framework.RemotePlayerEventType.ANY_CHANGE,
|
|
47
|
+
event => this.Update(event)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const context = cast.framework.CastContext.getInstance();
|
|
51
|
+
context.addEventListener(
|
|
52
|
+
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
|
53
|
+
event => {
|
|
54
|
+
switch (event.sessionState) {
|
|
55
|
+
case cast.framework.SessionState.SESSION_STARTED:
|
|
56
|
+
this.Start();
|
|
57
|
+
break;
|
|
58
|
+
case cast.framework.SessionState.SESSION_RESUMED:
|
|
59
|
+
break;
|
|
60
|
+
case cast.framework.SessionState.SESSION_ENDED:
|
|
61
|
+
this.Disconnect(true);
|
|
62
|
+
// Update locally as necessary
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.ready = true;
|
|
68
|
+
|
|
69
|
+
if(this.playoutUrl) {
|
|
70
|
+
this.onReady && this.onReady();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async SetMedia({playoutOptions, playoutParameters}) {
|
|
75
|
+
// Get dash options
|
|
76
|
+
let dashOptions = ((playoutOptions || {}).dash || {}).playoutMethods || {};
|
|
77
|
+
let options = dashOptions.clear;
|
|
78
|
+
|
|
79
|
+
if(!options) {
|
|
80
|
+
// Dash options might be available under the default_dash offering
|
|
81
|
+
try {
|
|
82
|
+
playoutOptions = await (await this.player.__Client()).PlayoutOptions({
|
|
83
|
+
...playoutParameters,
|
|
84
|
+
offering: "default_dash"
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
dashOptions = ((playoutOptions || {}).dash || {}).playoutMethods || {};
|
|
88
|
+
options = dashOptions.clear || {};
|
|
89
|
+
} catch(error) {
|
|
90
|
+
this.player.Log("Unable to find dash playout options for chromecast");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.playoutUrl = (options || {}).playoutUrl;
|
|
95
|
+
|
|
96
|
+
if(this.playoutUrl && this.ready) {
|
|
97
|
+
this.onReady && this.onReady();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async Start() {
|
|
102
|
+
this.player && this.player.__SetCasting(true);
|
|
103
|
+
|
|
104
|
+
window.addEventListener("beforeunload", () => this.Disconnect(true));
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
|
|
108
|
+
const mediaInfo = new chrome.cast.media.MediaInfo(this.playoutUrl, "application/dash+xml");
|
|
109
|
+
|
|
110
|
+
mediaInfo.contentUrl = this.playoutUrl;
|
|
111
|
+
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
|
|
112
|
+
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
|
|
113
|
+
mediaInfo.metadata.title = "Test Chromecast";
|
|
114
|
+
|
|
115
|
+
let { title, subtitle, image, headers } = (this.player.controls.GetContentInfo() || {});
|
|
116
|
+
mediaInfo.metadata.title = title || "Eluvio";
|
|
117
|
+
|
|
118
|
+
if(!subtitle && headers && headers.length > 0) {
|
|
119
|
+
subtitle = headers.join(" ");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
mediaInfo.metadata.subtitle = subtitle || "";
|
|
123
|
+
|
|
124
|
+
if(image) {
|
|
125
|
+
mediaInfo.metadata.images = [
|
|
126
|
+
new chrome.cast.Image(image)
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const request = new chrome.cast.media.LoadRequest(mediaInfo);
|
|
131
|
+
await castSession.loadMedia(request);
|
|
132
|
+
|
|
133
|
+
this.connected = true;
|
|
134
|
+
} catch(error) {
|
|
135
|
+
this.player.Log("Failed to start chromecast stream:", true);
|
|
136
|
+
this.player.Log(error, true);
|
|
137
|
+
this.Disconnect(true);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Controls */
|
|
142
|
+
IsPlaying() {
|
|
143
|
+
return !this.remotePlayer.isPaused;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
TogglePlay() {
|
|
147
|
+
this.remotePlayerController.playOrPause();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
GetCurrentTime() {
|
|
151
|
+
return this.remotePlayer.currentTime;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
GetDuration() {
|
|
155
|
+
return this.remotePlayer.duration || this.player.video.duration;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
Play() {
|
|
159
|
+
this.remotePlayer.isPaused && this.remotePlayerController.playOrPause();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Pause() {
|
|
163
|
+
!this.remotePlayer.isPaused && this.remotePlayerController.playOrPause();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
Stop() {
|
|
167
|
+
this.remotePlayerController.stop();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
IsMuted() {
|
|
171
|
+
return this.remotePlayer.isMuted;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Mute() {
|
|
175
|
+
!this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Unmute() {
|
|
179
|
+
this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
ToggleMuted() {
|
|
183
|
+
this.remotePlayerController.muteOrUnmute();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
GetVolume() {
|
|
187
|
+
return this.remotePlayer.volumeLevel;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
SetVolume({fraction, relativeFraction}) {
|
|
191
|
+
let volume;
|
|
192
|
+
if(relativeFraction) {
|
|
193
|
+
volume = Math.min(1, Math.max(0, this.remotePlayer.volume + relativeFraction));
|
|
194
|
+
} else {
|
|
195
|
+
volume = fraction;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if(this.player.video.volume > 0) {
|
|
199
|
+
this.remotePlayer.isMuted && this.remotePlayerController.muteOrUnmute();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this.remotePlayer.volumeLevel = volume;
|
|
203
|
+
this.remotePlayerController.setVolumeLevel();
|
|
204
|
+
|
|
205
|
+
return volume;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Seek({fraction, time, relativeSeconds}) {
|
|
209
|
+
const originalTime = this.remotePlayer.currentTime;
|
|
210
|
+
|
|
211
|
+
if(relativeSeconds) {
|
|
212
|
+
time = Math.max(
|
|
213
|
+
0,
|
|
214
|
+
Math.min(
|
|
215
|
+
this.remotePlayer.duration,
|
|
216
|
+
this.remotePlayer.currentTime + relativeSeconds
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
} else if(typeof fraction !== "undefined") {
|
|
220
|
+
time = this.remotePlayer.duration * fraction;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
this.remotePlayer.currentTime = time;
|
|
224
|
+
this.remotePlayerController.seek();
|
|
225
|
+
|
|
226
|
+
return originalTime <= this.player.video.currentTime;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
GetPlaybackRate() {
|
|
230
|
+
return this.playbackRate || 1;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
SetPlaybackRate({index, rate}) {
|
|
234
|
+
if(typeof index !== "undefined") {
|
|
235
|
+
const option = this.player.controls.GetPlaybackRates().options[index];
|
|
236
|
+
|
|
237
|
+
if(option) {
|
|
238
|
+
rate = option.rate || 1;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
|
|
243
|
+
const media = castSession.getMediaSession();
|
|
244
|
+
castSession.sendMessage("urn:x-cast:com.google.cast.media",{
|
|
245
|
+
type: "SET_PLAYBACK_RATE",
|
|
246
|
+
playbackRate: rate,
|
|
247
|
+
mediaSessionId: media.mediaSessionId,
|
|
248
|
+
requestId: 2
|
|
249
|
+
})
|
|
250
|
+
.then(() => this.playbackRate = rate);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Disconnect(force) {
|
|
254
|
+
(this.connected || force) && cast.framework.CastContext.getInstance().endCurrentSession();
|
|
255
|
+
this.connected = false;
|
|
256
|
+
this.player && this.player.__SetCasting(false);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Register a listener that will be called any time the video settings have changed
|
|
260
|
+
RegisterListener(listener) {
|
|
261
|
+
this.__listeners.push(listener);
|
|
262
|
+
|
|
263
|
+
return () => this.__listeners = this.__listeners.filter(l => l !== listener);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Indicate to controls that the settings have updated
|
|
267
|
+
Update(event) {
|
|
268
|
+
try {
|
|
269
|
+
this.onUpdate && this.onUpdate(event);
|
|
270
|
+
} catch(error) {
|
|
271
|
+
this.player.Log("Failed to call update listener", true);
|
|
272
|
+
this.player.Log(error, true);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
this.__listeners.forEach(listener => {
|
|
276
|
+
try {
|
|
277
|
+
listener(event);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
this.player.Log("Failed to call cast listener", true);
|
|
280
|
+
this.player.Log(error, true);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
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
|
}
|
|
@@ -717,6 +745,19 @@ class PlayerControls {
|
|
|
717
745
|
}
|
|
718
746
|
}
|
|
719
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
|
+
|
|
720
761
|
/**
|
|
721
762
|
* Retrieve the currently available playback rates
|
|
722
763
|
*
|
|
@@ -725,12 +766,20 @@ class PlayerControls {
|
|
|
725
766
|
* @returns {Object} - All options, as well as the active option.
|
|
726
767
|
*/
|
|
727
768
|
GetPlaybackRates() {
|
|
728
|
-
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
|
|
729
778
|
.map((speed, index) => ({
|
|
730
779
|
index,
|
|
731
780
|
rate: parseFloat(speed),
|
|
732
781
|
label: `${speed}x`,
|
|
733
|
-
active:
|
|
782
|
+
active: currentPlaybackRate.toFixed(2) === parseFloat(speed).toFixed(2)
|
|
734
783
|
}));
|
|
735
784
|
|
|
736
785
|
let active = options.find(option => option.active);
|
|
@@ -738,8 +787,8 @@ class PlayerControls {
|
|
|
738
787
|
if(!active) {
|
|
739
788
|
active = {
|
|
740
789
|
index: -1,
|
|
741
|
-
rate: this.
|
|
742
|
-
label: `${this.
|
|
790
|
+
rate: this.GetPlaybackRate(),
|
|
791
|
+
label: `${this.GetPlaybackRate()}x`,
|
|
743
792
|
active: true
|
|
744
793
|
};
|
|
745
794
|
}
|
|
@@ -761,6 +810,8 @@ class PlayerControls {
|
|
|
761
810
|
* @returns {Object} - The rate that was set, as well as whether the rate was increased or decreased
|
|
762
811
|
*/
|
|
763
812
|
SetPlaybackRate({index, rate}) {
|
|
813
|
+
if(this.player.casting) { return this.player.castHandler.SetPlaybackRate({index, rate}); }
|
|
814
|
+
|
|
764
815
|
const originalSpeed = this.player.video.playbackRate;
|
|
765
816
|
|
|
766
817
|
if(rate) {
|
|
@@ -782,6 +833,51 @@ class PlayerControls {
|
|
|
782
833
|
}
|
|
783
834
|
}
|
|
784
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
|
+
|
|
785
881
|
/**
|
|
786
882
|
* Retrieve the currently available player profiles
|
|
787
883
|
*
|