@stremio/stremio-video 0.0.23 → 0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stremio/stremio-video",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "Abstraction layer on top of different media players",
5
5
  "author": "Smart Code OOD",
6
6
  "main": "src/index.js",
@@ -0,0 +1,94 @@
1
+ var VIDEO_CODEC_CONFIGS = [
2
+ {
3
+ codec: 'h264',
4
+ mime: 'video/mp4; codecs="avc1.42E01E"',
5
+ },
6
+ {
7
+ codec: 'h265',
8
+ mime: 'video/mp4; codecs="hev1.1.6.L150.B0"',
9
+ aliases: ['hevc']
10
+ },
11
+ {
12
+ codec: 'vp8',
13
+ mime: 'video/mp4; codecs="vp8"'
14
+ },
15
+ {
16
+ codec: 'vp9',
17
+ mime: 'video/mp4; codecs="vp9"'
18
+ }
19
+ ];
20
+
21
+ var AUDIO_CODEC_CONFIGS = [
22
+ {
23
+ codec: 'aac',
24
+ mime: 'audio/mp4; codecs="mp4a.40.2"'
25
+ },
26
+ {
27
+ codec: 'mp3',
28
+ mime: 'audio/mp4; codecs="mp3"'
29
+ },
30
+ {
31
+ codec: 'ac3',
32
+ mime: 'audio/mp4; codecs="ac-3"'
33
+ },
34
+ {
35
+ codec: 'eac3',
36
+ mime: 'audio/mp4; codecs="ec-3"'
37
+ },
38
+ {
39
+ codec: 'vorbis',
40
+ mime: 'audio/mp4; codecs="vorbis"'
41
+ },
42
+ {
43
+ codec: 'opus',
44
+ mime: 'audio/mp4; codecs="opus"'
45
+ }
46
+ ];
47
+
48
+ function canPlay(config, options) {
49
+ return options.mediaElement.canPlayType(config.mime) ?
50
+ [config.codec].concat(config.aliases || [])
51
+ :
52
+ [];
53
+ }
54
+
55
+ function getMaxAudioChannels() {
56
+ if (/firefox/i.test(window.navigator.userAgent)) {
57
+ return 6;
58
+ }
59
+
60
+ if (!window.AudioContext) {
61
+ return 2;
62
+ }
63
+
64
+ var maxChannelCount = new AudioContext().destination.maxChannelCount;
65
+ return maxChannelCount > 0 ? maxChannelCount : 2;
66
+ }
67
+
68
+ function getMediaCapabilities() {
69
+ var mediaElement = document.createElement('video');
70
+ var formats = ['mp4'];
71
+ var videoCodecs = VIDEO_CODEC_CONFIGS
72
+ .map(function(config) {
73
+ return canPlay(config, { mediaElement: mediaElement });
74
+ })
75
+ .reduce(function(result, value) {
76
+ return result.concat(value);
77
+ }, []);
78
+ var audioCodecs = AUDIO_CODEC_CONFIGS
79
+ .map(function(config) {
80
+ return canPlay(config, { mediaElement: mediaElement });
81
+ })
82
+ .reduce(function(result, value) {
83
+ return result.concat(value);
84
+ }, []);
85
+ var maxAudioChannels = getMaxAudioChannels();
86
+ return {
87
+ formats: formats,
88
+ videoCodecs: videoCodecs,
89
+ audioCodecs: audioCodecs,
90
+ maxAudioChannels: maxAudioChannels
91
+ };
92
+ }
93
+
94
+ module.exports = getMediaCapabilities();
@@ -3,6 +3,7 @@ var url = require('url');
3
3
  var hat = require('hat');
4
4
  var cloneDeep = require('lodash.clonedeep');
5
5
  var deepFreeze = require('deep-freeze');
6
+ var mediaCapabilities = require('../mediaCapabilities');
6
7
  var convertStream = require('./convertStream');
7
8
  var ERROR = require('../error');
8
9
 
