feat(podcasts): Download All queues in the LISTENING order + add-modal order dropdown

Download All previously queued in feed-native order — 'getting the
last chapter first doesn't help me'. Now the queue follows the feed's
effective listening order (§0 item 5b): QueueFeedDownloadsAs reads the
CALLER's order override and runs episodes through services.OrderEpisodes
(same helper as the sequence/reader/page surfaces — the consolidation
from item 5a landed with the reverse-order commit). Queue tickets
(SEQUENCE-stamped, item 4) make that enqueue order the claim order, so
chapters land in the order you'll actually listen.

Add modal (§0 item 5c): with 'Download all episodes now' checked, a
'Download order' select appears (pure-CSS :checked sibling reveal — no
JS island, CSP-clean). Its choice is the feed's INITIAL order override
(reader_settings upsert; 'feed' = no row) AND the queue order for the
initial batch. Per-book by design: the override IS the download order.

Test TestPodcastAddModalDownloadOrder: add with download_all+reverse →
the override row exists AND persisted tickets run position 3→1. Tickets
are asserted (not live queued rows) because the shared dev server's
worker legitimately races this test's queue — tickets survive every
state flip.
This commit is contained in:
John O'Keefe committed 2026-10-30 10:26:00 -04:00
1 parent 0f3c4a8cec
commit 5c545534c2
7 files changed
+176 -9

No files matched your search

+18 -4
View File
@@ -238,10 +238,24 @@ templ PodcastAddFeedModal(libraries []LibraryData) {
} else if len(libraries) == 1 {
<input type="hidden" name="library_id" value={ libraries[0].ID }/>
}
<label class="flex items-center gap-2 text-sm" style="color: var(--text-secondary)">
<input type="checkbox" name="download_all" value="true" class="cursor-pointer"/>
Download all episodes now
</label>
<div class="flex items-center gap-2 text-sm">
<input type="checkbox" id="podcast-download-all" name="download_all" value="true" class="cursor-pointer"/>
<label for="podcast-download-all" style="color: var(--text-secondary)">Download all episodes now</label>
</div>
<div class="podcast-add-order flex items-center gap-2 text-sm pl-6">
<label for="podcast-download-order" style="color: var(--text-secondary)">Download order</label>
<select
id="podcast-download-order"
name="download_order"
class="input w-auto py-1.5 cursor-pointer"
title="Listen/download order for this feed — chapters land in this order"
>
<option value="feed" selected>Feed order</option>
<option value="reverse">Feed order (reversed)</option>
<option value="oldest">Oldest first (pub date)</option>
<option value="newest">Newest first (pub date)</option>
</select>
</div>
<div id="podcast-add-feed-error" class="text-sm hidden" style="color: var(--status-danger)"></div>
<div class="flex justify-end gap-2">
<button type="button" class="btn btn-secondary" @click="hideAddFeed()">Cancel</button>