Commit Graph
8 Commits
Author SHA1 Message Date
vicrodh 1503b8236f feat(core): read the Windows memory figures from GlobalMemoryStatusEx
detect_profile fell back to MemoryProfile::from_total_kb(u64::MAX) -- the top
tier -- on any machine without /proc/meminfo, and read_memory_pressure
returned None forever. The prefetch and buffer tiers were therefore pinned at
the top on Windows and the memory watchdog was blind: it continues on None, so
evict_l1_audio_cache and the prefetch halt could never fire at any pressure.

Both halves had to land together. With the old u64::MAX total, a working
pressure probe would have computed roughly 0 per cent available and reported
critical permanently.

ullAvailPhys is the analogue of MemAvailable: what an allocation can take
without going to disk. The Normal-fallback contract is preserved, so a probe
that fails still never throttles the machine. windows-sys 0.61 is already in
the workspace lock via qbz-local-catalog and qbzd, so nothing new is pulled.

Measured on a 32 GB box: 57.9 per cent available, class Normal, which is the
same class the old fallback produced -- the change is the true total and a
pressure figure that exists at all.

cc
2026-08-27 12:44:20 -06:00
vicrodh 9cc44f5d1d feat(reco): wire generate_playlist_suggestions into qbz-core (T6)
Add QbzCore::generate_playlist_suggestions + a per-user artist_vectors store
field (Arc<tokio::Mutex<Option<ArtistVectorStore>>>) with async
set_artist_vectors / clear_artist_vectors. It resolves each playlist artist NAME
to a confident MusicBrainz id (reusing musicbrainz_resolve_artist; the names come
from the playlist's own Qobuz tracks so they're already canonical, making the
Tauri command's extra Qobuz-name re-fetch unnecessary), then runs the
SuggestionsEngine over the core-owned clients + vector store.

Also aligns the qbz-reco builder/engine handle types to qbz-core's reality (the
plan's by-ref pattern doesn't fit): mb_client = Arc<MusicBrainzClient> (no lock,
Send+Sync); mb_cache = Arc<std::sync::Mutex<...>> (locked only in await-free
windows); Qobuz client = Arc<RwLock<Option<QobuzClient>>> (unwrapped per access).
The vector store stays tokio::Mutex (held across awaits by the engine). No
dependency cycle (qbz-reco does not depend on qbz-core). qbz-core checks clean;
23 qbz-reco tests green.

cc
2026-06-26 20:58:37 -06:00
vicrodh d0a4a3299b feat(core): shared offline-tier resolver (Slice 1 foundation)
Adds qbz_core::offline_resolve::resolve_offline_bytes — the OFFLINE tier of
the playback tier-walk, frontend-agnostic and player-untouched (the user's
locked Slice-1 decision): resolve a track's offline-cached bytes by Qobuz id
(v2 CMAF decrypt via the secret vault, optionally emitting UnlockStart/End
through a sink; v1 plain-FLAC read; None on miss).

qbz-core now depends on qbz-offline-cache (aligns with the long-intended
`offline` feature seam). Both frontends will slot this in before the network
tier: Tauri keeps its hardware/quality gate around the returned bytes; Slint
calls it before Player::play_track. Player's L1/L2 + network path is unchanged.

Next: QbzCore compose methods (play_track_resolved / gapless), wire Slint's
session to construct + own an OfflineCacheState, route the Slint play path
through the resolver, and point Tauri's offline branch at it.

cc
2026-05-27 20:53:26 -06:00
vicrodh 4a9cbdeb90 feat(qbz-radio): agnostic smart-radio pool builder crate
Ports the Tauri radio_engine into a standalone, frontend-agnostic
crate so any client (Slint, TUI, CLI) can build and play a smart
radio without Tauri.

  - New crate qbz-radio (builder + db + engine + tests), copied
    verbatim from src-tauri/radio_engine with the only change being
    the dependency rewrite: crate::api::{QobuzClient, Track,
    TracksContainer} -> qbz_qobuz::QobuzClient + qbz_models. Depends
    only on qbz-qobuz + qbz-models + rusqlite + dirs. All four engine
    tests pass.
  - QbzCore::create_smart_artist_radio builds the session pool + pulls
    up to 50 track ids + resolves them to full tracks. The radio DB's
    rusqlite Connection is !Send, so the build + pull run on
    spawn_blocking threads (the async builder driven via block_on),
    mirroring the Tauri command.
  - The artist "radio" action (Spotlight RADIO card + artist radio)
    now uses the smart builder (playback::play_smart_artist_radio);
    album radio (Radio Stations) keeps the Qobuz /radio/album
    endpoint, so both radio systems are in use. play_artist_radio
    (Qobuz /radio/artist) is retained as the simpler alternative.

cc
2026-05-21 07:49:01 -06:00
vicrodh 4430d7fb2f feat(core): add MusicBrainz orchestration methods to QbzCore
Adds qbz-integrations as a dependency of qbz-core and embeds a
MusicBrainzClient on the QbzCore struct (initialized in new()). The
client's own enabled flag governs whether requests fire; calls return
the integration-layer ServiceUnavailable error when disabled.

New methods on QbzCore<A>:

  musicbrainz_is_enabled()
  musicbrainz_set_enabled(enabled)
  musicbrainz_resolve_artist(name) -> Option<ResolvedArtist>
  musicbrainz_get_artist_metadata(mbid) -> ArtistMetadata
  musicbrainz_get_artist_relationships(mbid) -> ArtistRelationships

The metadata method calls location::extract_metadata on the full artist
response and then resolves the real country from the begin_area
hierarchy when a city-level location was found (MB's "country" field is
where the artist is currently active, not where they were born/formed).
The relationships method splits relations into members / past_members /
groups / collaborators by relation_type and direction, mirroring
v2_musicbrainz_get_artist_relationships exactly.

No cache wiring yet — every call hits the network. A cache wrapper can
be plugged in later via a setter without changing the method
signatures.

cc
2026-05-20 08:57:50 -06:00
vicrodh 9365eb450d feat(core): add QbzCore::search_all with parameterized blacklist
search_all wraps catalog_search, parses the four category pages and the
most_popular hero, and drops blacklisted artists. The blacklist is a
parameter (BlacklistFilter) so Search does not depend on the un-migrated
artist_blacklist module.

cc
2026-05-19 11:03:42 -06:00
vicrodh 7a133e2915 Add V2 favorites commands using QbzCore
- Add get_favorites, add_favorite, remove_favorite to QbzCore
- Add favorites methods to CoreBridge
- Add v2_get_favorites, v2_add_favorite, v2_remove_favorite commands
- Migrate favoritesStore, artistFavoritesStore, albumFavoritesStore
- Migrate ArtistDetailView favorites toggle

Favorites operations now flow through V2 architecture.
2026-02-15 00:10:09 -06:00
vicrodh 0911cf75df refactor(backend): Phase 0 - Initialize multi-crate workspace
Create the foundational workspace structure for the multi-crate
architecture refactor. This phase establishes placeholder crates
that will be populated in subsequent phases.

Crates created:
- qbz-models: Shared types, events, and traits (Tier 0)
- qbz-audio: Audio backend system (Tier 1)
- qbz-player: Playback engine and queue (Tier 1)
- qbz-qobuz: Qobuz API client (Tier 1)
- qbz-core: Orchestrator (Tier 3)

All crates compile successfully with placeholder implementations.
The workspace uses shared dependencies via workspace.dependencies.

cc
2026-02-14 12:48:52 -06:00