From 2e206da87953d41d12ac74b9439ca4b9abb122e3 Mon Sep 17 00:00:00 2001 From: Dicken Date: Sat, 6 Jun 2026 20:52:30 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20media=20=E2=80=93=20FSK=20nur=20Top10=20?= =?UTF-8?q?parallel,=20kein=20FSK-Lookup=20bei=20allen=20Filmen=20(Timeout?= =?UTF-8?q?-Fix)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/tools/media/routes.js | 102 +++++++++++++----------------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/backend/src/tools/media/routes.js b/backend/src/tools/media/routes.js index 1d990a6..5df4735 100644 --- a/backend/src/tools/media/routes.js +++ b/backend/src/tools/media/routes.js @@ -39,15 +39,17 @@ function extractFSK(releaseDates) { return de.release_dates.find(r => r.certification)?.certification || null; } -// Alle Seiten einer TMDb-Liste holen (bis max. maxPages) -async function fetchAllPages(path, maxPages = 5) { +// Alle Seiten holen (parallel) +async function fetchAllPages(path, maxPages = 3) { const first = await tmdb(path, { page: 1 }); const total = Math.min(first.total_pages || 1, maxPages); let results = [...first.results]; - const extra = await Promise.all( - Array.from({ length: total - 1 }, (_, i) => tmdb(path, { page: i + 2 })) - ); - for (const p of extra) results = results.concat(p.results); + if (total > 1) { + const extra = await Promise.all( + Array.from({ length: total - 1 }, (_, i) => tmdb(path, { page: i + 2 })) + ); + for (const p of extra) results = results.concat(p.results); + } return results; } @@ -55,95 +57,83 @@ function enrichMovie(movie, genreMap, fsk, rank) { return { id: movie.id, title: movie.title || movie.original_title, - original_title: movie.original_title, original_language: movie.original_language, poster_path: movie.poster_path, overview: movie.overview, release_date: movie.release_date, vote_average: movie.vote_average, - genres: (movie.genre_ids || movie.genres?.map(g => g.id) || []) - .map(id => genreMap[id]).filter(Boolean), + genres: (movie.genre_ids || []).map(id => genreMap[id]).filter(Boolean), fsk: fsk || null, rank: rank || null, }; } -// FSK für eine Liste von Filmen parallel holen -async function withFSK(movies, genreMap, topN = 10) { - return Promise.all(movies.map(async (m, i) => { - let fsk = null; - try { - const detail = await tmdb(`/movie/${m.id}/release_dates`); - fsk = extractFSK(detail); - } catch (_) {} - return enrichMovie(m, genreMap, fsk, i < topN ? i + 1 : null); - })); -} - -// GET /api/tools/media/now-playing – alles was aktuell in DE läuft +// GET /api/tools/media/now-playing +// FSK nur für Top 10 parallel holen, Rest ohne – kein sequentielles Warten router.get('/now-playing', authenticate, async (req, res) => { try { - const [all, genreMap] = await Promise.all([ + const [pages, genreMap] = await Promise.all([ fetchAllPages('/movie/now_playing', 3), getGenreMap(), ]); - const filtered = all.filter(m => m.original_language !== 'tr'); - const enriched = await withFSK(filtered, genreMap, 10); - res.json(enriched); + + const filtered = pages.filter(m => m.original_language !== 'tr'); + + // Top 10: FSK parallel holen + const top10raw = filtered.slice(0, 10); + const restRaw = filtered.slice(10); + + const top10 = await Promise.all(top10raw.map(async (m, i) => { + let fsk = null; + try { const d = await tmdb(`/movie/${m.id}/release_dates`); fsk = extractFSK(d); } catch (_) {} + return enrichMovie(m, genreMap, fsk, i + 1); + })); + + const rest = restRaw.map(m => enrichMovie(m, genreMap, null, null)); + + res.json([...top10, ...rest]); } catch (e) { res.status(500).json({ error: e.message }); } }); -// GET /api/tools/media/upcoming – wochenweise Neustarts, alle verfügbaren +// GET /api/tools/media/upcoming +// Wochenweise gruppiert, kein FSK-Lookup beim Listing router.get('/upcoming', authenticate, async (req, res) => { try { - const [all, genreMap] = await Promise.all([ - fetchAllPages('/movie/upcoming', 4), + const [pages, genreMap] = await Promise.all([ + fetchAllPages('/movie/upcoming', 3), getGenreMap(), ]); - const filtered = all.filter(m => m.original_language !== 'tr'); - // Deduplizieren nach ID const seen = new Set(); - const unique = filtered.filter(m => { if (seen.has(m.id)) return false; seen.add(m.id); return true; }); + const filtered = pages + .filter(m => m.original_language !== 'tr') + .filter(m => { if (seen.has(m.id)) return false; seen.add(m.id); return true; }) + .filter(m => m.release_date); - // Nach Erscheinungsdatum sortieren - unique.sort((a, b) => (a.release_date || '').localeCompare(b.release_date || '')); + filtered.sort((a, b) => a.release_date.localeCompare(b.release_date)); - // Wochenweise gruppieren (Montag der jeweiligen Woche als Key) + // Wochenweise gruppieren (Montag als Key) const groups = {}; - for (const m of unique) { - if (!m.release_date) continue; - const d = new Date(m.release_date); - // Montag der Woche berechnen - const day = d.getDay(); // 0=So - const diff = (day === 0 ? -6 : 1 - day); + for (const m of filtered) { + const d = new Date(m.release_date); + const dow = d.getDay(); // 0=So + const diff = dow === 0 ? -6 : 1 - dow; const mon = new Date(d); mon.setDate(d.getDate() + diff); const key = mon.toISOString().slice(0, 10); if (!groups[key]) groups[key] = []; - groups[key].push(m); + groups[key].push(enrichMovie(m, genreMap, null, null)); } - // Anreichern: nur die erste Gruppe bekommt FSK (spart API-Calls), Rest ohne - const result = {}; - let globalRank = 0; - for (const [week, movies] of Object.entries(groups)) { - result[week] = await Promise.all(movies.map(async m => { - globalRank++; - let fsk = null; - try { const d = await tmdb(`/movie/${m.id}/release_dates`); fsk = extractFSK(d); } catch (_) {} - return enrichMovie(m, genreMap, fsk, null); - })); - } - res.json(result); // { "2026-06-02": [...], "2026-06-09": [...], ... } + res.json(groups); } catch (e) { res.status(500).json({ error: e.message }); } }); -// GET /api/tools/media/movie/:id – Detail + Credits für Modal +// GET /api/tools/media/movie/:id – Details + Credits (nur für Modal) router.get('/movie/:id', authenticate, async (req, res) => { try { const [detail, genreMap] = await Promise.all([ @@ -153,7 +143,6 @@ router.get('/movie/:id', authenticate, async (req, res) => { res.json({ id: detail.id, title: detail.title || detail.original_title, - original_title: detail.original_title, tagline: detail.tagline, overview: detail.overview, poster_path: detail.poster_path, @@ -161,7 +150,6 @@ router.get('/movie/:id', authenticate, async (req, res) => { release_date: detail.release_date, runtime: detail.runtime, vote_average: detail.vote_average, - vote_count: detail.vote_count, genres: (detail.genres || []).map(g => g.name), fsk: extractFSK(detail.release_dates), cast: (detail.credits?.cast || []).slice(0, 8).map(a => a.name),