Skip to content

Commit

Permalink
adjust code to protobuf changes
Browse files Browse the repository at this point in the history
  • Loading branch information
photovoltex committed Dec 16, 2024
1 parent 0ca5875 commit ff4545d
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 160 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
on Android platform.
- [core] Fix "Invalid Credentials" when using a Keymaster access token and
client ID on Android platform.
= [connect] Fix "play" command not handled if missing "offset" property
- [connect] Fix "play" command not handled if missing "offset" property

### Removed

- [core] Removed `get_canvases` from SpClient (breaking)
- [metadata] Removed `genres` from Album (breaking)
- [metadata] Removed `genre` from Artists (breaking)

## [0.6.0] - 2024-10-30

This version takes another step into the direction of the HTTP API, fixes a
Expand Down
12 changes: 7 additions & 5 deletions connect/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::state::ConnectState;
use librespot_core::dealer::protocol::SkipTo;
use librespot_protocol::player::Context;
use librespot_protocol::context::Context;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};

Expand Down Expand Up @@ -77,7 +77,7 @@ impl ResolveContext {
let fallback_uri = fallback.into();
Self {
context: Context {
uri: uri.into(),
uri: Some(uri.into()),
..Default::default()
},
fallback: (!fallback_uri.is_empty()).then_some(fallback_uri),
Expand Down Expand Up @@ -114,7 +114,7 @@ impl ResolveContext {

Self {
context: Context {
uri,
uri: Some(uri),
..Default::default()
},
fallback: None,
Expand All @@ -134,7 +134,9 @@ impl ResolveContext {

/// the actual context uri
pub fn context_uri(&self) -> &str {
&self.context.uri
self.context
.uri.as_deref()
.unwrap_or_default()
}

pub fn autoplay(&self) -> bool {
Expand All @@ -150,7 +152,7 @@ impl Display for ResolveContext {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"resolve_uri: <{:?}>, context_uri: <{}>, autoplay: <{}>, update: <{}>",
"resolve_uri: <{:?}>, context_uri: <{:?}>, autoplay: <{}>, update: <{}>",
self.resolve_uri(),
self.context.uri,
self.autoplay,
Expand Down
67 changes: 33 additions & 34 deletions connect/src/spirc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ use crate::{
protocol::{
autoplay_context_request::AutoplayContextRequest,
connect::{Cluster, ClusterUpdate, LogoutCommand, SetVolumeCommand},
context::Context,
explicit_content_pubsub::UserAttributesUpdate,
player::{Context, TransferState},
playlist4_external::PlaylistModificationInfo,
social_connect_v2::{session::_host_active_device_id, SessionUpdate},
social_connect_v2::SessionUpdate,
transfer_state::TransferState,
user_attributes::UserAttributesMutation,
},
};
Expand Down Expand Up @@ -525,14 +526,14 @@ impl SpircTask {
let mut ctx = self.session.spclient().get_context(resolve_uri).await?;

if update {
ctx.uri = context_uri.to_string();
ctx.url = format!("context://{context_uri}");
ctx.uri = Some(context_uri.to_string());
ctx.url = Some(format!("context://{context_uri}"));

self.connect_state
.update_context(ctx, UpdateContext::Default)?
} else if matches!(ctx.pages.first(), Some(p) if !p.tracks.is_empty()) {
debug!(
"update context from single page, context {} had {} pages",
"update context from single page, context {:?} had {} pages",
ctx.uri,
ctx.pages.len()
);
Expand Down Expand Up @@ -883,7 +884,7 @@ impl SpircTask {
let attributes: UserAttributes = update
.pairs
.iter()
.map(|pair| (pair.key().to_owned(), pair.value().to_owned()))
.map(|(key, value)| (key.to_owned(), value.to_owned()))
.collect();
self.session.set_user_attributes(attributes)
}
Expand Down Expand Up @@ -998,9 +999,10 @@ impl SpircTask {
Unknown(unknown) => Err(SpircError::UnknownEndpoint(unknown))?,
// implicit update of the connect_state
UpdateContext(update_context) => {
if &update_context.context.uri != self.connect_state.context_uri() {
if matches!(update_context.context.uri, Some(ref uri) if uri != self.connect_state.context_uri())
{
debug!(
"ignoring context update for <{}>, because it isn't the current context <{}>",
"ignoring context update for <{:?}>, because it isn't the current context <{}>",
update_context.context.uri, self.connect_state.context_uri()
)
} else {
Expand All @@ -1020,24 +1022,26 @@ impl SpircTask {
.options
.player_options_override
.as_ref()
.map(|o| o.shuffling_context)
.map(|o| o.shuffling_context.unwrap_or_default())
.unwrap_or_else(|| self.connect_state.shuffling_context());
let repeat = play
.options
.player_options_override
.as_ref()
.map(|o| o.repeating_context)
.map(|o| o.repeating_context.unwrap_or_default())
.unwrap_or_else(|| self.connect_state.repeat_context());
let repeat_track = play
.options
.player_options_override
.as_ref()
.map(|o| o.repeating_track)
.map(|o| o.repeating_track.unwrap_or_default())
.unwrap_or_else(|| self.connect_state.repeat_track());

let context_uri = play.context.uri.as_ref().ok_or(SpircError::NoData)?.clone();

self.handle_load(
SpircLoadCommand {
context_uri: play.context.uri.clone(),
context_uri,
start_playing: true,
seek_to: play.options.seek_to.unwrap_or_default(),
playing_track: play.options.skip_to.unwrap_or_default().into(),
Expand Down Expand Up @@ -1088,12 +1092,13 @@ impl SpircTask {
}

fn handle_transfer(&mut self, mut transfer: TransferState) -> Result<(), Error> {
self.connect_state
.reset_context(ResetContext::WhenDifferent(
&transfer.current_session.context.uri,
));
let mut ctx_uri = match transfer.current_session.context.uri {
None => Err(SpircError::NoData)?,
Some(ref uri) => uri.clone(),
};

let mut ctx_uri = transfer.current_session.context.uri.clone();
self.connect_state
.reset_context(ResetContext::WhenDifferent(&ctx_uri));

match self.connect_state.current_track_from_transfer(&transfer) {
Err(why) => warn!("didn't find initial track: {why}"),
Expand All @@ -1118,17 +1123,18 @@ impl SpircTask {
state.set_active(true);
state.handle_initial_transfer(&mut transfer);

// update position if the track continued playing
let position = if transfer.playback.is_paused {
transfer.playback.position_as_of_timestamp.into()
} else if transfer.playback.position_as_of_timestamp > 0 {
let time_since_position_update = timestamp - transfer.playback.timestamp;
i64::from(transfer.playback.position_as_of_timestamp) + time_since_position_update
} else {
0
let transfer_timestamp = transfer.playback.timestamp.unwrap_or_default();
let position = match transfer.playback.position_as_of_timestamp {
Some(position) if transfer.playback.is_paused.unwrap_or_default() => position.into(),
// update position if the track continued playing
Some(position) if position > 0 => {
let time_since_position_update = timestamp - transfer_timestamp;
i64::from(position) + time_since_position_update
}
_ => 0,
};

let is_playing = !transfer.playback.is_paused;
let is_playing = matches!(transfer.playback.is_paused, Some(is_playing) if is_playing);

if self.connect_state.current_track(|t| t.is_autoplay()) || autoplay {
debug!("currently in autoplay context, async resolving autoplay for {ctx_uri}");
Expand Down Expand Up @@ -1537,14 +1543,7 @@ impl SpircTask {
Some(session) => session,
};

let active_device = session._host_active_device_id.take().map(|id| match id {
_host_active_device_id::HostActiveDeviceId(id) => id,
other => {
warn!("unexpected active device id {other:?}");
String::new()
}
});

let active_device = session.host_active_device_id.take();
if matches!(active_device, Some(ref device) if device == self.session.device_id()) {
info!(
"session update: <{:?}> for self, current session_id {}, new session_id {}",
Expand Down
36 changes: 20 additions & 16 deletions connect/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,25 @@ mod tracks;
mod transfer;

use crate::model::SpircPlayStatus;
use crate::state::{
context::{ContextType, ResetContext, StateContext},
provider::{IsProvider, Provider},
};
use librespot_core::{
config::DeviceType, date::Date, dealer::protocol::Request, spclient::SpClientResult, version,
Error, Session,
};
use librespot_protocol::connect::{
Capabilities, Device, DeviceInfo, MemberType, PutStateReason, PutStateRequest,
};
use librespot_protocol::player::{
ContextIndex, ContextPage, ContextPlayerOptions, PlayOrigin, PlayerState, ProvidedTrack,
Suppressions,
use crate::{
core::{
config::DeviceType, date::Date, dealer::protocol::Request, spclient::SpClientResult,
version, Error, Session,
},
protocol::{
connect::{Capabilities, Device, DeviceInfo, MemberType, PutStateReason, PutStateRequest},
context_page::ContextPage,
player::{
ContextIndex, ContextPlayerOptions, PlayOrigin, PlayerState, ProvidedTrack,
Suppressions,
},
},
state::{
context::{ContextType, ResetContext, StateContext},
provider::{IsProvider, Provider},
},
};

use log::LevelFilter;
use protobuf::{EnumOrUnknown, MessageField};
use std::{
Expand Down Expand Up @@ -52,8 +56,8 @@ pub enum StateError {
ContextHasNoTracks,
#[error("playback of local files is not supported")]
UnsupportedLocalPlayBack,
#[error("track uri <{0}> contains invalid characters")]
InvalidTrackUri(String),
#[error("track uri <{0:?}> contains invalid characters")]
InvalidTrackUri(Option<String>),
}

impl From<StateError> for Error {
Expand Down
Loading

0 comments on commit ff4545d

Please sign in to comment.