fix: xREL parallel queries, complete/bluray/hevc/remux filter, Produktionsland im Modal

This commit is contained in:
2026-06-10 23:35:33 +02:00
parent 82ee05f902
commit ad4f2dbb72
2 changed files with 23 additions and 20 deletions

View File

@@ -93,7 +93,7 @@ function enrichMovie(m, genreMap, fsk, rank) {
} }
// ── xREL ───────────────────────────────────────────────────────────────────── // ── 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 = {}) { async function xrelFetch(path, params = {}) {
const url = new URL(XREL_BASE + path); const url = new URL(XREL_BASE + path);
@@ -118,30 +118,31 @@ async function getXrelData(tmdbId, imdbId, title, originalTitle) {
const cached = cacheGet(cacheKey); const cached = cacheGet(cacheKey);
if (cached !== undefined) return cached; if (cached !== undefined) return cached;
let extInfoId = null; // Alle Suchen parallel originaltitel und deutsch gleichzeitig
// Suche ext_info_id via IMDb-URI (exakter Match)
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(_) {}
}
}
// Fallback: exakter Titel-Match
if (!extInfoId) {
const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase(); const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase();
const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i); const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i);
for (const q of queries) {
const searchResults = await Promise.all(queries.map(async q => {
try { try {
const data = await xrelFetch('/search/ext_info.json', { q: q.replace(/[*#!?:]/g,''), type:'movie', limit:5 }); return await xrelFetch('/search/ext_info.json', {
const hit = (data.results||[]).find(h => clean(h.title)===clean(q) || clean(h.alt_title)===clean(q)); q: q.replace(/[*#!?:]/g,''), type:'movie', limit:10
});
} catch(_) { return null; }
}));
let extInfoId = null;
// IMDb-URI Match zuerst
if (imdbId) {
for (const data of searchResults) {
const hit = (data?.results||[]).find(h => (h.uris||[]).includes(`imdb:${imdbId}`));
if (hit?.id) { extInfoId = hit.id; break; }
}
}
// Exakter Titel-Match als Fallback
if (!extInfoId) {
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; } if (hit?.id) { extInfoId = hit.id; break; }
} catch(_) {}
} }
} }
@@ -238,6 +239,7 @@ router.get('/movie/:id', authenticate, async (req, res) => {
tmdb_url: `https://www.themoviedb.org/movie/${detail.id}`, tmdb_url: `https://www.themoviedb.org/movie/${detail.id}`,
imdb_url: imdbId ? `https://www.imdb.com/title/${imdbId}` : null, imdb_url: imdbId ? `https://www.imdb.com/title/${imdbId}` : null,
imdb_id: imdbId, imdb_id: imdbId,
countries: (detail.production_countries||[]).map(c => c.name),
}); });
} catch(e) { res.status(500).json({ error: e.message }); } } catch(e) { res.status(500).json({ error: e.message }); }
}); });

View File

@@ -564,6 +564,7 @@ function MovieModal({ tmdbId, onClose, mobile }) {
{detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)"> {detail.runtime} Min</Badge>} {detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)"> {detail.runtime} Min</Badge>}
{fskStyle && <Badge bg={fskStyle.bg} color={fskStyle.color}>FSK {detail.fsk}</Badge>} {fskStyle && <Badge bg={fskStyle.bg} color={fskStyle.color}>FSK {detail.fsk}</Badge>}
{detail.release_date && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 {fmtDE(detail.release_date)}</Badge>} {detail.release_date && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 {fmtDE(detail.release_date)}</Badge>}
{detail.countries?.length > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.5)">🌍 {detail.countries.slice(0,2).join(' · ')}</Badge>}
</div> </div>
{detail.genres?.length > 0 && ( {detail.genres?.length > 0 && (
<div style={{ display:'flex', gap:4, flexWrap:'wrap' }}> <div style={{ display:'flex', gap:4, flexWrap:'wrap' }}>