feat: Streaming-Tab mit Top 10 pro Anbieter (Netflix, Disney+, Prime, Apple TV+, WOW, RTL+)
This commit is contained in:
@@ -8,6 +8,7 @@ const BACKDROP = 'https://image.tmdb.org/t/p/w780';
|
||||
const TOOL_DEFS = [
|
||||
{ id: 'kino', label: '🎬 Kino', desc: 'Aktuell im Kino (DE) – alle laufenden Filme', ready: true },
|
||||
{ id: 'demnächst', label: '🗓 Demnächst', desc: 'Neustarts wochenweise – nächste Wochen', ready: true },
|
||||
{ id: 'streaming', label: '📡 Streaming', desc: 'Top 10 der deutschen Streaming-Anbieter', ready: true },
|
||||
{ id: 'favoriten', label: '❤ Favoriten', desc: 'Deine gespeicherten Lieblingsfilme', ready: true },
|
||||
{ id: 'suchen', label: '🔍 Suchen', desc: 'Filme suchen und Infos abrufen', ready: true },
|
||||
];
|
||||
@@ -143,6 +144,7 @@ export default function Media({ toast, mobile, initTab, onInitTabConsumed }) {
|
||||
|
||||
{activeTool === 'kino' && <KinoGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||
{activeTool === 'demnächst' && <DemnächstGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||
{activeTool === 'streaming' && <StreamingGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||
{activeTool === 'favoriten' && <FavoritenKalender onOpenModal={setModal} />}
|
||||
{activeTool === 'suchen' && <SucheGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||
</div>
|
||||
@@ -154,7 +156,7 @@ export default function Media({ toast, mobile, initTab, onInitTabConsumed }) {
|
||||
onClose={() => setModal(null)}
|
||||
mobile={mobile}
|
||||
onHasXrel={id => setXrelIds(prev => new Set([...prev, id]))}
|
||||
noYearFilter={activeTool === 'suchen'}
|
||||
noYearFilter={activeTool === 'suchen' || activeTool === 'streaming'}
|
||||
isFav={favIds.has(modal?.id || modal)}
|
||||
onToggleFav={movie => toggleFav(movie, favIds.has(modal?.id || modal))}
|
||||
/>,
|
||||
@@ -446,6 +448,61 @@ function SectionedGrid({ films, serien, favIds, xrelIds, onToggle, onOpenModal }
|
||||
);
|
||||
}
|
||||
|
||||
function StreamingGrid({ onOpenModal, xrelIds, onXrelLoaded, favIds: favIdsProp, onToggleFav: toggleFavProp }) {
|
||||
const [favIdsLocal, onToggleLocal] = useFavIds();
|
||||
const favIds = favIdsProp || favIdsLocal;
|
||||
const onToggle = toggleFavProp || onToggleLocal;
|
||||
|
||||
const [providers, setProviders] = useState([]);
|
||||
const [activeProvider, setActiveProvider] = useState(null);
|
||||
const [data, setData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
api('/tools/media/streaming/providers')
|
||||
.then(list => { setProviders(list); if (list.length) setActiveProvider(list[0].id); })
|
||||
.catch(e => setError(e.message));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeProvider) return;
|
||||
setLoading(true); setError('');
|
||||
api(`/tools/media/streaming/${activeProvider}`)
|
||||
.then(setData)
|
||||
.catch(e => setError(e.message))
|
||||
.finally(() => setLoading(false));
|
||||
}, [activeProvider]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Anbieter-Auswahl */}
|
||||
<div style={{display:'flex',gap:6,flexWrap:'wrap',marginBottom:16}}>
|
||||
{providers.map(p => (
|
||||
<button key={p.id} onClick={() => setActiveProvider(p.id)} style={{
|
||||
background: activeProvider===p.id ? 'rgba(78,205,196,0.15)' : 'rgba(255,255,255,0.04)',
|
||||
border: `1px solid ${activeProvider===p.id ? 'rgba(78,205,196,0.5)' : 'rgba(255,255,255,0.1)'}`,
|
||||
borderRadius:20, padding:'6px 14px',
|
||||
color: activeProvider===p.id ? '#4ecdc4' : 'rgba(255,255,255,0.6)',
|
||||
fontFamily:'monospace', fontSize:12, cursor:'pointer', fontWeight: activeProvider===p.id?700:400,
|
||||
}}>{p.label}</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{error && <ErrorBox msg={error} />}
|
||||
{loading && <StatusBox>⏳ Lädt Top 10…</StatusBox>}
|
||||
|
||||
{!loading && data && (
|
||||
<SectionedGrid
|
||||
films={data.movies || []}
|
||||
serien={data.tvShows || []}
|
||||
favIds={favIds} xrelIds={xrelIds} onToggle={onToggle} onOpenModal={onOpenModal}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SucheGrid({ onOpenModal, xrelIds, onXrelLoaded }) {
|
||||
const [query, setQuery] = useState('');
|
||||
const [results, setResults] = useState(null); // null=noch nicht gesucht
|
||||
|
||||
Reference in New Issue
Block a user