From e8be6cb724d7014acd9290490c1760dad5509d27 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sun, 16 Feb 2025 23:16:01 +0100 Subject: [PATCH] feat: home beautiful images --- .../[bookId]/pages/[pageNumber]/route.ts | 33 ++++++---------- .../series/[seriesId]/first-page/route.ts | 39 +++++++++++++++++++ src/components/home/MediaRow.tsx | 4 +- src/lib/services/series.service.ts | 29 ++++++++++++++ 4 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 src/app/api/komga/images/series/[seriesId]/first-page/route.ts diff --git a/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/route.ts b/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/route.ts index c6704bc..d20f134 100644 --- a/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/route.ts +++ b/src/app/api/komga/images/books/[bookId]/pages/[pageNumber]/route.ts @@ -1,34 +1,25 @@ -import { NextResponse } from "next/server"; -import { BookService } from "@/lib/services/book.service"; +import { NextRequest, NextResponse } from "next/server"; +import { ImageService } from "@/lib/services/image.service"; export const dynamic = "force-dynamic"; export async function GET( - request: Request, + request: NextRequest, { params }: { params: { bookId: string; pageNumber: string } } ) { try { - // Convertir le numéro de page en nombre - const pageNumber = parseInt(params.pageNumber); - if (isNaN(pageNumber) || pageNumber < 1) { - return NextResponse.json({ error: "Numéro de page invalide" }, { status: 400 }); - } - - const response = await BookService.getPage(params.bookId, pageNumber); - const buffer = await response.arrayBuffer(); - const headers = new Headers(); - headers.set("Content-Type", response.headers.get("Content-Type") || "image/jpeg"); - headers.set("Cache-Control", "public, max-age=31536000"); // Cache for 1 year + const { buffer, contentType } = await ImageService.getImage( + `books/${params.bookId}/pages/${params.pageNumber}` + ); return new NextResponse(buffer, { - status: 200, - headers, + headers: { + "Content-Type": contentType || "image/jpeg", + "Cache-Control": "public, max-age=31536000, immutable", + }, }); } catch (error) { - console.error("API Book Page - Erreur:", error); - return NextResponse.json( - { error: "Erreur lors de la récupération de la page" }, - { status: 500 } - ); + console.error("Erreur lors de la récupération de la page du livre:", error); + return new NextResponse("Erreur lors de la récupération de la page", { status: 500 }); } } diff --git a/src/app/api/komga/images/series/[seriesId]/first-page/route.ts b/src/app/api/komga/images/series/[seriesId]/first-page/route.ts new file mode 100644 index 0000000..4f961fb --- /dev/null +++ b/src/app/api/komga/images/series/[seriesId]/first-page/route.ts @@ -0,0 +1,39 @@ +import { NextRequest, NextResponse } from "next/server"; +import { ImageService } from "@/lib/services/image.service"; +import { SeriesService } from "@/lib/services/series.service"; + +export const dynamic = "force-dynamic"; + +export async function GET(request: NextRequest, { params }: { params: { seriesId: string } }) { + try { + // Récupérer l'ID du premier livre + const firstBookId = await SeriesService.getFirstBook(params.seriesId); + + // Récupérer la première page du premier livre + const { buffer, contentType } = await ImageService.getImage(`books/${firstBookId}/pages/1`); + + return new NextResponse(buffer, { + headers: { + "Content-Type": contentType || "image/jpeg", + "Cache-Control": "public, max-age=31536000, immutable", + }, + }); + } catch (error) { + console.error("Erreur lors de la récupération de la première page de la série:", error); + + // En cas d'erreur, on essaie de récupérer le thumbnail comme fallback + try { + const { buffer, contentType } = await ImageService.getImage( + `series/${params.seriesId}/thumbnail` + ); + return new NextResponse(buffer, { + headers: { + "Content-Type": contentType || "image/jpeg", + "Cache-Control": "public, max-age=31536000, immutable", + }, + }); + } catch (fallbackError) { + return new NextResponse("Erreur lors de la récupération de l'image", { status: 500 }); + } + } +} diff --git a/src/components/home/MediaRow.tsx b/src/components/home/MediaRow.tsx index c7c225e..e01e051 100644 --- a/src/components/home/MediaRow.tsx +++ b/src/components/home/MediaRow.tsx @@ -111,7 +111,9 @@ function MediaCard({ item, onClick }: MediaCardProps) { <> {`Couverture { + try { + const config = await this.getKomgaConfig(); + const url = this.buildUrl(config, `series/${seriesId}/books`); + const headers = this.getAuthHeaders(config); + + return this.fetchWithCache( + `series-first-book-${seriesId}`, + async () => { + const response = await fetch(`${url}?page=0&size=1`, { headers }); + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + + const data = await response.json(); + if (!data.content || data.content.length === 0) { + throw new Error("Aucun livre trouvé dans la série"); + } + + return data.content[0].id; + }, + "SERIES" + ); + } catch (error) { + console.error("Erreur lors de la récupération du premier livre:", error); + return this.handleError(error, "Impossible de récupérer le premier livre"); + } + } }