"use client"; import { useEffect, useState } from "react"; import { Nav, useAuth } from "@/components/Nav"; interface PendingFolder { key: string; nodeId: string; nodeName: string; folder: string; parsedTitle: string | null; fileCount: number; seasons: number[]; samplePaths: string[]; } interface MetaHit { tmdbId: number | null; title: string; year: number | null; overview: string | null; posterUrl: string | null; imdbId: string | null; source?: "tmdb" | "omdb"; } export default function PendingSeriesPage() { useAuth(); const [pending, setPending] = useState([]); const [totalFiles, setTotalFiles] = useState(0); const [msg, setMsg] = useState(""); const [link, setLink] = useState(null); const [query, setQuery] = useState(""); const [hits, setHits] = useState([]); const [busy, setBusy] = useState(false); const [linkMsg, setLinkMsg] = useState(""); function load() { fetch("/api/v1/admin/library/pending-series", { credentials: "include" }) .then((r) => r.json()) .then((d) => { setPending(d.pending ?? []); setTotalFiles(d.totalFiles ?? 0); }); } useEffect(() => { load(); }, []); function openLink(row: PendingFolder) { setLink(row); setQuery(row.parsedTitle || row.folder.split("/").filter(Boolean).pop() || ""); setHits([]); setLinkMsg(""); void searchMeta(row.parsedTitle || row.folder.split("/").filter(Boolean).pop() || ""); } async function searchMeta(q = query) { const term = q.trim(); if (!term) return; setBusy(true); setLinkMsg(""); try { const res = await fetch( `/api/v1/admin/metadata/search?type=series&q=${encodeURIComponent(term)}`, { credentials: "include" } ); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Zoeken mislukt"); setHits([]); return; } setHits(data.results ?? []); if (!(data.results ?? []).length) setLinkMsg("Geen resultaten"); } finally { setBusy(false); } } async function applyHit(hit: MetaHit) { if (!link) return; if ( !confirm( `${link.fileCount} bestanden in\n${link.folder}\n(${link.nodeName})\nkoppelen aan “${hit.title}${hit.year ? ` (${hit.year})` : ""}”?` ) ) { return; } setBusy(true); setLinkMsg("Koppelen…"); try { const res = await fetch("/api/v1/admin/library/relink-folder", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nodeId: link.nodeId, folder: link.folder, ...(hit.tmdbId != null ? { tmdbId: hit.tmdbId } : {}), ...(hit.imdbId ? { imdbId: hit.imdbId } : {}), }), }); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Koppelen mislukt"); return; } setMsg( `Gekoppeld → ${data.seriesTitle}: ${data.moved}/${data.total}` + (data.failed ? ` (${data.failed} mislukt)` : "") ); setLink(null); load(); } finally { setBusy(false); } } async function applyImdb() { const raw = query.trim(); if (!link) return; const tmdbFromUrl = raw.match(/themoviedb\.org\/(?:movie|tv)\/(\d+)/i)?.[1]; const tmdbId = tmdbFromUrl ? parseInt(tmdbFromUrl, 10) : /^\d{1,8}$/.test(raw) ? parseInt(raw, 10) : null; if (tmdbId != null && Number.isFinite(tmdbId)) { setBusy(true); setLinkMsg("Koppelen via TMDB…"); try { const res = await fetch("/api/v1/admin/library/relink-folder", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nodeId: link.nodeId, folder: link.folder, tmdbId, }), }); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Koppelen mislukt"); return; } setMsg(`Gekoppeld → ${data.seriesTitle}: ${data.moved}/${data.total}`); setLink(null); load(); } finally { setBusy(false); } return; } if (!/^tt\d+$/i.test(raw)) { setLinkMsg("Vul een titel, TMDB-id of IMDb-id (tt…) in."); return; } setBusy(true); setLinkMsg("Koppelen via IMDb…"); try { const res = await fetch("/api/v1/admin/library/relink-folder", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nodeId: link.nodeId, folder: link.folder, imdbId: raw, }), }); const data = await res.json(); if (!res.ok) { setLinkMsg(data.error?.message ?? "Koppelen mislukt"); return; } setMsg(`Gekoppeld → ${data.seriesTitle}: ${data.moved}/${data.total}`); setLink(null); load(); } finally { setBusy(false); } } return ( <>