import Link from "next/link"; import type { Metadata } from "next"; import { requireUser } from "@/lib/auth"; import { getSettings } from "@/lib/settings"; import { env } from "@/lib/env"; import { searchMovies, searchMulti, searchSeries, type TmdbSearchResult } from "@/lib/tmdb"; import { AppShell } from "@/components/AppShell"; import { Poster } from "@/components/Poster"; import { SearchField } from "@/components/SearchField"; export const metadata: Metadata = { title: "Suchen" }; type Filter = "alle" | "serien" | "filme"; const FILTERS: { key: Filter; label: string }[] = [ { key: "alle", label: "Alles" }, { key: "serien", label: "Serien" }, { key: "filme", label: "Filme" }, ]; /** Normalisiert die drei TMDB-Antwortformen auf eine gemeinsame Darstellung. */ function normalize(item: TmdbSearchResult, fallbackType: "tv" | "movie") { const type = item.media_type === "tv" || item.media_type === "movie" ? item.media_type : fallbackType; const date = type === "tv" ? item.first_air_date : item.release_date; return { tmdbId: item.id, type, title: (type === "tv" ? item.name : item.title) ?? item.original_name ?? item.original_title ?? "Ohne Titel", overview: item.overview ?? "", posterPath: item.poster_path ?? null, year: date ? date.slice(0, 4) : null, rating: item.vote_average ?? null, }; } export default async function SearchPage({ searchParams, }: { searchParams: Promise<{ q?: string; typ?: string }>; }) { const user = await requireUser("/suche"); const settings = await getSettings(); const params = await searchParams; const query = (params.q ?? "").trim(); const filter: Filter = FILTERS.some((f) => f.key === params.typ) ? (params.typ as Filter) : "alle"; return (

Suchen

Serien und Filme aus der TMDB-Datenbank — mit Postern, Staffeln und Episoden.

Nichts dabei?{" "} Titel selbst anlegen

{!env.tmdb.isConfigured ? ( Ohne TMDB-Schlüssel kann Flimmer nicht suchen. Trage TMDB_API_KEY in der{" "} .env ein und starte die Instanz neu. ) : query.length < 2 ? ( Gib mindestens zwei Zeichen ein, um zu suchen. ) : ( )}
); } async function Results({ query, filter }: { query: string; filter: Filter }) { let items: ReturnType[]; try { if (filter === "serien") { const data = await searchSeries(query); items = data.results.map((item) => normalize(item, "tv")); } else if (filter === "filme") { const data = await searchMovies(query); items = data.results.map((item) => normalize(item, "movie")); } else { const data = await searchMulti(query); items = data.results.map((item) => normalize(item, "movie")); } } catch (error) { return ( {error instanceof Error ? error.message : "Die Suche bei TMDB ist fehlgeschlagen."} ); } if (items.length === 0) { return Zu „{query}" hat TMDB nichts gefunden.; } return ( <>

{items.length} {items.length === 1 ? "Treffer" : "Treffer"} zu „{query}"

); } function Notice({ children, tone = "neutral", }: { children: React.ReactNode; tone?: "neutral" | "warning" | "danger"; }) { const color = tone === "warning" ? "var(--fl-warning)" : tone === "danger" ? "var(--fl-danger)" : "var(--fl-muted)"; return (

{children}

); }