feat(library): exclude chosen folders from music browsing
Replaces `src/lib/utils/podcastFilter.ts` — a shipped personal workaround that dropped any item whose name, album, album artist or artist was literally "Podcasts" — with a real user setting applied in Rust. The old filter was wrong twice over: it hardcoded one user's folder layout keyed on an English literal, and it put a domain rule (what a query should return) in the presentation layer. It slipped past `check:boundary` only because it matched on names rather than on an item-type array. - `repository::exclusions` owns the rule and the process-wide id set, the same shape as `online::STREAMING_QUALITY` so it survives a repository being rebuilt on re-login. - `HybridRepository` applies it where the cache and server legs of every cache-first query converge (`parallel_race` / `race_with_refresh`), plus the bespoke `get_items` path and the server-only reads. Filtering before the "has content" check is what makes a cache page of nothing but hidden items fall through to the server. - Exclusion is by stable item id, never by name, and matches an item's own id or any container link it carries (parent, album, library, series, season, artist). - A direct `get_item` lookup and the Downloads surface are deliberately unfiltered: hiding those would break playback and file management of anything inside a hidden folder. - `LibrarySettings` persists to `app_settings` and is restored in the setup hook, alongside the streaming-quality cap. Default is an empty list — nobody inherits the old "Podcasts" behaviour. - New commands `library_get_settings`, `library_set_settings` and `library_get_exclusion_candidates`; the candidates read goes through `get_items_unfiltered` so an already-hidden folder still appears in the picker and the setting can be undone. - Settings page gains a "Hidden Folders" section that renders the backend's candidate list and sends back ticked ids; it decides nothing. TRACES: UR-076 | DR-209 | UT-203
This commit is contained in:
+9
-14
@@ -4,7 +4,6 @@
|
||||
import { writable, derived } from "svelte/store";
|
||||
import type { MediaItem, Genre } from "$lib/api/types";
|
||||
import { auth } from "./auth";
|
||||
import { excludePodcasts } from "$lib/utils/podcastFilter";
|
||||
import { selectDiverseGenres, sampleAcross } from "$lib/utils/genreDiversity";
|
||||
import { buildHeroMix } from "$lib/utils/heroMix";
|
||||
|
||||
@@ -97,23 +96,20 @@ function createMusicStore() {
|
||||
.catch(() => [] as MediaItem[]),
|
||||
]);
|
||||
|
||||
// HACK: drop the "Podcasts" folder that lives inside the music library.
|
||||
const recentlyPlayedAlbums = excludePodcasts(recentlyPlayed);
|
||||
const newlyAddedAlbums = excludePodcasts(newlyAdded.items);
|
||||
const playlistItems = excludePodcasts(playlistsResult.items);
|
||||
const rediscoverAlbums = excludePodcasts(rediscover);
|
||||
const surpriseAlbums = excludePodcasts(surprise);
|
||||
// Nothing is filtered here: folders the user chose to hide are already
|
||||
// gone, dropped by the repository layer that answered these queries.
|
||||
// TRACES: UR-076 | DR-209
|
||||
|
||||
// Mix the hero: fresh-in-your-ears first, then "remember this?", then
|
||||
// random albums from across the library.
|
||||
const heroItems = buildHeroMix([recentlyPlayedAlbums, rediscoverAlbums, surpriseAlbums], hasArt);
|
||||
const heroItems = buildHeroMix([recentlyPlayed, rediscover, surprise], hasArt);
|
||||
|
||||
update(s => ({
|
||||
...s,
|
||||
recentlyPlayed: recentlyPlayedAlbums,
|
||||
newlyAdded: newlyAddedAlbums,
|
||||
playlists: playlistItems,
|
||||
rediscover: rediscoverAlbums,
|
||||
recentlyPlayed,
|
||||
newlyAdded: newlyAdded.items,
|
||||
playlists: playlistsResult.items,
|
||||
rediscover,
|
||||
heroItems,
|
||||
isLoading: false,
|
||||
}));
|
||||
@@ -140,8 +136,7 @@ function createMusicStore() {
|
||||
recursive: true,
|
||||
limit: SECTION_LIMIT,
|
||||
});
|
||||
// HACK: drop the "Podcasts" folder that lives in the music library.
|
||||
return { id: genre.id, name: genre.name, items: excludePodcasts(result.items) };
|
||||
return { id: genre.id, name: genre.name, items: result.items };
|
||||
} catch (e) {
|
||||
console.warn(`Failed to load genre row "${genre.name}":`, e);
|
||||
return { id: genre.id, name: genre.name, items: [] };
|
||||
|
||||
Reference in New Issue
Block a user