From f05268ce28666cf34b31035c8b2472a9478bc969 Mon Sep 17 00:00:00 2001 From: Andreas Tsarida Date: Mon, 25 Mar 2024 08:38:37 +0100 Subject: [PATCH] multiple (#57) * multiple * small * nocache * revert id --- src/cache.js | 5 ++--- src/config.js | 4 ++++ src/helpers.js | 9 +++++++-- src/index.js | 23 +++++++++-------------- src/jackett.js | 9 +++++++++ 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/cache.js b/src/cache.js index 6d62d1b..d00855c 100644 --- a/src/cache.js +++ b/src/cache.js @@ -11,9 +11,8 @@ function getCacheVariable(key, renewalMinutes = 0) { const cachedItem = cache[key]; if (cachedItem && Date.now() < cachedItem.expirationTime) { - // Renew the expiration time - if (renewalMinutes > 0) { - cachedItem.expirationTime = Date.now() + renewalMinutes * 60 * 1000; + if (renewalMinutes > 0 && cache[key]) { + cache[key].expirationTime = Date.now() + renewalMinutes * 60 * 1000; } return cachedItem.value; } diff --git a/src/config.js b/src/config.js index 075fcd1..04b5338 100644 --- a/src/config.js +++ b/src/config.js @@ -20,6 +20,8 @@ const defaultConfig = { "searchByType": process.env.SEARCH_BY_TYPE || false, + "dontSearchByYear": process.env.DONT_SEARCH_BY_YEAR || false, + "responseTimeout": parseInt(process.env.RESPONSE_TIMEOUT) || 8000, "addonPort": parseInt(process.env.PORT) || 7000, @@ -30,6 +32,8 @@ const defaultConfig = { "maximumSize": process.env.MAX_SIZE || "5GB", + "ignoreTitles": process.env.IGNORE_TITLES || "\\b(Telecine|CAMRip)\\b|\\b(?:HD-?)?T(?:ELE)?S(?:YNC)?\\b|\\b(?:HD-?)?CAM\\b|\\b(?:HQ-?)?CAM\\b", + "downloadTorrentQueue": parseInt(process.env.DOWNLOAD_TORRENT_QUEUE) || 10, "cacheIndexersTime": parseInt(process.env.CACHE_INDEXERS_TIME) || 30, diff --git a/src/helpers.js b/src/helpers.js index 3887e87..94dfe0b 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -57,13 +57,18 @@ const helper = { }, findQuality: (tag) => { - const regex = /DLRip|HDTV|\b(DivX|XviD)\b|\b(?:DL|WEB|BD|BR)MUX\b|\bWEB-?Rip\b|\bWEB-?DL\b|\bBluray\b|\bVHSSCR\b|\bR5\b|\bPPVRip\b|\bTC\b|\b(?:HD-?)?TVRip\b|\bDVDscr\b|\bDVD(?:R[0-9])?\b|\bDVDRip\b|\bBDRip\b|\bBRRip\b|\bHD-?Rip\b|\b(?:HD-?)?T(?:ELE)?S(?:YNC)?\b|\b(?:HD-?)?CAM\b|(4k)|([0-9]{3,4}[pi])/i; + const regex = /DLRip|HDTV|\b(DivX|XviD)\b|\b(?:DL|WEB|BD|BR)MUX\b|\bWEB-?Rip\b|\bWEB-?DL\b|\b(WEB|Telecine|CAMRip|HQCAM)\b|\bBluray\b|\bVHSSCR\b|\bR5\b|\bPPVRip\b|\bTC\b|\b(?:HD-?)?TVRip\b|\bDVDscr\b|\bDVD(?:R[0-9])?\b|\bDVDRip\b|\bBDRip\b|\bBRRip\b|\bHD-?Rip\b|\b(?:HD-?)?T(?:ELE)?S(?:YNC)?\b|\b(?:HD-?)?CAM\b/i; + const regexP = /(4k)|([0-9]{3,4}[pi])/i; const match = tag.match(regex); + const matchP = tag.match(regexP); let quality = ""; if (match !== null) { quality = match[0]; + } else if (matchP !== null) { + quality = matchP[0]; } - return quality + return quality; + }, normalizeTitle: (torrent, info) => { diff --git a/src/index.js b/src/index.js index 4e71950..02eb0eb 100644 --- a/src/index.js +++ b/src/index.js @@ -28,7 +28,7 @@ const manifest = { "version": version, "name": config.addonName, - "description": "Stremio Add-on to get torrent results from Jackett", + "description": "Stremio Add-on to get torrent results from Jackett.", "icon": "https://svgur.com/i/12Ss.svg", "logo": "https://uxwing.com/wp-content/themes/uxwing/download/clothes-and-accessories/hoodie-jacket-icon.png", @@ -54,10 +54,7 @@ const manifest = { "configurationRequired": false }, - // works for both movies and series "types": ["movie", "series"], - - // prefix of item IDs (ie: "tt0032138") "idPrefixes": ["tt", "tmdb"], "catalogs": [] @@ -187,7 +184,7 @@ function streamFromParsed(tor, parsedTorrent, streamInfo, cb) { } else { let regEx = null; if (streamInfo.type === 'movie') { - regEx = new RegExp(`${streamInfo.name.split(' ').join('.*')}.*${config.searchByYear && streamInfo.year ? streamInfo.year : ''}.*`, 'i'); + regEx = new RegExp(`${streamInfo.name.split(' ').join('.*')}.*${!config.dontSearchByYear && streamInfo.year ? streamInfo.year : ''}.*`, 'i'); } else { regEx = new RegExp(`${streamInfo.name.split(' ').join('.*')}.*${helper.episodeTag(streamInfo.season, streamInfo.episode)}.*`, 'i'); } @@ -313,10 +310,10 @@ addon.get('/stream/:type/:id.json', async (req, res) => { config.debug && console.log("Received request for :", req.params.type, req.params.id); // cache - if (config.cacheResultsTime && config.cacheResultsTime != 0) { + if (config.cacheResultsTime && config.cacheResultsTime != 0 && !req.headers['no-cache']) { const cached = getCacheVariable(req.params.id, config.cacheResultsTime); if (cached) { - console.log("C: Serving cached results for " + req.params.type + " id: " + req.params.id); + console.log("C: " + req.params.id + " cached."); return respond(res, { streams: cached, "cacheMaxAge": 7200, @@ -366,9 +363,7 @@ addon.get('/stream/:type/:id.json', async (req, res) => { }); } - console.log(`Q: ${streamInfo.Id} / title: ${streamInfo.name} / type: ${streamInfo.type} / year: ${streamInfo.year}` + - (streamInfo.season && streamInfo.episode ? ` / season: ${streamInfo.season} / episode: ${streamInfo.episode}` : '') + - '.'); + console.log(`Q: ${req.params.id} / title: ${streamInfo.name} / year: ${streamInfo.year}`); let inProgressCount = 0; let searchFinished = false; @@ -387,7 +382,7 @@ addon.get('/stream/:type/:id.json', async (req, res) => { clearInterval(intervalId); const finalData = processTorrentList(streams); config.debug && console.log("Sliced & Sorted data ", finalData); - console.log(`A: ${streamInfo.Id} / time: ${elapsedTime} / results: ${finalData.length} / timeout: ${(elapsedTime >= config.responseTimeout)} / search finished: ${searchFinished} / queue idle: ${asyncQueue.idle()} / pending downloads: ${inProgressCount} / discarded: ${(streams.length - finalData.length)}`); + console.log(`A: ${req.params.id} / time: ${elapsedTime} / results: ${finalData.length} / timeout: ${(elapsedTime >= config.responseTimeout)} / search finished: ${searchFinished} / queue idle: ${asyncQueue.idle()} / pending downloads: ${inProgressCount} / discarded: ${(streams.length - finalData.length)}`); if (finalData.length > 0) { res.setHeader('Cache-Control', 'max-age=7200, stale-while-revalidate=14400, stale-if-error=604800, public'); // Set cache-related headers if "streams" contains data @@ -408,12 +403,12 @@ addon.get('/stream/:type/:id.json', async (req, res) => { }); } } - config.debug && console.log(`s: id: ${streamInfo.Id} / time pending: ${(config.responseTimeout - elapsedTime)} / search finished: ${searchFinished} / queue idle: ${asyncQueue.idle()} / pending downloads: ${inProgressCount} / processed streams: ${streams.length}`); + config.debug && console.log(`S: id: ${streamInfo.Id} / time pending: ${(config.responseTimeout - elapsedTime)} / search finished: ${searchFinished} / queue idle: ${asyncQueue.idle()} / pending downloads: ${inProgressCount} / processed streams: ${streams.length}`); }, config.interval); const processMagnets = async (task) => { - if (requestSent) { // Check the flag before processing each task + if (requestSent) { return; } const uri = task.magneturl || task.link; @@ -436,7 +431,7 @@ addon.get('/stream/:type/:id.json', async (req, res) => { config.debug && console.log("Processing link: ", task.link); const response = await axios.get(task.link, { timeout: config.responseTimeout, // we don't want to overdo it here and neither set something in config. Request should timeout anyway. - maxRedirects: 0, // Equivalent to 'redirect: 'manual'' in fetch + maxRedirects: 0, validateStatus: null, signal: signal, responseType: 'arraybuffer', // Specify the response type as 'arraybuffer' diff --git a/src/jackett.js b/src/jackett.js index fe22d8d..9a87343 100644 --- a/src/jackett.js +++ b/src/jackett.js @@ -85,6 +85,7 @@ const search = async (query, abortSignals, cb, end) => { let countFinished = 0; let searchedIndexers = {}; let sortedReults = []; + let ignoreTitles = null; const simpleName = encodeURIComponent(helper.simpleName(query.name)); // This is not ideal and should probably be moved to a configuration file, but currently, I cannot think of any other items that are miscategorized. @@ -109,6 +110,10 @@ const search = async (query, abortSignals, cb, end) => { } } + if (config.ignoreTitles) { + ignoreTitles = new RegExp(config.ignoreTitles, 'i'); + } + await Promise.all(hostsAndApiKeys.map(async ({ host, apiKey }) => { const apiIndexersArray = await getIndexers(host, apiKey, abortSignals); @@ -184,6 +189,10 @@ const search = async (query, abortSignals, cb, end) => { newObj[ofInterestElm] = tempObj[ofInterestElm]; }); + if (ignoreTitles && ignoreTitles.test(newObj.title)) { + return; + } + const toInt = ['seeders', 'peers', 'size', 'files']; toInt.forEach(toIntElm => {