feat: DE/US Kinostart + US Digital Release-Datum im Modal

This commit is contained in:
2026-06-11 09:46:55 +02:00
parent 5941cc26d8
commit 71c411a350
2 changed files with 39 additions and 2 deletions

View File

@@ -65,6 +65,26 @@ function extractFSK(rd) {
for (const r of sorted) { const c = (r.certification||'').trim(); if (c) return c; } for (const r of sorted) { const c = (r.certification||'').trim(); if (c) return c; }
return null; return null;
} }
function extractReleaseDates(rd) {
const out = {};
// DE Kinostart (type 3)
const de = rd?.results?.find(r => r.iso_3166_1 === 'DE');
if (de) {
const theatrical = de.release_dates.find(r => r.type === 3);
if (theatrical?.release_date) out.de_cinema = theatrical.release_date.slice(0,10);
}
// US Kinostart (type 3)
const us = rd?.results?.find(r => r.iso_3166_1 === 'US');
if (us) {
const theatrical = us.release_dates.find(r => r.type === 3);
if (theatrical?.release_date) out.us_cinema = theatrical.release_date.slice(0,10);
// US Digital (type 4)
const digital = us.release_dates.find(r => r.type === 4);
if (digital?.release_date) out.us_digital = digital.release_date.slice(0,10);
}
return out;
}
async function fetchAllPages(path, maxPages = 3) { 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);
@@ -262,6 +282,7 @@ router.get('/movie/:id', authenticate, async (req, res) => {
backdrop_path: detail.backdrop_path, release_date: detail.release_date, backdrop_path: detail.backdrop_path, release_date: detail.release_date,
runtime: detail.runtime, vote_average: detail.vote_average, runtime: detail.runtime, vote_average: detail.vote_average,
genres: (detail.genres||[]).map(g => g.name), fsk, genres: (detail.genres||[]).map(g => g.name), fsk,
release_dates: extractReleaseDates(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),
director: detail.credits?.crew?.find(c => c.job==='Director')?.name||null, director: detail.credits?.crew?.find(c => c.job==='Director')?.name||null,
tmdb_url: `https://www.themoviedb.org/movie/${detail.id}`, tmdb_url: `https://www.themoviedb.org/movie/${detail.id}`,

View File

@@ -580,8 +580,12 @@ function MovieModal({ tmdbId, onClose, mobile, onHasXrel }) {
{detail.vote_average > 0 && <Badge bg="rgba(255,230,109,0.15)" color="#ffe66d"> {detail.vote_average.toFixed(1)}</Badge>} {detail.vote_average > 0 && <Badge bg="rgba(255,230,109,0.15)" color="#ffe66d"> {detail.vote_average.toFixed(1)}</Badge>}
{detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)"> {detail.runtime} Min</Badge>} {detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)"> {detail.runtime} Min</Badge>}
{fskStyle && <Badge bg={fskStyle.bg} color={fskStyle.color}>FSK {detail.fsk}</Badge>} {fskStyle && <Badge bg={fskStyle.bg} color={fskStyle.color}>FSK {detail.fsk}</Badge>}
{detail.release_date && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 {fmtDE(detail.release_date)}</Badge>} {detail.release_dates?.de_cinema
{detail.countries?.length > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.5)">🌍 {detail.countries.slice(0,2).join(' · ')}</Badge>} ? <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 Kino {fmtDE(detail.release_dates.de_cinema)}</Badge>
: detail.release_date && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 {fmtDE(detail.release_date)}</Badge>}
{detail.release_dates?.us_cinema && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.5)">🇺🇸 Kino {fmtDE(detail.release_dates.us_cinema)}</Badge>}
{detail.release_dates?.us_digital && <Badge bg="rgba(78,205,196,0.1)" color="#4ecdc4">💻 Digital {fmtDE(detail.release_dates.us_digital)}</Badge>}
{detail.countries?.length > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.4)">🌍 {detail.countries.slice(0,2).join(' · ')}</Badge>}
</div> </div>
{detail.genres?.length > 0 && ( {detail.genres?.length > 0 && (
<div style={{ display:'flex', gap:4, flexWrap:'wrap' }}> <div style={{ display:'flex', gap:4, flexWrap:'wrap' }}>
@@ -642,6 +646,18 @@ function MovieModal({ tmdbId, onClose, mobile, onHasXrel }) {
{/* xREL Releases */} {/* xREL Releases */}
<div style={{ marginTop:18 }}> <div style={{ marginTop:18 }}>
{/* Web-Release aus frühestem WEB-Release ableiten */}
{xrel?.length > 0 && (() => {
const webRelease = xrel
.filter(r => /web/i.test(r.dirname||''))
.sort((a,b) => (a.date||'').localeCompare(b.date||''))[0];
return webRelease?.date ? (
<div style={{ fontSize:11, color:'rgba(255,255,255,0.4)', fontFamily:'monospace', marginBottom:8 }}>
🌐 Erster Web-Release: <span style={{ color:'#4ecdc4' }}>{fmtDE(webRelease.date)}</span>
<span style={{ marginLeft:6, color:'rgba(255,255,255,0.25)', fontSize:10 }}>{webRelease.p2p ? 'P2P' : 'SCN'}</span>
</div>
) : null;
})()}
<div style={{ display:'flex', alignItems:'center', gap:8, marginBottom: xrel?.length ? 8 : 0 }}> <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom: xrel?.length ? 8 : 0 }}>
<div style={{ ...S.head, marginBottom:0, flex:1 }}>RELEASES (XREL.TO)</div> <div style={{ ...S.head, marginBottom:0, flex:1 }}>RELEASES (XREL.TO)</div>
<button <button