add Ready to Listen feature: audio book shelf on home + /listen browse page
- getBooksWithAudioCount() in pocketbase.ts aggregates done audio_jobs, deduplicates by chapter per slug, caches 5 min - GET /api/audio/books endpoint - home page: readyToListen shelf with headphones badge, chapter count, Listen button, hideable - /listen page: full grid with search, sort (most narrated / A-Z / recent), empty state
This commit is contained in:
@@ -6,7 +6,8 @@ import {
|
||||
getHomeStats,
|
||||
getSubscriptionFeed,
|
||||
getTrendingBooks,
|
||||
getRecommendedBooks
|
||||
getRecommendedBooks,
|
||||
getBooksWithAudioCount
|
||||
} from '$lib/server/pocketbase';
|
||||
import { log } from '$lib/server/logger';
|
||||
import type { Book, Progress } from '$lib/server/pocketbase';
|
||||
@@ -87,8 +88,8 @@ export const load: PageServerLoad = async ({ locals }) => {
|
||||
const inProgressSlugs = new Set(continueReading.map((c) => c.book.slug));
|
||||
const recentlyUpdated = recentBooks.filter((b) => !inProgressSlugs.has(b.slug)).slice(0, 6);
|
||||
|
||||
// Fetch trending, recommendations, and subscription feed in parallel
|
||||
const [trendingBooks, recommendedBooks, subscriptionFeed] = await Promise.all([
|
||||
// Fetch trending, recommendations, subscription feed, and audio books in parallel
|
||||
const [trendingBooks, recommendedBooks, subscriptionFeed, audioBooks] = await Promise.all([
|
||||
getTrendingBooks(8).catch(() => [] as Book[]),
|
||||
topGenres.length > 0
|
||||
? getRecommendedBooks(topGenres, inProgressSlugs, 8).catch(() => [] as Book[])
|
||||
@@ -98,12 +99,18 @@ export const load: PageServerLoad = async ({ locals }) => {
|
||||
log.error('home', 'failed to load subscription feed', { err: String(e) });
|
||||
return [] as Awaited<ReturnType<typeof getSubscriptionFeed>>;
|
||||
})
|
||||
: Promise.resolve([])
|
||||
: Promise.resolve([]),
|
||||
getBooksWithAudioCount(20).catch(() => [])
|
||||
]);
|
||||
|
||||
// Strip books the user is already reading from trending (redundant)
|
||||
const trendingFiltered = trendingBooks.filter((b) => !inProgressSlugs.has(b.slug));
|
||||
|
||||
// Strip already-reading books from audio shelf; cap at 8
|
||||
const readyToListen = audioBooks
|
||||
.filter((e) => !inProgressSlugs.has(e.book.slug))
|
||||
.slice(0, 8);
|
||||
|
||||
return {
|
||||
continueInProgress,
|
||||
continueCompleted,
|
||||
@@ -111,6 +118,7 @@ export const load: PageServerLoad = async ({ locals }) => {
|
||||
subscriptionFeed,
|
||||
trendingBooks: trendingFiltered,
|
||||
recommendedBooks,
|
||||
readyToListen,
|
||||
topGenre: topGenres[0] ?? null,
|
||||
stats: {
|
||||
...stats,
|
||||
|
||||
Reference in New Issue
Block a user