@stremio/stremio-video 0.0.43 → 0.0.45

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.43",
3
+ "version": "0.0.45",
4
4
  "description": "Abstraction layer on top of different media players",
5
5
  "author": "Smart Code OOD",
6
6
  "main": "src/index.js",
@@ -31,22 +31,22 @@ function selectVideoImplementation(commandArgs, options) {
31
31
  }
32
32
 
33
33
  if (typeof commandArgs.streamingServerURL === 'string') {
34
- if (typeof global.tizen !== 'undefined') {
34
+ if (commandArgs.platform === 'Tizen') {
35
35
  return withStreamingServer(withHTMLSubtitles(TizenVideo));
36
36
  }
37
- if (typeof global.webOS !== 'undefined') {
37
+ if (commandArgs.platform === 'webOS') {
38
38
  return withStreamingServer(withHTMLSubtitles(WebOsVideo));
39
39
  }
40
40
  return withStreamingServer(withHTMLSubtitles(HTMLVideo));
41
41
  }
42
42
 
43
43
  if (typeof commandArgs.stream.url === 'string') {
44
- if (typeof global.webOS !== 'undefined') {
45
- return withVideoParams(withHTMLSubtitles(WebOsVideo));
46
- }
47
- if (typeof global.tizen !== 'undefined') {
44
+ if (commandArgs.platform === 'Tizen') {
48
45
  return withVideoParams(withHTMLSubtitles(TizenVideo));
49
46
  }
47
+ if (commandArgs.platform === 'webOS') {
48
+ return withVideoParams(withHTMLSubtitles(WebOsVideo));
49
+ }
50
50
  return withVideoParams(withHTMLSubtitles(HTMLVideo));
51
51
  }
52
52
 
@@ -0,0 +1,98 @@
1
+ const SCOPE = 'AVPlay';
2
+
3
+ const createAVPlay = (transport) => {
4
+ const getState = () => {
5
+ return transport.request(SCOPE, 'getState');
6
+ };
7
+
8
+ const getCurrentTime = () => {
9
+ return transport.request(SCOPE, 'getCurrentTime');
10
+ };
11
+
12
+ const getDuration = () => {
13
+ return transport.request(SCOPE, 'getDuration');
14
+ };
15
+
16
+ const getTotalTrackInfo = () => {
17
+ return transport.request(SCOPE, 'getTotalTrackInfo');
18
+ };
19
+
20
+ const getCurrentStreamInfo = () => {
21
+ return transport.request(SCOPE, 'getCurrentStreamInfo');
22
+ };
23
+
24
+ const open = (path) => {
25
+ return transport.request(SCOPE, 'open', path);
26
+ };
27
+
28
+ const prepareAsync = async (successHandler, errorHandler) => {
29
+ const [handler, handlerResult] = await transport.request(SCOPE, 'prepareAsync', 'handler:success', 'handler:error');
30
+ if (handler === 'handler:success') successHandler();
31
+ if (handler === 'handler:error') errorHandler(...handlerResult);
32
+ };
33
+
34
+ const pause = () => {
35
+ return transport.request(SCOPE, 'pause');
36
+ };
37
+
38
+ const play = () => {
39
+ return transport.request(SCOPE, 'play');
40
+ };
41
+
42
+ const stop = () => {
43
+ return transport.request(SCOPE, 'stop');
44
+ };
45
+
46
+ const seekTo = (time) => {
47
+ return transport.request(SCOPE, 'seekTo', time);
48
+ };
49
+
50
+ const setSpeed = (rate) => {
51
+ return transport.request(SCOPE, 'setSpeed', rate);
52
+ };
53
+
54
+ const setSelectTrack = (type, id) => {
55
+ return transport.request(SCOPE, 'setSelectTrack', type, id);
56
+ };
57
+
58
+ const setDisplayRect = (x, y, width, height) => {
59
+ return transport.request(SCOPE, 'setDisplayRect', x, y, width, height);
60
+ };
61
+
62
+ const setDisplayMethod = (method) => {
63
+ return transport.request(SCOPE, 'setDisplayMethod', method);
64
+ };
65
+
66
+ const setListener = (listener) => {
67
+ const handlers = Object.keys(listener).map((name) => `handler:${name}`);
68
+ const onHandlerResponse = (handler, handlerResult) => {
69
+ const name = handler.replace('handler:', '');
70
+ if (listener[name]) {
71
+ handlerResult ? listener[name](...handlerResult) : listener[name]();
72
+ }
73
+ };
74
+
75
+ transport.listen(SCOPE, 'setListener', onHandlerResponse, ...handlers);
76
+ };
77
+
78
+ return {
79
+ getState,
80
+ getCurrentTime,
81
+ getDuration,
82
+ getTotalTrackInfo,
83
+ getCurrentStreamInfo,
84
+ open,
85
+ prepareAsync,
86
+ pause,
87
+ play,
88
+ stop,
89
+ seekTo,
90
+ setSpeed,
91
+ setSelectTrack,
92
+ setDisplayRect,
93
+ setDisplayMethod,
94
+ setListener,
95
+ };
96
+ };
97
+
98
+ module.exports = createAVPlay;
@@ -4,6 +4,7 @@ var deepFreeze = require('deep-freeze');
4
4
  var Color = require('color');
5
5
  var ERROR = require('../error');
6
6
  var getTracksData = require('../tracksData');
7
+ var createAVPlay = require('./AVPlay');
7
8
 
8
9
  function TizenVideo(options) {
9
10
  options = options || {};
@@ -18,6 +19,8 @@ function TizenVideo(options) {
18
19
  throw new Error('Container element required to be instance of HTMLElement');
19
20
  }
20
21
 
22
+ var AVPlay = createAVPlay(options.transport);
23
+
21
24
  var promiseAudioTrackChange = false;
22
25
 
23
26
  var size = 100;
@@ -36,20 +39,22 @@ function TizenVideo(options) {
36
39
  var lastSub;
37
40
  var disabledSubs = false;
38
41
 
39
- function refreshSubtitle() {
42
+ async function refreshSubtitle() {
40
43
  if (lastSub) {
41
- var lastSubDurationDiff = lastSub.duration - (getProp('time') - lastSub.now);
44
+ var currentTime = await getProp('time');
45
+ var lastSubDurationDiff = lastSub.duration - (currentTime - lastSub.now);
42
46
  if (lastSubDurationDiff > 0) renderSubtitle(lastSubDurationDiff, lastSub.text);
43
47
  }
44
48
  }
45
49
 
46
- function renderSubtitle(duration, text) {
50
+ async function renderSubtitle(duration, text) {
47
51
  if (disabledSubs) return;
52
+ var now = await getProp('time');
48
53
  // we ignore custom delay here, it's not needed for embedded subs
49
54
  lastSub = {
50
55
  duration: duration,
51
56
  text: text,
52
- now: getProp('time'),
57
+ now: now,
53
58
  };
54
59
  if (subtitleTimeout) {
55
60
  clearTimeout(subtitleTimeout);
@@ -85,7 +90,8 @@ function TizenVideo(options) {
85
90
  }
86
91
 
87
92
  var subtitleTimeout = false;
88
- var Listener = {
93
+
94
+ AVPlay.setListener({
89
95
  onbufferingstart: function() {
90
96
  isBuffering = true;
91
97
  onPropChanged('buffering');
@@ -107,8 +113,7 @@ function TizenVideo(options) {
107
113
  onstreamcompleted: function() {
108
114
  onEnded();
109
115
  }
110
- };
111
- window.webapis.avplay.setListener(Listener);
116
+ });
112
117
 
113
118
  containerElement.appendChild(objElement);
114
119
 
@@ -169,7 +174,7 @@ function TizenVideo(options) {
169
174
  }
170
175
  }
171
176
 
172
- function getProp(propName) {
177
+ async function getProp(propName) {
173
178
  switch (propName) {
174
179
  case 'stream': {
175
180
  return stream;
@@ -182,17 +187,18 @@ function TizenVideo(options) {
182
187
  return null;
183
188
  }
184
189
 
185
- var isPaused = !!(window.webapis.avplay.getState() === 'PAUSED');
190
+ var state = await AVPlay.getState();
191
+ var isPaused = !!(state === 'PAUSED');
186
192
 
187
193
  if (!isPaused && promiseAudioTrackChange) {
188
- window.webapis.avplay.setSelectTrack('AUDIO', parseInt(promiseAudioTrackChange.replace('EMBEDDED_', '')));
194
+ AVPlay.setSelectTrack('AUDIO', parseInt(promiseAudioTrackChange.replace('EMBEDDED_', '')));
189
195
  promiseAudioTrackChange = false;
190
196
  }
191
197
 
192
198
  return isPaused;
193
199
  }
194
200
  case 'time': {
195
- var currentTime = window.webapis.avplay.getCurrentTime();
201
+ var currentTime = await AVPlay.getCurrentTime();
196
202
  if (stream === null || currentTime === null || !isFinite(currentTime)) {
197
203
  return null;
198
204
  }
@@ -200,7 +206,7 @@ function TizenVideo(options) {
200
206
  return Math.floor(currentTime);
201
207
  }
202
208
  case 'duration': {
203
- var duration = window.webapis.avplay.getDuration();
209
+ var duration = await AVPlay.getDuration();
204
210
  if (stream === null || duration === null || !isFinite(duration)) {
205
211
  return null;
206
212
  }
@@ -219,7 +225,7 @@ function TizenVideo(options) {
219
225
  return [];
220
226
  }
221
227
 
222
- var totalTrackInfo = window.webapis.avplay.getTotalTrackInfo();
228
+ var totalTrackInfo = await AVPlay.getTotalTrackInfo();
223
229
  var textTracks = [];
224
230
 
225
231
  for (var i = 0; i < totalTrackInfo.length; i++) {
@@ -260,7 +266,7 @@ function TizenVideo(options) {
260
266
  return null;
261
267
  }
262
268
 
263
- var currentTracks = window.webapis.avplay.getCurrentStreamInfo();
269
+ var currentTracks = await AVPlay.getCurrentStreamInfo();
264
270
  var currentIndex;
265
271
 
266
272
  for (var i = 0; i < currentTracks.length; i++) {
@@ -321,7 +327,7 @@ function TizenVideo(options) {
321
327
  return [];
322
328
  }
323
329
 
324
- var totalTrackInfo = window.webapis.avplay.getTotalTrackInfo();
330
+ var totalTrackInfo = await AVPlay.getTotalTrackInfo();
325
331
  var audioTracks = [];
326
332
 
327
333
  for (var i = 0; i < totalTrackInfo.length; i++) {
@@ -366,7 +372,7 @@ function TizenVideo(options) {
366
372
  return promiseAudioTrackChange;
367
373
  }
368
374
 
369
- var currentTracks = window.webapis.avplay.getCurrentStreamInfo();
375
+ var currentTracks = await AVPlay.getCurrentStreamInfo();
370
376
  var currentIndex = false;
371
377
 
372
378
  for (var i = 0; i < currentTracks.length; i++) {
@@ -400,23 +406,25 @@ function TizenVideo(options) {
400
406
  function onEnded() {
401
407
  events.emit('ended');
402
408
  }
403
- function onPropChanged(propName) {
409
+ async function onPropChanged(propName) {
404
410
  if (observedProps[propName]) {
405
- events.emit('propChanged', propName, getProp(propName));
411
+ var propValue = await getProp(propName);
412
+ events.emit('propChanged', propName, propValue);
406
413
  }
407
414
  }
408
- function observeProp(propName) {
415
+ async function observeProp(propName) {
409
416
  if (observedProps.hasOwnProperty(propName)) {
410
- events.emit('propValue', propName, getProp(propName));
417
+ var propValue = await getProp(propName);
418
+ events.emit('propValue', propName, propValue);
411
419
  observedProps[propName] = true;
412
420
  }
413
421
  }
414
- function setProp(propName, propValue) {
422
+ async function setProp(propName, propValue) {
415
423
  switch (propName) {
416
424
  case 'paused': {
417
425
  if (stream !== null) {
418
426
  var willPause = !!propValue;
419
- willPause ? window.webapis.avplay.pause() : window.webapis.avplay.play();
427
+ willPause ? AVPlay.pause() : AVPlay.play();
420
428
  if (willPause) {
421
429
  if (subtitleTimeout) {
422
430
  clearTimeout(subtitleTimeout);
@@ -430,10 +438,10 @@ function TizenVideo(options) {
430
438
 
431
439
  // the paused state is usually correct, but i have seen it not change on tizen 3
432
440
  // which causes all kinds of issues in the UI: (only happens with some videos)
433
- var lastKnownProp = getProp('paused');
441
+ var lastKnownProp = await getProp('paused');
434
442
 
435
- setTimeout(function() {
436
- if (getProp('paused') !== lastKnownProp) {
443
+ setTimeout(async function() {
444
+ if (await getProp('paused') !== lastKnownProp) {
437
445
  onPropChanged('paused');
438
446
  }
439
447
  }, 1000);
@@ -442,7 +450,7 @@ function TizenVideo(options) {
442
450
  }
443
451
  case 'time': {
444
452
  if (stream !== null && propValue !== null && isFinite(propValue)) {
445
- window.webapis.avplay.seekTo(parseInt(propValue, 10));
453
+ AVPlay.seekTo(parseInt(propValue, 10));
446
454
  renderSubtitle(1, '');
447
455
  onPropChanged('time');
448
456
  }
@@ -462,12 +470,13 @@ function TizenVideo(options) {
462
470
 
463
471
  currentSubTrack = propValue;
464
472
 
465
- var selectedSubtitlesTrack = getProp('subtitlesTracks')
473
+ var subtitlesTracks = await getProp('subtitlesTracks');
474
+ var selectedSubtitlesTrack = subtitlesTracks
466
475
  .find(function(track) {
467
476
  return track.id === propValue;
468
477
  });
469
478
 
470
- window.webapis.avplay.setSelectTrack('TEXT', parseInt(currentSubTrack.replace('EMBEDDED_', '')));
479
+ AVPlay.setSelectTrack('TEXT', parseInt(currentSubTrack.replace('EMBEDDED_', '')));
471
480
 
472
481
  if (selectedSubtitlesTrack) {
473
482
  events.emit('subtitlesTrackLoaded', selectedSubtitlesTrack);
@@ -565,15 +574,15 @@ function TizenVideo(options) {
565
574
  }
566
575
  case 'selectedAudioTrackId': {
567
576
  if (stream !== null) {
568
-
569
577
  currentAudioTrack = propValue;
570
578
 
571
- var selectedAudioTrack = getProp('audioTracks')
579
+ var audioTracks = await getProp('audioTracks');
580
+ var selectedAudioTrack = audioTracks
572
581
  .find(function(track) {
573
582
  return track.id === propValue;
574
583
  });
575
584
 
576
- if (getProp('paused')) {
585
+ if (await getProp('paused')) {
577
586
  // issues before this logic:
578
587
  // tizen 3 does not allow changing audio track when paused
579
588
  // tizen 5 does, but it will only change getProp('selectedAudioTrackId') after playback starts
@@ -582,7 +591,7 @@ function TizenVideo(options) {
582
591
  promiseAudioTrackChange = propValue;
583
592
  onPropChanged('selectedAudioTrackId');
584
593
  } else {
585
- window.webapis.avplay.setSelectTrack('AUDIO', parseInt(currentAudioTrack.replace('EMBEDDED_', '')));
594
+ AVPlay.setSelectTrack('AUDIO', parseInt(currentAudioTrack.replace('EMBEDDED_', '')));
586
595
  }
587
596
  if (selectedAudioTrack) {
588
597
  events.emit('audioTrackLoaded', selectedAudioTrack);
@@ -597,7 +606,7 @@ function TizenVideo(options) {
597
606
  videoSpeed = parseFloat(propValue);
598
607
 
599
608
  try {
600
- window.webapis.avplay.setSpeed(videoSpeed);
609
+ AVPlay.setSpeed(videoSpeed);
601
610
  } catch (e) {}
602
611
 
603
612
  onPropChanged('playbackSpeed');
@@ -628,13 +637,14 @@ function TizenVideo(options) {
628
637
  retrieveExtendedTracks();
629
638
  }
630
639
 
631
- window.webapis.avplay.open(stream.url);
632
- window.webapis.avplay.setDisplayRect(0, 0, window.innerWidth, window.innerHeight);
633
- window.webapis.avplay.setDisplayMethod('PLAYER_DISPLAY_MODE_LETTER_BOX');
634
- window.webapis.avplay.seekTo(commandArgs.time !== null && isFinite(commandArgs.time) ? parseInt(commandArgs.time, 10) : 0);
635
- window.webapis.avplay.prepareAsync(function() {
640
+ AVPlay.open(stream.url);
641
+ AVPlay.setDisplayRect(0, 0, window.innerWidth, window.innerHeight);
642
+ AVPlay.setDisplayMethod('PLAYER_DISPLAY_MODE_LETTER_BOX');
643
+ AVPlay.seekTo(commandArgs.time !== null && isFinite(commandArgs.time) ? parseInt(commandArgs.time, 10) : 0);
644
+
645
+ function onPrepareSuccess() {
636
646
  onPropChanged('duration');
637
- window.webapis.avplay.play();
647
+ AVPlay.play();
638
648
 
639
649
  isLoaded = true;
640
650
  onPropChanged('loaded');
@@ -646,11 +656,13 @@ function TizenVideo(options) {
646
656
  onPropChanged('selectedSubtitlesTrackId');
647
657
  onPropChanged('audioTracks');
648
658
  onPropChanged('selectedAudioTrackId');
649
- }, function(error) {
659
+ }
660
+
661
+ function onPrepareError(error) {
650
662
  if (retries < maxRetries) {
651
663
  retries++;
652
664
  try {
653
- window.webapis.avplay.stop();
665
+ AVPlay.stop();
654
666
  } catch(e) {}
655
667
  command('load', commandArgs);
656
668
  } else {
@@ -660,7 +672,9 @@ function TizenVideo(options) {
660
672
  error: error,
661
673
  }));
662
674
  }
663
- });
675
+ }
676
+
677
+ AVPlay.prepareAsync(onPrepareSuccess, onPrepareError);
664
678
  } else {
665
679
  onError(Object.assign({}, ERROR.UNSUPPORTED_STREAM, {
666
680
  critical: true,
@@ -671,7 +685,7 @@ function TizenVideo(options) {
671
685
  }
672
686
  case 'unload': {
673
687
  stream = null;
674
- window.webapis.avplay.stop();
688
+ AVPlay.stop();
675
689
  isLoaded = false;
676
690
  onPropChanged('loaded');
677
691
  onPropChanged('stream');
@@ -688,6 +702,7 @@ function TizenVideo(options) {
688
702
  case 'destroy': {
689
703
  command('unload');
690
704
  destroyed = true;
705
+ AVPlay.stop();
691
706
  onPropChanged('subtitlesOffset');
692
707
  onPropChanged('subtitlesSize');
693
708
  onPropChanged('subtitlesTextColor');