diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d6125b47..e3211ac03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- [connect] Preserve live queue continuation when refreshing the same context, preventing already-traversed tracks from being replayed. - [audio] Fixed integer overflow in throughput calculation - [main] Fixed `--volume-ctrl fixed` not disabling volume control - [core] Fix default permissions on credentials file and warn user if file is world readable diff --git a/connect/src/state/context.rs b/connect/src/state/context.rs index 59130228d..89c56d820 100644 --- a/connect/src/state/context.rs +++ b/connect/src/state/context.rs @@ -235,19 +235,36 @@ impl ConnectState { && matches!(context.uri, Some(ref uri) if uri == self.context_uri()) { if let Some(new_index) = self.find_last_index_in_new_context(&new_context) { - new_context.index.track = match new_index { - Ok(i) => i, - Err(i) => { - self.player_mut().index = MessageField::none(); - i + match new_index { + Ok(i) => { + /* + * A same-context UpdateContext is a refresh of the context, + * not a new playback command. + * + * Keep the live next_tracks queue and the existing context fill + * position. Rebuilding them from the refreshed context can replace + * Spotify's established playback order. + */ + let previous_fill_index = self + .context + .as_ref() + .map(|ctx| ctx.index.track) + .unwrap_or(i); + + debug!( + "same-context refresh mapped playback to index {}; preserving live continuation with fill index {}", + i, previous_fill_index + ); + + new_context.index.track = previous_fill_index; + } + Err(fallback_index) => { + warn!( + "ignoring ambiguous same-context refresh instead of replacing playback continuation with fallback index {fallback_index}" + ); + return Ok(None); } - }; - - // enforce reloading the context - if let Ok(autoplay_ctx) = self.get_context_mut(ContextType::Autoplay) { - autoplay_ctx.index.track = 0 } - self.clear_next_tracks(); } }