mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 11:42:05 +00:00
integrate video-name-parser and extract pure functions from middleware impl
This commit is contained in:
parent
ec7bb07c12
commit
146a80d310
1 changed files with 132 additions and 119 deletions
|
|
@ -2,6 +2,66 @@
|
||||||
|
|
||||||
var UrlUtils = require('url');
|
var UrlUtils = require('url');
|
||||||
var EventEmitter = require('events');
|
var EventEmitter = require('events');
|
||||||
|
var parseVideoName = require('video-name-parser');
|
||||||
|
|
||||||
|
var VIDEO_FILE_EXTENTIONS = /.mkv$|.avi$|.mp4$|.wmv$|.vp8$|.mov$|.mpg$|.ts$|.webm$/i;
|
||||||
|
|
||||||
|
function createTorrent(streamingServerUrl, infoHash, sources) {
|
||||||
|
return fetch(UrlUtils.resolve(streamingServerUrl, `/${encodeURIComponent(infoHash)}/create`), {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
torrent: {
|
||||||
|
infoHash,
|
||||||
|
peerSearch: {
|
||||||
|
sources: [`dht:${infoHash}`].concat(Array.isArray(sources) ? sources : []),
|
||||||
|
min: 40,
|
||||||
|
max: 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).then(function(resp) {
|
||||||
|
return resp.json();
|
||||||
|
}).catch(function(error) {
|
||||||
|
throw {
|
||||||
|
message: 'Unable to get files from torrent',
|
||||||
|
critical: true,
|
||||||
|
error: error
|
||||||
|
};
|
||||||
|
}).then(function(resp) {
|
||||||
|
if (!resp || !Array.isArray(resp.files) || resp.files.length === 0) {
|
||||||
|
throw {
|
||||||
|
message: 'Unable to get files from torrent',
|
||||||
|
critical: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function guessFileIdx(files, seriesInfo) {
|
||||||
|
var videoFilesForEpisode = files.filter(function(file) {
|
||||||
|
if (seriesInfo && file.path.match(VIDEO_FILE_EXTENTIONS)) {
|
||||||
|
try {
|
||||||
|
var info = parseVideoName(file.path);
|
||||||
|
return !isNaN(info.season) && Array.isArray(info.episode) &&
|
||||||
|
info.season === seriesInfo.season && info.episode.indexOf(seriesInfo.episode) !== -1;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var largestFile = (videoFilesForEpisode.length > 0 ? videoFilesForEpisode : files)
|
||||||
|
.reduce((result, file) => {
|
||||||
|
if (!result || file.length > result.length) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, null);
|
||||||
|
return files.indexOf(largestFile);
|
||||||
|
}
|
||||||
|
|
||||||
function withStreamingServer(Video) {
|
function withStreamingServer(Video) {
|
||||||
function StreamingServerVideo(options) {
|
function StreamingServerVideo(options) {
|
||||||
|
|
@ -9,156 +69,109 @@ function withStreamingServer(Video) {
|
||||||
var events = new EventEmitter();
|
var events = new EventEmitter();
|
||||||
|
|
||||||
var destroyed = false;
|
var destroyed = false;
|
||||||
var loaded = false;
|
|
||||||
var stream = null;
|
var stream = null;
|
||||||
var dispatchArgsLoadingQueue = [];
|
|
||||||
|
|
||||||
events.on('error', function() { });
|
events.on('error', function() { });
|
||||||
|
|
||||||
function onError(error) {
|
function onError(error) {
|
||||||
if (!error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.freeze(error);
|
|
||||||
events.emit('error', error);
|
events.emit('error', error);
|
||||||
if (error.critical) {
|
if (error.critical) {
|
||||||
dispatch({ commandName: 'stop' });
|
stop();
|
||||||
|
video.dispatch({ commandName: 'stop' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function flushDispatchArgsQueue(dispatchArgsQueue) {
|
function stop() {
|
||||||
while (dispatchArgsQueue.length > 0) {
|
stream = null;
|
||||||
var args = dispatchArgsQueue.shift();
|
|
||||||
dispatch(args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function on(eventName, listener) {
|
function load(args) {
|
||||||
|
video.dispatch({ commandName: 'stop' });
|
||||||
|
stream = args.stream;
|
||||||
|
new Promise(function(resolve, reject) {
|
||||||
|
if (typeof args.stream.ytId === 'string') {
|
||||||
|
resolve(UrlUtils.resolve(args.streamingServerUrl, `/yt/${encodeURIComponent(args.stream.ytId)}?${new URLSearchParams([['request', Date.now()]])}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof args.stream.infoHash === 'string') {
|
||||||
|
if (args.stream.fileIdx !== null && !isNaN(args.stream.fileIdx)) {
|
||||||
|
resolve(UrlUtils.resolve(args.streamingServerUrl, `/${args.stream.infoHash}/${args.stream.fileIdx}`));
|
||||||
|
} else {
|
||||||
|
createTorrent(args.streamingServerUrl, args.stream.infoHash, args.stream.sources)
|
||||||
|
.then(function(resp) {
|
||||||
|
var fileIdx = guessFileIdx(resp.files, args.stream.seriesInfo);
|
||||||
|
resolve(UrlUtils.resolve(args.streamingServerUrl, `/${args.stream.infoHash}/${fileIdx}`));
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reject({
|
||||||
|
message: 'Unable to play stream',
|
||||||
|
critical: true,
|
||||||
|
stream: args.stream
|
||||||
|
});
|
||||||
|
}).then(function(url) {
|
||||||
|
if (destroyed || args.stream !== stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
video.dispatch({
|
||||||
|
commandName: 'load',
|
||||||
|
commandArgs: {
|
||||||
|
autoplay: args.autoplay,
|
||||||
|
time: args.time,
|
||||||
|
stream: {
|
||||||
|
url: url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(function(error) {
|
||||||
|
if (destroyed || args.stream !== stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function destroy() {
|
||||||
|
stop();
|
||||||
|
destroyed = true;
|
||||||
|
events.removeAllListeners();
|
||||||
|
events.on('error', function() { });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.on = function(eventName, listener) {
|
||||||
if (!destroyed) {
|
if (!destroyed) {
|
||||||
events.on(eventName, listener);
|
events.on(eventName, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
video.on(eventName, listener);
|
video.on(eventName, listener);
|
||||||
}
|
};
|
||||||
function dispatch(args) {
|
this.dispatch = function(args) {
|
||||||
if (!destroyed && args) {
|
if (!destroyed && args) {
|
||||||
if (typeof args.commandName === 'string') {
|
if (typeof args.commandName === 'string') {
|
||||||
switch (args.commandName) {
|
switch (args.commandName) {
|
||||||
case 'addSubtitlesTracks': {
|
|
||||||
if (!loaded && stream !== null) {
|
|
||||||
dispatchArgsLoadingQueue.push(args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'stop': {
|
case 'stop': {
|
||||||
loaded = false;
|
stop();
|
||||||
stream = null;
|
|
||||||
dispatchArgsLoadingQueue = [];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'load': {
|
case 'load': {
|
||||||
dispatch({ commandName: 'stop' });
|
load(args.commandArgs);
|
||||||
if (args.commandArgs && typeof args.commandArgs.streamingServerUrl === 'string' && args.commandArgs.stream) {
|
return;
|
||||||
if (typeof args.commandArgs.stream.infoHash === 'string') {
|
|
||||||
stream = args.commandArgs.stream;
|
|
||||||
if (stream.fileIdx !== null && !isNaN(stream.fileIdx)) {
|
|
||||||
video.dispatch({
|
|
||||||
commandName: 'load',
|
|
||||||
commandArgs: {
|
|
||||||
autoplay: args.commandArgs.autoplay,
|
|
||||||
time: args.commandArgs.time,
|
|
||||||
stream: {
|
|
||||||
url: UrlUtils.resolve(args.commandArgs.streamingServerUrl, stream.infoHash + '/' + String(stream.fileIdx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
loaded = true;
|
|
||||||
} else {
|
|
||||||
fetch(UrlUtils.resolve(args.commandArgs.streamingServerUrl, stream.infoHash + '/create'), {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
torrent: {
|
|
||||||
infoHash: stream.infoHash
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).then(function(resp) {
|
|
||||||
return resp.json();
|
|
||||||
}).then(function(resp) {
|
|
||||||
if (stream !== args.commandArgs.stream) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(resp.files) || resp.files.length === 0) {
|
|
||||||
onError({
|
|
||||||
message: 'Unable to get files from torrent',
|
|
||||||
critical: true
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileIdx = resp.files.reduce((fileIdx, _, index, files) => {
|
|
||||||
if (files[index].length > files[fileIdx].length) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileIdx;
|
|
||||||
}, 0);
|
|
||||||
video.dispatch({
|
|
||||||
commandName: 'load',
|
|
||||||
commandArgs: {
|
|
||||||
autoplay: args.commandArgs.autoplay,
|
|
||||||
time: args.commandArgs.time,
|
|
||||||
stream: {
|
|
||||||
url: UrlUtils.resolve(args.commandArgs.streamingServerUrl, stream.infoHash + '/' + String(fileIdx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
loaded = true;
|
|
||||||
flushDispatchArgsQueue(dispatchArgsLoadingQueue);
|
|
||||||
}).catch(function(error) {
|
|
||||||
if (stream !== args.commandArgs.stream) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onError({
|
|
||||||
message: 'Unable to get files from torrent',
|
|
||||||
critical: true,
|
|
||||||
error: error
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'destroy': {
|
case 'destroy': {
|
||||||
dispatch({ commandName: 'stop' });
|
destroy();
|
||||||
destroyed = true;
|
|
||||||
events.removeAllListeners();
|
|
||||||
events.on('error', function() { });
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (typeof args.propName === 'string') {
|
|
||||||
if (!loaded && stream !== null && ['paused', 'time', 'selectedSubtitlesTrackId', 'subtitlesDelay'].indexOf(args.propName) !== -1) {
|
|
||||||
dispatchArgsLoadingQueue.push(args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
video.dispatch(args);
|
video.dispatch(args);
|
||||||
}
|
};
|
||||||
|
|
||||||
this.on = on;
|
|
||||||
this.dispatch = dispatch;
|
|
||||||
|
|
||||||
Object.freeze(this);
|
Object.freeze(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue