diff --git a/connect/src/context_resolver.rs b/connect/src/context_resolver.rs new file mode 100644 index 00000000..bcc4a8df --- /dev/null +++ b/connect/src/context_resolver.rs @@ -0,0 +1,91 @@ +use crate::state::ConnectState; +use librespot_protocol::player::Context; +use std::{ + fmt::{Display, Formatter}, + hash::{Hash, Hasher}, +}; + +#[derive(Debug, Clone)] +pub(super) struct ResolveContext { + context: Context, + fallback: Option, + autoplay: bool, +} + +impl ResolveContext { + pub fn from_uri(uri: impl Into, fallback: impl Into, autoplay: bool) -> Self { + let fallback_uri = fallback.into(); + Self { + context: Context { + uri: uri.into(), + ..Default::default() + }, + fallback: (!fallback_uri.is_empty()).then_some(fallback_uri), + autoplay, + } + } + + pub fn from_context(context: Context, autoplay: bool) -> Self { + Self { + context, + fallback: None, + autoplay, + } + } + + /// the uri which should be used to resolve the context, might not be the context uri + pub fn resolve_uri(&self) -> Option<&String> { + // it's important to call this always, or at least for every ResolveContext + // otherwise we might not even check if we need to fallback and just use the fallback uri + ConnectState::get_context_uri_from_context(&self.context) + .and_then(|s| (!s.is_empty()).then_some(s)) + .or(self.fallback.as_ref()) + } + + /// the actual context uri + pub fn context_uri(&self) -> &str { + &self.context.uri + } + + pub fn autoplay(&self) -> bool { + self.autoplay + } +} + +impl Display for ResolveContext { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "resolve_uri: <{:?}>, context_uri: <{}>, autoplay: <{}>", + self.resolve_uri(), + self.context.uri, + self.autoplay, + ) + } +} + +impl PartialEq for ResolveContext { + fn eq(&self, other: &Self) -> bool { + let eq_context = self.context_uri() == other.context_uri(); + let eq_resolve = self.resolve_uri() == other.resolve_uri(); + let eq_autoplay = self.autoplay == other.autoplay; + + eq_context && eq_resolve && eq_autoplay + } +} + +impl Eq for ResolveContext {} + +impl Hash for ResolveContext { + fn hash(&self, state: &mut H) { + self.context_uri().hash(state); + self.resolve_uri().hash(state); + self.autoplay.hash(state); + } +} + +impl From for Context { + fn from(value: ResolveContext) -> Self { + value.context + } +} diff --git a/connect/src/lib.rs b/connect/src/lib.rs index 3cfbbca1..11a65186 100644 --- a/connect/src/lib.rs +++ b/connect/src/lib.rs @@ -5,6 +5,7 @@ use librespot_core as core; use librespot_playback as playback; use librespot_protocol as protocol; +mod context_resolver; mod model; pub mod spirc; pub mod state; diff --git a/connect/src/model.rs b/connect/src/model.rs index a7ff6e22..63d48efe 100644 --- a/connect/src/model.rs +++ b/connect/src/model.rs @@ -1,8 +1,4 @@ -use crate::state::ConnectState; use librespot_core::dealer::protocol::SkipTo; -use librespot_protocol::player::Context; -use std::fmt::{Display, Formatter}; -use std::hash::{Hash, Hasher}; #[derive(Debug)] pub struct SpircLoadCommand { @@ -58,88 +54,3 @@ pub(super) enum SpircPlayStatus { preloading_of_next_track_triggered: bool, }, } - -#[derive(Debug, Clone)] -pub(super) struct ResolveContext { - context: Context, - fallback: Option, - autoplay: bool, -} - -impl ResolveContext { - pub fn from_uri(uri: impl Into, fallback: impl Into, autoplay: bool) -> Self { - let fallback_uri = fallback.into(); - Self { - context: Context { - uri: uri.into(), - ..Default::default() - }, - fallback: (!fallback_uri.is_empty()).then_some(fallback_uri), - autoplay, - } - } - - pub fn from_context(context: Context, autoplay: bool) -> Self { - Self { - context, - fallback: None, - autoplay, - } - } - - /// the uri which should be used to resolve the context, might not be the context uri - pub fn resolve_uri(&self) -> Option<&String> { - // it's important to call this always, or at least for every ResolveContext - // otherwise we might not even check if we need to fallback and just use the fallback uri - ConnectState::get_context_uri_from_context(&self.context) - .and_then(|s| (!s.is_empty()).then_some(s)) - .or(self.fallback.as_ref()) - } - - /// the actual context uri - pub fn context_uri(&self) -> &str { - &self.context.uri - } - - pub fn autoplay(&self) -> bool { - self.autoplay - } -} - -impl Display for ResolveContext { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "resolve_uri: <{:?}>, context_uri: <{}>, autoplay: <{}>", - self.resolve_uri(), - self.context.uri, - self.autoplay, - ) - } -} - -impl PartialEq for ResolveContext { - fn eq(&self, other: &Self) -> bool { - let eq_context = self.context_uri() == other.context_uri(); - let eq_resolve = self.resolve_uri() == other.resolve_uri(); - let eq_autoplay = self.autoplay == other.autoplay; - - eq_context && eq_resolve && eq_autoplay - } -} - -impl Eq for ResolveContext {} - -impl Hash for ResolveContext { - fn hash(&self, state: &mut H) { - self.context_uri().hash(state); - self.resolve_uri().hash(state); - self.autoplay.hash(state); - } -} - -impl From for Context { - fn from(value: ResolveContext) -> Self { - value.context - } -} diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index e19d7b2a..a6bc482d 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -1,5 +1,14 @@ pub use crate::model::{PlayingTrack, SpircLoadCommand}; use crate::state::{context::ResetContext, metadata::Metadata}; +use crate::{ + context_resolver::ResolveContext, + model::SpircPlayStatus, + state::{ + context::{ContextType, UpdateContext}, + provider::IsProvider, + {ConnectState, ConnectStateConfig}, + }, +}; use crate::{ core::{ authentication::Credentials, @@ -24,14 +33,6 @@ use crate::{ user_attributes::UserAttributesMutation, }, }; -use crate::{ - model::{ResolveContext, SpircPlayStatus}, - state::{ - context::{ContextType, UpdateContext}, - provider::IsProvider, - {ConnectState, ConnectStateConfig}, - }, -}; use futures_util::StreamExt; use protobuf::MessageField; use std::collections::HashMap;