import Link from "next/link"; import type { Metadata } from "next"; import { requireUser } from "@/lib/auth"; import { getSettings } from "@/lib/settings"; import { getActiveYears, getGenreDistribution, getMonthlyActivity, getMostWatched, getProviderDistribution, getTopRated, getTotals, getYearReview, } from "@/lib/stats"; import { formatMinutes } from "@/lib/labels"; import { AppShell } from "@/components/AppShell"; import { Poster } from "@/components/Poster"; import { DistributionBars, MonthlyChart } from "@/components/stats/Charts"; export const metadata: Metadata = { title: "Statistik" }; export default async function StatsPage({ searchParams, }: { searchParams: Promise<{ jahr?: string }>; }) { const user = await requireUser("/statistik"); const settings = await getSettings(); const params = await searchParams; const years = await getActiveYears(user.id); const requested = Number.parseInt(params.jahr ?? "", 10); const year = years.includes(requested) ? requested : (years[0] ?? new Date().getFullYear()); const [totals, monthly, providers, genres, topRated, mostWatched, review] = await Promise.all([ getTotals(user.id), getMonthlyActivity(user.id, 12), getProviderDistribution(user.id), getGenreDistribution(user.id), getTopRated(user.id, 5), getMostWatched(user.id, 5), getYearReview(user.id, year), ]); if (totals.minutes === 0 && totals.episodes === 0 && totals.movies === 0) { return (

Statistik

Noch keine Sichtungen. Sobald du die erste Episode abhakst, entstehen hier Schauzeit, Verteilungen und der Jahresrückblick.

Zur Bibliothek
); } const days = totals.minutes / (60 * 24); return (

Statistik

Alles gerechnet aus deinen Sichtungen — Rewatches zählen mit.

Gesamte Schauzeit

{Math.round(totals.minutes / 60).toLocaleString("de-DE")} h

{formatMinutes(totals.minutes)} · das sind {days.toFixed(1).replace(".", ",")} Tage am Stück

Die letzten zwölf Monate

Abgehakte Episoden und Filme je Monat.

({ label, episodes, movies, minutes }))} />

Nach Streamingdienst

Wo du tatsächlich geschaut hast — aus dem Feld „wo schaue ich das".

Nach Genre

Titel mit mehreren Genres zählen in jedem mit.

{review.year} in Zahlen

{years.length > 1 && (
{years.slice(0, 6).map((entry) => ( {entry} ))}
)}
{review.busiestMonth && (

Stärkster Monat: {review.busiestMonth.label} {" "} mit {formatMinutes(review.busiestMonth.minutes)}

)} {review.topTitle && (

Die meiste Zeit ging an: {review.topTitle.title} ({formatMinutes(review.topTitle.minutes)})

)}
formatMinutes(item.minutes)} emptyText="Noch nichts gesehen." /> (item.rating ? `${item.rating}/10` : "—")} emptyText="Noch nichts bewertet." />
); } function Stat({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } function TitleList({ id, heading, items, renderMeta, emptyText, }: { id: string; heading: string; items: { titleId: string; title: string; posterPath: string | null; rating: number | null; minutes: number; type: string }[]; renderMeta: (item: { rating: number | null; minutes: number }) => string; emptyText: string; }) { return (

{heading}

{items.length === 0 ? (

{emptyText}

) : (
    {items.map((item, index) => (
  1. {index + 1} {item.title} {renderMeta(item)}
  2. ))}
)}
); }