Add two-level audio cache system (L1: memory, L2: disk)

L1 (Memory): 300MB for ~3-4 Hi-Res tracks, instant access
L2 (Disk): 500MB playback cache at ~/.cache/qbz/playback/

Flow:
- When track evicted from memory, saved to disk cache
- When loading: check memory → disk → download cache → network
- Tracks promoted back to memory when accessed from disk

This reduces re-downloads when navigating back to recently played
tracks in mixed playlists.
This commit is contained in:
vicrodh committed 2026-01-16 08:49:56 -06:00
1 parent 2bdde3d592
commit 73d022ae20
5 files changed
+406 -24

No files matched your search

+23 -2
View File
@@ -53,7 +53,7 @@ pub async fn play_track(
let cache = state.audio_cache.clone();
// Check if track is in memory cache
// Check if track is in memory cache (L1)
if let Some(cached) = cache.get(track_id) {
log::info!("Playing track {} from memory cache ({} bytes)", track_id, cached.size_bytes);
state.player.play_data(cached.data, track_id)?;
@@ -68,8 +68,29 @@ pub async fn play_track(
return Ok(());
}
// Check if track is in playback cache (L2 - disk)
if let Some(playback_cache) = cache.get_playback_cache() {
if let Some(audio_data) = playback_cache.get(track_id) {
log::info!("Playing track {} from playback cache ({} bytes)", track_id, audio_data.len());
// Promote back to memory cache
cache.insert(track_id, audio_data.clone());
state.player.play_data(audio_data, track_id)?;
// Prefetch next track in background
spawn_prefetch(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
);
return Ok(());
}
}
// Not in any cache - download and cache in memory
log::info!("Track {} not in cache, streaming...", track_id);
log::info!("Track {} not in any cache, streaming...", track_id);
let client = state.client.lock().await;