fix(playback): persist streaming quality setting

Quality was hardcoded to UltraHiRes in backend. Now:
- Frontend passes quality from localStorage to play_track command
- Backend parses quality string to Quality enum
- All prefetch and stream URL calls use the user's preferred quality
This commit is contained in:
vicrodh committed 2026-01-28 11:24:11 -06:00
1 parent 700dc07014
commit a6fc264903
3 files changed
+54 -8

No files matched your search

+27 -6
View File
@@ -13,16 +13,29 @@ use crate::player::PlaybackState;
use crate::queue::QueueManager;
use crate::AppState;
/// Convert quality string from frontend to Quality enum
fn parse_quality(quality_str: Option<&str>) -> Quality {
match quality_str {
Some("MP3") => Quality::Mp3,
Some("CD Quality") => Quality::Lossless,
Some("Hi-Res") => Quality::HiRes,
Some("Hi-Res+") => Quality::UltraHiRes,
_ => Quality::UltraHiRes, // Default to highest
}
}
/// Play a track by ID (with caching support)
#[tauri::command]
pub async fn play_track(
track_id: u64,
duration_secs: Option<u64>,
quality: Option<String>,
state: State<'_, AppState>,
offline_cache: State<'_, OfflineCacheState>,
audio_settings: State<'_, AudioSettingsState>,
) -> Result<(), String> {
log::info!("Command: play_track {} (duration: {:?}s)", track_id, duration_secs);
let preferred_quality = parse_quality(quality.as_deref());
log::info!("Command: play_track {} (duration: {:?}s, quality: {:?})", track_id, duration_secs, preferred_quality);
// First check offline cache (persistent disk cache)
{
@@ -47,6 +60,7 @@ pub async fn play_track(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
preferred_quality,
);
return Ok(());
@@ -66,6 +80,7 @@ pub async fn play_track(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
preferred_quality,
);
return Ok(());
@@ -86,6 +101,7 @@ pub async fn play_track(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
preferred_quality,
);
return Ok(());
@@ -109,9 +125,9 @@ pub async fn play_track(
let client = state.client.lock().await;
// Get the stream URL with highest quality available
// Get the stream URL with preferred quality
let stream_url = client
.get_stream_url_with_fallback(track_id, Quality::UltraHiRes)
.get_stream_url_with_fallback(track_id, preferred_quality)
.await
.map_err(|e| format!("Failed to get stream URL: {}", e))?;
@@ -162,6 +178,7 @@ pub async fn play_track(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
preferred_quality,
);
return Ok(());
@@ -190,6 +207,7 @@ pub async fn play_track(
state.client.clone(),
state.audio_cache.clone(),
&state.queue,
preferred_quality,
);
Ok(())
@@ -199,10 +217,12 @@ pub async fn play_track(
#[tauri::command]
pub async fn prefetch_track(
track_id: u64,
quality: Option<String>,
state: State<'_, AppState>,
offline_cache: State<'_, OfflineCacheState>,
) -> Result<(), String> {
log::info!("Command: prefetch_track {}", track_id);
let preferred_quality = parse_quality(quality.as_deref());
log::info!("Command: prefetch_track {} (quality: {:?})", track_id, preferred_quality);
let cache = state.audio_cache.clone();
@@ -236,7 +256,7 @@ pub async fn prefetch_track(
let client = state.client.lock().await;
let stream_url = client
.get_stream_url_with_fallback(track_id, Quality::UltraHiRes)
.get_stream_url_with_fallback(track_id, preferred_quality)
.await
.map_err(|e| format!("Failed to get stream URL: {}", e))?;
drop(client);
@@ -578,6 +598,7 @@ fn spawn_prefetch(
client: Arc<Mutex<QobuzClient>>,
cache: Arc<AudioCache>,
queue: &QueueManager,
quality: Quality,
) {
// Look further ahead to find Qobuz tracks in mixed playlists
let upcoming_tracks = queue.peek_upcoming(PREFETCH_LOOKAHEAD);
@@ -631,7 +652,7 @@ fn spawn_prefetch(
let result = async {
let client_guard = client_clone.lock().await;
let stream_url = client_guard
.get_stream_url_with_fallback(track_id, Quality::UltraHiRes)
.get_stream_url_with_fallback(track_id, quality)
.await
.map_err(|e| format!("Failed to get stream URL: {}", e))?;
drop(client_guard);
+14 -1
View File
@@ -10,6 +10,15 @@
*/
import { invoke } from '@tauri-apps/api/core';
/**
* Get the preferred streaming quality from localStorage
* Returns: 'MP3', 'CD Quality', 'Hi-Res', or 'Hi-Res+' (default)
*/
function getStreamingQuality(): string {
if (typeof localStorage === 'undefined') return 'Hi-Res+';
return localStorage.getItem('qbz-streaming-quality') || 'Hi-Res+';
}
import {
setCurrentTrack,
setIsPlaying,
@@ -114,7 +123,11 @@ export async function playTrack(
if (isLocal) {
await invoke('library_play_track', { trackId: track.id });
} else {
await invoke('play_track', { trackId: track.id, durationSecs: track.duration });
await invoke('play_track', {
trackId: track.id,
durationSecs: track.duration,
quality: getStreamingQuality()
});
}
}
+13 -1
View File
@@ -6,6 +6,14 @@
*/
import { invoke } from '@tauri-apps/api/core';
/**
* Get the preferred streaming quality from localStorage
*/
function getStreamingQuality(): string {
if (typeof localStorage === 'undefined') return 'Hi-Res+';
return localStorage.getItem('qbz-streaming-quality') || 'Hi-Res+';
}
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
import {
isCasting,
@@ -251,7 +259,11 @@ export async function togglePlay(): Promise<void> {
await invoke('library_play_track', { trackId: localTrackId });
} else {
// Qobuz track - use play_track with duration for seekbar
await invoke('play_track', { trackId: currentTrack.id, durationSecs: currentTrack.duration });
await invoke('play_track', {
trackId: currentTrack.id,
durationSecs: currentTrack.duration,
quality: getStreamingQuality()
});
}
// Seek to saved position after a short delay to let audio load