@stremio/stremio-video 0.0.58 → 0.0.60
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/package.json
CHANGED
|
@@ -103,6 +103,7 @@ function HTMLVideo(options) {
|
|
|
103
103
|
var destroyed = false;
|
|
104
104
|
var stream = null;
|
|
105
105
|
var subtitlesOffset = 0;
|
|
106
|
+
var subtitlesOpacity = 1;
|
|
106
107
|
var observedProps = {
|
|
107
108
|
stream: false,
|
|
108
109
|
loaded: false,
|
|
@@ -244,6 +245,13 @@ function HTMLVideo(options) {
|
|
|
244
245
|
|
|
245
246
|
return styleElement.sheet.cssRules[0].style.textShadow.slice(0, styleElement.sheet.cssRules[0].style.textShadow.indexOf(')') + 1);
|
|
246
247
|
}
|
|
248
|
+
case 'subtitlesOpacity': {
|
|
249
|
+
if (destroyed) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return Math.round(subtitlesOpacity * 100);
|
|
254
|
+
}
|
|
247
255
|
case 'audioTracks': {
|
|
248
256
|
if (hls === null || !Array.isArray(hls.audioTracks)) {
|
|
249
257
|
return [];
|
|
@@ -460,6 +468,21 @@ function HTMLVideo(options) {
|
|
|
460
468
|
|
|
461
469
|
break;
|
|
462
470
|
}
|
|
471
|
+
case 'subtitlesOpacity': {
|
|
472
|
+
if (typeof propValue === 'number') {
|
|
473
|
+
try {
|
|
474
|
+
subtitlesOpacity = Math.min(Math.max(propValue / 100, 0), 1);
|
|
475
|
+
styleElement.sheet.cssRules[0].style.opacity = subtitlesOpacity + '';
|
|
476
|
+
} catch (error) {
|
|
477
|
+
// eslint-disable-next-line no-console
|
|
478
|
+
console.error('VVideo with HTML Subtitles', error);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
onPropChanged('subtitlesOpacity');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
463
486
|
case 'selectedAudioTrackId': {
|
|
464
487
|
if (hls !== null) {
|
|
465
488
|
var selecterdAudioTrack = getProp('audioTracks')
|
|
@@ -591,6 +614,7 @@ function HTMLVideo(options) {
|
|
|
591
614
|
onPropChanged('subtitlesTextColor');
|
|
592
615
|
onPropChanged('subtitlesBackgroundColor');
|
|
593
616
|
onPropChanged('subtitlesOutlineColor');
|
|
617
|
+
onPropChanged('subtitlesOpacity');
|
|
594
618
|
onPropChanged('volume');
|
|
595
619
|
onPropChanged('muted');
|
|
596
620
|
onPropChanged('playbackSpeed');
|
|
@@ -671,7 +695,7 @@ HTMLVideo.canPlayStream = function(stream) {
|
|
|
671
695
|
HTMLVideo.manifest = {
|
|
672
696
|
name: 'HTMLVideo',
|
|
673
697
|
external: false,
|
|
674
|
-
props: ['stream', 'loaded', 'paused', 'time', 'duration', 'buffering', 'buffered', 'audioTracks', 'selectedAudioTrackId', 'subtitlesTracks', 'selectedSubtitlesTrackId', 'subtitlesOffset', 'subtitlesSize', 'subtitlesTextColor', 'subtitlesBackgroundColor', 'subtitlesOutlineColor', 'volume', 'muted', 'playbackSpeed'],
|
|
698
|
+
props: ['stream', 'loaded', 'paused', 'time', 'duration', 'buffering', 'buffered', 'audioTracks', 'selectedAudioTrackId', 'subtitlesTracks', 'selectedSubtitlesTrackId', 'subtitlesOffset', 'subtitlesSize', 'subtitlesTextColor', 'subtitlesBackgroundColor', 'subtitlesOutlineColor', 'subtitlesOpacity', 'volume', 'muted', 'playbackSpeed'],
|
|
675
699
|
commands: ['load', 'unload', 'destroy'],
|
|
676
700
|
events: ['propValue', 'propChanged', 'ended', 'error', 'subtitlesTrackLoaded', 'audioTrackLoaded']
|
|
677
701
|
};
|
|
@@ -161,6 +161,13 @@ function ShellVideo(options) {
|
|
|
161
161
|
props[args.name] = Math.round(args.data*1000);
|
|
162
162
|
break;
|
|
163
163
|
}
|
|
164
|
+
case 'volume': {
|
|
165
|
+
if (typeof args.data === 'number' && isFinite(args.data)) {
|
|
166
|
+
props[args.name] = args.data;
|
|
167
|
+
onPropChanged('volume');
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
164
171
|
case 'paused-for-cache':
|
|
165
172
|
case 'seeking':
|
|
166
173
|
{
|
|
@@ -391,7 +398,6 @@ function ShellVideo(options) {
|
|
|
391
398
|
onPropChanged('time');
|
|
392
399
|
onPropChanged('duration');
|
|
393
400
|
onPropChanged('buffering');
|
|
394
|
-
onPropChanged('volume');
|
|
395
401
|
onPropChanged('muted');
|
|
396
402
|
onPropChanged('subtitlesTracks');
|
|
397
403
|
onPropChanged('selectedSubtitlesTrackId');
|
|
@@ -424,7 +430,6 @@ function ShellVideo(options) {
|
|
|
424
430
|
onPropChanged('time');
|
|
425
431
|
onPropChanged('duration');
|
|
426
432
|
onPropChanged('buffering');
|
|
427
|
-
onPropChanged('volume');
|
|
428
433
|
onPropChanged('muted');
|
|
429
434
|
onPropChanged('subtitlesTracks');
|
|
430
435
|
onPropChanged('selectedSubtitlesTrackId');
|
|
@@ -3,6 +3,7 @@ var ShellVideo = require('../ShellVideo');
|
|
|
3
3
|
var HTMLVideo = require('../HTMLVideo');
|
|
4
4
|
var TizenVideo = require('../TizenVideo');
|
|
5
5
|
var TitanVideo = require('../TitanVideo');
|
|
6
|
+
var VidaaVideo = require('../VidaaVideo');
|
|
6
7
|
var WebOsVideo = require('../WebOsVideo');
|
|
7
8
|
var IFrameVideo = require('../IFrameVideo');
|
|
8
9
|
var YouTubeVideo = require('../YouTubeVideo');
|
|
@@ -38,9 +39,12 @@ function selectVideoImplementation(commandArgs, options) {
|
|
|
38
39
|
if (commandArgs.platform === 'webOS') {
|
|
39
40
|
return withStreamingServer(withHTMLSubtitles(WebOsVideo));
|
|
40
41
|
}
|
|
41
|
-
if (commandArgs.platform === 'Titan' || commandArgs.platform === 'NetTV'
|
|
42
|
+
if (commandArgs.platform === 'Titan' || commandArgs.platform === 'NetTV') {
|
|
42
43
|
return withStreamingServer(withHTMLSubtitles(TitanVideo));
|
|
43
44
|
}
|
|
45
|
+
if (commandArgs.platform === 'Vidaa') {
|
|
46
|
+
return withStreamingServer(withHTMLSubtitles(VidaaVideo));
|
|
47
|
+
}
|
|
44
48
|
return withStreamingServer(withHTMLSubtitles(HTMLVideo));
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -51,9 +55,12 @@ function selectVideoImplementation(commandArgs, options) {
|
|
|
51
55
|
if (commandArgs.platform === 'webOS') {
|
|
52
56
|
return withVideoParams(withHTMLSubtitles(WebOsVideo));
|
|
53
57
|
}
|
|
54
|
-
if (commandArgs.platform === 'Titan' || commandArgs.platform === 'NetTV'
|
|
58
|
+
if (commandArgs.platform === 'Titan' || commandArgs.platform === 'NetTV') {
|
|
55
59
|
return withVideoParams(withHTMLSubtitles(TitanVideo));
|
|
56
60
|
}
|
|
61
|
+
if (commandArgs.platform === 'Vidaa') {
|
|
62
|
+
return withVideoParams(withHTMLSubtitles(VidaaVideo));
|
|
63
|
+
}
|
|
57
64
|
return withVideoParams(withHTMLSubtitles(HTMLVideo));
|
|
58
65
|
}
|
|
59
66
|
|
|
@@ -157,8 +157,7 @@ function TitanVideo(options) {
|
|
|
157
157
|
cueNode.innerHTML = text;
|
|
158
158
|
cueNode.style.display = 'inline-block';
|
|
159
159
|
cueNode.style.padding = '0.2em';
|
|
160
|
-
|
|
161
|
-
cueNode.style.fontSize = Math.floor((size / 25) * fontSizeMultiplier) + 'vmin';
|
|
160
|
+
cueNode.style.fontSize = Math.floor(size / 25) + 'vmin';
|
|
162
161
|
cueNode.style.color = textColor;
|
|
163
162
|
cueNode.style.backgroundColor = backgroundColor;
|
|
164
163
|
cueNode.style.textShadow = '1px 1px 0.1em ' + outlineColor;
|
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
var EventEmitter = require('eventemitter3');
|
|
2
|
+
var cloneDeep = require('lodash.clonedeep');
|
|
3
|
+
var deepFreeze = require('deep-freeze');
|
|
4
|
+
var ERROR = require('../error');
|
|
5
|
+
|
|
6
|
+
var SSA_DESCRIPTORS_REGEX = /^\{(\\an[1-8])+\}/i;
|
|
7
|
+
|
|
8
|
+
function VidaaVideo(options) {
|
|
9
|
+
options = options || {};
|
|
10
|
+
|
|
11
|
+
var containerElement = options.containerElement;
|
|
12
|
+
if (!(containerElement instanceof HTMLElement)) {
|
|
13
|
+
throw new Error('Container element required to be instance of HTMLElement');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var videoElement = document.createElement('video');
|
|
17
|
+
videoElement.style.width = '100%';
|
|
18
|
+
videoElement.style.height = '100%';
|
|
19
|
+
videoElement.style.backgroundColor = 'black';
|
|
20
|
+
videoElement.controls = false;
|
|
21
|
+
videoElement.playsInline = true;
|
|
22
|
+
videoElement.onerror = function() {
|
|
23
|
+
onVideoError();
|
|
24
|
+
};
|
|
25
|
+
videoElement.onended = function() {
|
|
26
|
+
onEnded();
|
|
27
|
+
};
|
|
28
|
+
videoElement.onpause = function() {
|
|
29
|
+
onPropChanged('paused');
|
|
30
|
+
};
|
|
31
|
+
videoElement.onplay = function() {
|
|
32
|
+
onPropChanged('paused');
|
|
33
|
+
};
|
|
34
|
+
videoElement.ontimeupdate = function() {
|
|
35
|
+
onPropChanged('time');
|
|
36
|
+
};
|
|
37
|
+
videoElement.ondurationchange = function() {
|
|
38
|
+
onPropChanged('duration');
|
|
39
|
+
};
|
|
40
|
+
videoElement.onwaiting = function() {
|
|
41
|
+
onPropChanged('buffering');
|
|
42
|
+
};
|
|
43
|
+
videoElement.onseeking = function() {
|
|
44
|
+
onPropChanged('time');
|
|
45
|
+
onPropChanged('buffering');
|
|
46
|
+
};
|
|
47
|
+
videoElement.onseeked = function() {
|
|
48
|
+
onPropChanged('time');
|
|
49
|
+
onPropChanged('buffering');
|
|
50
|
+
};
|
|
51
|
+
videoElement.onstalled = function() {
|
|
52
|
+
onPropChanged('buffering');
|
|
53
|
+
};
|
|
54
|
+
videoElement.onplaying = function() {
|
|
55
|
+
onPropChanged('time');
|
|
56
|
+
onPropChanged('buffering');
|
|
57
|
+
};
|
|
58
|
+
videoElement.oncanplay = function() {
|
|
59
|
+
onPropChanged('buffering');
|
|
60
|
+
};
|
|
61
|
+
videoElement.canplaythrough = function() {
|
|
62
|
+
onPropChanged('buffering');
|
|
63
|
+
};
|
|
64
|
+
videoElement.onloadedmetadata = function() {
|
|
65
|
+
onPropChanged('loaded');
|
|
66
|
+
};
|
|
67
|
+
videoElement.onloadeddata = function() {
|
|
68
|
+
onPropChanged('buffering');
|
|
69
|
+
};
|
|
70
|
+
videoElement.onvolumechange = function() {
|
|
71
|
+
onPropChanged('volume');
|
|
72
|
+
onPropChanged('muted');
|
|
73
|
+
};
|
|
74
|
+
videoElement.onratechange = function() {
|
|
75
|
+
onPropChanged('playbackSpeed');
|
|
76
|
+
};
|
|
77
|
+
videoElement.textTracks.onchange = function() {
|
|
78
|
+
onPropChanged('subtitlesTracks');
|
|
79
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
80
|
+
onCueChange();
|
|
81
|
+
Array.from(videoElement.textTracks).forEach(function(track) {
|
|
82
|
+
track.oncuechange = onCueChange;
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
containerElement.appendChild(videoElement);
|
|
86
|
+
|
|
87
|
+
var subtitlesElement = document.createElement('div');
|
|
88
|
+
subtitlesElement.style.position = 'absolute';
|
|
89
|
+
subtitlesElement.style.right = '0';
|
|
90
|
+
subtitlesElement.style.bottom = '0';
|
|
91
|
+
subtitlesElement.style.left = '0';
|
|
92
|
+
subtitlesElement.style.zIndex = '1';
|
|
93
|
+
subtitlesElement.style.textAlign = 'center';
|
|
94
|
+
containerElement.style.position = 'relative';
|
|
95
|
+
containerElement.style.zIndex = '0';
|
|
96
|
+
containerElement.appendChild(subtitlesElement);
|
|
97
|
+
|
|
98
|
+
var events = new EventEmitter();
|
|
99
|
+
var destroyed = false;
|
|
100
|
+
var stream = null;
|
|
101
|
+
var observedProps = {
|
|
102
|
+
stream: false,
|
|
103
|
+
loaded: false,
|
|
104
|
+
paused: false,
|
|
105
|
+
time: false,
|
|
106
|
+
duration: false,
|
|
107
|
+
buffering: false,
|
|
108
|
+
subtitlesTracks: false,
|
|
109
|
+
selectedSubtitlesTrackId: false,
|
|
110
|
+
audioTracks: false,
|
|
111
|
+
selectedAudioTrackId: false,
|
|
112
|
+
volume: false,
|
|
113
|
+
muted: false,
|
|
114
|
+
playbackSpeed: false
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
function getProp(propName) {
|
|
118
|
+
switch (propName) {
|
|
119
|
+
case 'stream': {
|
|
120
|
+
return stream;
|
|
121
|
+
}
|
|
122
|
+
case 'loaded': {
|
|
123
|
+
if (stream === null) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return videoElement.readyState >= videoElement.HAVE_METADATA;
|
|
128
|
+
}
|
|
129
|
+
case 'paused': {
|
|
130
|
+
if (stream === null) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return !!videoElement.paused;
|
|
135
|
+
}
|
|
136
|
+
case 'time': {
|
|
137
|
+
if (stream === null || videoElement.currentTime === null || !isFinite(videoElement.currentTime)) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return Math.floor(videoElement.currentTime * 1000);
|
|
142
|
+
}
|
|
143
|
+
case 'duration': {
|
|
144
|
+
if (stream === null || videoElement.duration === null || !isFinite(videoElement.duration)) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return Math.floor(videoElement.duration * 1000);
|
|
149
|
+
}
|
|
150
|
+
case 'buffering': {
|
|
151
|
+
if (stream === null) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return videoElement.readyState < videoElement.HAVE_FUTURE_DATA;
|
|
156
|
+
}
|
|
157
|
+
case 'subtitlesTracks': {
|
|
158
|
+
if (stream === null) {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return Array.from(videoElement.textTracks)
|
|
163
|
+
.map(function(track, index) {
|
|
164
|
+
return Object.freeze({
|
|
165
|
+
id: 'EMBEDDED_' + String(index),
|
|
166
|
+
lang: track.language,
|
|
167
|
+
label: track.label || null,
|
|
168
|
+
origin: 'EMBEDDED',
|
|
169
|
+
embedded: true
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
case 'selectedSubtitlesTrackId': {
|
|
174
|
+
if (stream === null) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return Array.from(videoElement.textTracks)
|
|
179
|
+
.reduce(function(result, track, index) {
|
|
180
|
+
if (result === null && track.mode === 'showing') {
|
|
181
|
+
return 'EMBEDDED_' + String(index);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result;
|
|
185
|
+
}, null);
|
|
186
|
+
}
|
|
187
|
+
case 'audioTracks': {
|
|
188
|
+
if (stream === null) {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!videoElement.audioTracks || !Array.from(videoElement.audioTracks).length) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return Array.from(videoElement.audioTracks)
|
|
197
|
+
.map(function(track, index) {
|
|
198
|
+
return Object.freeze({
|
|
199
|
+
id: 'EMBEDDED_' + String(index),
|
|
200
|
+
lang: track.language,
|
|
201
|
+
label: track.label || null,
|
|
202
|
+
origin: 'EMBEDDED',
|
|
203
|
+
embedded: true
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
case 'selectedAudioTrackId': {
|
|
208
|
+
|
|
209
|
+
if (stream === null) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!videoElement.audioTracks || !Array.from(videoElement.audioTracks).length) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return Array.from(videoElement.audioTracks)
|
|
218
|
+
.reduce(function(result, track, index) {
|
|
219
|
+
if (result === null && track.enabled) {
|
|
220
|
+
return 'EMBEDDED_' + String(index);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return result;
|
|
224
|
+
}, null);
|
|
225
|
+
}
|
|
226
|
+
case 'volume': {
|
|
227
|
+
if (destroyed || videoElement.volume === null || !isFinite(videoElement.volume)) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return Math.floor(videoElement.volume * 100);
|
|
232
|
+
}
|
|
233
|
+
case 'muted': {
|
|
234
|
+
if (destroyed) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return !!videoElement.muted;
|
|
239
|
+
}
|
|
240
|
+
case 'playbackSpeed': {
|
|
241
|
+
if (destroyed || videoElement.playbackRate === null || !isFinite(videoElement.playbackRate)) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return videoElement.playbackRate;
|
|
246
|
+
}
|
|
247
|
+
default: {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function onCueChange() {
|
|
253
|
+
Array.from(videoElement.textTracks).forEach(function(track) {
|
|
254
|
+
Array.from(track.cues || []).forEach(function(cue) {
|
|
255
|
+
cue.snapToLines = false;
|
|
256
|
+
cue.line = 100;
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
function onVideoError() {
|
|
261
|
+
if (destroyed) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
var error;
|
|
266
|
+
switch (videoElement.error.code) {
|
|
267
|
+
case 1: {
|
|
268
|
+
error = ERROR.HTML_VIDEO.MEDIA_ERR_ABORTED;
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
case 2: {
|
|
272
|
+
error = ERROR.HTML_VIDEO.MEDIA_ERR_NETWORK;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case 3: {
|
|
276
|
+
error = ERROR.HTML_VIDEO.MEDIA_ERR_DECODE;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
case 4: {
|
|
280
|
+
error = ERROR.HTML_VIDEO.MEDIA_ERR_SRC_NOT_SUPPORTED;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
default: {
|
|
284
|
+
error = ERROR.UNKNOWN_ERROR;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
onError(Object.assign({}, error, {
|
|
288
|
+
critical: true,
|
|
289
|
+
error: videoElement.error
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
function onError(error) {
|
|
293
|
+
events.emit('error', error);
|
|
294
|
+
if (error.critical) {
|
|
295
|
+
command('unload');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function onEnded() {
|
|
299
|
+
events.emit('ended');
|
|
300
|
+
}
|
|
301
|
+
function onPropChanged(propName) {
|
|
302
|
+
if (observedProps[propName]) {
|
|
303
|
+
events.emit('propChanged', propName, getProp(propName));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function observeProp(propName) {
|
|
307
|
+
if (observedProps.hasOwnProperty(propName)) {
|
|
308
|
+
events.emit('propValue', propName, getProp(propName));
|
|
309
|
+
observedProps[propName] = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function setProp(propName, propValue) {
|
|
313
|
+
switch (propName) {
|
|
314
|
+
case 'paused': {
|
|
315
|
+
if (stream !== null) {
|
|
316
|
+
propValue ? videoElement.pause() : videoElement.play();
|
|
317
|
+
onPropChanged('paused');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case 'time': {
|
|
323
|
+
if (stream !== null && propValue !== null && isFinite(propValue)) {
|
|
324
|
+
videoElement.currentTime = parseInt(propValue, 10) / 1000;
|
|
325
|
+
onPropChanged('time');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case 'selectedSubtitlesTrackId': {
|
|
331
|
+
if (stream !== null) {
|
|
332
|
+
Array.from(videoElement.textTracks)
|
|
333
|
+
.forEach(function(track, index) {
|
|
334
|
+
track.mode = 'EMBEDDED_' + String(index) === propValue ? 'showing' : 'disabled';
|
|
335
|
+
});
|
|
336
|
+
var selecterdSubtitlesTrack = getProp('subtitlesTracks')
|
|
337
|
+
.find(function(track) {
|
|
338
|
+
return track.id === propValue;
|
|
339
|
+
});
|
|
340
|
+
if (selecterdSubtitlesTrack) {
|
|
341
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
342
|
+
events.emit('subtitlesTrackLoaded', selecterdSubtitlesTrack);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
case 'selectedAudioTrackId': {
|
|
349
|
+
if (stream !== null) {
|
|
350
|
+
for (var index = 0; index < videoElement.audioTracks.length; index++) {
|
|
351
|
+
videoElement.audioTracks[index].enabled = !!('EMBEDDED_' + String(index) === propValue);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
var selectedAudioTrack = getProp('audioTracks')
|
|
356
|
+
.find(function(track) {
|
|
357
|
+
return track.id === propValue;
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
if (selectedAudioTrack) {
|
|
361
|
+
onPropChanged('selectedAudioTrackId');
|
|
362
|
+
events.emit('audioTrackLoaded', selectedAudioTrack);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
case 'volume': {
|
|
368
|
+
if (propValue !== null && isFinite(propValue)) {
|
|
369
|
+
videoElement.muted = false;
|
|
370
|
+
videoElement.volume = Math.max(0, Math.min(100, parseInt(propValue, 10))) / 100;
|
|
371
|
+
onPropChanged('muted');
|
|
372
|
+
onPropChanged('volume');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
case 'muted': {
|
|
378
|
+
videoElement.muted = !!propValue;
|
|
379
|
+
onPropChanged('muted');
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
case 'playbackSpeed': {
|
|
383
|
+
if (propValue !== null && isFinite(propValue)) {
|
|
384
|
+
videoElement.playbackRate = parseFloat(propValue);
|
|
385
|
+
onPropChanged('playbackSpeed');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function command(commandName, commandArgs) {
|
|
393
|
+
switch (commandName) {
|
|
394
|
+
case 'load': {
|
|
395
|
+
command('unload');
|
|
396
|
+
if (commandArgs && commandArgs.stream && typeof commandArgs.stream.url === 'string') {
|
|
397
|
+
stream = commandArgs.stream;
|
|
398
|
+
onPropChanged('stream');
|
|
399
|
+
onPropChanged('loaded');
|
|
400
|
+
videoElement.autoplay = typeof commandArgs.autoplay === 'boolean' ? commandArgs.autoplay : true;
|
|
401
|
+
videoElement.currentTime = commandArgs.time !== null && isFinite(commandArgs.time) ? parseInt(commandArgs.time, 10) / 1000 : 0;
|
|
402
|
+
onPropChanged('paused');
|
|
403
|
+
onPropChanged('time');
|
|
404
|
+
onPropChanged('duration');
|
|
405
|
+
onPropChanged('buffering');
|
|
406
|
+
if (videoElement.textTracks) {
|
|
407
|
+
videoElement.textTracks.onaddtrack = function() {
|
|
408
|
+
videoElement.textTracks.onaddtrack = null;
|
|
409
|
+
setTimeout(function() {
|
|
410
|
+
onPropChanged('subtitlesTracks');
|
|
411
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
412
|
+
});
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (videoElement.audioTracks) {
|
|
416
|
+
videoElement.audioTracks.onaddtrack = function() {
|
|
417
|
+
videoElement.audioTracks.onaddtrack = null;
|
|
418
|
+
setTimeout(function() {
|
|
419
|
+
onPropChanged('audioTracks');
|
|
420
|
+
onPropChanged('selectedAudioTrackId');
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
videoElement.src = stream.url;
|
|
425
|
+
} else {
|
|
426
|
+
onError(Object.assign({}, ERROR.UNSUPPORTED_STREAM, {
|
|
427
|
+
critical: true,
|
|
428
|
+
stream: commandArgs ? commandArgs.stream : null
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
case 'unload': {
|
|
434
|
+
stream = null;
|
|
435
|
+
Array.from(videoElement.textTracks).forEach(function(track) {
|
|
436
|
+
track.oncuechange = null;
|
|
437
|
+
});
|
|
438
|
+
videoElement.removeAttribute('src');
|
|
439
|
+
videoElement.load();
|
|
440
|
+
videoElement.currentTime = 0;
|
|
441
|
+
onPropChanged('stream');
|
|
442
|
+
onPropChanged('loaded');
|
|
443
|
+
onPropChanged('paused');
|
|
444
|
+
onPropChanged('time');
|
|
445
|
+
onPropChanged('duration');
|
|
446
|
+
onPropChanged('buffering');
|
|
447
|
+
onPropChanged('subtitlesTracks');
|
|
448
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
449
|
+
onPropChanged('audioTracks');
|
|
450
|
+
onPropChanged('selectedAudioTrackId');
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case 'destroy': {
|
|
454
|
+
command('unload');
|
|
455
|
+
destroyed = true;
|
|
456
|
+
onPropChanged('volume');
|
|
457
|
+
onPropChanged('muted');
|
|
458
|
+
onPropChanged('playbackSpeed');
|
|
459
|
+
events.removeAllListeners();
|
|
460
|
+
videoElement.onerror = null;
|
|
461
|
+
videoElement.onended = null;
|
|
462
|
+
videoElement.onpause = null;
|
|
463
|
+
videoElement.onplay = null;
|
|
464
|
+
videoElement.ontimeupdate = null;
|
|
465
|
+
videoElement.ondurationchange = null;
|
|
466
|
+
videoElement.onwaiting = null;
|
|
467
|
+
videoElement.onseeking = null;
|
|
468
|
+
videoElement.onseeked = null;
|
|
469
|
+
videoElement.onstalled = null;
|
|
470
|
+
videoElement.onplaying = null;
|
|
471
|
+
videoElement.oncanplay = null;
|
|
472
|
+
videoElement.canplaythrough = null;
|
|
473
|
+
videoElement.onloadeddata = null;
|
|
474
|
+
videoElement.onvolumechange = null;
|
|
475
|
+
videoElement.onratechange = null;
|
|
476
|
+
videoElement.textTracks.onchange = null;
|
|
477
|
+
containerElement.removeChild(videoElement);
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
this.on = function(eventName, listener) {
|
|
484
|
+
if (destroyed) {
|
|
485
|
+
throw new Error('Video is destroyed');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
events.on(eventName, listener);
|
|
489
|
+
};
|
|
490
|
+
this.dispatch = function(action) {
|
|
491
|
+
if (destroyed) {
|
|
492
|
+
throw new Error('Video is destroyed');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (action) {
|
|
496
|
+
action = deepFreeze(cloneDeep(action));
|
|
497
|
+
switch (action.type) {
|
|
498
|
+
case 'observeProp': {
|
|
499
|
+
observeProp(action.propName);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
case 'setProp': {
|
|
503
|
+
setProp(action.propName, action.propValue);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
case 'command': {
|
|
507
|
+
command(action.commandName, action.commandArgs);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
throw new Error('Invalid action dispatched: ' + JSON.stringify(action));
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
VidaaVideo.canPlayStream = function(stream) {
|
|
518
|
+
if (!stream) {
|
|
519
|
+
return Promise.resolve(false);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return Promise.resolve(true);
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
VidaaVideo.manifest = {
|
|
526
|
+
name: 'VidaaVideo',
|
|
527
|
+
external: false,
|
|
528
|
+
props: ['stream', 'loaded', 'paused', 'time', 'duration', 'buffering', 'audioTracks', 'selectedAudioTrackId', 'subtitlesTracks', 'selectedSubtitlesTrackId', 'volume', 'muted', 'playbackSpeed'],
|
|
529
|
+
commands: ['load', 'unload', 'destroy'],
|
|
530
|
+
events: ['propValue', 'propChanged', 'ended', 'error', 'subtitlesTrackLoaded', 'audioTrackLoaded']
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
module.exports = VidaaVideo;
|