@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stremio/stremio-video",
3
- "version": "0.0.20-rc.2",
3
+ "version": "0.0.20-rc.5",
4
4
  "description": "Abstraction layer on top of different media players",
5
5
  "author": "Smart Code OOD",
6
6
  "main": "src/index.js",
@@ -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 onTransportError(error, action) {
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
- var parsedMessage;
82
- try {
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(parsedMessage.args) ? parsedMessage.args : [];
100
- events.emit.apply(events, [parsedMessage.event].concat(args));
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
- onTransportError(error, action);
160
+ onMessageSendError(error, action);
168
161
  });
169
162
  return;
170
163
  }
171
164
  case 'setProp': {
172
165
  chromecastTransport.sendMessage(action).catch(function(error) {
173
- onTransportError(error, action);
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
- onTransportError(error, action);
173
+ onMessageSendError(error, action);
181
174
  });
182
175
  return;
183
176
  }
@@ -101,4 +101,6 @@ function StremioVideo() {
101
101
  };
102
102
  }
103
103
 
104
+ StremioVideo.ERROR = ERROR;
105
+
104
106
  module.exports = StremioVideo;
@@ -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;
@@ -0,0 +1,3 @@
1
+ var TizenVideo = require('./TizenVideo');
2
+
3
+ module.exports = TizenVideo;