mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
Add per-user home sections & unified Audible cache
Introduce per-user configurable home page sections and a unified Audible cache/category model. Adds Prisma models (UserHomeSection, AudibleCacheCategory) and migrations to create tables and remove legacy popular/new_release flags; updates schema.prisma accordingly. Add API routes for user home sections, live Audible categories, and category-based audiobook listing, and refactor popular/new-releases/covers routes to read from AudibleCacheCategory. Frontend: new HomeSection component, HomeSectionConfigModal, useHomeSections hook, and homepage changes to render dynamic sections plus image fallback to a placeholder SVG. Also add placeholder_cover.svg and tests for home sections and the audible refresh processor.
This commit is contained in:
@@ -77,6 +77,7 @@
|
||||
- **Component catalog (cards, badges, forms)** → [frontend/components.md](frontend/components.md)
|
||||
- **RequestCard, StatusBadge, ProgressBar** → [frontend/components.md](frontend/components.md)
|
||||
- **Pages: home, search, requests, profile** → [frontend/components.md](frontend/components.md)
|
||||
- **Home page sections (per-user, configurable)** → [features/home-sections.md](features/home-sections.md)
|
||||
|
||||
## BookDate (AI Recommendations)
|
||||
- **AI-powered recommendations, swipe interface** → [features/bookdate.md](features/bookdate.md)
|
||||
@@ -150,3 +151,6 @@
|
||||
**"Why do BookDate library books show placeholders?"** → [features/library-thumbnail-cache.md](features/library-thumbnail-cache.md)
|
||||
**"How does file hash matching work?"** → [fixes/file-hash-matching.md](fixes/file-hash-matching.md)
|
||||
**"Why is ABS matching the wrong book?"** → [fixes/file-hash-matching.md](fixes/file-hash-matching.md) (file hash prevents false positives)
|
||||
**"How do I customize my home page?"** → [features/home-sections.md](features/home-sections.md)
|
||||
**"How do Audible categories work?"** → [features/home-sections.md](features/home-sections.md)
|
||||
**"How do I add category sections to the home page?"** → [features/home-sections.md](features/home-sections.md)
|
||||
|
||||
@@ -129,10 +129,10 @@ interface ScheduledJob {
|
||||
## Audible Refresh Processor
|
||||
|
||||
**Implementation:**
|
||||
1. Clear previous `isPopular`/`isNewRelease` flags
|
||||
2. Fetch 200 popular + 200 new releases (multi-page scraping)
|
||||
3. Download and cache cover thumbnails locally (stored in `/app/cache/thumbnails`)
|
||||
4. Store/update in DB with category flags, rankings (`popularRank`, `newReleaseRank`), and cached cover paths
|
||||
1. Fetch 200 popular + 200 new releases (multi-page scraping)
|
||||
2. Download and cache cover thumbnails locally (stored in `/app/cache/thumbnails`)
|
||||
3. Wipe and re-populate `AudibleCacheCategory` entries with reserved IDs (`__popular__`, `__new_releases__`) and user-configured category IDs
|
||||
4. Upsert book metadata in `AudibleCache`, ranked entries in `AudibleCacheCategory`
|
||||
5. Record sync timestamp (`lastAudibleSync`)
|
||||
6. Clean up unused thumbnails (removes covers for audiobooks no longer in cache)
|
||||
7. Perform fuzzy matching (70% threshold) against Plex library
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Home Page Sections (Per-User Configurable)
|
||||
|
||||
**Status:** Implemented | Per-user home page with configurable sections (popular, new releases, Audible categories)
|
||||
|
||||
## Overview
|
||||
Users customize their home page by adding/removing/reordering sections. Each section displays audiobooks from a specific source: built-in Popular, New Releases, or scraped Audible categories.
|
||||
|
||||
## Data Models
|
||||
|
||||
**UserHomeSection** (`user_home_sections`):
|
||||
- `id`, `userId` (FK User), `sectionType` ('popular'|'new_releases'|'category'), `categoryId` (nullable), `categoryName` (nullable), `sortOrder` (int)
|
||||
- Unique: `(userId, sectionType, categoryId)`
|
||||
- Default: Popular (0) + New Releases (1) created on first access
|
||||
|
||||
**AudibleCacheCategory** (`audible_cache_categories`):
|
||||
- `id`, `asin`, `categoryId`, `rank`, `lastSyncedAt`
|
||||
- Unique: `(asin, categoryId)`, Indexes: `categoryId`, `(categoryId, rank)`
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/api/user/home-sections` | user | Returns sections + nextRefresh |
|
||||
| PUT | `/api/user/home-sections` | user | Save full config (delete-recreate), max 10 |
|
||||
| GET | `/api/audible/categories` | user | Live scrape top-level categories |
|
||||
| GET | `/api/audiobooks/category/[categoryId]` | public | Paginated category books from cache |
|
||||
|
||||
## Refresh Processor (Unified Storage)
|
||||
- All section data stored in `AudibleCacheCategory` with reserved IDs: `__popular__` and `__new_releases__` for built-in sections
|
||||
- Popular/new-releases use same wipe-and-populate pattern as user categories
|
||||
- After built-in sections, queries DISTINCT categoryIds from `UserHomeSection`
|
||||
- Per section: wipe `AudibleCacheCategory` rows, scrape, upsert `AudibleCache` metadata, insert ranked category entries
|
||||
- Batch cooldown between sections (10-20s random)
|
||||
- Constants exported from `audible-refresh.processor.ts`: `POPULAR_CATEGORY_ID`, `NEW_RELEASES_CATEGORY_ID`
|
||||
|
||||
## AudibleService Methods
|
||||
- `getCategories()`: Scrapes `{baseUrl}/categories`, returns `{id, name}[]`
|
||||
- `getCategoryBooks(categoryId, limit)`: Scrapes `/search?node={id}&pageSize=50&sort=popularity-rank`, up to 200 results
|
||||
|
||||
## Frontend
|
||||
- **Hooks:** `useHomeSections()`, `useCategoryAudiobooks()`, `useAudibleCategories()` in `src/lib/hooks/useHomeSections.ts`
|
||||
- **Config Modal:** `src/components/home/HomeSectionConfigModal.tsx` — drag-and-drop (desktop), up/down arrows (mobile), auto-save with debounce
|
||||
- **Section Component:** `src/components/home/HomeSection.tsx` — renders individual section with color-coded header
|
||||
- **Home Page:** `src/app/page.tsx` — dynamic sections from user config, gear icon for customize
|
||||
- **Pagination:** `src/components/ui/UnifiedPagination.tsx` — updated to support 1-12 dynamic sections
|
||||
|
||||
## Key Decisions
|
||||
- 10 section limit per user (total)
|
||||
- Category picker scraped live (no categories table)
|
||||
- Top-level categories only (v1)
|
||||
- Wipe-and-re-scrape per category during refresh
|
||||
- Deduplication of categories across users before scraping
|
||||
- If category disappears, user sees empty section
|
||||
- 10-color palette assigned by sort order
|
||||
|
||||
## Files
|
||||
- Schema: `prisma/schema.prisma` (UserHomeSection, AudibleCacheCategory)
|
||||
- Migration: `prisma/migrations/20260306000000_add_home_sections/migration.sql`
|
||||
- Service: `src/lib/integrations/audible.service.ts` (getCategories, getCategoryBooks)
|
||||
- Processor: `src/lib/processors/audible-refresh.processor.ts`
|
||||
- API Routes: `src/app/api/user/home-sections/route.ts`, `src/app/api/audible/categories/route.ts`, `src/app/api/audiobooks/category/[categoryId]/route.ts`
|
||||
- Hooks: `src/lib/hooks/useHomeSections.ts`
|
||||
- Components: `src/components/home/HomeSectionConfigModal.tsx`, `src/components/home/HomeSection.tsx`
|
||||
- Tests: `tests/api/home-sections.routes.test.ts`, `tests/processors/audible-refresh.processor.test.ts`
|
||||
@@ -128,11 +128,11 @@ Single matching algorithm used everywhere (search, popular, new-releases, jobs).
|
||||
Discovery APIs serve cached data from DB with real-time matching.
|
||||
|
||||
**Flow:**
|
||||
1. `audible_refresh` job runs daily → fetches 200 popular + 200 new releases
|
||||
1. `audible_refresh` job runs daily → fetches 200 popular + 200 new releases + user-configured categories
|
||||
2. Downloads and caches cover thumbnails locally (reduces Audible load)
|
||||
3. Stores in DB with flags (`isPopular`, `isNewRelease`) and rankings
|
||||
3. Stores metadata in `audible_cache`, ranked entries in `audible_cache_categories` with reserved IDs (`__popular__`, `__new_releases__`) and user category IDs
|
||||
4. Cleans up unused thumbnails after sync
|
||||
5. API routes query DB → apply real-time matching → return enriched results
|
||||
5. API routes query `AudibleCacheCategory` by categoryId → join with `AudibleCache` metadata → apply real-time matching → return enriched results
|
||||
6. Homepage loads instantly (no Audible API hits)
|
||||
|
||||
## Thumbnail Caching
|
||||
|
||||
Reference in New Issue
Block a user