fix: media – FSK nur Top10 parallel, kein FSK-Lookup bei allen Filmen (Timeout-Fix)

This commit is contained in:
2026-06-06 20:52:30 +02:00
parent ae9291b8d6
commit 2e206da879

View File

@@ -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),