import { revalidatePath } from "next/cache"; import Link from "next/link"; import { listFolders, createLibrary, deleteLibrary, fetchLibraries, fetchSeries, scanLibrary, startMetadataBatch, LibraryDto, FolderItem } from "../../lib/api"; import { LibraryActions } from "../components/LibraryActions"; import { LibraryForm } from "../components/LibraryForm"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Badge } from "../components/ui"; export const dynamic = "force-dynamic"; function formatNextScan(nextScanAt: string | null): string { if (!nextScanAt) return "-"; const date = new Date(nextScanAt); const now = new Date(); const diff = date.getTime() - now.getTime(); if (diff < 0) return "Imminent"; if (diff < 60000) return "< 1 min"; if (diff < 3600000) return `${Math.floor(diff / 60000)}m`; if (diff < 86400000) return `${Math.floor(diff / 3600000)}h`; return `${Math.floor(diff / 86400000)}d`; } export default async function LibrariesPage() { const [libraries, folders] = await Promise.all([ fetchLibraries().catch(() => [] as LibraryDto[]), listFolders().catch(() => [] as FolderItem[]) ]); const seriesCounts = await Promise.all( libraries.map(async (lib) => { try { const seriesPage = await fetchSeries(lib.id); return { id: lib.id, count: seriesPage.items.length }; } catch { return { id: lib.id, count: 0 }; } }) ); const seriesCountMap = new Map(seriesCounts.map(s => [s.id, s.count])); async function addLibrary(formData: FormData) { "use server"; const name = formData.get("name") as string; const rootPath = formData.get("root_path") as string; if (name && rootPath) { await createLibrary(name, rootPath); revalidatePath("/libraries"); } } async function removeLibrary(formData: FormData) { "use server"; const id = formData.get("id") as string; await deleteLibrary(id); revalidatePath("/libraries"); } async function scanLibraryAction(formData: FormData) { "use server"; const id = formData.get("id") as string; await scanLibrary(id); revalidatePath("/libraries"); revalidatePath("/jobs"); } async function scanLibraryFullAction(formData: FormData) { "use server"; const id = formData.get("id") as string; await scanLibrary(id, true); revalidatePath("/libraries"); revalidatePath("/jobs"); } async function batchMetadataAction(formData: FormData) { "use server"; const id = formData.get("id") as string; await startMetadataBatch(id); revalidatePath("/libraries"); revalidatePath("/jobs"); } return ( <>

Bibliothèques

{/* Add Library Form */} Ajouter une bibliothèque Créer une nouvelle bibliothèque à partir d'un dossier existant {/* Libraries Grid */}
{libraries.map((lib) => { const seriesCount = seriesCountMap.get(lib.id) || 0; return (
{lib.name} {!lib.enabled && Désactivée}
{/* Path */} {lib.root_path} {/* Stats */}
{lib.book_count} Livres {seriesCount} Séries
{/* Status */}
{lib.monitor_enabled ? '●' : '○'} {lib.monitor_enabled ? 'Auto' : 'Manuel'} {lib.watcher_enabled && ( )} {lib.monitor_enabled && lib.next_scan_at && ( Prochain : {formatNextScan(lib.next_scan_at)} )}
{/* Actions */}
{lib.metadata_provider !== "none" && (
)}
); })}
); }