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:
@@ -19,7 +19,6 @@
|
||||
import LibraryGrid from "./LibraryGrid.svelte";
|
||||
import TrackList from "./TrackList.svelte";
|
||||
import AlphabetScrollBar from "./AlphabetScrollBar.svelte";
|
||||
import { excludePodcasts } from "$lib/utils/podcastFilter";
|
||||
|
||||
/**
|
||||
* Generic media list page supporting Albums, Artists, Playlists, and Tracks
|
||||
@@ -84,7 +83,7 @@
|
||||
unlistenSearch = await listen<SearchUpdateEvent>("search-event", (event) => {
|
||||
const { requestId, result } = event.payload;
|
||||
if (requestId !== searchRequestId) return;
|
||||
items = excludePodcasts(result.items);
|
||||
items = result.items;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -118,8 +117,9 @@
|
||||
if (items.length === 0) loading = true;
|
||||
const repo = auth.getRepository();
|
||||
|
||||
// Use backend search if search query is provided, otherwise use getItems with sort
|
||||
// HACK: excludePodcasts drops the "Podcasts" folder stored in the music library.
|
||||
// Use backend search if search query is provided, otherwise use getItems
|
||||
// with sort. Neither result is filtered here: folders the user chose to
|
||||
// hide are dropped by the repository layer. TRACES: UR-076 | DR-209
|
||||
if (debouncedSearchQuery.trim()) {
|
||||
// Phase 1: instant cache-only (downloaded) results. The merged
|
||||
// cache+server union arrives later via the `search-event` listener,
|
||||
@@ -136,7 +136,7 @@
|
||||
);
|
||||
// Only apply if this is still the active query.
|
||||
if (requestId === searchRequestId) {
|
||||
items = excludePodcasts(result.items);
|
||||
items = result.items;
|
||||
}
|
||||
} else {
|
||||
// Leaving search — invalidate any in-flight server results.
|
||||
@@ -151,7 +151,7 @@
|
||||
// resolves to online vs offline. TRACES: UR-067 | DR-116
|
||||
favoritesOnly: favoritesOnly ? true : undefined,
|
||||
});
|
||||
items = excludePodcasts(result.items);
|
||||
items = result.items;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to load ${config.itemType}:`, e);
|
||||
|
||||
Reference in New Issue
Block a user