diff --git a/src/lib/services/book.service.ts b/src/lib/services/book.service.ts index 72c4936..3ba8bb5 100644 --- a/src/lib/services/book.service.ts +++ b/src/lib/services/book.service.ts @@ -4,10 +4,9 @@ import type { ImageResponse } from "./image.service"; import { ImageService } from "./image.service"; import { PreferencesService } from "./preferences.service"; import { ConfigDBService } from "./config-db.service"; +import { SeriesService } from "./series.service"; import { ERROR_CODES } from "../../constants/errorCodes"; import { AppError } from "../../utils/errors"; -import { SeriesService } from "./series.service"; -import type { Series } from "@/types/series"; import logger from "@/lib/logger"; export class BookService extends BaseApiService { @@ -43,10 +42,23 @@ export class BookService extends BaseApiService { throw new AppError(ERROR_CODES.BOOK.NOT_FOUND, {}, error); } } - public static async getNextBook(bookId: string, seriesId: string): Promise { - const books = await SeriesService.getAllSeriesBooks(seriesId); - const currentIndex = books.findIndex((book) => book.id === bookId); - return books[currentIndex + 1] || null; + public static async getNextBook(bookId: string, _seriesId: string): Promise { + try { + // Utiliser l'endpoint natif Komga pour obtenir le livre suivant + return await this.fetchFromApi({ path: `books/${bookId}/next` }); + } catch (error) { + // Si le livre suivant n'existe pas, Komga retourne 404 + // On retourne null dans ce cas + if ( + error instanceof AppError && + error.code === ERROR_CODES.KOMGA.HTTP_ERROR && + (error as any).context?.status === 404 + ) { + return null; + } + // Pour les autres erreurs, on les propage + throw error; + } } static async updateReadProgress( @@ -191,34 +203,7 @@ export class BookService extends BaseApiService { const { LibraryService } = await import("./library.service"); - // Essayer d'abord d'utiliser le cache des bibliothèques - const allSeriesFromCache: Series[] = []; - - for (const libraryId of libraryIds) { - try { - // Essayer de récupérer les séries depuis le cache (rapide si en cache) - const series = await LibraryService.getAllLibrarySeries(libraryId); - allSeriesFromCache.push(...series); - } catch { - // Si erreur, on continue avec les autres bibliothèques - } - } - - if (allSeriesFromCache.length > 0) { - // Choisir une série au hasard parmi toutes celles trouvées - const randomSeriesIndex = Math.floor(Math.random() * allSeriesFromCache.length); - const randomSeries = allSeriesFromCache[randomSeriesIndex]; - - // Récupérer les books de cette série - const books = await SeriesService.getAllSeriesBooks(randomSeries.id); - - if (books.length > 0) { - const randomBookIndex = Math.floor(Math.random() * books.length); - return books[randomBookIndex].id; - } - } - - // Si pas de cache, faire une requête légère : prendre une page de séries d'une bibliothèque au hasard + // Faire une requête légère : prendre une page de séries d'une bibliothèque au hasard const randomLibraryIndex = Math.floor(Math.random() * libraryIds.length); const randomLibraryId = libraryIds[randomLibraryIndex]; @@ -235,17 +220,17 @@ export class BookService extends BaseApiService { const randomSeriesIndex = Math.floor(Math.random() * seriesResponse.content.length); const randomSeries = seriesResponse.content[randomSeriesIndex]; - // Récupérer les books de cette série - const books = await SeriesService.getAllSeriesBooks(randomSeries.id); + // Récupérer les books de cette série avec pagination + const booksResponse = await SeriesService.getSeriesBooks(randomSeries.id, 0, 100); - if (books.length === 0) { + if (booksResponse.content.length === 0) { throw new AppError(ERROR_CODES.BOOK.NOT_FOUND, { message: "Aucun livre trouvé dans la série", }); } - const randomBookIndex = Math.floor(Math.random() * books.length); - return books[randomBookIndex].id; + const randomBookIndex = Math.floor(Math.random() * booksResponse.content.length); + return booksResponse.content[randomBookIndex].id; } catch (error) { if (error instanceof AppError) { throw error; diff --git a/src/lib/services/library.service.ts b/src/lib/services/library.service.ts index 973db6a..20de65d 100644 --- a/src/lib/services/library.service.ts +++ b/src/lib/services/library.service.ts @@ -35,45 +35,6 @@ export class LibraryService extends BaseApiService { } } - static async getAllLibrarySeries(libraryId: string): Promise { - try { - const headers = { "Content-Type": "application/json" }; - - const searchBody = { - condition: { - libraryId: { - operator: "is", - value: libraryId, - }, - }, - }; - - const cacheKey = `library-${libraryId}-all-series`; - const response = await this.fetchWithCache>( - cacheKey, - async () => - this.fetchFromApi>( - { - path: "series/list", - params: { - size: "5000", // On récupère un maximum de livres - }, - }, - headers, - { - method: "POST", - body: JSON.stringify(searchBody), - } - ), - "SERIES" - ); - - return response.content; - } catch (error) { - throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error); - } - } - static async getLibrarySeries( libraryId: string, page: number = 0, @@ -88,7 +49,7 @@ export class LibraryService extends BaseApiService { let condition: any; if (unreadOnly) { - // Utiliser allOf pour combiner les conditions + // Utiliser allOf pour combiner libraryId avec anyOf pour UNREAD ou IN_PROGRESS condition = { allOf: [ { @@ -98,10 +59,20 @@ export class LibraryService extends BaseApiService { }, }, { - readStatus: { - operator: "is", - value: "UNREAD", - }, + anyOf: [ + { + readStatus: { + operator: "is", + value: "UNREAD", + }, + }, + { + readStatus: { + operator: "is", + value: "IN_PROGRESS", + }, + }, + ], }, ], }; @@ -166,8 +137,6 @@ export class LibraryService extends BaseApiService { // Invalider toutes les clés de cache pour cette bibliothèque // Format: library-{id}-series-p{page}-s{size}-u{unread}-q{search} await cacheService.deleteAll(`library-${libraryId}-series-`); - // Invalider aussi l'ancienne clé pour compatibilité - await cacheService.delete(`library-${libraryId}-all-series`); } catch (error) { throw new AppError(ERROR_CODES.CACHE.DELETE_ERROR, {}, error); } diff --git a/src/lib/services/series.service.ts b/src/lib/services/series.service.ts index 1510ec9..41190c5 100644 --- a/src/lib/services/series.service.ts +++ b/src/lib/services/series.service.ts @@ -45,52 +45,6 @@ export class SeriesService extends BaseApiService { } } - static async getAllSeriesBooks(seriesId: string): Promise { - try { - const headers = { "Content-Type": "application/json" }; - - const searchBody = { - condition: { - seriesId: { - operator: "is", - value: seriesId, - }, - }, - }; - - const cacheKey = `series-${seriesId}-all-books`; - const response = await this.fetchWithCache>( - cacheKey, - async () => - this.fetchFromApi>( - { - path: "books/list", - params: { - size: "1000", // On récupère un maximum de livres - }, - }, - headers, - { - method: "POST", - body: JSON.stringify(searchBody), - } - ), - "BOOKS" - ); - - if (!response.content.length) { - throw new AppError(ERROR_CODES.SERIES.NO_BOOKS_FOUND); - } - - return response.content; - } catch (error) { - if (error instanceof AppError) { - throw error; - } - throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error); - } - } - static async getSeriesBooks( seriesId: string, page: number = 0, @@ -104,7 +58,7 @@ export class SeriesService extends BaseApiService { let condition: any; if (unreadOnly) { - // Utiliser allOf pour combiner les conditions + // Utiliser allOf pour combiner seriesId avec anyOf pour UNREAD ou IN_PROGRESS condition = { allOf: [ { @@ -114,10 +68,20 @@ export class SeriesService extends BaseApiService { }, }, { - readStatus: { - operator: "is", - value: "UNREAD", - }, + anyOf: [ + { + readStatus: { + operator: "is", + value: "UNREAD", + }, + }, + { + readStatus: { + operator: "is", + value: "IN_PROGRESS", + }, + }, + ], }, ], }; @@ -175,8 +139,6 @@ export class SeriesService extends BaseApiService { // Invalider toutes les clés de cache pour cette série // Format: series-{id}-books-p{page}-s{size}-u{unread} await cacheService.deleteAll(`series-${seriesId}-books-`); - // Invalider aussi l'ancienne clé pour compatibilité - await cacheService.delete(`series-${seriesId}-all-books`); } catch (error) { throw new AppError(ERROR_CODES.CACHE.DELETE_ERROR, {}, error); }