diff --git a/controller/search.js b/controller/search.js index 9d009fe..edd8b0d 100644 --- a/controller/search.js +++ b/controller/search.js @@ -100,9 +100,16 @@ async function tpbSearch(title){ return parseTPBHtml(await res.text()); } +// Low-quality source tags we never want to recommend( token match to avoid false hits +// like "GHOSTS" matching "TS"). +const JUNK = new Set(['cam', 'hdcam', 'camrip', 'ts', 'hdts', 'telesync', 'tc', 'telecine', 'scr', 'screener', 'dvdscr', 'workprint']); +function isJunk(name){ + return String(name).toLowerCase().split(/[.\s_\-\[\]()]+/).some(tok => JUNK.has(tok)); +} + // Deterministic pre-filter before the torrents ever reach the LLM. function prefilter(torrents, imdbId){ - let out = torrents.filter(t => videoKind(t.category) && Number(t.seeders) > 0); + let out = torrents.filter(t => videoKind(t.category) && Number(t.seeders) > 0 && !isJunk(t.name)); // If we can positively identify the title by IMDB id, trust it and drop the rest. if(imdbId){ @@ -244,6 +251,13 @@ async function findReleases(tmdbId, mediaType){ let torrents = await tpbSearch(meta.title); let candidates = prefilter(torrents, meta.imdbId); + // For movies, require the confirmed release year in the name. TPB search is fuzzy + // (a "Toy Story 5" query returns Toy Story 4/3/…), and without this the fallback can + // cross to the wrong movie. If nothing matches, we genuinely have no good copy yet. + if(mediaType !== 'tv' && meta.year){ + candidates = candidates.filter(t => t.name.includes(meta.year)); + } + if(!candidates.length){ return { title: meta.title, year: meta.year, options: [] }; } @@ -345,4 +359,5 @@ module.exports = { tpbSearch, parseTPBHtml, sizeToBytes, + isJunk, }; diff --git a/public/partial/header.html b/public/partial/header.html index 9cad9ae..c63df04 100644 --- a/public/partial/header.html +++ b/public/partial/header.html @@ -396,7 +396,7 @@ // Step 3: render the release cards; a tap feeds the existing add dialog. function tbpRenderReleases(data){ - if(!data.options.length){ tbpSearchBody('
No good torrents found for '+ tbpEsc(data.title) +'.
'); return; } + if(!data.options.length){ tbpSearchBody('No good-quality copy of '+ tbpEsc(data.title) +' found — it may not be released yet, or only low-quality (CAM) copies exist.
'); return; } var header = '✓ Already in your library ('+ tbpEsc(data.library.quality) +') — only upgrades are offered.
'; tbpSearchBody(header);