connect: adjust finish of context resolving

This commit is contained in:
Felix Prillwitz 2024-12-17 21:02:50 +01:00
parent dfbac73136
commit 0dfced80ba
No known key found for this signature in database
GPG key ID: DE334B43606D1455
2 changed files with 83 additions and 36 deletions

View file

@ -337,29 +337,27 @@ impl ContextResolver {
} }
} }
if let Some(transfer_state) = transfer_state.take() { let active_ctx = state.get_context(state.active_context);
if let Err(why) = state.finish_transfer(transfer_state) { let res = if let Some(transfer_state) = transfer_state.take() {
error!("finishing setup of transfer failed: {why}") state.finish_transfer(transfer_state)
} } else if state.shuffling_context() {
state.shuffle()
} else if matches!(active_ctx, Ok(ctx) if ctx.index.track == 0) {
// has context, and context is not touched
// when the index is not zero, the next index was already evaluated elsewhere
let ctx = active_ctx.expect("checked by precondition");
let idx = ConnectState::find_index_in_context(ctx, |t| {
state.current_track(|c| t.uri == c.uri)
})
.ok();
state.reset_playback_to_position(idx)
} else { } else {
let res = if state.shuffling_context() { state.fill_up_next_tracks()
state.shuffle() };
} else if let Ok(ctx) = state.get_context(state.active_context) {
let idx = ConnectState::find_index_in_context(ctx, |t| {
state.current_track(|c| t.uri == c.uri)
})
.ok();
state if let Err(why) = res {
.reset_playback_to_position(idx) error!("setup of state failed: {why}, last used resolve {next:#?}")
.and_then(|_| state.fill_up_next_tracks())
} else {
state.fill_up_next_tracks()
};
if let Err(why) = res {
error!("setting up state failed after updating contexts: {why}")
}
} }
state.update_restrictions(); state.update_restrictions();

View file

@ -3,7 +3,11 @@ use crate::{
protocol::player::{ protocol::player::{
Context, ContextIndex, ContextPage, ContextTrack, ProvidedTrack, Restrictions, Context, ContextIndex, ContextPage, ContextTrack, ProvidedTrack, Restrictions,
}, },
state::{metadata::Metadata, provider::Provider, ConnectState, StateError}, state::{
metadata::Metadata,
provider::{IsProvider, Provider},
ConnectState, StateError, SPOTIFY_MAX_NEXT_TRACKS_SIZE,
},
}; };
use protobuf::MessageField; use protobuf::MessageField;
use std::collections::HashMap; use std::collections::HashMap;
@ -222,22 +226,21 @@ impl ConnectState {
if !self.context_uri().starts_with(SEARCH_IDENTIFIER) if !self.context_uri().starts_with(SEARCH_IDENTIFIER)
&& self.context_uri() == &context.uri && self.context_uri() == &context.uri
{ {
match Self::find_index_in_context(&new_context, |t| { if let Some(new_index) = self.find_last_index_in_new_context(&new_context) {
self.current_track(|t| &t.uri) == &t.uri new_context.index.track = match new_index {
}) { Ok(i) => i,
Ok(new_pos) => { Err(i) => {
debug!("found new index of current track, updating new_context index to {new_pos}"); self.player_mut().index = MessageField::none();
new_context.index.track = (new_pos + 1) as u32; i
}
};
// enforce reloading the context
if let Some(autoplay_ctx) = self.autoplay_context.as_mut() {
autoplay_ctx.index.track = 0
} }
// the track isn't anymore in the context self.clear_next_tracks();
Err(_) if matches!(self.active_context, ContextType::Default) => {
warn!("current track was removed, setting pos to last known index");
new_context.index.track = self.player().index.track
}
Err(_) => {}
} }
// enforce reloading the context
self.clear_next_tracks();
} }
self.context = Some(new_context); self.context = Some(new_context);
@ -283,6 +286,52 @@ impl ConnectState {
Ok(Some(next_contexts)) Ok(Some(next_contexts))
} }
fn find_first_prev_track_index(&self, ctx: &StateContext) -> Option<usize> {
let prev_tracks = self.prev_tracks();
for i in (0..prev_tracks.len()).rev() {
let prev_track = prev_tracks.get(i)?;
if let Ok(idx) = Self::find_index_in_context(ctx, |t| prev_track.uri == t.uri) {
return Some(idx);
}
}
None
}
fn find_last_index_in_new_context(
&self,
new_context: &StateContext,
) -> Option<Result<u32, u32>> {
let ctx = self.context.as_ref()?;
let is_queued_item = self.current_track(|t| t.is_queue() || t.is_from_queue());
let new_index = if ctx.index.track as usize >= SPOTIFY_MAX_NEXT_TRACKS_SIZE {
Some(ctx.index.track as usize - SPOTIFY_MAX_NEXT_TRACKS_SIZE)
} else if is_queued_item {
self.find_first_prev_track_index(new_context)
} else {
Self::find_index_in_context(new_context, |current| {
self.current_track(|t| t.uri == current.uri)
})
.ok()
}
.map(|i| i as u32 + 1);
Some(new_index.ok_or_else(|| {
info!(
"couldn't distinguish index from current or previous tracks in the updated context"
);
let fallback_index = self
.player()
.index
.as_ref()
.map(|i| i.track)
.unwrap_or_default();
info!("falling back to index {fallback_index}");
fallback_index
}))
}
fn state_context_from_page( fn state_context_from_page(
&mut self, &mut self,
page: ContextPage, page: ContextPage,