From 8cc013405918b8b18b37eac45b0fb6750711c06f Mon Sep 17 00:00:00 2001 From: Dicken Date: Thu, 11 Jun 2026 01:36:20 +0200 Subject: [PATCH] fix: Badge=Release-Cache unified, 3er-Batches parallel, COMPLETE.BLURAY filter korrekt --- backend/src/tools/media/routes.js | 52 ++++++++----------------------- frontend/src/tools/media.jsx | 14 +++++---- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/backend/src/tools/media/routes.js b/backend/src/tools/media/routes.js index a3a111f..08b3913 100644 --- a/backend/src/tools/media/routes.js +++ b/backend/src/tools/media/routes.js @@ -262,48 +262,22 @@ router.get('/movie/:id/xrel', authenticate, async (req, res) => { } catch(e) { res.status(500).json({ error: e.message }); } }); -// Badge-Check: nur prüfen ob ext_info_id existiert (1 Call statt 3) -// Volle Releases werden erst beim Modal-Öffnen geladen +// Badge-Check: bis zu 3 Filme parallel, cached in xrel:tmdb:ID router.post('/xrel-check', authenticate, async (req, res) => { - const movies = (req.body.movies||[]).slice(0,1); + const movies = (req.body.movies||[]).slice(0,3); if (!movies.length) return res.json({}); - const m = movies[0]; - // Wenn volle Daten bereits gecacht: sofort antworten - const fullCacheKey = `xrel:tmdb:${m.id}`; - const fullCached = cacheGet(fullCacheKey); - if (fullCached !== undefined) return res.json({ [m.id]: fullCached.length > 0 }); - - // Sonst: nur ext_info_id suchen (Badge-only Cache, 6h) - const badgeCacheKey = `xrel:badge:${m.id}`; - const badgeCached = cacheGet(badgeCacheKey); - if (badgeCached !== undefined) return res.json({ [m.id]: badgeCached }); - - try { - const clean = (s) => (s||'').replace(/[*#!?:]/g,'').trim().toLowerCase(); - const queries = [m.original_title, m.title].filter(Boolean).filter((v,i,a) => a.indexOf(v)===i); - 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 found = false; - // IMDb match - if (m.imdb_id) { - for (const data of searchResults) { - if ((data?.results||[]).some(h => (h.uris||[]).includes(`imdb:${m.imdb_id}`))) { found = true; break; } - } - } - // Titel-match Fallback - if (!found) { - for (const data of searchResults) { - if ((data?.results||[]).some(h => clean(h.title)===clean(queries[0]) || clean(h.alt_title)===clean(queries[0]))) { found = true; break; } - } - } - - cacheSet(badgeCacheKey, found, 6*60*60*1000); - res.json({ [m.id]: found }); - } catch(_) { res.json({ [m.id]: false }); } + const result = {}; + await Promise.all(movies.map(async m => { + const cacheKey = `xrel:tmdb:${m.id}`; + const cached = cacheGet(cacheKey); + if (cached !== undefined) { result[m.id] = cached.length > 0; return; } + try { + const xrel = await getXrelData(m.id, m.imdb_id||null, m.title, m.original_title); + result[m.id] = xrel.length > 0; + } catch(_) { result[m.id] = false; } + })); + res.json(result); }); router.get('/favorites', authenticate, (req, res) => { diff --git a/frontend/src/tools/media.jsx b/frontend/src/tools/media.jsx index d30144f..965763c 100644 --- a/frontend/src/tools/media.jsx +++ b/frontend/src/tools/media.jsx @@ -303,12 +303,13 @@ function KinoGrid({ onOpenModal }) { const moviesMeta = movies.map(m => ({ id: m.id, title: m.title, original_title: m.original_title })); let active = true; (async () => { - for (const m of moviesMeta) { + for (let bi = 0; bi < moviesMeta.length; bi += 3) { if (!active) break; + const chunk = moviesMeta.slice(bi, bi + 3); try { - const result = await api('/tools/media/xrel-check', { method:'POST', body:{ movies: [m] } }); + const result = await api('/tools/media/xrel-check', { method:'POST', body:{ movies: chunk } }); if (!active) break; - if (result[m.id]) setXrelIds(prev => new Set([...prev, m.id])); + chunk.forEach(m => { if (result[m.id]) setXrelIds(prev => new Set([...prev, m.id])); }); } catch (_) {} } })(); @@ -371,12 +372,13 @@ function DemnächstGrid({ onOpenModal }) { const moviesMeta = allMovies.map(m => ({ id: m.id, title: m.title, original_title: m.original_title })); let active = true; (async () => { - for (const m of moviesMeta) { + for (let bi = 0; bi < moviesMeta.length; bi += 3) { if (!active) break; + const chunk = moviesMeta.slice(bi, bi + 3); try { - const result = await api('/tools/media/xrel-check', { method:'POST', body:{ movies: [m] } }); + const result = await api('/tools/media/xrel-check', { method:'POST', body:{ movies: chunk } }); if (!active) break; - if (result[m.id]) setXrelIds(prev => new Set([...prev, m.id])); + chunk.forEach(m => { if (result[m.id]) setXrelIds(prev => new Set([...prev, m.id])); }); } catch (_) {} } })();