feat: Neuerscheinungen-Endpoint pro Anbieter (zuverlässig, nur Release-Datum), Network-ID-Debug für Originals-Recherche
This commit is contained in:
@@ -536,6 +536,73 @@ router.get('/streaming/providers', authenticate, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// GET /streaming/:providerId – Top 10 Filme + Serien für einen Anbieter (DE)
|
// GET /streaming/:providerId – Top 10 Filme + Serien für einen Anbieter (DE)
|
||||||
|
// GET /streaming/:providerId/new – Neuerscheinungen (letzte 60 Tage, neueste zuerst)
|
||||||
|
// Zuverlässig für ALLE Anbieter, da nur release_date + watch_provider kombiniert wird –
|
||||||
|
// keine Sprach-/Popularitäts-Heuristik nötig, die Reihenfolge ergibt sich einfach
|
||||||
|
// aus dem tatsächlichen Veröffentlichungsdatum.
|
||||||
|
router.get('/streaming/:providerId/new', authenticate, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const provider = STREAMING_PROVIDERS.find(p => p.id === req.params.providerId);
|
||||||
|
if (!provider) return res.status(404).json({ error: 'Unbekannter Anbieter' });
|
||||||
|
|
||||||
|
const cacheKey = `streaming-new:${provider.id}`;
|
||||||
|
const cached = cacheGet(cacheKey);
|
||||||
|
if (cached !== undefined) return res.json(cached);
|
||||||
|
|
||||||
|
const since = (() => {
|
||||||
|
const d = new Date();
|
||||||
|
d.setDate(d.getDate() - 60);
|
||||||
|
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
|
||||||
|
})();
|
||||||
|
const today = (() => {
|
||||||
|
const d = new Date();
|
||||||
|
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
|
||||||
|
})();
|
||||||
|
|
||||||
|
function baseParams(mediaKind) {
|
||||||
|
return {
|
||||||
|
watch_region: 'DE',
|
||||||
|
with_watch_providers: provider.tmdbId,
|
||||||
|
with_watch_monetization_types: 'flatrate',
|
||||||
|
sort_by: mediaKind === 'movie' ? 'primary_release_date.desc' : 'first_air_date.desc',
|
||||||
|
...(mediaKind === 'movie'
|
||||||
|
? { 'primary_release_date.gte': since, 'primary_release_date.lte': today }
|
||||||
|
: { 'first_air_date.gte': since, 'first_air_date.lte': today }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [movieData, tvData, genreMap] = await Promise.all([
|
||||||
|
tmdb('/discover/movie', { ...baseParams('movie'), page: 1 }),
|
||||||
|
tmdb('/discover/tv', { ...baseParams('tv'), page: 1 }),
|
||||||
|
getGenreMap(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const movies = (movieData.results || [])
|
||||||
|
.filter(m => !BLOCKED_LANGS.has(m.original_language))
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((m, i) => ({ ...enrichMovie(m, genreMap, null, i + 1), media_type: 'movie' }));
|
||||||
|
|
||||||
|
const tvShows = (tvData.results || [])
|
||||||
|
.filter(m => !BLOCKED_LANGS.has(m.original_language))
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((m, i) => ({
|
||||||
|
id: m.id, media_type: 'tv', rank: i + 1,
|
||||||
|
title: m.name || m.original_name,
|
||||||
|
original_title: m.original_name,
|
||||||
|
release_date: m.first_air_date || '',
|
||||||
|
poster_path: m.poster_path || '',
|
||||||
|
genres: (m.genre_ids||[]).map(gid => genreMap[gid]).filter(Boolean),
|
||||||
|
vote_average: m.vote_average,
|
||||||
|
original_language: m.original_language,
|
||||||
|
origin_country: m.origin_country || [],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const result = { provider: { id: provider.id, label: provider.label }, movies, tvShows, since };
|
||||||
|
cacheSet(cacheKey, result, 6 * 60 * 60 * 1000);
|
||||||
|
res.json(result);
|
||||||
|
} catch(e) { res.status(500).json({ error: e.message }); }
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/streaming/:providerId', authenticate, async (req, res) => {
|
router.get('/streaming/:providerId', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const provider = STREAMING_PROVIDERS.find(p => p.id === req.params.providerId);
|
const provider = STREAMING_PROVIDERS.find(p => p.id === req.params.providerId);
|
||||||
@@ -837,6 +904,14 @@ router.get('/streaming/debug/:providerId', authenticate, requireAdmin, async (re
|
|||||||
} catch(e) { res.status(500).json({ error: e.message }); }
|
} catch(e) { res.status(500).json({ error: e.message }); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Debug: TV-Network-ID per Namenssuche finden (für Originals-Filter)
|
||||||
|
router.get('/streaming/debug-network/:name', authenticate, requireAdmin, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const data = await tmdb('/search/network', { query: req.params.name });
|
||||||
|
res.json(data.results || []);
|
||||||
|
} catch(e) { res.status(500).json({ error: e.message }); }
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/streaming/clear-cache', authenticate, requireAdmin, (req, res) => {
|
router.post('/streaming/clear-cache', authenticate, requireAdmin, (req, res) => {
|
||||||
const r = db.prepare("DELETE FROM xrel_cache WHERE cache_key LIKE 'streaming-top10:%'").run();
|
const r = db.prepare("DELETE FROM xrel_cache WHERE cache_key LIKE 'streaming-top10:%'").run();
|
||||||
res.json({ ok: true, cleared: r.changes });
|
res.json({ ok: true, cleared: r.changes });
|
||||||
|
|||||||
Reference in New Issue
Block a user