"use client"; import { useEffect, useState } from "react"; import { Nav, useAuth } from "@/components/Nav"; interface MovieFile { id: string; node: string; nodeStatus: string; resolution: string | null; sizeBytes: string; videoCodec: string | null; audioCodec: string | null; releaseName: string; available: boolean; } interface Movie { id: string; title: string; year: number | null; imdbId: string | null; tmdbId: number | null; overview: string | null; posterUrl: string | null; fileCount: number; nodeCount: number; qualities: string[]; files: MovieFile[]; } interface MetaHit { tmdbId: number; title: string; year: number | null; overview: string | null; posterUrl: string | null; imdbId: string | null; } function formatBytes(bytes: string | number | null | undefined): string { const valNum = Number(bytes ?? 0); if (!Number.isFinite(valNum) || valNum < 0) return "0 B"; let val = valNum; const units = ["B", "KB", "MB", "GB", "TB"]; let i = 0; while (val >= 1024 && i < units.length - 1) { val /= 1024; i++; } return `${val.toFixed(1)} ${units[i]}`; } export default function MoviesPage() { useAuth(); const [movies, setMovies] = useState([]); const [search, setSearch] = useState(""); const [expanded, setExpanded] = useState(null); const [linkMovieId, setLinkMovieId] = useState(null); const [linkQuery, setLinkQuery] = useState(""); const [linkHits, setLinkHits] = useState([]); const [linkBusy, setLinkBusy] = useState(false); const [linkMsg, setLinkMsg] = useState(""); function load(q = search) { const qs = q ? `?search=${encodeURIComponent(q)}` : ""; fetch(`/api/v1/admin/movies${qs}`, { credentials: "include" }) .then((r) => r.json()) .then((d) => setMovies(d.movies ?? [])); } useEffect(() => { load(); }, []); async function ignoreFile(fileId: string) { if (!confirm("Dit bestand negeren?")) return; await fetch(`/api/v1/admin/media-files/${fileId}/match`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ignore: true }), }); load(); } async function refreshMeta(fileId: string) { await fetch(`/api/v1/admin/media-files/${fileId}/refresh-metadata`, { method: "POST", credentials: "include", }); load(); } function openLink(m: Movie) { setLinkMovieId(m.id); setLinkQuery(m.year ? `${m.title} ${m.year}` : m.title); setLinkHits([]); setLinkMsg(""); void searchMeta(m.year ? `${m.title} ${m.year}` : m.title); } async function searchMeta(q = linkQuery) { const query = q.trim(); if (!query) return; setLinkBusy(true); setLinkMsg(""); try { const res = await fetch( `/api/v1/admin/metadata/search?type=movie&q=${encodeURIComponent(query)}`, { credentials: "include" } ); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Zoeken mislukt"); setLinkHits([]); return; } setLinkHits(data.results ?? []); if (!(data.results ?? []).length) setLinkMsg("Geen resultaten"); } finally { setLinkBusy(false); } } async function applyLink(hit: MetaHit) { if (!linkMovieId) return; setLinkBusy(true); setLinkMsg("Koppelen…"); try { const res = await fetch(`/api/v1/admin/movies/${linkMovieId}/link`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ tmdbId: hit.tmdbId, ...(hit.imdbId ? { imdbId: hit.imdbId } : {}), }), }); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Opslaan mislukt"); return; } setLinkMsg( data.merged ? "Gekoppeld (samengevoegd met bestaande film). Metadata vernieuwd." : "Gekoppeld. Metadata vernieuwd." ); setLinkMovieId(null); setExpanded(data.movieId ?? linkMovieId); load(); } finally { setLinkBusy(false); } } async function applyImdbDirect() { const imdb = linkQuery.trim(); if (!/^tt\d+$/i.test(imdb) || !linkMovieId) { setLinkMsg("Vul een IMDb-id in (bijv. tt1375666) of zoek eerst op titel."); return; } setLinkBusy(true); setLinkMsg("Koppelen via IMDb…"); try { const res = await fetch(`/api/v1/admin/movies/${linkMovieId}/link`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ imdbId: imdb }), }); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Opslaan mislukt"); return; } setLinkMsg("Gekoppeld via IMDb. Metadata vernieuwd."); setLinkMovieId(null); setExpanded(data.movieId ?? linkMovieId); load(); } finally { setLinkBusy(false); } } const activeMovie = movies.find((m) => m.id === linkMovieId); return ( <>