Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions spotify_player/src/cli/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async fn handle_socket_request(
}

match request {
Request::Get(GetRequest::Key(key)) => handle_get_key_request(client, key).await,
Request::Get(GetRequest::Key(key)) => handle_get_key_request(client, state, key).await,
Request::Get(GetRequest::Item(item_type, id_or_name)) => {
handle_get_item_request(client, item_type, id_or_name).await
}
Expand Down Expand Up @@ -145,13 +145,10 @@ async fn handle_socket_request(
}
}

async fn handle_get_key_request(client: &Client, key: Key) -> Result<Vec<u8>> {
async fn handle_get_key_request(client: &Client, state: &SharedState, key: Key) -> Result<Vec<u8>> {
Ok(match key {
Key::Playback => {
let playback = client
.spotify
.current_playback(None, None::<Vec<_>>)
.await?;
let playback = state.player.read().current_playback();
serde_json::to_vec(&playback)?
}
Key::Devices => {
Expand Down Expand Up @@ -357,8 +354,22 @@ async fn handle_playback_request(
}
};

client.handle_player_request(state, player_request).await?;
client.update_playback(state);
tokio::task::spawn({
let client = client.clone();
let state = state.clone();
async move {
match client.handle_player_request(&state, player_request).await {
Ok(()) => {
client.update_playback(&state);
}
Err(err) => {
tracing::warn!(
"Failed to handle a player request for playback CLI command: {err:#}"
);
}
}
}
});
Ok(())
}

Expand Down
31 changes: 31 additions & 0 deletions spotify_player/src/state/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,37 @@ pub struct PlayerState {
}

impl PlayerState {
/// gets the current playback state
///
/// # Note
/// Because playback data stored inside the player state is buffered and cached,
/// this function tries to estimate the current playback based on the available state data.
pub fn current_playback(&self) -> Option<rspotify_model::CurrentPlaybackContext> {
let mut playback = self.playback.clone()?;

// update the playback's progress based on the `playback_last_updated_time`
playback.progress = playback.progress.map(|d| {
d + if playback.is_playing {
chrono::Duration::from_std(self.playback_last_updated_time.unwrap().elapsed())
.unwrap()
} else {
chrono::Duration::zero()
}
});

// update the playback's metadata based on the `buffered_playback` metadata
if let Some(ref p) = self.buffered_playback {
playback.device.name = p.device_name.clone();
playback.device.id = p.device_id.clone();
playback.is_playing = p.is_playing;
playback.device.volume_percent = p.volume;
playback.repeat_state = p.repeat_state;
playback.shuffle_state = p.shuffle_state;
}

Some(playback)
}

/// gets the current playing track
pub fn current_playing_track(&self) -> Option<&rspotify_model::FullTrack> {
match self.playback {
Expand Down