Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
495f386b4f |
@@ -241,9 +241,9 @@
|
||||
}
|
||||
|
||||
// Keep nextChapter in the store so the layout's onended can navigate.
|
||||
// NOTE: we do NOT clear on unmount here — the store retains the value so
|
||||
// onended (which may fire after {#key} unmounts this component) can still
|
||||
// read it. The value is superseded when the new chapter mounts.
|
||||
// We write null on mount (before deriving the real value) so there is no
|
||||
// stale window where the previous chapter's nextChapter is still set while
|
||||
// this chapter's AudioPlayer hasn't written its own value yet.
|
||||
$effect(() => {
|
||||
audioStore.nextChapter = nextChapter ?? null;
|
||||
});
|
||||
@@ -566,21 +566,27 @@
|
||||
audioStore.errorMsg = '';
|
||||
|
||||
try {
|
||||
// Fast path A: pre-fetch already landed for THIS chapter.
|
||||
// Fast path A: pre-fetch already confirmed audio is in MinIO for THIS chapter.
|
||||
// Re-presign instead of using the cached URL — it may have expired if the
|
||||
// user paused for a while between the prefetch and actually reaching this chapter.
|
||||
if (
|
||||
audioStore.nextStatus === 'prefetched' &&
|
||||
audioStore.nextChapterPrefetched === chapter &&
|
||||
audioStore.nextAudioUrl
|
||||
audioStore.nextChapterPrefetched === chapter
|
||||
) {
|
||||
const url = audioStore.nextAudioUrl;
|
||||
// Consume the pre-fetch — reset so it doesn't carry over
|
||||
// Consume the pre-fetch state first so it doesn't carry over on error.
|
||||
audioStore.resetNextPrefetch();
|
||||
audioStore.audioUrl = url;
|
||||
audioStore.status = 'ready';
|
||||
// Don't restore saved time for auto-next; position is 0
|
||||
// Immediately start pre-generating the chapter after this one.
|
||||
maybeStartPrefetch();
|
||||
return;
|
||||
// Fresh presign — audio is confirmed in MinIO so this is a fast, cheap call.
|
||||
const presigned = await tryPresign(slug, chapter, voice);
|
||||
if (presigned.ready) {
|
||||
audioStore.audioUrl = presigned.url;
|
||||
audioStore.status = 'ready';
|
||||
// Don't restore saved time for auto-next; position is 0.
|
||||
// Immediately start pre-generating the chapter after this one.
|
||||
maybeStartPrefetch();
|
||||
return;
|
||||
}
|
||||
// Presign returned not-ready (race: MinIO object vanished?).
|
||||
// Fall through to the normal slow path below.
|
||||
}
|
||||
|
||||
// Fast path B: audio already in MinIO (presign check).
|
||||
|
||||
@@ -538,16 +538,17 @@
|
||||
<div class="flex items-center justify-between pt-3 pb-4 shrink-0">
|
||||
<!-- Prev chapter — smaller, clearly secondary -->
|
||||
{#if audioStore.chapter > 1 && audioStore.slug}
|
||||
<a
|
||||
href="/books/{audioStore.slug}/chapters/{audioStore.chapter - 1}"
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => playChapter(audioStore.chapter - 1)}
|
||||
class="p-2 rounded-full text-(--color-muted)/60 hover:text-(--color-text) hover:bg-(--color-surface-2) transition-colors"
|
||||
title="Previous chapter"
|
||||
aria-label="Previous chapter"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/>
|
||||
<path d="M6 6h2v12H6zm2 6 8.5 6V6z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</button>
|
||||
{:else}
|
||||
<div class="w-9 h-9"></div>
|
||||
{/if}
|
||||
@@ -601,16 +602,17 @@
|
||||
|
||||
<!-- Next chapter — smaller, clearly secondary -->
|
||||
{#if audioStore.nextChapter !== null && audioStore.slug}
|
||||
<a
|
||||
href="/books/{audioStore.slug}/chapters/{audioStore.nextChapter}"
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => playChapter(audioStore.nextChapter!)}
|
||||
class="p-2 rounded-full text-(--color-muted)/60 hover:text-(--color-text) hover:bg-(--color-surface-2) transition-colors"
|
||||
title="Next chapter"
|
||||
aria-label="Next chapter"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 18l8.5-6L6 6v12zm8.5-6L23 6v12l-8.5-6z"/>
|
||||
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</button>
|
||||
{:else}
|
||||
<div class="w-9 h-9"></div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user