feat(podcasts): reverse order — position DESC, date-agnostic; single order helper
The 'Oldest first' order sorts by PUB DATE, which breaks on Scribl's migrated podiobooks feeds (messy/all-equal dates). New order value 'reverse' = feed position DESC with a date-DESC tiebreak — dates are not involved, so nothing can break. - services.OrderEpisodes: THE single order source of truth (§0 items 3+5a). The four surfaces (sequence JSON, reader chain context, SSR page list) previously carried three near-identical handwritten comparators — all now route through one generic helper. The SSR page list gains a SortDate key (lexical 2006-01-02) so the pub-date tiebreak is actually chronological; the old comparator compared 'Jan 2, 2006' display strings alphabetically (latent drift bug). - Dropdown becomes four options: Feed order / Feed order (reversed) / Oldest first (pub date) / Newest first (pub date). - Serial suggestion button renamed 'Reverse feed order' (sets reverse, not oldest) and its response out-of-band-swaps the order select (PodcastOrderSelectOOB — same mechanism as Download All's policy select), so the dropdown mirrors the server state immediately. - Validation: oneof=native reverse oldest newest everywhere. - Tests: reverse binds via the form wire; messy-dates sequence returns 3,2,1; existing reorder-safety stays green.
This commit is contained in:
1 parent
7c7c08748e
commit
e3675536aa
9 files changed
+708
-463
No files matched your search
@@ -116,21 +116,24 @@ templ PodcastDetailPage(user User, data PodcastDetailData) {
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<option value="native" selected={ data.Order == "native" }>Feed order</option>
|
||||
<option value="oldest" selected={ data.Order == "oldest" }>Oldest first</option>
|
||||
<option value="newest" selected={ data.Order == "newest" }>Newest first</option>
|
||||
<option value="reverse" selected={ data.Order == "reverse" }>Feed order (reversed)</option>
|
||||
<option value="oldest" selected={ data.Order == "oldest" }>Oldest first (pub date)</option>
|
||||
<option value="newest" selected={ data.Order == "newest" }>Newest first (pub date)</option>
|
||||
</select>
|
||||
|
||||
<!-- Serial suggestion (D5): one-click, never silent -->
|
||||
<!-- Serial suggestion (D5, §0 item 3 rename): one-click,
|
||||
never silent. "reverse" sorts by FEED POSITION DESC —
|
||||
no pub dates involved, so messy dates can't break it. -->
|
||||
if data.IsSerial && data.Order == "native" {
|
||||
<button
|
||||
class="btn btn-secondary text-sm"
|
||||
hx-put={ "/api/podcasts/feeds/" + data.Feed.ID + "/order" }
|
||||
hx-vals='{"order": "oldest"}'
|
||||
hx-vals='{"order": "reverse"}'
|
||||
hx-target="#episode-list"
|
||||
hx-swap="outerHTML"
|
||||
title="Serial feed: publishers list newest first — listen oldest-first"
|
||||
title="Serial feed: publishers list newest first — reverse the feed order to start at chapter 1"
|
||||
>
|
||||
<span>Serial? Listen oldest-first</span>
|
||||
<span>Reverse feed order</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -382,6 +385,27 @@ templ PodcastAutoDownloadSelect(feed PodcastFeedCard) {
|
||||
</select>
|
||||
}
|
||||
|
||||
// PodcastOrderSelectOOB is the out-of-band variant of the order
|
||||
// dropdown: same element id + hx-swap-oob so htmx replaces the
|
||||
// action-row select in place (§0 item 3 — the "Reverse feed order"
|
||||
// button flips the order server-side; the dropdown must show it).
|
||||
templ PodcastOrderSelectOOB(feedID string, order string) {
|
||||
<select
|
||||
id="podcast-order-select"
|
||||
name="order"
|
||||
hx-swap-oob="true"
|
||||
class="input w-auto py-1.5 cursor-pointer"
|
||||
hx-put={ "/api/podcasts/feeds/" + feedID + "/order" }
|
||||
hx-target="#episode-list"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<option value="native" selected={ order == "native" }>Feed order</option>
|
||||
<option value="reverse" selected={ order == "reverse" }>Feed order (reversed)</option>
|
||||
<option value="oldest" selected={ order == "oldest" }>Oldest first (pub date)</option>
|
||||
<option value="newest" selected={ order == "newest" }>Newest first (pub date)</option>
|
||||
</select>
|
||||
}
|
||||
|
||||
// PodcastAutoDownloadSelectOOB is the out-of-band variant: same element
|
||||
// id + hx-swap-oob so htmx replaces the action-row select in place.
|
||||
templ PodcastAutoDownloadSelectOOB(feed PodcastFeedCard) {
|
||||
|
||||
+424
-313
File diff suppressed because it is too large.
Load diff
@@ -86,6 +86,7 @@ type PodcastEpisodeRow struct {
|
||||
Title string
|
||||
Description string
|
||||
Date string // display-formatted (user tz)
|
||||
SortDate string // lexical-comparable pub-date key (2006-01-02) for ordering
|
||||
Position int
|
||||
Duration string // human ("58:02" / "1:02:10")
|
||||
Size string // human MB/GB when known
|
||||
|
||||
Reference in new issue
Block a user