feat: unify job creation — tous les types créent N jobs par librairie côté backend
- metadata_batch, metadata_refresh, reading_status_match, reading_status_push, download_detection : library_id devient optionnel, la boucle passe côté API - rebuild (index_jobs.rs), thumbnail_rebuild, thumbnail_regenerate : même logique, suppression du job unique library_id=NULL au profit d'un job par lib - Backoffice simplifié : suppression des boucles frontend, les Server Actions appellent directement l'API sans library_id pour le cas "toutes les librairies" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -63,152 +63,41 @@ export default async function JobsPage({ searchParams }: { searchParams: Promise
|
||||
async function triggerMetadataBatch(formData: FormData) {
|
||||
"use server";
|
||||
const libraryId = formData.get("library_id") as string;
|
||||
if (libraryId) {
|
||||
let result;
|
||||
try {
|
||||
result = await startMetadataBatch(libraryId);
|
||||
} catch {
|
||||
// Library may have metadata disabled — ignore silently
|
||||
return;
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(`/jobs?highlight=${result.id}`);
|
||||
} else {
|
||||
// All libraries — skip those with metadata disabled
|
||||
const allLibraries = await fetchLibraries().catch(() => [] as LibraryDto[]);
|
||||
let lastId: string | undefined;
|
||||
for (const lib of allLibraries) {
|
||||
if (lib.metadata_provider === "none") continue;
|
||||
try {
|
||||
const result = await startMetadataBatch(lib.id);
|
||||
if (result.status !== "already_running") lastId = result.id;
|
||||
} catch {
|
||||
// Library may have metadata disabled or other issue — skip
|
||||
}
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(lastId ? `/jobs?highlight=${lastId}` : "/jobs");
|
||||
}
|
||||
const result = await startMetadataBatch(libraryId || undefined);
|
||||
revalidatePath("/jobs");
|
||||
redirect(result.id ? `/jobs?highlight=${result.id}` : "/jobs");
|
||||
}
|
||||
|
||||
async function triggerMetadataRefresh(formData: FormData) {
|
||||
"use server";
|
||||
const libraryId = formData.get("library_id") as string;
|
||||
if (libraryId) {
|
||||
let result;
|
||||
try {
|
||||
result = await startMetadataRefresh(libraryId);
|
||||
} catch {
|
||||
revalidatePath("/jobs");
|
||||
redirect("/jobs");
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(`/jobs?highlight=${result.id}`);
|
||||
} else {
|
||||
// All libraries — skip those with metadata disabled
|
||||
const allLibraries = await fetchLibraries().catch(() => [] as LibraryDto[]);
|
||||
let lastId: string | undefined;
|
||||
for (const lib of allLibraries) {
|
||||
if (lib.metadata_provider === "none") continue;
|
||||
try {
|
||||
const result = await startMetadataRefresh(lib.id);
|
||||
if (result.status !== "already_running") lastId = result.id;
|
||||
} catch {
|
||||
// Library may have metadata disabled or no approved links — skip
|
||||
}
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(lastId ? `/jobs?highlight=${lastId}` : "/jobs");
|
||||
}
|
||||
const result = await startMetadataRefresh(libraryId || undefined);
|
||||
revalidatePath("/jobs");
|
||||
redirect(result.id ? `/jobs?highlight=${result.id}` : "/jobs");
|
||||
}
|
||||
|
||||
async function triggerReadingStatusMatch(formData: FormData) {
|
||||
"use server";
|
||||
const libraryId = formData.get("library_id") as string;
|
||||
if (libraryId) {
|
||||
let result;
|
||||
try {
|
||||
result = await startReadingStatusMatch(libraryId);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(`/jobs?highlight=${result.id}`);
|
||||
} else {
|
||||
// All libraries — only those with reading_status_provider configured
|
||||
const allLibraries = await fetchLibraries().catch(() => [] as LibraryDto[]);
|
||||
let lastId: string | undefined;
|
||||
for (const lib of allLibraries) {
|
||||
if (!lib.reading_status_provider) continue;
|
||||
try {
|
||||
const result = await startReadingStatusMatch(lib.id);
|
||||
if (result.status !== "already_running") lastId = result.id;
|
||||
} catch {
|
||||
// Skip libraries with errors
|
||||
}
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(lastId ? `/jobs?highlight=${lastId}` : "/jobs");
|
||||
}
|
||||
const result = await startReadingStatusMatch(libraryId || undefined);
|
||||
revalidatePath("/jobs");
|
||||
redirect(result.id ? `/jobs?highlight=${result.id}` : "/jobs");
|
||||
}
|
||||
|
||||
async function triggerReadingStatusPush(formData: FormData) {
|
||||
"use server";
|
||||
const libraryId = formData.get("library_id") as string;
|
||||
if (libraryId) {
|
||||
let result;
|
||||
try {
|
||||
result = await startReadingStatusPush(libraryId);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(`/jobs?highlight=${result.id}`);
|
||||
} else {
|
||||
// All libraries — only those with reading_status_provider configured
|
||||
const allLibraries = await fetchLibraries().catch(() => [] as LibraryDto[]);
|
||||
let lastId: string | undefined;
|
||||
for (const lib of allLibraries) {
|
||||
if (!lib.reading_status_provider) continue;
|
||||
try {
|
||||
const result = await startReadingStatusPush(lib.id);
|
||||
if (result.status !== "already_running") lastId = result.id;
|
||||
} catch {
|
||||
// Skip libraries with errors
|
||||
}
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(lastId ? `/jobs?highlight=${lastId}` : "/jobs");
|
||||
}
|
||||
const result = await startReadingStatusPush(libraryId || undefined);
|
||||
revalidatePath("/jobs");
|
||||
redirect(result.id ? `/jobs?highlight=${result.id}` : "/jobs");
|
||||
}
|
||||
|
||||
async function triggerDownloadDetection(formData: FormData) {
|
||||
"use server";
|
||||
const libraryId = formData.get("library_id") as string;
|
||||
if (libraryId) {
|
||||
let result;
|
||||
try {
|
||||
result = await startDownloadDetection(libraryId);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(`/jobs?highlight=${result.id}`);
|
||||
} else {
|
||||
// All libraries
|
||||
const allLibraries = await fetchLibraries().catch(() => [] as LibraryDto[]);
|
||||
let lastId: string | undefined;
|
||||
for (const lib of allLibraries) {
|
||||
try {
|
||||
const result = await startDownloadDetection(lib.id);
|
||||
if (result.status !== "already_running") lastId = result.id;
|
||||
} catch {
|
||||
// Skip libraries with errors (e.g. Prowlarr not configured)
|
||||
}
|
||||
}
|
||||
revalidatePath("/jobs");
|
||||
redirect(lastId ? `/jobs?highlight=${lastId}` : "/jobs");
|
||||
}
|
||||
const result = await startDownloadDetection(libraryId || undefined);
|
||||
revalidatePath("/jobs");
|
||||
redirect(result.id ? `/jobs?highlight=${result.id}` : "/jobs");
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1061,24 +1061,24 @@ export type MetadataBatchResultDto = {
|
||||
error_message: string | null;
|
||||
};
|
||||
|
||||
export async function startMetadataBatch(libraryId: string) {
|
||||
return apiFetch<{ id: string; status: string }>("/metadata/batch", {
|
||||
export async function startMetadataBatch(libraryId?: string) {
|
||||
return apiFetch<{ id: string | null; status: string }>("/metadata/batch", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ library_id: libraryId }),
|
||||
body: JSON.stringify(libraryId ? { library_id: libraryId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function startMetadataRefresh(libraryId: string) {
|
||||
return apiFetch<{ id: string; status: string }>("/metadata/refresh", {
|
||||
export async function startMetadataRefresh(libraryId?: string) {
|
||||
return apiFetch<{ id: string | null; status: string }>("/metadata/refresh", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ library_id: libraryId }),
|
||||
body: JSON.stringify(libraryId ? { library_id: libraryId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function startReadingStatusMatch(libraryId: string) {
|
||||
return apiFetch<{ id: string; status: string }>("/reading-status/match", {
|
||||
export async function startReadingStatusMatch(libraryId?: string) {
|
||||
return apiFetch<{ id: string | null; status: string }>("/reading-status/match", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ library_id: libraryId }),
|
||||
body: JSON.stringify(libraryId ? { library_id: libraryId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1111,10 +1111,10 @@ export async function getReadingStatusMatchResults(jobId: string) {
|
||||
return apiFetch<ReadingStatusMatchResultDto[]>(`/reading-status/match/${jobId}/results`);
|
||||
}
|
||||
|
||||
export async function startReadingStatusPush(libraryId: string) {
|
||||
return apiFetch<{ id: string; status: string }>("/reading-status/push", {
|
||||
export async function startReadingStatusPush(libraryId?: string) {
|
||||
return apiFetch<{ id: string | null; status: string }>("/reading-status/push", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ library_id: libraryId }),
|
||||
body: JSON.stringify(libraryId ? { library_id: libraryId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1148,10 +1148,10 @@ export async function getReadingStatusPushResults(jobId: string) {
|
||||
return apiFetch<ReadingStatusPushResultDto[]>(`/reading-status/push/${jobId}/results`);
|
||||
}
|
||||
|
||||
export async function startDownloadDetection(libraryId: string) {
|
||||
return apiFetch<{ id: string; status: string }>("/download-detection/start", {
|
||||
export async function startDownloadDetection(libraryId?: string) {
|
||||
return apiFetch<{ id: string | null; status: string }>("/download-detection/start", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ library_id: libraryId }),
|
||||
body: JSON.stringify(libraryId ? { library_id: libraryId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user