From 75fc3a482ad6a9d303a05d15c7eb5f1727ae75a9 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sun, 23 Feb 2025 09:19:55 +0100 Subject: [PATCH] chore(library): review deprecated get, now paging and all are local and not by API --- src/lib/services/base-api.service.ts | 22 ++---- src/lib/services/image.service.ts | 2 +- src/lib/services/library.service.ts | 106 +++++++++++++++++++++++---- 3 files changed, 100 insertions(+), 30 deletions(-) diff --git a/src/lib/services/base-api.service.ts b/src/lib/services/base-api.service.ts index b9dae68..c87f90e 100644 --- a/src/lib/services/base-api.service.ts +++ b/src/lib/services/base-api.service.ts @@ -5,6 +5,10 @@ import { ConfigDBService } from "./config-db.service"; // Types de cache disponibles export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES"; +interface KomgaRequestInit extends RequestInit { + isImage?: boolean; +} + export abstract class BaseApiService { protected static async getKomgaConfig(): Promise { try { @@ -76,26 +80,14 @@ export abstract class BaseApiService { protected static async fetchFromApi( url: string, headers: Headers, - isImage: boolean = false + options: KomgaRequestInit = {} ): Promise { - // const startTime = Date.now(); // Capture le temps de début - - const response = await fetch(url, { headers }); - - // const endTime = Date.now(); // Capture le temps de fin - // const responseTime = endTime - startTime; // Calcule le temps de réponse - - // // Log le temps de réponse en ms ou en s - // if (responseTime >= 1000) { - // console.log(`Temps de réponse pour ${url}: ${(responseTime / 1000).toFixed(2)}s`); - // } else { - // console.log(`Temps de réponse pour ${url}: ${responseTime}ms`); - // } + const response = await fetch(url, { headers, ...options }); if (!response.ok) { throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`); } - return isImage ? response : response.json(); + return options.isImage ? response : response.json(); } } diff --git a/src/lib/services/image.service.ts b/src/lib/services/image.service.ts index 40830c5..9847eff 100644 --- a/src/lib/services/image.service.ts +++ b/src/lib/services/image.service.ts @@ -16,7 +16,7 @@ export class ImageService extends BaseApiService { return this.fetchWithCache( `image-${path}`, async () => { - const response = await this.fetchFromApi(url, headers, true); + const response = await this.fetchFromApi(url, headers, { isImage: true }); const contentType = response.headers.get("content-type"); const arrayBuffer = await response.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); diff --git a/src/lib/services/library.service.ts b/src/lib/services/library.service.ts index 94b25b6..579e393 100644 --- a/src/lib/services/library.service.ts +++ b/src/lib/services/library.service.ts @@ -29,6 +29,41 @@ export class LibraryService extends BaseApiService { return library; } + static async getAllLibrarySeries(libraryId: string): Promise { + try { + const config = await this.getKomgaConfig(); + const url = this.buildUrl(config, "series/list", { + size: "1000", // On récupère un maximum de séries + }); + const headers = this.getAuthHeaders(config); + headers.set("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>(url, headers, { + method: "POST", + body: JSON.stringify(searchBody), + }), + "SERIES" + ); + + return response.content; + } catch (error) { + return this.handleError(error, "Impossible de récupérer toutes les séries"); + } + } + static async getLibrarySeries( libraryId: string, page: number = 0, @@ -37,21 +72,64 @@ export class LibraryService extends BaseApiService { search?: string ): Promise> { try { - const config = await this.getKomgaConfig(); - const url = this.buildUrl(config, "series", { - library_id: libraryId, - page: page.toString(), - size: size.toString(), - ...(unreadOnly && { read_status: "UNREAD,IN_PROGRESS" }), - ...(search && { search }), - }); - const headers = this.getAuthHeaders(config); + // Récupérer toutes les séries depuis le cache + const allSeries = await this.getAllLibrarySeries(libraryId); - return this.fetchWithCache>( - `library-${libraryId}-series-${page}-${size}-${unreadOnly}-${search}`, - async () => this.fetchFromApi>(url, headers), - "SERIES" - ); + // Filtrer les séries + let filteredSeries = allSeries; + + if (unreadOnly) { + filteredSeries = filteredSeries.filter( + (series) => series.booksReadCount < series.booksCount + ); + } + + if (search) { + const searchLower = search.toLowerCase(); + filteredSeries = filteredSeries.filter((series) => + series.metadata.title.toLowerCase().includes(searchLower) + ); + } + + // Trier les séries + filteredSeries.sort((a, b) => a.metadata.titleSort.localeCompare(b.metadata.titleSort)); + + // Calculer la pagination + const totalElements = filteredSeries.length; + const totalPages = Math.ceil(totalElements / size); + const startIndex = page * size; + const endIndex = Math.min(startIndex + size, totalElements); + const paginatedSeries = filteredSeries.slice(startIndex, endIndex); + + // Construire la réponse + return { + content: paginatedSeries, + empty: paginatedSeries.length === 0, + first: page === 0, + last: page >= totalPages - 1, + number: page, + numberOfElements: paginatedSeries.length, + pageable: { + offset: startIndex, + pageNumber: page, + pageSize: size, + paged: true, + sort: { + empty: false, + sorted: true, + unsorted: false, + }, + unpaged: false, + }, + size, + sort: { + empty: false, + sorted: true, + unsorted: false, + }, + totalElements, + totalPages, + }; } catch (error) { return this.handleError(error, "Impossible de récupérer les séries"); }