@stremio/stremio-video 0.0.20-rc.2 → 0.0.20-rc.5
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
|
@@ -39,6 +39,7 @@ function ChromecastSenderVideo(options) {
|
|
|
39
39
|
deviceNameContainerElement.appendChild(deviceNameLabelElement);
|
|
40
40
|
containerElement.appendChild(deviceNameContainerElement);
|
|
41
41
|
chromecastTransport.on('message', onMessage);
|
|
42
|
+
chromecastTransport.on('message-error', onMessageReceivedError);
|
|
42
43
|
|
|
43
44
|
var events = new EventEmitter();
|
|
44
45
|
var destroyed = false;
|
|
@@ -71,33 +72,25 @@ function ChromecastSenderVideo(options) {
|
|
|
71
72
|
extraSubtitlesOutlineColor: false
|
|
72
73
|
};
|
|
73
74
|
|
|
74
|
-
function
|
|
75
|
+
function onMessageSendError(error, action) {
|
|
75
76
|
events.emit('error', Object.assign({}, ERROR.CHROMECAST_SENDER_VIDEO.MESSAGE_SEND_FAILED, {
|
|
76
77
|
error: error,
|
|
77
78
|
action: action
|
|
78
79
|
}));
|
|
79
80
|
}
|
|
81
|
+
function onMessageReceivedError(error) {
|
|
82
|
+
events.emit('error', Object.assign({}, ERROR.CHROMECAST_SENDER_VIDEO.INVALID_MESSAGE_RECEIVED, {
|
|
83
|
+
error: error
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
80
86
|
function onMessage(message) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
parsedMessage = JSON.parse(message);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
events.emit('error', Object.assign({}, ERROR.CHROMECAST_SENDER_VIDEO.INVALID_MESSAGE_RECEIVED, {
|
|
86
|
-
error: error,
|
|
87
|
-
args: message
|
|
88
|
-
}));
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!parsedMessage || typeof parsedMessage.event !== 'string') {
|
|
93
|
-
events.emit('error', Object.assign({}, ERROR.CHROMECAST_SENDER_VIDEO.INVALID_MESSAGE_RECEIVED, {
|
|
94
|
-
args: message
|
|
95
|
-
}));
|
|
87
|
+
if (!message || typeof message.event !== 'string') {
|
|
88
|
+
onMessageReceivedError(new Error('Invalid message: ' + message));
|
|
96
89
|
return;
|
|
97
90
|
}
|
|
98
91
|
|
|
99
|
-
var args = Array.isArray(
|
|
100
|
-
events.emit.apply(events, [
|
|
92
|
+
var args = Array.isArray(message.args) ? message.args : [];
|
|
93
|
+
events.emit.apply(events, [message.event].concat(args));
|
|
101
94
|
}
|
|
102
95
|
function onPropChanged(propName, propValue) {
|
|
103
96
|
if (observedProps[propName]) {
|
|
@@ -164,20 +157,20 @@ function ChromecastSenderVideo(options) {
|
|
|
164
157
|
case 'observeProp': {
|
|
165
158
|
observeProp(action.propName);
|
|
166
159
|
chromecastTransport.sendMessage(action).catch(function(error) {
|
|
167
|
-
|
|
160
|
+
onMessageSendError(error, action);
|
|
168
161
|
});
|
|
169
162
|
return;
|
|
170
163
|
}
|
|
171
164
|
case 'setProp': {
|
|
172
165
|
chromecastTransport.sendMessage(action).catch(function(error) {
|
|
173
|
-
|
|
166
|
+
onMessageSendError(error, action);
|
|
174
167
|
});
|
|
175
168
|
return;
|
|
176
169
|
}
|
|
177
170
|
case 'command': {
|
|
178
171
|
command(action.commandName, action.commandArgs);
|
|
179
172
|
chromecastTransport.sendMessage(action).catch(function(error) {
|
|
180
|
-
|
|
173
|
+
onMessageSendError(error, action);
|
|
181
174
|
});
|
|
182
175
|
return;
|
|
183
176
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var ChromecastSenderVideo = require('../ChromecastSenderVideo');
|
|
2
2
|
var HTMLVideo = require('../HTMLVideo');
|
|
3
|
+
var TizenVideo = require('../TizenVideo');
|
|
3
4
|
var IFrameVideo = require('../IFrameVideo');
|
|
4
5
|
var YouTubeVideo = require('../YouTubeVideo');
|
|
5
6
|
var withStreamingServer = require('../withStreamingServer');
|
|
@@ -23,10 +24,16 @@ function selectVideoImplementation(commandArgs, options) {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
if (typeof commandArgs.streamingServerURL === 'string') {
|
|
27
|
+
if (typeof global.tizen !== 'undefined') {
|
|
28
|
+
return withStreamingServer(withHTMLSubtitles(TizenVideo));
|
|
29
|
+
}
|
|
26
30
|
return withStreamingServer(withHTMLSubtitles(HTMLVideo));
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
if (typeof commandArgs.stream.url === 'string') {
|
|
34
|
+
if (typeof global.tizen !== 'undefined') {
|
|
35
|
+
return withHTMLSubtitles(TizenVideo);
|
|
36
|
+
}
|
|
30
37
|
return withHTMLSubtitles(HTMLVideo);
|
|
31
38
|
}
|
|
32
39
|
|
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
var EventEmitter = require('eventemitter3');
|
|
2
|
+
var cloneDeep = require('lodash.clonedeep');
|
|
3
|
+
var deepFreeze = require('deep-freeze');
|
|
4
|
+
var Color = require('color');
|
|
5
|
+
var ERROR = require('../error');
|
|
6
|
+
|
|
7
|
+
function TizenVideo(options) {
|
|
8
|
+
options = options || {};
|
|
9
|
+
|
|
10
|
+
var isBuffering = true;
|
|
11
|
+
var videoSpeed = 1;
|
|
12
|
+
var currentSubTrack = null;
|
|
13
|
+
var currentAudioTrack = null;
|
|
14
|
+
|
|
15
|
+
var containerElement = options.containerElement;
|
|
16
|
+
if (!(containerElement instanceof HTMLElement)) {
|
|
17
|
+
throw new Error('Container element required to be instance of HTMLElement');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var size = 100;
|
|
21
|
+
var offset = 0;
|
|
22
|
+
var textColor = 'rgb(255, 255, 255)';
|
|
23
|
+
var backgroundColor = 'rgba(0, 0, 0, 0)';
|
|
24
|
+
var outlineColor = 'rgb(34, 34, 34)';
|
|
25
|
+
|
|
26
|
+
var objElement = document.createElement('object');
|
|
27
|
+
objElement.type = 'application/avplayer';
|
|
28
|
+
objElement.style.width = '100%';
|
|
29
|
+
objElement.style.height = '100%';
|
|
30
|
+
objElement.style.backgroundColor = 'black';
|
|
31
|
+
|
|
32
|
+
var lastSub;
|
|
33
|
+
var disabledSubs = false;
|
|
34
|
+
|
|
35
|
+
function refreshSubtitle() {
|
|
36
|
+
if (lastSub) {
|
|
37
|
+
var lastSubDurationDiff = lastSub.duration - (getProp('time') - lastSub.now);
|
|
38
|
+
if (lastSubDurationDiff > 0) renderSubtitle(lastSubDurationDiff, lastSub.text);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function renderSubtitle(duration, text) {
|
|
43
|
+
if (disabledSubs) return;
|
|
44
|
+
// we ignore custom delay here, it's not needed for embedded subs
|
|
45
|
+
lastSub = {
|
|
46
|
+
duration: duration,
|
|
47
|
+
text: text,
|
|
48
|
+
now: getProp('time'),
|
|
49
|
+
};
|
|
50
|
+
if (subtitleTimeout) {
|
|
51
|
+
clearTimeout(subtitleTimeout);
|
|
52
|
+
subtitleTimeout = false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
while (subtitlesElement.hasChildNodes()) {
|
|
56
|
+
subtitlesElement.removeChild(subtitlesElement.lastChild);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
subtitlesElement.style.bottom = offset + '%';
|
|
60
|
+
var cueNode = document.createElement('span');
|
|
61
|
+
cueNode.innerHTML = text;
|
|
62
|
+
cueNode.style.display = 'inline-block';
|
|
63
|
+
cueNode.style.padding = '0.2em';
|
|
64
|
+
cueNode.style.fontSize = Math.floor(size / 25) + 'vmin';
|
|
65
|
+
cueNode.style.color = textColor;
|
|
66
|
+
cueNode.style.backgroundColor = backgroundColor;
|
|
67
|
+
cueNode.style.textShadow = '1px 1px 0.1em ' + outlineColor;
|
|
68
|
+
|
|
69
|
+
subtitlesElement.appendChild(cueNode);
|
|
70
|
+
subtitlesElement.appendChild(document.createElement('br'));
|
|
71
|
+
|
|
72
|
+
if (duration) {
|
|
73
|
+
subtitleTimeout = setTimeout(function() {
|
|
74
|
+
while (subtitlesElement.hasChildNodes()) {
|
|
75
|
+
subtitlesElement.removeChild(subtitlesElement.lastChild);
|
|
76
|
+
}
|
|
77
|
+
}, parseInt(duration * videoSpeed));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
var subtitleTimeout = false;
|
|
82
|
+
var Listener = {
|
|
83
|
+
onbufferingstart: function() {
|
|
84
|
+
isBuffering = true;
|
|
85
|
+
onPropChanged('buffering');
|
|
86
|
+
},
|
|
87
|
+
onbufferingprogress: function() {
|
|
88
|
+
isBuffering = true;
|
|
89
|
+
onPropChanged('buffering');
|
|
90
|
+
},
|
|
91
|
+
onbufferingcomplete: function() {
|
|
92
|
+
isBuffering = false;
|
|
93
|
+
onPropChanged('buffering');
|
|
94
|
+
},
|
|
95
|
+
oncurrentplaytime: function() {
|
|
96
|
+
onPropChanged('time');
|
|
97
|
+
},
|
|
98
|
+
onerror: function() {
|
|
99
|
+
onVideoError();
|
|
100
|
+
},
|
|
101
|
+
onsubtitlechange: function(duration, text) {
|
|
102
|
+
renderSubtitle(duration, text);
|
|
103
|
+
},
|
|
104
|
+
onstreamcompleted: function() {
|
|
105
|
+
onEnded();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
window.webapis.avplay.setListener(Listener);
|
|
109
|
+
|
|
110
|
+
containerElement.appendChild(objElement);
|
|
111
|
+
|
|
112
|
+
var subtitlesElement = document.createElement('div');
|
|
113
|
+
subtitlesElement.style.position = 'absolute';
|
|
114
|
+
subtitlesElement.style.right = '0';
|
|
115
|
+
subtitlesElement.style.bottom = '0';
|
|
116
|
+
subtitlesElement.style.left = '0';
|
|
117
|
+
subtitlesElement.style.zIndex = '1';
|
|
118
|
+
subtitlesElement.style.textAlign = 'center';
|
|
119
|
+
containerElement.style.position = 'relative';
|
|
120
|
+
containerElement.style.zIndex = '0';
|
|
121
|
+
containerElement.appendChild(subtitlesElement);
|
|
122
|
+
|
|
123
|
+
var events = new EventEmitter();
|
|
124
|
+
var destroyed = false;
|
|
125
|
+
var stream = null;
|
|
126
|
+
var observedProps = {
|
|
127
|
+
stream: false,
|
|
128
|
+
paused: false,
|
|
129
|
+
time: false,
|
|
130
|
+
duration: false,
|
|
131
|
+
buffering: false,
|
|
132
|
+
subtitlesTracks: false,
|
|
133
|
+
selectedSubtitlesTrackId: false,
|
|
134
|
+
subtitlesOffset: false,
|
|
135
|
+
subtitlesSize: false,
|
|
136
|
+
subtitlesTextColor: false,
|
|
137
|
+
subtitlesBackgroundColor: false,
|
|
138
|
+
subtitlesOutlineColor: false,
|
|
139
|
+
audioTracks: false,
|
|
140
|
+
selectedAudioTrackId: false,
|
|
141
|
+
playbackSpeed: false
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function getProp(propName) {
|
|
145
|
+
switch (propName) {
|
|
146
|
+
case 'stream': {
|
|
147
|
+
return stream;
|
|
148
|
+
}
|
|
149
|
+
case 'paused': {
|
|
150
|
+
if (stream === null) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return !!(window.webapis.avplay.getState() === 'PAUSED');
|
|
155
|
+
}
|
|
156
|
+
case 'time': {
|
|
157
|
+
var currentTime = window.webapis.avplay.getCurrentTime();
|
|
158
|
+
if (stream === null || currentTime === null || !isFinite(currentTime)) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return Math.floor(currentTime);
|
|
163
|
+
}
|
|
164
|
+
case 'duration': {
|
|
165
|
+
var duration = window.webapis.avplay.getDuration();
|
|
166
|
+
if (stream === null || duration === null || !isFinite(duration)) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return Math.floor(duration);
|
|
171
|
+
}
|
|
172
|
+
case 'buffering': {
|
|
173
|
+
if (stream === null) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return isBuffering;
|
|
178
|
+
}
|
|
179
|
+
case 'subtitlesTracks': {
|
|
180
|
+
if (stream === null) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
var totalTrackInfo = window.webapis.avplay.getTotalTrackInfo();
|
|
185
|
+
var textTracks = [];
|
|
186
|
+
|
|
187
|
+
for (var i = 0; i < totalTrackInfo.length; i++) {
|
|
188
|
+
if (totalTrackInfo[i].type === 'TEXT') {
|
|
189
|
+
var textTrack = totalTrackInfo[i];
|
|
190
|
+
var textTrackId = 'EMBEDDED_' + String(textTrack.index);
|
|
191
|
+
if (!currentSubTrack && !textTracks.length) {
|
|
192
|
+
currentSubTrack = textTrackId;
|
|
193
|
+
}
|
|
194
|
+
var extra = {};
|
|
195
|
+
try {
|
|
196
|
+
extra = JSON.parse(textTrack.extra_info);
|
|
197
|
+
} catch(e) {}
|
|
198
|
+
var textTrackLang = (extra.track_lang || '').trim();
|
|
199
|
+
textTracks.push({
|
|
200
|
+
id: textTrackId,
|
|
201
|
+
lang: textTrackLang,
|
|
202
|
+
label: textTrackLang,
|
|
203
|
+
origin: 'EMBEDDED',
|
|
204
|
+
embedded: true,
|
|
205
|
+
mode: textTrackId === currentSubTrack ? 'showing' : 'disabled',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return textTracks;
|
|
211
|
+
}
|
|
212
|
+
case 'selectedSubtitlesTrackId': {
|
|
213
|
+
if (stream === null || disabledSubs) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
var currentTracks = window.webapis.avplay.getCurrentStreamInfo();
|
|
218
|
+
var currentIndex;
|
|
219
|
+
|
|
220
|
+
for (var i = 0; i < currentTracks.length; i++) {
|
|
221
|
+
if (currentTracks[i].type === 'TEXT') {
|
|
222
|
+
currentIndex = currentTracks[i].index;
|
|
223
|
+
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return currentIndex ? 'EMBEDDED_' + String(currentIndex) : null;
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
case 'subtitlesOffset': {
|
|
232
|
+
if (destroyed) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return offset;
|
|
237
|
+
}
|
|
238
|
+
case 'subtitlesSize': {
|
|
239
|
+
if (destroyed) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return size;
|
|
244
|
+
}
|
|
245
|
+
case 'subtitlesTextColor': {
|
|
246
|
+
if (destroyed) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return textColor;
|
|
251
|
+
}
|
|
252
|
+
case 'subtitlesBackgroundColor': {
|
|
253
|
+
if (destroyed) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return backgroundColor;
|
|
258
|
+
}
|
|
259
|
+
case 'subtitlesOutlineColor': {
|
|
260
|
+
if (destroyed) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return outlineColor;
|
|
265
|
+
}
|
|
266
|
+
case 'audioTracks': {
|
|
267
|
+
if (stream === null) {
|
|
268
|
+
return [];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
var totalTrackInfo = window.webapis.avplay.getTotalTrackInfo();
|
|
272
|
+
var audioTracks = [];
|
|
273
|
+
|
|
274
|
+
for (var i = 0; i < totalTrackInfo.length; i++) {
|
|
275
|
+
if (totalTrackInfo[i].type === 'AUDIO') {
|
|
276
|
+
var audioTrack = totalTrackInfo[i];
|
|
277
|
+
var audioTrackId = 'EMBEDDED_' + String(audioTrack.index);
|
|
278
|
+
if (!currentAudioTrack && !audioTracks.length) {
|
|
279
|
+
currentAudioTrack = audioTrackId;
|
|
280
|
+
}
|
|
281
|
+
var extra = {};
|
|
282
|
+
try {
|
|
283
|
+
extra = JSON.parse(audioTrack.extra_info);
|
|
284
|
+
} catch(e) {}
|
|
285
|
+
var audioTrackLang = extra.language || '';
|
|
286
|
+
audioTracks.push({
|
|
287
|
+
id: audioTrackId,
|
|
288
|
+
lang: audioTrackLang,
|
|
289
|
+
label: audioTrackLang,
|
|
290
|
+
origin: 'EMBEDDED',
|
|
291
|
+
embedded: true,
|
|
292
|
+
mode: audioTrackId === currentAudioTrack ? 'showing' : 'disabled',
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return audioTracks;
|
|
298
|
+
}
|
|
299
|
+
case 'selectedAudioTrackId': {
|
|
300
|
+
if (stream === null) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
var currentTracks = window.webapis.avplay.getCurrentStreamInfo();
|
|
305
|
+
var currentIndex;
|
|
306
|
+
|
|
307
|
+
for (var i = 0; i < currentTracks.length; i++) {
|
|
308
|
+
if (currentTracks[i].type === 'AUDIO') {
|
|
309
|
+
currentIndex = currentTracks[i].index;
|
|
310
|
+
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return currentIndex ? 'EMBEDDED_' + String(currentIndex) : null;
|
|
316
|
+
}
|
|
317
|
+
case 'playbackSpeed': {
|
|
318
|
+
if (destroyed || videoSpeed === null || !isFinite(videoSpeed)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return videoSpeed;
|
|
323
|
+
}
|
|
324
|
+
default: {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function onVideoError() {
|
|
330
|
+
if (destroyed) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
var error;
|
|
335
|
+
error = ERROR.UNKNOWN_ERROR;
|
|
336
|
+
onError(Object.assign({}, error, {
|
|
337
|
+
critical: true,
|
|
338
|
+
error: error
|
|
339
|
+
}));
|
|
340
|
+
}
|
|
341
|
+
function onError(error) {
|
|
342
|
+
events.emit('error', error);
|
|
343
|
+
if (error.critical) {
|
|
344
|
+
command('unload');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function onEnded() {
|
|
348
|
+
events.emit('ended');
|
|
349
|
+
}
|
|
350
|
+
function onPropChanged(propName) {
|
|
351
|
+
if (observedProps[propName]) {
|
|
352
|
+
events.emit('propChanged', propName, getProp(propName));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function observeProp(propName) {
|
|
356
|
+
if (observedProps.hasOwnProperty(propName)) {
|
|
357
|
+
events.emit('propValue', propName, getProp(propName));
|
|
358
|
+
observedProps[propName] = true;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function setProp(propName, propValue) {
|
|
362
|
+
switch (propName) {
|
|
363
|
+
case 'paused': {
|
|
364
|
+
if (stream !== null) {
|
|
365
|
+
var willPause = !!propValue;
|
|
366
|
+
willPause ? window.webapis.avplay.pause() : window.webapis.avplay.play();
|
|
367
|
+
if (willPause) {
|
|
368
|
+
if (subtitleTimeout) {
|
|
369
|
+
clearTimeout(subtitleTimeout);
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
refreshSubtitle();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
onPropChanged('paused');
|
|
377
|
+
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case 'time': {
|
|
381
|
+
if (stream !== null && propValue !== null && isFinite(propValue)) {
|
|
382
|
+
window.webapis.avplay.seekTo(parseInt(propValue, 10));
|
|
383
|
+
renderSubtitle(0, '');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
case 'selectedSubtitlesTrackId': {
|
|
389
|
+
if (stream !== null) {
|
|
390
|
+
if ((currentSubTrack || '').indexOf('EMBEDDED_') === 0) {
|
|
391
|
+
if ((propValue || '').indexOf('EMBEDDED_') === -1) {
|
|
392
|
+
renderSubtitle(0, '');
|
|
393
|
+
disabledSubs = true;
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
disabledSubs = false;
|
|
397
|
+
|
|
398
|
+
currentSubTrack = propValue;
|
|
399
|
+
|
|
400
|
+
var selectedSubtitlesTrack = getProp('subtitlesTracks')
|
|
401
|
+
.find(function(track) {
|
|
402
|
+
return track.id === propValue;
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
window.webapis.avplay.setSelectTrack('TEXT', parseInt(currentSubTrack.replace('EMBEDDED_', '')));
|
|
406
|
+
|
|
407
|
+
if (selectedSubtitlesTrack) {
|
|
408
|
+
events.emit('subtitlesTrackLoaded', selectedSubtitlesTrack);
|
|
409
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
410
|
+
}
|
|
411
|
+
} else if (!propValue) {
|
|
412
|
+
disabledSubs = true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
case 'subtitlesOffset': {
|
|
419
|
+
if (propValue !== null && isFinite(propValue)) {
|
|
420
|
+
offset = Math.max(0, Math.min(100, parseInt(propValue, 10)));
|
|
421
|
+
refreshSubtitle();
|
|
422
|
+
onPropChanged('subtitlesOffset');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
case 'subtitlesSize': {
|
|
428
|
+
if (propValue !== null && isFinite(propValue)) {
|
|
429
|
+
size = Math.max(0, parseInt(propValue, 10));
|
|
430
|
+
refreshSubtitle();
|
|
431
|
+
onPropChanged('subtitlesSize');
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
case 'subtitlesTextColor': {
|
|
437
|
+
if (typeof propValue === 'string') {
|
|
438
|
+
try {
|
|
439
|
+
textColor = Color(propValue).rgb().string();
|
|
440
|
+
} catch (error) {
|
|
441
|
+
// eslint-disable-next-line no-console
|
|
442
|
+
console.error('Tizen player with HTML Subtitles', error);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
refreshSubtitle();
|
|
446
|
+
onPropChanged('subtitlesTextColor');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
case 'subtitlesBackgroundColor': {
|
|
452
|
+
if (typeof propValue === 'string') {
|
|
453
|
+
try {
|
|
454
|
+
backgroundColor = Color(propValue).rgb().string();
|
|
455
|
+
} catch (error) {
|
|
456
|
+
// eslint-disable-next-line no-console
|
|
457
|
+
console.error('Tizen player with HTML Subtitles', error);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
refreshSubtitle();
|
|
461
|
+
|
|
462
|
+
onPropChanged('subtitlesBackgroundColor');
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
case 'subtitlesOutlineColor': {
|
|
468
|
+
if (typeof propValue === 'string') {
|
|
469
|
+
try {
|
|
470
|
+
outlineColor = Color(propValue).rgb().string();
|
|
471
|
+
} catch (error) {
|
|
472
|
+
// eslint-disable-next-line no-console
|
|
473
|
+
console.error('Tizen player with HTML Subtitles', error);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
refreshSubtitle();
|
|
477
|
+
|
|
478
|
+
onPropChanged('subtitlesOutlineColor');
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
case 'selectedAudioTrackId': {
|
|
484
|
+
if (stream !== null) {
|
|
485
|
+
|
|
486
|
+
currentAudioTrack = propValue;
|
|
487
|
+
|
|
488
|
+
var selectedAudioTrack = getProp('audioTracks')
|
|
489
|
+
.find(function(track) {
|
|
490
|
+
return track.id === propValue;
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
window.webapis.avplay.setSelectTrack('AUDIO', parseInt(currentAudioTrack.replace('EMBEDDED_', '')));
|
|
494
|
+
|
|
495
|
+
if (selectedAudioTrack) {
|
|
496
|
+
events.emit('audioTrackLoaded', selectedAudioTrack);
|
|
497
|
+
onPropChanged('selectedAudioTrackId');
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
case 'playbackSpeed': {
|
|
504
|
+
if (propValue !== null && isFinite(propValue)) {
|
|
505
|
+
videoSpeed = parseFloat(propValue);
|
|
506
|
+
|
|
507
|
+
try {
|
|
508
|
+
window.webapis.avplay.setSpeed(videoSpeed);
|
|
509
|
+
} catch (e) {}
|
|
510
|
+
|
|
511
|
+
onPropChanged('playbackSpeed');
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function command(commandName, commandArgs) {
|
|
519
|
+
switch (commandName) {
|
|
520
|
+
case 'load': {
|
|
521
|
+
if (commandArgs && commandArgs.stream && typeof commandArgs.stream.url === 'string') {
|
|
522
|
+
stream = commandArgs.stream;
|
|
523
|
+
|
|
524
|
+
if (stream !== commandArgs.stream) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
onPropChanged('buffering');
|
|
528
|
+
|
|
529
|
+
window.webapis.avplay.open(stream.url);
|
|
530
|
+
window.webapis.avplay.setDisplayRect(0, 0, window.innerWidth, window.innerHeight);
|
|
531
|
+
window.webapis.avplay.setDisplayMethod('PLAYER_DISPLAY_MODE_LETTER_BOX');
|
|
532
|
+
window.webapis.avplay.seekTo(commandArgs.time !== null && isFinite(commandArgs.time) ? parseInt(commandArgs.time, 10) : 0);
|
|
533
|
+
window.webapis.avplay.prepare();
|
|
534
|
+
onPropChanged('duration');
|
|
535
|
+
window.webapis.avplay.play();
|
|
536
|
+
|
|
537
|
+
onPropChanged('stream');
|
|
538
|
+
onPropChanged('paused');
|
|
539
|
+
onPropChanged('time');
|
|
540
|
+
onPropChanged('duration');
|
|
541
|
+
onPropChanged('subtitlesTracks');
|
|
542
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
543
|
+
onPropChanged('audioTracks');
|
|
544
|
+
onPropChanged('selectedAudioTrackId');
|
|
545
|
+
|
|
546
|
+
} else {
|
|
547
|
+
onError(Object.assign({}, ERROR.UNSUPPORTED_STREAM, {
|
|
548
|
+
critical: true,
|
|
549
|
+
stream: commandArgs ? commandArgs.stream : null
|
|
550
|
+
}));
|
|
551
|
+
}
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
case 'unload': {
|
|
555
|
+
stream = null;
|
|
556
|
+
window.webapis.avplay.stop();
|
|
557
|
+
onPropChanged('stream');
|
|
558
|
+
onPropChanged('paused');
|
|
559
|
+
onPropChanged('time');
|
|
560
|
+
onPropChanged('duration');
|
|
561
|
+
onPropChanged('buffering');
|
|
562
|
+
onPropChanged('subtitlesTracks');
|
|
563
|
+
onPropChanged('selectedSubtitlesTrackId');
|
|
564
|
+
onPropChanged('audioTracks');
|
|
565
|
+
onPropChanged('selectedAudioTrackId');
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
case 'destroy': {
|
|
569
|
+
command('unload');
|
|
570
|
+
destroyed = true;
|
|
571
|
+
onPropChanged('subtitlesOffset');
|
|
572
|
+
onPropChanged('subtitlesSize');
|
|
573
|
+
onPropChanged('subtitlesTextColor');
|
|
574
|
+
onPropChanged('subtitlesBackgroundColor');
|
|
575
|
+
onPropChanged('subtitlesOutlineColor');
|
|
576
|
+
onPropChanged('playbackSpeed');
|
|
577
|
+
events.removeAllListeners();
|
|
578
|
+
containerElement.removeChild(objElement);
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
this.on = function(eventName, listener) {
|
|
585
|
+
if (destroyed) {
|
|
586
|
+
throw new Error('Video is destroyed');
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
events.on(eventName, listener);
|
|
590
|
+
};
|
|
591
|
+
this.dispatch = function(action) {
|
|
592
|
+
if (destroyed) {
|
|
593
|
+
throw new Error('Video is destroyed');
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (action) {
|
|
597
|
+
action = deepFreeze(cloneDeep(action));
|
|
598
|
+
switch (action.type) {
|
|
599
|
+
case 'observeProp': {
|
|
600
|
+
observeProp(action.propName);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
case 'setProp': {
|
|
604
|
+
setProp(action.propName, action.propValue);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
case 'command': {
|
|
608
|
+
command(action.commandName, action.commandArgs);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
throw new Error('Invalid action dispatched: ' + JSON.stringify(action));
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
TizenVideo.canPlayStream = function() {
|
|
619
|
+
return Promise.resolve(true);
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
TizenVideo.manifest = {
|
|
623
|
+
name: 'TizenVideo',
|
|
624
|
+
external: false,
|
|
625
|
+
props: ['stream', 'paused', 'time', 'duration', 'buffering', 'audioTracks', 'selectedAudioTrackId', 'subtitlesTracks', 'selectedSubtitlesTrackId', 'subtitlesOffset', 'subtitlesSize', 'subtitlesTextColor', 'subtitlesBackgroundColor', 'subtitlesOutlineColor', 'playbackSpeed'],
|
|
626
|
+
commands: ['load', 'unload', 'destroy'],
|
|
627
|
+
events: ['propValue', 'propChanged', 'ended', 'error', 'subtitlesTrackLoaded', 'audioTrackLoaded']
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
module.exports = TizenVideo;
|