fix(offline): Downloaded browse groups by container and loads on large libraries

Two bugs on the Downloaded browse surface (UR-055/UR-056):

1. Grouping — browsing a downloaded *library* listed individual leaves
   (songs, episodes) instead of their containers. The library-level match in
   `get_downloaded_items` selected every downloaded item on the server; add a
   NOT EXISTS clause so the top level shows only albums/series/movies, with
   leaves still reachable by drilling in. Regression tests for music + TV.

2. "Loading your downloads…" hung on large libraries. The disk-usage
   partiality query did an OR-based self-join over the entire synced catalog
   (O(items^2), unindexable). Narrow it to downloaded containers first via a
   CTE, and add the missing idx_items_season index (migration 020 + base
   schema) — parent_id/album_id/series_id were already indexed.

Also annotate the existing backend tests that cover the IT-016/IT-017
end-to-end offline-listing scenarios with their trace IDs.
This commit is contained in:
2026-07-24 21:42:12 +02:00
parent 6391720d23
commit 57b24f8c74
3 changed files with 172 additions and 8 deletions
+14
View File
@@ -24,6 +24,7 @@ pub const MIGRATIONS: &[(&str, &str)] = &[
("017_downloads_resume_url", MIGRATION_017),
("018_items_is_folder", MIGRATION_018),
("019_genres_cache", MIGRATION_019),
("020_items_season_index", MIGRATION_020),
];
/// Initial schema migration
@@ -281,6 +282,7 @@ CREATE INDEX IF NOT EXISTS idx_items_parent ON items(parent_id);
CREATE INDEX IF NOT EXISTS idx_items_type ON items(item_type);
CREATE INDEX IF NOT EXISTS idx_items_album ON items(album_id);
CREATE INDEX IF NOT EXISTS idx_items_series ON items(series_id);
CREATE INDEX IF NOT EXISTS idx_items_season ON items(season_id);
CREATE INDEX IF NOT EXISTS idx_user_data_user ON user_data(user_id);
CREATE INDEX IF NOT EXISTS idx_user_data_item ON user_data(item_id);
CREATE INDEX IF NOT EXISTS idx_downloads_status ON downloads(status);
@@ -714,3 +716,15 @@ CREATE TABLE IF NOT EXISTS genres (
CREATE INDEX IF NOT EXISTS idx_genres_scope ON genres(server_id, library_id);
"#;
/// Migration to index `items.season_id`.
///
/// Episodes link to their season via `season_id` (parent_id is NULL in the
/// cache). The container-rollup queries used by the Downloaded browse and the
/// disk-usage aggregation join `children.season_id = c.id`, which without this
/// index degrades to an unindexable scan — a large synced catalog then makes
/// the Downloaded page hang ("Loading your downloads…"). `parent_id`,
/// `album_id`, and `series_id` were already indexed; this closes the gap.
const MIGRATION_020: &str = r#"
CREATE INDEX IF NOT EXISTS idx_items_season ON items(season_id);
"#;