From de0bb87a7976341d23b34f4d35c2acc6faec17a5 Mon Sep 17 00:00:00 2001 From: RXWatcher <14085001+RXWatcher@users.noreply.github.com> Date: Mon, 25 May 2026 01:39:24 +0200 Subject: [PATCH] feat(audiobooks): hero shows progress + chapter-aware Resume label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Progress bar moves above the Resume / Play-from-Start row. Caption becomes \"Xh Ym listened · NN%\" (was just the listened time). Resume button now reads \"Resume · \" derived from findChapterAt so the user sees where they'll land without opening the player. No progress → no bar, no chapter; the Play button keeps its existing label. Co-Authored-By: Claude Opus 4.7 (1M context) --- web/src/pages/audiobooks/AudiobookDetail.tsx | 46 ++++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/web/src/pages/audiobooks/AudiobookDetail.tsx b/web/src/pages/audiobooks/AudiobookDetail.tsx index 96ea1047..5373fc79 100644 --- a/web/src/pages/audiobooks/AudiobookDetail.tsx +++ b/web/src/pages/audiobooks/AudiobookDetail.tsx @@ -31,6 +31,18 @@ function totalDuration(files: AudiobookFile[]): number { return files.reduce((acc, f) => acc + (f.duration_seconds ?? 0), 0); } +function findChapterAt( + chapters: ReturnType, + seconds: number, +): { label: string; index: number } | null { + for (let i = chapters.length - 1; i >= 0; i--) { + if (seconds >= chapters[i].absoluteStart) { + return { label: chapters[i].label, index: i + 1 }; + } + } + return chapters[0] ? { label: chapters[0].label, index: 1 } : null; +} + /** Gather all chapters across files, adjusting start/end by each file's cumulative offset. */ function buildChapterList(files: AudiobookFile[]): Array<{ chapter: AudiobookChapter; @@ -233,20 +245,9 @@ export default function AudiobookDetail() { genres={data.audiobook.genres} actions={ files.length > 0 && ( -
-
- - {hasProgress && ( - - )} -
+
{hasProgress && durationTotal > 0 && ( -
+

- {formatSeconds(resumeSeconds)} listened + {formatSeconds(resumeSeconds)} listened ·{" "} + {Math.round((resumeSeconds / durationTotal) * 100)}%

)} +
+ + {hasProgress && ( + + )} +
) }