fix(library): podcasts list newest episode first
A Jellypod podcast listed its episodes alphabetically. The store pinned SortBy=SortName onto every drill-down, which overrode the order the channel plugin returns — and since Jellypod prefixes played episodes with "[Played]", the name sort also clumped every heard episode at the top. Which order a container's children take is domain knowledge, so it moves to Rust: the caller names the container (GetItemsOptions.parentKind) and default_listing_sort answers with the sort. A channel folder is PremiereDate descending, every other container keeps SortName ascending, and a caller naming no container still gets no SortBy, so the paths that rely on the server's own order keep it. An explicit sort always wins. ChannelFolderItem with is_folder now maps to MediaKind::ChannelFolder instead of collapsing into Folder — while both were Folder there was nothing to key the rule on. The offline leg of the cache/server race applies the same order, so the cached list no longer flashes in name order before the server's arrives. TRACES: UR-007 | DR-257 | UT-229, UT-230, UT-231
This commit is contained in:
@@ -1239,10 +1239,29 @@ impl MediaRepository for OfflineRepository {
|
||||
let start_index = opts.start_index.unwrap_or(0);
|
||||
|
||||
// SortBy=Random is the only sort the landing pages rely on offline (the
|
||||
// hero "surprise" pool); everything else keeps the stable name order.
|
||||
let order_by = match opts.sort_by.as_deref() {
|
||||
Some("Random") => "RANDOM()",
|
||||
_ => "i.sort_name ASC, i.name ASC",
|
||||
// hero "surprise" pool); PremiereDate is what a channel folder's
|
||||
// children are listed by (DR-257), so the cached leg of the race agrees
|
||||
// with the server's order instead of flashing a name-sorted list first.
|
||||
// Everything else keeps the stable name order.
|
||||
//
|
||||
// Rows with no premiere date sort last rather than leading the list.
|
||||
let default_sort = default_listing_sort(opts.parent_kind);
|
||||
let sort_field = opts
|
||||
.sort_by
|
||||
.as_deref()
|
||||
.or(default_sort.map(|(field, _)| field));
|
||||
let descending = opts
|
||||
.sort_order
|
||||
.as_deref()
|
||||
.or(default_sort.map(|(_, order)| order))
|
||||
== Some("Descending");
|
||||
let order_by = match sort_field {
|
||||
Some("Random") => "RANDOM()".to_string(),
|
||||
Some("PremiereDate") => format!(
|
||||
"i.premiere_date IS NULL, i.premiere_date {}, i.sort_name ASC",
|
||||
if descending { "DESC" } else { "ASC" }
|
||||
),
|
||||
_ => "i.sort_name ASC, i.name ASC".to_string(),
|
||||
};
|
||||
|
||||
// Bind the type filter rather than interpolating it: `include_item_types`
|
||||
|
||||
Reference in New Issue
Block a user