@@ -96,7 +97,29 @@ function withStreamingServer(Video) {
96
97
  onPropChanged('stream');
97
98
  convertStream(commandArgs.streamingServerURL, commandArgs.stream, commandArgs.seriesInfo)
98
99
  .then(function(mediaURL) {
99
- return (commandArgs.forceTranscoding ? Promise.resolve(false) : Video.canPlayStream({ url: mediaURL }))
100
+ var formats = Array.isArray(commandArgs.formats) ?
101
+ commandArgs.formats
102
+ :
103
+ mediaCapabilities.formats;
104
+ var videoCodecs = Array.isArray(commandArgs.videoCodecs) ?
105
+ commandArgs.videoCodecs
106
+ :
107
+ mediaCapabilities.videoCodecs;
108
+ var audioCodecs = Array.isArray(commandArgs.audioCodecs) ?
109
+ commandArgs.audioCodecs
110
+ :
111
+ mediaCapabilities.audioCodecs;
112
+ var maxAudioChannels = commandArgs.maxAudioChannels !== null && isFinite(commandArgs.maxAudioChannels) ?
113
+ commandArgs.maxAudioChannels
114
+ :
115
+ mediaCapabilities.maxAudioChannels;
116
+ var canPlayStreamOptions = Object.assign({}, commandArgs, {
117
+ formats: formats,
118
+ videoCodecs: videoCodecs,
119
+ audioCodecs: audioCodecs,
120
+ maxAudioChannels: maxAudioChannels
121
+ });
122
+ return (commandArgs.forceTranscoding ? Promise.resolve(false) : VideoWithStreamingServer.canPlayStream({ url: mediaURL }, canPlayStreamOptions))
100
123
  .catch(function(error) {
101
124
  console.warn('Media probe error', error);
102
125
  return false;
@@ -113,9 +136,16 @@ function withStreamingServer(Video) {
113
136
  if (commandArgs.forceTranscoding) {
114
137
  queryParams.set('forceTranscoding', '1');
115
138
  }
116
- if (commandArgs.maxAudioChannels !== null && isFinite(commandArgs.maxAudioChannels)) {
117
- queryParams.set('maxAudioChannels', commandArgs.maxAudioChannels);
118
- }
139
+
140
+ videoCodecs.forEach(function(videoCodec) {
141
+ queryParams.append('videoCodecs', videoCodec);
142
+ });
143
+
144
+ audioCodecs.forEach(function(audioCodec) {
145
+ queryParams.append('audioCodecs', audioCodec);
146
+ });
147
+
148
+ queryParams.set('maxAudioChannels', maxAudioChannels);
119
149
 
120
150
  return {
121
151
  url: url.resolve(commandArgs.streamingServerURL, '/hlsv2/' + id + '/master.m3u8?' + queryParams.toString()),
@@ -269,8 +299,38 @@ function withStreamingServer(Video) {
269
299
  };
270
300
  }
271
301
 
272
- VideoWithStreamingServer.canPlayStream = function(stream) {
273
- return Video.canPlayStream(stream);
302
+ VideoWithStreamingServer.canPlayStream = function(stream, options) {
303
+ return Video.canPlayStream(stream)
304
+ .then(function(canPlay) {
305
+ if (!canPlay) {
306
+ throw new Error('Fallback using /hlsv2/probe');
307
+ }
308
+
309
+ return canPlay;
310
+ })
311
+ .catch(function() {
312
+ var queryParams = new URLSearchParams([['mediaURL', stream.url]]);
313
+ return fetch(url.resolve(options.streamingServerURL, '/hlsv2/probe?' + queryParams.toString()))
314
+ .then(function(resp) {
315
+ return resp.json();
316
+ })
317
+ .then(function(probe) {
318
+ var isFormatSupported = options.formats.some(function(format) {
319
+ return probe.format.name.indexOf(format) !== -1;
320
+ });
321
+ var areStreamsSupported = probe.streams.every(function(stream) {
322
+ if (stream.track === 'audio') {
323
+ return stream.channels <= options.maxAudioChannels &&
324
+ options.audioCodecs.indexOf(stream.codec) !== -1;
325
+ } else if (stream.track === 'video') {
326
+ return options.videoCodecs.indexOf(stream.codec) !== -1;
327
+ }
328
+
329
+ return true;
330
+ });
331
+ return isFormatSupported && areStreamsSupported;
332
+ });
333
+ });
274
334
  };
275
335
 
276
336
  VideoWithStreamingServer.manifest = {