integrate video-name-parser and extract pure functions from middleware impl

This commit is contained in:
nklhrstv 2020-04-23 15:02:09 +03:00
parent ec7bb07c12
commit 146a80d310

View file

@ -2,6 +2,66 @@
var UrlUtils = require('url');
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 StreamingServerVideo(options) {
@ -9,156 +69,109 @@ function withStreamingServer(Video) {
var events = new EventEmitter();
var destroyed = false;
var loaded = false;
var stream = null;
var dispatchArgsLoadingQueue = [];
events.on('error', function() { });
function onError(error) {
if (!error) {
return;
}
Object.freeze(error);
events.emit('error', error);
if (error.critical) {
dispatch({ commandName: 'stop' });
stop();
video.dispatch({ commandName: 'stop' });
}
}
function flushDispatchArgsQueue(dispatchArgsQueue) {
while (dispatchArgsQueue.length > 0) {
var args = dispatchArgsQueue.shift();
dispatch(args);
}
function stop() {
stream = null;
}
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) {
events.on(eventName, listener);
}
video.on(eventName, listener);
}
function dispatch(args) {
};
this.dispatch = function(args) {
if (!destroyed && args) {
if (typeof args.commandName === 'string') {
switch (args.commandName) {
case 'addSubtitlesTracks': {
if (!loaded && stream !== null) {
dispatchArgsLoadingQueue.push(args);
return;
}
break;
}
case 'stop': {
loaded = false;
stream = null;
dispatchArgsLoadingQueue = [];
stop();
break;
}
case 'load': {
dispatch({ commandName: 'stop' });
if (args.commandArgs && typeof args.commandArgs.streamingServerUrl === 'string' && args.commandArgs.stream) {
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;
load(args.commandArgs);
return;
}
case 'destroy': {
dispatch({ commandName: 'stop' });
destroyed = true;
events.removeAllListeners();
events.on('error', function() { });
destroy();
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);
}
this.on = on;
this.dispatch = dispatch;
};
Object.freeze(this);
}