Add series browsing, search, and detail UI

Introduce full support for Audible series exploration: API routes, frontend pages, components, hooks, and integrations. Key changes:

- Prisma: add Audiobook.seriesAsin for linking audiobooks to series detail pages.
- Backend: add /api/series/search and /api/series/[asin] routes that require auth; scrape Audible series data and enrich books with library availability.
- Integrations/services: add audible-series integration and update request/HTTP services to support the workflow.
- Frontend: add /series and /series/[asin] pages, new components (SeriesCard, SeriesGrid, SeriesDetailCard, SimilarSeriesRow) and wire them to a new useSeries hook; update AudiobookDetailsModal to show/link series; add Series link to Header.
- Misc: extend audiobook types with series fields and add seriesLabels to language-config for scraping.

These changes enable users to search for series, view series metadata and books, and navigate between audiobook and series detail pages.
This commit is contained in:
kikootwo
2026-02-20 10:19:30 -05:00
parent 5d8ac2f73d
commit cb9f1b81bc
17 changed files with 1663 additions and 1 deletions
+20 -1
View File
@@ -48,6 +48,7 @@ export interface AudibleAudiobook {
genres?: string[];
series?: string;
seriesPart?: string;
seriesAsin?: string;
}
export interface AudibleSearchResult {
@@ -77,6 +78,22 @@ export class AudibleService {
return this.baseUrl;
}
/**
* Get the current Audible region code
*/
public getRegion(): AudibleRegion {
return this.region;
}
/**
* Public fetch wrapper for external scraping modules (e.g. audible-series.ts).
* Ensures the service is initialized and delegates to fetchWithRetry.
*/
public async fetch(url: string, config: any = {}): Promise<{ data: any; meta: FetchResultMeta }> {
await this.initialize();
return this.fetchWithRetry(url, config);
}
/**
* Get the language config for the current region
*/
@@ -749,6 +766,7 @@ export class AudibleService {
genres: data.genres?.map((g: any) => typeof g === 'string' ? g : g.name).slice(0, 5) || undefined,
series: data.seriesPrimary?.name || undefined,
seriesPart: data.seriesPrimary?.position || undefined,
seriesAsin: data.seriesPrimary?.asin || undefined,
};
// Ensure cover art URL is high quality
@@ -765,7 +783,8 @@ export class AudibleService {
rating: result.rating,
genreCount: result.genres?.length || 0,
series: result.series,
seriesPart: result.seriesPart
seriesPart: result.seriesPart,
seriesAsin: result.seriesAsin
});
return result;