From ad4f2dbb7243c063b4961d7c89413475a240c981 Mon Sep 17 00:00:00 2001 From: Dicken Date: Wed, 10 Jun 2026 23:35:33 +0200 Subject: [PATCH] fix: xREL parallel queries, complete/bluray/hevc/remux filter, Produktionsland im Modal --- backend/src/tools/media/routes.js | 42 ++++++++++++++++--------------- frontend/src/tools/media.jsx | 1 + 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/backend/src/tools/media/routes.js b/backend/src/tools/media/routes.js index a4c5c0f..e299bf9 100644 --- a/backend/src/tools/media/routes.js +++ b/backend/src/tools/media/routes.js @@ -93,7 +93,7 @@ function enrichMovie(m, genreMap, fsk, rank) { } // ── xREL ───────────────────────────────────────────────────────────────────── -const QUALITY_BLOCKLIST = /\b(2160p|4k|uhd|uhdbluray|uhdbd)\b/i; +const QUALITY_BLOCKLIST = /\b(2160p|4k|uhd|uhdbluray|uhdbd|complete|bluray|blu-ray|remux|hevc|x265|h265)\b/i; async function xrelFetch(path, params = {}) { const url = new URL(XREL_BASE + path); @@ -118,30 +118,31 @@ async function getXrelData(tmdbId, imdbId, title, originalTitle) { const cached = cacheGet(cacheKey); if (cached !== undefined) return cached; - let extInfoId = null; + // Alle Suchen parallel – originaltitel und deutsch gleichzeitig + const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase(); + const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i); - // Suche ext_info_id via IMDb-URI (exakter Match) + const searchResults = await Promise.all(queries.map(async q => { + try { + return await xrelFetch('/search/ext_info.json', { + q: q.replace(/[*#!?:]/g,''), type:'movie', limit:10 + }); + } catch(_) { return null; } + })); + + let extInfoId = null; + // IMDb-URI Match zuerst if (imdbId) { - const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i); - for (const q of queries) { - try { - const data = await xrelFetch('/search/ext_info.json', { q: q.replace(/[*]/g,''), type:'movie', limit:10 }); - const hit = (data.results||[]).find(h => (h.uris||[]).includes(`imdb:${imdbId}`)); - if (hit?.id) { extInfoId = hit.id; break; } - } catch(_) {} + for (const data of searchResults) { + const hit = (data?.results||[]).find(h => (h.uris||[]).includes(`imdb:${imdbId}`)); + if (hit?.id) { extInfoId = hit.id; break; } } } - - // Fallback: exakter Titel-Match + // Exakter Titel-Match als Fallback if (!extInfoId) { - const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase(); - const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i); - for (const q of queries) { - try { - const data = await xrelFetch('/search/ext_info.json', { q: q.replace(/[*#!?:]/g,''), type:'movie', limit:5 }); - const hit = (data.results||[]).find(h => clean(h.title)===clean(q) || clean(h.alt_title)===clean(q)); - if (hit?.id) { extInfoId = hit.id; break; } - } catch(_) {} + for (const data of searchResults) { + const hit = (data?.results||[]).find(h => clean(h.title)===clean(queries[0]) || clean(h.alt_title)===clean(queries[0])); + if (hit?.id) { extInfoId = hit.id; break; } } } @@ -238,6 +239,7 @@ router.get('/movie/:id', authenticate, async (req, res) => { tmdb_url: `https://www.themoviedb.org/movie/${detail.id}`, imdb_url: imdbId ? `https://www.imdb.com/title/${imdbId}` : null, imdb_id: imdbId, + countries: (detail.production_countries||[]).map(c => c.name), }); } catch(e) { res.status(500).json({ error: e.message }); } }); diff --git a/frontend/src/tools/media.jsx b/frontend/src/tools/media.jsx index 6478b7a..3a22319 100644 --- a/frontend/src/tools/media.jsx +++ b/frontend/src/tools/media.jsx @@ -564,6 +564,7 @@ function MovieModal({ tmdbId, onClose, mobile }) { {detail.runtime > 0 && ⏱ {detail.runtime} Min} {fskStyle && FSK {detail.fsk}} {detail.release_date && 🇩🇪 {fmtDE(detail.release_date)}} + {detail.countries?.length > 0 && 🌍 {detail.countries.slice(0,2).join(' · ')}} {detail.genres?.length > 0 && (