From 385c9cd8f2548b828a605157759bd571d9837562 Mon Sep 17 00:00:00 2001 From: Admin Date: Sun, 5 Apr 2026 20:20:19 +0500 Subject: [PATCH] feat(reader): voice modal with search, chapter search, comments collapse, audio stream fix - ListeningMode: replace inline voice dropdown with full-screen modal + voice search - ListeningMode: add chapter search box (shown when > 6 chapters) + click-to-play via autoStartChapter - CommentsSection: collapse by default when empty, auto-expand once comments load - AudioPlayer: always use streaming endpoint for Kokoro/PocketTTS (backend deduplicates via AudioExists) --- ui/src/lib/components/AudioPlayer.svelte | 13 +- ui/src/lib/components/CommentsSection.svelte | 534 ++++++++++--------- ui/src/lib/components/ListeningMode.svelte | 186 +++++-- 3 files changed, 427 insertions(+), 306 deletions(-) diff --git a/ui/src/lib/components/AudioPlayer.svelte b/ui/src/lib/components/AudioPlayer.svelte index 1a67da6..6d2448b 100644 --- a/ui/src/lib/components/AudioPlayer.svelte +++ b/ui/src/lib/components/AudioPlayer.svelte @@ -575,11 +575,14 @@ // Slow path: audio not yet in MinIO. // - // For Kokoro / PocketTTS when presign has NOT already enqueued the runner: - // use the streaming endpoint — audio starts playing within seconds while - // generation runs and MinIO is populated concurrently. - // Skip when enqueued=true to avoid double-generation with the async runner. - if (!voice.startsWith('cfai:') && !presignResult.enqueued) { + // For Kokoro / PocketTTS: always use the streaming endpoint so audio + // starts playing within seconds. The stream handler checks MinIO first + // (fast redirect if already cached) and otherwise generates + uploads + // concurrently. Even if the async runner is already working on this + // chapter, the stream will redirect to MinIO the moment the runner + // finishes — no harmful double-generation occurs because the backend + // deduplications via AudioExists on the next request. + if (!voice.startsWith('cfai:')) { // PocketTTS outputs raw WAV — skip the ffmpeg transcode entirely. // WAV (PCM) is natively supported on all platforms including iOS Safari. // Kokoro and CF AI output MP3 natively, so keep mp3 for those. diff --git a/ui/src/lib/components/CommentsSection.svelte b/ui/src/lib/components/CommentsSection.svelte index a757c98..15346cb 100644 --- a/ui/src/lib/components/CommentsSection.svelte +++ b/ui/src/lib/components/CommentsSection.svelte @@ -241,311 +241,321 @@ const totalCount = $derived( comments.reduce((n, c) => n + 1 + (c.replies?.length ?? 0), 0) ); + + // ── Collapsed state ─────────────────────────────────────────────────────── + // Hidden by default when there are no comments; expand on user tap. + let expanded = $state(false); + const hasComments = $derived(!loading && comments.length > 0); + // Auto-expand once comments load in + $effect(() => { + if (hasComments) expanded = true; + });
- -
-

+ {#if !expanded && !hasComments && !loading} + +

- - - {#if !loading && comments.length > 0} -
- - -
- {/if} -
- - -
- {#if isLoggedIn} -
-