fix: xREL parallel queries, complete/bluray/hevc/remux filter, Produktionsland im Modal
This commit is contained in:
@@ -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
|
||||||
|
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) {
|
if (imdbId) {
|
||||||
const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i);
|
for (const data of searchResults) {
|
||||||
for (const q of queries) {
|
const hit = (data?.results||[]).find(h => (h.uris||[]).includes(`imdb:${imdbId}`));
|
||||||
try {
|
if (hit?.id) { extInfoId = hit.id; break; }
|
||||||
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(_) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Exakter Titel-Match als Fallback
|
||||||
// Fallback: exakter Titel-Match
|
|
||||||
if (!extInfoId) {
|
if (!extInfoId) {
|
||||||
const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase();
|
for (const data of searchResults) {
|
||||||
const queries = [originalTitle, title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i);
|
const hit = (data?.results||[]).find(h => clean(h.title)===clean(queries[0]) || clean(h.alt_title)===clean(queries[0]));
|
||||||
for (const q of queries) {
|
if (hit?.id) { extInfoId = hit.id; break; }
|
||||||
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(_) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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 }); }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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' }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user