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:
2026-08-23 18:38:24 +02:00
parent 2ff07bfa49
commit 231ffae626
15 changed files with 285 additions and 16 deletions
+9 -2
View File
@@ -72,7 +72,7 @@ pub fn kind_from_jellyfin(item_type: &str, is_folder: bool) -> MediaKind {
// channel leaf (distinct kind so the UI can route it to playback).
"ChannelFolderItem" => {
if is_folder {
MediaKind::Folder
MediaKind::ChannelFolder
} else {
MediaKind::ChannelItem
}
@@ -142,11 +142,18 @@ mod tests {
assert_eq!(kind_from_jellyfin("BoxSet", true), MediaKind::Folder);
}
/// A channel container is not an ordinary folder. Jellyfin gives both the
/// same item type, but only the channel one holds plugin content whose
/// natural order is by release date — a podcast, for instance. Collapsing
/// it into `Folder` left the repository with no way to tell the two apart,
/// so every podcast listed alphabetically.
///
/// TRACES: UR-007 | DR-257 | UT-230
#[test]
fn channel_folder_item_disambiguates_on_is_folder() {
assert_eq!(
kind_from_jellyfin("ChannelFolderItem", true),
MediaKind::Folder
MediaKind::ChannelFolder
);
assert_eq!(
kind_from_jellyfin("ChannelFolderItem", false),