diff --git a/addon/moch/alldebrid.js b/addon/moch/alldebrid.js index 31c06b8..d4c4c5d 100644 --- a/addon/moch/alldebrid.js +++ b/addon/moch/alldebrid.js @@ -3,6 +3,7 @@ const { Type } = require('../lib/types'); const { isVideo, isArchive } = require('../lib/extension'); const StaticResponse = require('./static'); const { getMagnetLink } = require('../lib/magnetHelper'); +const { BadTokenError } = require('./mochHelper'); const KEY = 'alldebrid'; const AGENT = 'torrentio'; @@ -13,7 +14,10 @@ async function getCachedStreams(streams, apiKey) { const hashes = streams.map(stream => stream.infoHash); const available = await AD.magnet.instant(hashes) .catch(error => { - console.warn('Failed AllDebrid cached torrent availability request: ', error); + if (error && error.code === 'AUTH_BAD_APIKEY') { + return Promise.reject(BadTokenError); + } + console.warn('Failed AllDebrid cached torrent availability request:', error); return undefined; }); return available && available.data && available.data.magnets && streams diff --git a/addon/moch/debridlink.js b/addon/moch/debridlink.js index 40fdf0d..630b7db 100644 --- a/addon/moch/debridlink.js +++ b/addon/moch/debridlink.js @@ -3,7 +3,7 @@ const { Type } = require('../lib/types'); const { isVideo, isArchive } = require('../lib/extension'); const StaticResponse = require('./static'); const { getMagnetLink } = require('../lib/magnetHelper'); -const { chunkArray } = require('./mochHelper'); +const { chunkArray, BadTokenError } = require('./mochHelper'); const delay = require('./delay'); const KEY = 'debridlink'; @@ -17,7 +17,10 @@ async function getCachedStreams(streams, apiKey) { .then(results => results.map(result => result.value)) .then(results => results.reduce((all, result) => Object.assign(all, result), {})) .catch(error => { - console.warn('Failed DebridLink cached torrent availability request: ', error); + if (error === 'badToken') { + return Promise.reject(BadTokenError); + } + console.warn('Failed DebridLink cached torrent availability request:', error); return undefined; }); return available && streams diff --git a/addon/moch/moch.js b/addon/moch/moch.js index d42b4f8..4bf1c6a 100644 --- a/addon/moch/moch.js +++ b/addon/moch/moch.js @@ -7,8 +7,10 @@ const debridlink = require('./debridlink'); const putio = require('./putio'); const StaticResponse = require('./static'); const { cacheWrapResolvedUrl } = require('../lib/cache'); +const { BadTokenError } = require('./mochHelper'); const MIN_API_KEY_SYMBOLS = 15; +const TOKEN_BLACKLIST = []; const RESOLVER_HOST = process.env.RESOLVER_HOST || 'http://localhost:7050'; const MOCHS = { realdebrid: { @@ -56,24 +58,23 @@ async function applyMochs(streams, config) { if (!streams || !streams.length || !Object.keys(MOCHS).find(moch => config[moch])) { return streams; } - - const includeTorrentLinks = options.includeTorrentLinks(config); - const excludeDownloadLinks = options.excludeDownloadLinks(config); - - const configuredMochs = Object.keys(config) + return Promise.all(Object.keys(config) .filter(configKey => MOCHS[configKey]) - .filter(configKey => config[configKey].length >= MIN_API_KEY_SYMBOLS) - .map(configKey => MOCHS[configKey]); - const mochResults = await Promise.all(configuredMochs - .map(moch => moch.instance.getCachedStreams(streams, config[moch.key]) - .then(mochStreams => ({ moch, mochStreams })) - .catch(error => console.warn(error)))) - .then(results => results.filter(result => result && result.mochStreams)); - const cachedStreams = mochResults - .reduce((resultStreams, mochResult) => populateCachedLinks(resultStreams, mochResult), streams); - const resultStreams = excludeDownloadLinks ? cachedStreams : populateDownloadLinks(cachedStreams, mochResults); - - return includeTorrentLinks ? resultStreams : resultStreams.filter(stream => stream.url); + .map(configKey => MOCHS[configKey]) + .map(moch => { + if (isInvalidToken(config[moch.key], moch.key)) { + return { moch, error: BadTokenError }; + } + return moch.instance.getCachedStreams(streams, config[moch.key]) + .then(mochStreams => ({ moch, mochStreams })) + .catch(error => { + if (error === BadTokenError) { + blackListToken(config[moch.key], moch.key); + } + return { moch, error }; + }) + })) + .then(results => processMochResults(streams, config, results)); } async function resolve(parameters) { @@ -102,10 +103,9 @@ async function getMochCatalog(mochKey, config) { if (!moch) { return Promise.reject(`Not a valid moch provider: ${mochKey}`); } - if (config[mochKey].length < MIN_API_KEY_SYMBOLS) { + if (isInvalidToken(config[mochKey], mochKey)) { return Promise.reject(`Invalid API key for moch provider: ${mochKey}`); } - return moch.instance.getCatalog(config[moch.key], config.skip, config.ip); } @@ -127,6 +127,22 @@ async function getMochItemMeta(mochKey, itemId, config) { }); } +function processMochResults(streams, config, results) { + const errorResults = results.filter(result => result && result.error === BadTokenError); + if (errorResults.length) { + return errorResults.map(result => badTokenStreamResponse(result.moch.key)) + } + + const includeTorrentLinks = options.includeTorrentLinks(config); + const excludeDownloadLinks = options.excludeDownloadLinks(config); + const mochResults = results.filter(result => result && result.mochStreams); + + const cachedStreams = mochResults + .reduce((resultStreams, mochResult) => populateCachedLinks(resultStreams, mochResult), streams); + const resultStreams = excludeDownloadLinks ? cachedStreams : populateDownloadLinks(cachedStreams, mochResults); + return includeTorrentLinks ? resultStreams : resultStreams.filter(stream => stream.url); +} + function populateCachedLinks(streams, mochResult) { return streams.map(stream => { const cachedEntry = stream.infoHash && mochResult.mochStreams[stream.infoHash]; @@ -159,4 +175,22 @@ function populateDownloadLinks(streams, mochResults) { return streams; } +function isInvalidToken(token, mochKey) { + return token.length < MIN_API_KEY_SYMBOLS || TOKEN_BLACKLIST.includes(`${mochKey}|${token}`); +} + +function blackListToken(token, mochKey) { + const tokenKey = `${mochKey}|${token}`; + console.log(`Blacklisting invalid token: ${tokenKey}`) + TOKEN_BLACKLIST.push(tokenKey); +} + +function badTokenStreamResponse(mochKey) { + return { + name: `Torrentio\n${MOCHS[mochKey].shortName} error`, + title: `Invalid ${MOCHS[mochKey].name} ApiKey/Token!`, + url: StaticResponse.FAILED_ACCESS + }; +} + module.exports = { applyMochs, getMochCatalog, getMochItemMeta, resolve, MochOptions: MOCHS } \ No newline at end of file diff --git a/addon/moch/mochHelper.js b/addon/moch/mochHelper.js index 4cbedf6..7510b4b 100644 --- a/addon/moch/mochHelper.js +++ b/addon/moch/mochHelper.js @@ -1,7 +1,9 @@ +const BadTokenError = { code: 'BAD_TOKEN' } + function chunkArray(arr, size) { return arr.length > size ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)] : [arr]; } -module.exports = { chunkArray } \ No newline at end of file +module.exports = { chunkArray, BadTokenError } \ No newline at end of file diff --git a/addon/moch/premiumize.js b/addon/moch/premiumize.js index 018884d..3e76697 100644 --- a/addon/moch/premiumize.js +++ b/addon/moch/premiumize.js @@ -4,6 +4,7 @@ const { Type } = require('../lib/types'); const { isVideo } = require('../lib/extension'); const StaticResponse = require('./static'); const { getMagnetLink } = require('../lib/magnetHelper'); +const { BadTokenError } = require('./mochHelper'); const KEY = 'premiumize'; @@ -13,7 +14,10 @@ async function getCachedStreams(streams, apiKey) { const hashes = streams.map(stream => stream.infoHash); const available = await PM.cache.check(hashes) .catch(error => { - console.warn('Failed Premiumize cached torrent availability request: ', error); + if (error && error.message === 'customer_id and pin parameter missing or not logged in ') { + return Promise.reject(BadTokenError); + } + console.warn('Failed Premiumize cached torrent availability request:', error); return undefined; }); return available && streams diff --git a/addon/moch/realdebrid.js b/addon/moch/realdebrid.js index d45cf19..bf4c023 100644 --- a/addon/moch/realdebrid.js +++ b/addon/moch/realdebrid.js @@ -41,10 +41,13 @@ async function _getInstantAvailable(hashes, apiKey, retries = 3) { }))) .then(results => results.reduce((all, result) => Object.assign(all, result), {})) .catch(error => { + if (error && error.code === 8) { + return Promise.reject(BadTokenError); + } if (retries > 0 && NON_BLACKLIST_ERRORS.some(v => error.message && error.message.includes(v))) { return _getInstantAvailable(hashes, apiKey, retries - 1); } - console.warn(`Failed RealDebrid cached [${hashes[0]}] torrent availability request: `, error.message); + console.warn(`Failed RealDebrid cached [${hashes[0]}] torrent availability request:`, error.message); return undefined; }); }