feat(local-library): Plex consolidation in chunked albums page query
Plex cache lives in a separate SQLite database
(`<data_dir>/qbz/plex_cache.db`), which is why `v2_library_get_albums_page`
previously only saw local_tracks and the LocalLibraryView chunked
path had to fall back to the legacy virtualizer when Plex was on.
That fallback meant Plex-dominant users (which is the common case)
got none of the chunked-store / recycling-pool perf work.
Now consolidated server-side via SQL `ATTACH DATABASE` + `UNION ALL`:
Backend (qbz-library):
- `get_albums_metadata_page` accepts `plex_cache_path: Option<&Path>`.
When the file exists it `ATTACH`es the plex DB to the connection,
runs a CTE that aggregates `plex_cache.plex_cache_tracks` by
`album_key` into the same column shape as local_aggregated, and
UNIONs both before the filter/sort/pagination step. DETACHes at
the end so subsequent queries don't see stale attachment.
Plex group_key prefixed with `'plex:'` so it doesn't collide with
local group keys; `'plex'` literal in the `source` column drives
the frontend's SourceBadge mapping.
- Schema differences smoothed via `CAST` in the plex arm:
`duration_ms / 1000 → total_duration` (matches local seconds),
`sampling_rate_hz → sample_rate` (INTEGER → REAL).
- `count_albums_metadata_for_page` mirrors the same UNION so total
is consistent across empty-page edge cases.
Backend (Tauri command):
- `v2_library_get_albums_page` accepts an `include_plex` bool.
When true, resolves the plex cache path the same way
`plex/mod.rs::open_plex_cache_db` does and passes it through.
Frontend:
- Chunked store's `LocalAlbumsQueryParams` carries an `includePlex`
flag, included in the `paramsEqual` check so toggling Plex
visibility invalidates the chunk cache.
- LocalLibraryView drops the `!isPlexLibraryEnabled()` guard from
both the `$effect` that calls `setParams` and the render
condition that picks chunked vs legacy. The new path serves
Plex-only, local-only, and mixed libraries the same way.
cc
This commit is contained in:
4 files changed
+155
-16
No files matched your search
@@ -2584,6 +2584,10 @@ pub async fn v2_library_get_albums_metadata(
|
||||
/// recycling-grid pool + chunked store on the frontend: caller asks for
|
||||
/// `[offset, offset+limit)` and receives that page plus the total count
|
||||
/// of albums matching the same filter (drives scrollbar pre-allocation).
|
||||
///
|
||||
/// When `include_plex` is true and the `plex_cache.db` cache file
|
||||
/// exists in the user's data dir, the result is the UNION of local and
|
||||
/// plex sources — sort, filter, and pagination apply to both at once.
|
||||
#[tauri::command]
|
||||
pub async fn v2_library_get_albums_page(
|
||||
offset: u64,
|
||||
@@ -2592,6 +2596,7 @@ pub async fn v2_library_get_albums_page(
|
||||
sort_by: Option<String>,
|
||||
sort_dir: Option<String>,
|
||||
exclude_network_folders: Option<bool>,
|
||||
include_plex: Option<bool>,
|
||||
state: State<'_, LibraryState>,
|
||||
download_settings_state: State<'_, DownloadSettingsState>,
|
||||
) -> Result<qbz_library::AlbumsMetadataPage, String> {
|
||||
@@ -2603,6 +2608,17 @@ pub async fn v2_library_get_albums_page(
|
||||
.map(|s| s.show_in_library)
|
||||
.unwrap_or(false);
|
||||
|
||||
// Resolve the plex_cache.db path the same way `plex/mod.rs`
|
||||
// does (`dirs::data_dir() + qbz/plex_cache.db`). The qbz-library
|
||||
// crate doesn't know about Plex — passing `None` here keeps the
|
||||
// local-only behavior; passing the path lets the SQL ATTACH + UNION
|
||||
// light up.
|
||||
let plex_path: Option<std::path::PathBuf> = if include_plex.unwrap_or(false) {
|
||||
dirs::data_dir().map(|d| d.join("qbz").join("plex_cache.db"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let guard__ = state.db.lock().await;
|
||||
let db = guard__
|
||||
.as_ref()
|
||||
@@ -2616,6 +2632,7 @@ pub async fn v2_library_get_albums_page(
|
||||
sort_dir.as_deref().unwrap_or("asc"),
|
||||
include_qobuz,
|
||||
exclude_network_folders.unwrap_or(false),
|
||||
plex_path.as_deref(),
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user