@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
|
@@ -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
|
-
|
|
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
|
-
|
|
117
|
-
|
|
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 = {
|