diff --git a/addon/addon.js b/addon/addon.js index 4e83ee9..57311c9 100644 --- a/addon/addon.js +++ b/addon/addon.js @@ -6,7 +6,7 @@ const { cacheWrapStream } = require('./lib/cache'); const { toStreamInfo } = require('./lib/streamInfo'); const repository = require('./lib/repository'); const applySorting = require('./lib/sort'); -const applyMochs = require('./moch/moch'); +const { applyMochs } = require('./moch/moch'); const CACHE_MAX_AGE = process.env.CACHE_MAX_AGE || 4 * 60 * 60; // 4 hours in seconds const CACHE_MAX_AGE_EMPTY = 30 * 60; // 30 minutes diff --git a/addon/moch/moch.js b/addon/moch/moch.js index 4328661..4ac2b59 100644 --- a/addon/moch/moch.js +++ b/addon/moch/moch.js @@ -1,7 +1,12 @@ const realdebrid = require('./realdebrid'); +const RESOLVER_HOST = process.env.RESOLVER_HOST || 'http://localhost:7050'; const MOCHS = { - 'realdebrid': realdebrid + 'realdebrid': { + key: 'realdebrid', + instance: realdebrid, + shortName: 'RD' + } }; async function applyMochs(streams, config) { @@ -9,15 +14,34 @@ async function applyMochs(streams, config) { return streams; } - return Object.keys(config) + return Promise.all(Object.keys(config) .filter(configKey => MOCHS[configKey]) - .reduce(async (streams, moch) => { - return await MOCHS[moch].applyMoch(streams, config[moch]) - .catch(error => { - console.warn(error); - return streams; - }); - }, streams); + .map(configKey => MOCHS[configKey]) + .map(moch => moch.instance.getCachedStreams(streams, config[moch.key]) + .then(cachedStreams => ({ moch, cachedStreams })) + .catch(error => console.warn(error)))) + .then(mochResults => mochResults + .filter(result => result && result.cachedStreams) + .reduce((resultStreams, { moch, cachedStreams }) => { + resultStreams + .filter(stream => stream.infoHash) + .filter(stream => cachedStreams[stream.infoHash]) + .forEach(stream => { + stream.name = `[${moch.shortName}+] ${stream.name}`; + stream.url = `${RESOLVER_HOST}/${moch.key}/${cachedStreams[stream.infoHash]}`; + delete stream.infoHash; + delete stream.fileIndex; + }); + return resultStreams; + }, streams)); } -module.exports = applyMochs; \ No newline at end of file +async function resolve(parameters) { + const moch = MOCHS[parameters.mochKey]; + if (!moch) { + return Promise.reject('Not a valid moch provider'); + } + return moch.instance.resolve(parameters); +} + +module.exports = { applyMochs, resolve } \ No newline at end of file diff --git a/addon/moch/realdebrid.js b/addon/moch/realdebrid.js index 7d51ebc..f467252 100644 --- a/addon/moch/realdebrid.js +++ b/addon/moch/realdebrid.js @@ -5,13 +5,11 @@ const isVideo = require('../lib/video'); const { getRandomProxy, getRandomUserAgent } = require('../lib/request_helper'); const { cacheWrapResolvedUrl, cacheWrapProxy, cacheUserAgent } = require('../lib/cache'); -const RESOLVER_HOST = process.env.RESOLVER_HOST || 'http://localhost:7050'; - const unrestrictQueue = new namedQueue((task, callback) => task.method() .then(result => callback(false, result)) .catch((error => callback(error)))); -async function applyMoch(streams, apiKey) { +async function getCachedStreams(streams, apiKey) { const options = await getDefaultOptions(apiKey); const RD = new RealDebridClient(apiKey, options); const hashes = streams.map(stream => stream.infoHash); @@ -20,28 +18,23 @@ async function applyMoch(streams, apiKey) { console.warn('Failed cached torrent availability request: ', error); return undefined; }); - if (available) { - streams.forEach(stream => { - const cachedEntry = available[stream.infoHash]; - const cachedIds = _getCachedFileIds(stream.fileIdx, cachedEntry).join(','); - if (cachedIds.length) { - stream.name = `[RD+] ${stream.name}`; - stream.url = `${RESOLVER_HOST}/realdebrid/${apiKey}/${stream.infoHash}/${cachedIds}/${stream.fileIdx}`; - delete stream.infoHash; - delete stream.fileIndex; - } - }); - } - - return streams; + return available && streams + .reduce((cachedStreams, stream) => { + const cachedEntry = available[stream.infoHash]; + const cachedIds = _getCachedFileIds(stream.fileIdx, cachedEntry).join(','); + if (cachedIds.length) { + cachedStreams[stream.infoHash] = `${apiKey}/${stream.infoHash}/${cachedIds}/${stream.fileIdx}`; + } + return cachedStreams; + }, {}) } -async function resolve(apiKey, infoHash, cachedFileIds, fileIndex) { - if (!apiKey || !infoHash || !cachedFileIds || !cachedFileIds.length) { +async function resolve({ apiKey, infoHash, cachedEntryInfo, fileIndex }) { + if (!apiKey || !infoHash || !cachedEntryInfo) { return Promise.reject("No valid parameters passed"); } const id = `${apiKey}_${infoHash}_${fileIndex}`; - const method = () => cacheWrapResolvedUrl(id, () => _unrestrict(apiKey, infoHash, cachedFileIds, fileIndex)); + const method = () => cacheWrapResolvedUrl(id, () => _unrestrict(apiKey, infoHash, cachedEntryInfo, fileIndex)); return new Promise(((resolve, reject) => { unrestrictQueue.push({ id, method }, (error, result) => result ? resolve(result) : reject(error)); @@ -112,9 +105,9 @@ async function _unrestrictLink(RD, link) { async function getDefaultOptions(id) { const userAgent = await cacheUserAgent(id, () => getRandomUserAgent()).catch(() => getRandomUserAgent()); - const proxy = await cacheWrapProxy('realdebrid', () => getRandomProxy()).catch(() => getRandomProxy()); + const proxy = await cacheWrapProxy('moch', () => getRandomProxy()).catch(() => getRandomProxy()); return { proxy: proxy, headers: { 'User-Agent': userAgent } }; } -module.exports = { applyMoch, resolve }; \ No newline at end of file +module.exports = { getCachedStreams, resolve }; \ No newline at end of file diff --git a/addon/package-lock.json b/addon/package-lock.json index 73af197..13d8e09 100644 --- a/addon/package-lock.json +++ b/addon/package-lock.json @@ -1604,8 +1604,8 @@ } }, "parse-torrent-title": { - "version": "git://github.com/TheBeastLT/parse-torrent-title.git#6f837b460175695757395a0e1b40f760a40f0f59", - "from": "git://github.com/TheBeastLT/parse-torrent-title.git#6f837b460175695757395a0e1b40f760a40f0f59", + "version": "git://github.com/TheBeastLT/parse-torrent-title.git#49be4a2b4ab14e26fca4e52de82f6ad08948fdc7", + "from": "git://github.com/TheBeastLT/parse-torrent-title.git#49be4a2b4ab14e26fca4e52de82f6ad08948fdc7", "requires": { "moment": "^2.24.0" } diff --git a/addon/package.json b/addon/package.json index 3cea184..3718a0d 100644 --- a/addon/package.json +++ b/addon/package.json @@ -15,7 +15,7 @@ "named-queue": "^2.2.1", "needle": "^2.2.4", "magnet-uri": "^5.1.7", - "parse-torrent-title": "git://github.com/TheBeastLT/parse-torrent-title.git#6f837b460175695757395a0e1b40f760a40f0f59", + "parse-torrent-title": "git://github.com/TheBeastLT/parse-torrent-title.git#49be4a2b4ab14e26fca4e52de82f6ad08948fdc7", "pg": "^7.8.2", "pg-hstore": "^2.3.2", "real-debrid-api": "git://github.com/TheBeastLT/node-real-debrid.git#935a5c23ae809edbcd2a111526a7f74d6767c50d", diff --git a/addon/serverless.js b/addon/serverless.js index 7c647a7..433f710 100644 --- a/addon/serverless.js +++ b/addon/serverless.js @@ -4,7 +4,7 @@ const addonInterface = require('./addon'); const { manifest } = require('./lib/manifest'); const parseConfiguration = require('./lib/configuration'); const landingTemplate = require('./lib/landingTemplate'); -const realDebrid = require('./moch/realdebrid'); +const moch = require('./moch/moch'); const router = getRouter(addonInterface); const limiter = rateLimit({ @@ -69,9 +69,16 @@ router.get('/:configuration/:resource/:type/:id.json', (req, res, next) => { }); }); -router.get('/realdebrid/:apiKey/:infoHash/:cachedFileIds/:fileIndex?', (req, res) => { - const { apiKey, infoHash, cachedFileIds, fileIndex } = req.params; - realDebrid.resolve(apiKey, infoHash, cachedFileIds, isNaN(fileIndex) ? undefined : parseInt(fileIndex)) +router.get('/:moch/:apiKey/:infoHash/:cachedEntryInfo/:fileIndex?', (req, res) => { + const parameters = { + mochKey: req.params.moch, + apiKey: req.params.apiKey, + infoHash: req.params.infoHash, + fileIndex: isNaN(req.params.fileIndex) ? undefined : parseInt(req.params.fileIndex), + cachedEntryInfo: req.params.cachedEntryInfo, + ip: req.ip + } + moch.resolve(parameters) .then(url => { res.writeHead(302, { Location: url }); res.end();