fix(player): never skip the gapless target offline + bound the skip cascade (#467)
The offline-skip recursion walked the entire remaining queue synchronously, desyncing the logical queue from the still-playing engine. Fixes: - The gapless-transition target is the track the engine is already playing; never run the availability-skip branch for it. - isTrackAvailable now counts the in-memory/disk cache (new v2_is_track_cached command), not just downloaded copies. - Cap consecutive offline skips and play-failure auto-skips at 5 in both +page.svelte and playbackService.ts. cc
This commit is contained in:
4 files changed
+83
-6
No files matched your search
@@ -73,6 +73,41 @@ fn v2_prefetch_count(quality: qbz_models::Quality) -> usize {
|
||||
throttled_cap
|
||||
}
|
||||
|
||||
/// Lightweight offline-availability check used by the frontend queue guard
|
||||
/// (issue #467). A track counts as available offline if it is in the
|
||||
/// in-memory playback cache (covers the currently-playing, fully-buffered
|
||||
/// track and any prefetched upcoming tracks) OR has a ready file in the
|
||||
/// persistent offline cache. This stops the offline queue walk from skipping
|
||||
/// tracks that are actually playable.
|
||||
#[tauri::command]
|
||||
pub async fn v2_is_track_cached(
|
||||
track_id: u64,
|
||||
offline_cache: State<'_, OfflineCacheState>,
|
||||
app_state: State<'_, AppState>,
|
||||
) -> Result<bool, RuntimeError> {
|
||||
// In-memory playback cache: the currently-playing track and prefetched
|
||||
// upcoming tracks live here.
|
||||
if app_state.audio_cache.contains(track_id) {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// Persistent offline cache: a downloaded track whose file is still on disk.
|
||||
let cached_path = {
|
||||
let db_opt = offline_cache.db.lock().await;
|
||||
match db_opt.as_ref() {
|
||||
Some(db) => db.get_file_path(track_id).ok().flatten(),
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
if let Some(path) = cached_path {
|
||||
if std::path::Path::new(&path).exists() {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// How far ahead to look for tracks to prefetch (to handle mixed playlists
|
||||
/// with local/offline tracks interspersed with Qobuz tracks)
|
||||
const V2_PREFETCH_LOOKAHEAD: usize = 15;
|
||||
|
||||
@@ -1968,6 +1968,7 @@ pub fn run(qconnect_cli_override: Option<bool>) {
|
||||
commands_v2::v2_set_media_metadata,
|
||||
commands_v2::v2_play_next_gapless,
|
||||
commands_v2::v2_prefetch_track,
|
||||
commands_v2::v2_is_track_cached,
|
||||
commands_v2::v2_reinit_audio_device,
|
||||
commands_v2::v2_check_audio_device_presence,
|
||||
commands_v2::v2_get_audio_output_status,
|
||||
|
||||
Reference in new issue
Block a user