import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { listJobs, fetchLibraries, rebuildIndex, rebuildThumbnails, regenerateThumbnails, startMetadataBatch, IndexJobDto, LibraryDto } from "../../lib/api"; import { JobsList } from "../components/JobsList"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormSelect, FormRow } from "../components/ui"; export const dynamic = "force-dynamic"; export default async function JobsPage({ searchParams }: { searchParams: Promise<{ highlight?: string }> }) { const { highlight } = await searchParams; const [jobs, libraries] = await Promise.all([ listJobs().catch(() => [] as IndexJobDto[]), fetchLibraries().catch(() => [] as LibraryDto[]) ]); const libraryMap = new Map(libraries.map(l => [l.id, l.name])); async function triggerRebuild(formData: FormData) { "use server"; const libraryId = formData.get("library_id") as string; const result = await rebuildIndex(libraryId || undefined); revalidatePath("/jobs"); redirect(`/jobs?highlight=${result.id}`); } async function triggerFullRebuild(formData: FormData) { "use server"; const libraryId = formData.get("library_id") as string; const result = await rebuildIndex(libraryId || undefined, true); revalidatePath("/jobs"); redirect(`/jobs?highlight=${result.id}`); } async function triggerThumbnailsRebuild(formData: FormData) { "use server"; const libraryId = formData.get("library_id") as string; const result = await rebuildThumbnails(libraryId || undefined); revalidatePath("/jobs"); redirect(`/jobs?highlight=${result.id}`); } async function triggerThumbnailsRegenerate(formData: FormData) { "use server"; const libraryId = formData.get("library_id") as string; const result = await regenerateThumbnails(libraryId || undefined); revalidatePath("/jobs"); redirect(`/jobs?highlight=${result.id}`); } async function triggerMetadataBatch(formData: FormData) { "use server"; const libraryId = formData.get("library_id") as string; if (!libraryId) return; const result = await startMetadataBatch(libraryId); revalidatePath("/jobs"); redirect(`/jobs?highlight=${result.id}`); } return ( <>

Tâches d'indexation

Lancer une tâche Sélectionnez une bibliothèque (ou toutes) et choisissez l'action à effectuer.
{libraries.map((lib) => ( ))}
{/* Job types legend */} Référence des types de tâches
Reconstruction

Scan incrémental : détecte les fichiers ajoutés, modifiés ou supprimés depuis le dernier scan, les indexe et génère les miniatures manquantes. Les données existantes non modifiées sont conservées. C’est l’action la plus courante et la plus rapide.

Reconstruction complète

Supprime toutes les données indexées (livres, séries, miniatures) puis effectue un scan complet depuis zéro. Utile si la base de données est désynchronisée ou corrompue. Opération longue et destructive : les statuts de lecture et les métadonnées manuelles seront perdus.

Générer les miniatures

Génère les miniatures uniquement pour les livres qui n’en ont pas encore. Les miniatures existantes ne sont pas touchées. Utile après un import ou si certaines miniatures sont manquantes.

Regénérer les miniatures

Regénère toutes les miniatures depuis zéro, en remplaçant les existantes. Utile si la qualité ou la taille des miniatures a changé dans la configuration, ou si des miniatures sont corrompues.

Métadonnées en lot

Recherche automatiquement les métadonnées de chaque série de la bibliothèque auprès du provider configuré (avec fallback si configuré). Seuls les résultats avec un match unique à 100% de confiance sont appliqués automatiquement. Les séries déjà liées sont ignorées. Un rapport détaillé par série est disponible à la fin du job. Requiert une bibliothèque spécifique (ne fonctionne pas sur « Toutes les bibliothèques »).

); }