fix: media – FSK nur Top10 parallel, kein FSK-Lookup bei allen Filmen (Timeout-Fix)
This commit is contained in:
@@ -39,15 +39,17 @@ function extractFSK(releaseDates) {
|
|||||||
return de.release_dates.find(r => r.certification)?.certification || null;
|
return de.release_dates.find(r => r.certification)?.certification || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alle Seiten einer TMDb-Liste holen (bis max. maxPages)
|
// Alle Seiten holen (parallel)
|
||||||
async function fetchAllPages(path, maxPages = 5) {
|
async function fetchAllPages(path, maxPages = 3) {
|
||||||
const first = await tmdb(path, { page: 1 });
|
const first = await tmdb(path, { page: 1 });
|
||||||
const total = Math.min(first.total_pages || 1, maxPages);
|
const total = Math.min(first.total_pages || 1, maxPages);
|
||||||
let results = [...first.results];
|
let results = [...first.results];
|
||||||
|
if (total > 1) {
|
||||||
const extra = await Promise.all(
|
const extra = await Promise.all(
|
||||||
Array.from({ length: total - 1 }, (_, i) => tmdb(path, { page: i + 2 }))
|
Array.from({ length: total - 1 }, (_, i) => tmdb(path, { page: i + 2 }))
|
||||||
);
|
);
|
||||||
for (const p of extra) results = results.concat(p.results);
|
for (const p of extra) results = results.concat(p.results);
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,95 +57,83 @@ function enrichMovie(movie, genreMap, fsk, rank) {
|
|||||||
return {
|
return {
|
||||||
id: movie.id,
|
id: movie.id,
|
||||||
title: movie.title || movie.original_title,
|
title: movie.title || movie.original_title,
|
||||||
original_title: movie.original_title,
|
|
||||||
original_language: movie.original_language,
|
original_language: movie.original_language,
|
||||||
poster_path: movie.poster_path,
|
poster_path: movie.poster_path,
|
||||||
overview: movie.overview,
|
overview: movie.overview,
|
||||||
release_date: movie.release_date,
|
release_date: movie.release_date,
|
||||||
vote_average: movie.vote_average,
|
vote_average: movie.vote_average,
|
||||||
genres: (movie.genre_ids || movie.genres?.map(g => g.id) || [])
|
genres: (movie.genre_ids || []).map(id => genreMap[id]).filter(Boolean),
|
||||||
.map(id => genreMap[id]).filter(Boolean),
|
|
||||||
fsk: fsk || null,
|
fsk: fsk || null,
|
||||||
rank: rank || null,
|
rank: rank || null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FSK für eine Liste von Filmen parallel holen
|
// GET /api/tools/media/now-playing
|
||||||
async function withFSK(movies, genreMap, topN = 10) {
|
// FSK nur für Top 10 parallel holen, Rest ohne – kein sequentielles Warten
|
||||||
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
|
|
||||||
router.get('/now-playing', authenticate, async (req, res) => {
|
router.get('/now-playing', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [all, genreMap] = await Promise.all([
|
const [pages, genreMap] = await Promise.all([
|
||||||
fetchAllPages('/movie/now_playing', 3),
|
fetchAllPages('/movie/now_playing', 3),
|
||||||
getGenreMap(),
|
getGenreMap(),
|
||||||
]);
|
]);
|
||||||
const filtered = all.filter(m => m.original_language !== 'tr');
|
|
||||||
const enriched = await withFSK(filtered, genreMap, 10);
|
const filtered = pages.filter(m => m.original_language !== 'tr');
|
||||||
res.json(enriched);
|
|
||||||
|
// 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) {
|
} catch (e) {
|
||||||
res.status(500).json({ error: e.message });
|
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) => {
|
router.get('/upcoming', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [all, genreMap] = await Promise.all([
|
const [pages, genreMap] = await Promise.all([
|
||||||
fetchAllPages('/movie/upcoming', 4),
|
fetchAllPages('/movie/upcoming', 3),
|
||||||
getGenreMap(),
|
getGenreMap(),
|
||||||
]);
|
]);
|
||||||
const filtered = all.filter(m => m.original_language !== 'tr');
|
|
||||||
|
|
||||||
// Deduplizieren nach ID
|
|
||||||
const seen = new Set();
|
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
|
filtered.sort((a, b) => a.release_date.localeCompare(b.release_date));
|
||||||
unique.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 = {};
|
const groups = {};
|
||||||
for (const m of unique) {
|
for (const m of filtered) {
|
||||||
if (!m.release_date) continue;
|
|
||||||
const d = new Date(m.release_date);
|
const d = new Date(m.release_date);
|
||||||
// Montag der Woche berechnen
|
const dow = d.getDay(); // 0=So
|
||||||
const day = d.getDay(); // 0=So
|
const diff = dow === 0 ? -6 : 1 - dow;
|
||||||
const diff = (day === 0 ? -6 : 1 - day);
|
|
||||||
const mon = new Date(d);
|
const mon = new Date(d);
|
||||||
mon.setDate(d.getDate() + diff);
|
mon.setDate(d.getDate() + diff);
|
||||||
const key = mon.toISOString().slice(0, 10);
|
const key = mon.toISOString().slice(0, 10);
|
||||||
if (!groups[key]) groups[key] = [];
|
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
|
res.json(groups);
|
||||||
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": [...], ... }
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).json({ error: e.message });
|
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) => {
|
router.get('/movie/:id', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [detail, genreMap] = await Promise.all([
|
const [detail, genreMap] = await Promise.all([
|
||||||
@@ -153,7 +143,6 @@ router.get('/movie/:id', authenticate, async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
id: detail.id,
|
id: detail.id,
|
||||||
title: detail.title || detail.original_title,
|
title: detail.title || detail.original_title,
|
||||||
original_title: detail.original_title,
|
|
||||||
tagline: detail.tagline,
|
tagline: detail.tagline,
|
||||||
overview: detail.overview,
|
overview: detail.overview,
|
||||||
poster_path: detail.poster_path,
|
poster_path: detail.poster_path,
|
||||||
@@ -161,7 +150,6 @@ router.get('/movie/:id', authenticate, async (req, res) => {
|
|||||||
release_date: detail.release_date,
|
release_date: detail.release_date,
|
||||||
runtime: detail.runtime,
|
runtime: detail.runtime,
|
||||||
vote_average: detail.vote_average,
|
vote_average: detail.vote_average,
|
||||||
vote_count: detail.vote_count,
|
|
||||||
genres: (detail.genres || []).map(g => g.name),
|
genres: (detail.genres || []).map(g => g.name),
|
||||||
fsk: extractFSK(detail.release_dates),
|
fsk: extractFSK(detail.release_dates),
|
||||||
cast: (detail.credits?.cast || []).slice(0, 8).map(a => a.name),
|
cast: (detail.credits?.cast || []).slice(0, 8).map(a => a.name),
|
||||||
|
|||||||
Reference in New Issue
Block a user