mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-03 09:49:31 +02:00
Re-Add ability to handle/play tracks (#1468)
* re-add support to play a set of tracks * connect: reduce some cloning * connect: derive clone for LoadRequest * apply review, improve function naming * clippy fix
This commit is contained in:
parent
e2c3ac3146
commit
8b729540f4
6 changed files with 213 additions and 85 deletions
|
@ -76,7 +76,9 @@ impl ResolveContext {
|
||||||
// otherwise we might not even check if we need to fallback and just use the fallback uri
|
// otherwise we might not even check if we need to fallback and just use the fallback uri
|
||||||
match self.resolve {
|
match self.resolve {
|
||||||
Resolve::Uri(ref uri) => ConnectState::valid_resolve_uri(uri),
|
Resolve::Uri(ref uri) => ConnectState::valid_resolve_uri(uri),
|
||||||
Resolve::Context(ref ctx) => ConnectState::get_context_uri_from_context(ctx),
|
Resolve::Context(ref ctx) => {
|
||||||
|
ConnectState::find_valid_uri(ctx.uri.as_deref(), ctx.pages.first())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.or(self.fallback.as_deref())
|
.or(self.fallback.as_deref())
|
||||||
}
|
}
|
||||||
|
@ -260,7 +262,7 @@ impl ContextResolver {
|
||||||
ContextAction::Replace => {
|
ContextAction::Replace => {
|
||||||
let remaining = state.update_context(context, next.update);
|
let remaining = state.update_context(context, next.update);
|
||||||
if let Resolve::Context(ref ctx) = next.resolve {
|
if let Resolve::Context(ref ctx) = next.resolve {
|
||||||
state.merge_context(Some(ctx.clone()));
|
state.merge_context(ctx.pages.clone().pop());
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining
|
remaining
|
||||||
|
|
|
@ -5,9 +5,9 @@ use crate::{
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
/// Request for loading playback
|
/// Request for loading playback
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LoadRequest {
|
pub struct LoadRequest {
|
||||||
pub(super) context_uri: String,
|
pub(super) context: PlayContext,
|
||||||
pub(super) options: LoadRequestOptions,
|
pub(super) options: LoadRequestOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,14 @@ impl Deref for LoadRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(super) enum PlayContext {
|
||||||
|
Uri(String),
|
||||||
|
Tracks(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
/// The parameters for creating a load request
|
/// The parameters for creating a load request
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct LoadRequestOptions {
|
pub struct LoadRequestOptions {
|
||||||
/// Whether the given tracks should immediately start playing, or just be initially loaded.
|
/// Whether the given tracks should immediately start playing, or just be initially loaded.
|
||||||
pub start_playing: bool,
|
pub start_playing: bool,
|
||||||
|
@ -44,7 +50,7 @@ pub struct LoadRequestOptions {
|
||||||
///
|
///
|
||||||
/// Separated into an `enum` to exclude the other variants from being used
|
/// Separated into an `enum` to exclude the other variants from being used
|
||||||
/// simultaneously, as they are not compatible.
|
/// simultaneously, as they are not compatible.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LoadContextOptions {
|
pub enum LoadContextOptions {
|
||||||
/// Starts the context with options
|
/// Starts the context with options
|
||||||
Options(Options),
|
Options(Options),
|
||||||
|
@ -56,7 +62,7 @@ pub enum LoadContextOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The available options that indicate how to start the context
|
/// The available options that indicate how to start the context
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
/// Start the context in shuffle mode
|
/// Start the context in shuffle mode
|
||||||
pub shuffle: bool,
|
pub shuffle: bool,
|
||||||
|
@ -80,16 +86,30 @@ impl LoadRequest {
|
||||||
/// Create a load request from a `context_uri`
|
/// Create a load request from a `context_uri`
|
||||||
///
|
///
|
||||||
/// For supported `context_uri` see [`SpClient::get_context`](librespot_core::spclient::SpClient::get_context)
|
/// For supported `context_uri` see [`SpClient::get_context`](librespot_core::spclient::SpClient::get_context)
|
||||||
|
///
|
||||||
|
/// Equivalent to using [`/me/player/play`](https://developer.spotify.com/documentation/web-api/reference/start-a-users-playback)
|
||||||
|
/// and providing `context_uri`
|
||||||
pub fn from_context_uri(context_uri: String, options: LoadRequestOptions) -> Self {
|
pub fn from_context_uri(context_uri: String, options: LoadRequestOptions) -> Self {
|
||||||
Self {
|
Self {
|
||||||
context_uri,
|
context: PlayContext::Uri(context_uri),
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a load request from a set of `tracks`
|
||||||
|
///
|
||||||
|
/// Equivalent to using [`/me/player/play`](https://developer.spotify.com/documentation/web-api/reference/start-a-users-playback)
|
||||||
|
/// and providing `uris`
|
||||||
|
pub fn from_tracks(tracks: Vec<String>, options: LoadRequestOptions) -> Self {
|
||||||
|
Self {
|
||||||
|
context: PlayContext::Tracks(tracks),
|
||||||
options,
|
options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An item that represent a track to play
|
/// An item that represent a track to play
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PlayingTrack {
|
pub enum PlayingTrack {
|
||||||
/// Represent the track at a given index.
|
/// Represent the track at a given index.
|
||||||
Index(u32),
|
Index(u32),
|
||||||
|
|
|
@ -28,9 +28,10 @@ use crate::{
|
||||||
provider::IsProvider,
|
provider::IsProvider,
|
||||||
{ConnectConfig, ConnectState},
|
{ConnectConfig, ConnectState},
|
||||||
},
|
},
|
||||||
LoadContextOptions, LoadRequestOptions,
|
LoadContextOptions, LoadRequestOptions, PlayContext,
|
||||||
};
|
};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
|
use librespot_protocol::context_page::ContextPage;
|
||||||
use protobuf::MessageField;
|
use protobuf::MessageField;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
|
@ -975,12 +976,21 @@ impl SpircTask {
|
||||||
self.handle_transfer(transfer.data.expect("by condition checked"))?;
|
self.handle_transfer(transfer.data.expect("by condition checked"))?;
|
||||||
return self.notify().await;
|
return self.notify().await;
|
||||||
}
|
}
|
||||||
Play(play) => {
|
Play(mut play) => {
|
||||||
let context_uri = play
|
let first_page = play.context.pages.pop();
|
||||||
.context
|
let context = match play.context.uri {
|
||||||
.uri
|
Some(s) => PlayContext::Uri(s),
|
||||||
.clone()
|
None if !play.context.pages.is_empty() => PlayContext::Tracks(
|
||||||
.ok_or(SpircError::NoUri("context"))?;
|
play.context
|
||||||
|
.pages
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.flat_map(|p| p.tracks)
|
||||||
|
.flat_map(|t| t.uri)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
None => Err(SpircError::NoUri("context"))?,
|
||||||
|
};
|
||||||
|
|
||||||
let context_options = play
|
let context_options = play
|
||||||
.options
|
.options
|
||||||
|
@ -989,16 +999,16 @@ impl SpircTask {
|
||||||
.map(LoadContextOptions::Options);
|
.map(LoadContextOptions::Options);
|
||||||
|
|
||||||
self.handle_load(
|
self.handle_load(
|
||||||
LoadRequest::from_context_uri(
|
LoadRequest {
|
||||||
context_uri,
|
context,
|
||||||
LoadRequestOptions {
|
options: LoadRequestOptions {
|
||||||
start_playing: true,
|
start_playing: true,
|
||||||
seek_to: play.options.seek_to.unwrap_or_default(),
|
seek_to: play.options.seek_to.unwrap_or_default(),
|
||||||
playing_track: play.options.skip_to.and_then(|s| s.try_into().ok()),
|
playing_track: play.options.skip_to.and_then(|s| s.try_into().ok()),
|
||||||
context_options,
|
context_options,
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
Some(play.context),
|
first_page,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -1046,6 +1056,8 @@ impl SpircTask {
|
||||||
fn handle_transfer(&mut self, mut transfer: TransferState) -> Result<(), Error> {
|
fn handle_transfer(&mut self, mut transfer: TransferState) -> Result<(), Error> {
|
||||||
let mut ctx_uri = match transfer.current_session.context.uri {
|
let mut ctx_uri = match transfer.current_session.context.uri {
|
||||||
None => Err(SpircError::NoUri("transfer context"))?,
|
None => Err(SpircError::NoUri("transfer context"))?,
|
||||||
|
// can apparently happen when a state is transferred stared with "uris" via the api
|
||||||
|
Some(ref uri) if uri == "-" => String::new(),
|
||||||
Some(ref uri) => uri.clone(),
|
Some(ref uri) => uri.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1066,6 +1078,27 @@ impl SpircTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fallback = self.connect_state.current_track(|t| &t.uri).clone();
|
let fallback = self.connect_state.current_track(|t| &t.uri).clone();
|
||||||
|
let load_from_context_uri = !ctx_uri.is_empty();
|
||||||
|
|
||||||
|
if load_from_context_uri {
|
||||||
|
self.context_resolver.add(ResolveContext::from_uri(
|
||||||
|
ctx_uri.clone(),
|
||||||
|
&fallback,
|
||||||
|
ContextType::Default,
|
||||||
|
ContextAction::Replace,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
self.load_context_from_tracks(
|
||||||
|
transfer
|
||||||
|
.current_session
|
||||||
|
.context
|
||||||
|
.pages
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.flat_map(|p| p.tracks)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
|
||||||
self.context_resolver.add(ResolveContext::from_uri(
|
self.context_resolver.add(ResolveContext::from_uri(
|
||||||
ctx_uri.clone(),
|
ctx_uri.clone(),
|
||||||
|
@ -1112,7 +1145,15 @@ impl SpircTask {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if load_from_context_uri {
|
||||||
self.transfer_state = Some(transfer);
|
self.transfer_state = Some(transfer);
|
||||||
|
} else {
|
||||||
|
let ctx = self.connect_state.get_context(ContextType::Default)?;
|
||||||
|
let idx = ConnectState::find_index_in_context(ctx, |pt| {
|
||||||
|
self.connect_state.current_track(|t| pt.uri == t.uri)
|
||||||
|
})?;
|
||||||
|
self.connect_state.reset_playback_to_position(Some(idx))?;
|
||||||
|
}
|
||||||
|
|
||||||
self.load_track(is_playing, position.try_into()?)
|
self.load_track(is_playing, position.try_into()?)
|
||||||
}
|
}
|
||||||
|
@ -1181,61 +1222,41 @@ impl SpircTask {
|
||||||
async fn handle_load(
|
async fn handle_load(
|
||||||
&mut self,
|
&mut self,
|
||||||
cmd: LoadRequest,
|
cmd: LoadRequest,
|
||||||
context: Option<Context>,
|
page: Option<ContextPage>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.connect_state
|
self.connect_state
|
||||||
.reset_context(ResetContext::WhenDifferent(&cmd.context_uri));
|
.reset_context(if let PlayContext::Uri(ref uri) = cmd.context {
|
||||||
|
ResetContext::WhenDifferent(uri)
|
||||||
|
} else {
|
||||||
|
ResetContext::Completely
|
||||||
|
});
|
||||||
|
|
||||||
self.connect_state.reset_options();
|
self.connect_state.reset_options();
|
||||||
|
|
||||||
if !self.connect_state.is_active() {
|
let autoplay = matches!(cmd.context_options, Some(LoadContextOptions::Autoplay));
|
||||||
self.handle_activate();
|
match cmd.context {
|
||||||
|
PlayContext::Uri(uri) => {
|
||||||
|
self.load_context_from_uri(uri, page.as_ref(), autoplay)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
PlayContext::Tracks(tracks) => self.load_context_from_tracks(tracks)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
let fallback = if let Some(ref ctx) = context {
|
let cmd_options = cmd.options;
|
||||||
match ConnectState::get_context_uri_from_context(ctx) {
|
|
||||||
Some(ctx_uri) => ctx_uri,
|
|
||||||
None => Err(SpircError::InvalidUri(cmd.context_uri.clone()))?,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
&cmd.context_uri
|
|
||||||
};
|
|
||||||
|
|
||||||
let update_context = if matches!(cmd.context_options, Some(LoadContextOptions::Autoplay)) {
|
self.connect_state.set_active_context(ContextType::Default);
|
||||||
ContextType::Autoplay
|
|
||||||
} else {
|
|
||||||
ContextType::Default
|
|
||||||
};
|
|
||||||
|
|
||||||
self.connect_state.set_active_context(update_context);
|
|
||||||
|
|
||||||
let current_context_uri = self.connect_state.context_uri();
|
|
||||||
if current_context_uri == &cmd.context_uri && fallback == cmd.context_uri {
|
|
||||||
debug!("context <{current_context_uri}> didn't change, no resolving required")
|
|
||||||
} else {
|
|
||||||
debug!("resolving context for load command");
|
|
||||||
self.context_resolver.clear();
|
|
||||||
self.context_resolver.add(ResolveContext::from_uri(
|
|
||||||
&cmd.context_uri,
|
|
||||||
fallback,
|
|
||||||
update_context,
|
|
||||||
ContextAction::Replace,
|
|
||||||
));
|
|
||||||
let context = self.context_resolver.get_next_context(Vec::new).await;
|
|
||||||
self.handle_next_context(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for play commands with skip by uid, the context of the command contains
|
// for play commands with skip by uid, the context of the command contains
|
||||||
// tracks with uri and uid, so we merge the new context with the resolved/existing context
|
// tracks with uri and uid, so we merge the new context with the resolved/existing context
|
||||||
self.connect_state.merge_context(context);
|
self.connect_state.merge_context(page);
|
||||||
|
|
||||||
// load here, so that we clear the queue only after we definitely retrieved a new context
|
// load here, so that we clear the queue only after we definitely retrieved a new context
|
||||||
self.connect_state.clear_next_tracks();
|
self.connect_state.clear_next_tracks();
|
||||||
self.connect_state.clear_restrictions();
|
self.connect_state.clear_restrictions();
|
||||||
|
|
||||||
debug!("play track <{:?}>", cmd.playing_track);
|
debug!("play track <{:?}>", cmd_options.playing_track);
|
||||||
|
|
||||||
let index = match cmd.playing_track {
|
let index = match cmd_options.playing_track {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref playing_track) => Some(match playing_track {
|
Some(ref playing_track) => Some(match playing_track {
|
||||||
PlayingTrack::Index(i) => *i as usize,
|
PlayingTrack::Index(i) => *i as usize,
|
||||||
|
@ -1250,7 +1271,7 @@ impl SpircTask {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(LoadContextOptions::Options(ref options)) = cmd.context_options {
|
if let Some(LoadContextOptions::Options(ref options)) = cmd_options.context_options {
|
||||||
debug!(
|
debug!(
|
||||||
"loading with shuffle: <{}>, repeat track: <{}> context: <{}>",
|
"loading with shuffle: <{}>, repeat track: <{}> context: <{}>",
|
||||||
options.shuffle, options.repeat, options.repeat_track
|
options.shuffle, options.repeat, options.repeat_track
|
||||||
|
@ -1261,7 +1282,8 @@ impl SpircTask {
|
||||||
self.connect_state.set_repeat_track(options.repeat_track);
|
self.connect_state.set_repeat_track(options.repeat_track);
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(cmd.context_options, Some(LoadContextOptions::Options(ref o)) if o.shuffle) {
|
if matches!(cmd_options.context_options, Some(LoadContextOptions::Options(ref o)) if o.shuffle)
|
||||||
|
{
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
self.connect_state.set_current_track(index)?;
|
self.connect_state.set_current_track(index)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1282,7 +1304,7 @@ impl SpircTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.connect_state.current_track(MessageField::is_some) {
|
if self.connect_state.current_track(MessageField::is_some) {
|
||||||
self.load_track(cmd.start_playing, cmd.seek_to)?;
|
self.load_track(cmd_options.start_playing, cmd_options.seek_to)?;
|
||||||
} else {
|
} else {
|
||||||
info!("No active track, stopping");
|
info!("No active track, stopping");
|
||||||
self.handle_stop()
|
self.handle_stop()
|
||||||
|
@ -1291,6 +1313,67 @@ impl SpircTask {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn load_context_from_uri(
|
||||||
|
&mut self,
|
||||||
|
context_uri: String,
|
||||||
|
page: Option<&ContextPage>,
|
||||||
|
autoplay: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if !self.connect_state.is_active() {
|
||||||
|
self.handle_activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
let update_context = if autoplay {
|
||||||
|
ContextType::Autoplay
|
||||||
|
} else {
|
||||||
|
ContextType::Default
|
||||||
|
};
|
||||||
|
|
||||||
|
self.connect_state.set_active_context(update_context);
|
||||||
|
|
||||||
|
let fallback = match page {
|
||||||
|
// check that the uri is valid or the page has a valid uri that can be used
|
||||||
|
Some(page) => match ConnectState::find_valid_uri(Some(&context_uri), Some(page)) {
|
||||||
|
Some(ctx_uri) => ctx_uri,
|
||||||
|
None => return Err(SpircError::InvalidUri(context_uri).into()),
|
||||||
|
},
|
||||||
|
// when there is no page, the uri should be valid
|
||||||
|
None => &context_uri,
|
||||||
|
};
|
||||||
|
|
||||||
|
let current_context_uri = self.connect_state.context_uri();
|
||||||
|
|
||||||
|
if current_context_uri == &context_uri && fallback == context_uri {
|
||||||
|
debug!("context <{current_context_uri}> didn't change, no resolving required")
|
||||||
|
} else {
|
||||||
|
debug!("resolving context for load command");
|
||||||
|
self.context_resolver.clear();
|
||||||
|
self.context_resolver.add(ResolveContext::from_uri(
|
||||||
|
&context_uri,
|
||||||
|
fallback,
|
||||||
|
update_context,
|
||||||
|
ContextAction::Replace,
|
||||||
|
));
|
||||||
|
let context = self.context_resolver.get_next_context(Vec::new).await;
|
||||||
|
self.handle_next_context(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_context_from_tracks(&mut self, tracks: impl Into<ContextPage>) -> Result<(), Error> {
|
||||||
|
let ctx = Context {
|
||||||
|
pages: vec![tracks.into()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = self
|
||||||
|
.connect_state
|
||||||
|
.update_context(ctx, ContextType::Default)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_play(&mut self) {
|
fn handle_play(&mut self) {
|
||||||
match self.play_status {
|
match self.play_status {
|
||||||
SpircPlayStatus::Paused {
|
SpircPlayStatus::Paused {
|
||||||
|
@ -1433,7 +1516,8 @@ impl SpircTask {
|
||||||
let require_load_new = !self
|
let require_load_new = !self
|
||||||
.connect_state
|
.connect_state
|
||||||
.has_next_tracks(Some(CONTEXT_FETCH_THRESHOLD))
|
.has_next_tracks(Some(CONTEXT_FETCH_THRESHOLD))
|
||||||
&& self.session.autoplay();
|
&& self.session.autoplay()
|
||||||
|
&& !self.connect_state.context_uri().is_empty();
|
||||||
|
|
||||||
if !require_load_new {
|
if !require_load_new {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -116,6 +116,10 @@ impl ConnectState {
|
||||||
ResetContext::Completely => {
|
ResetContext::Completely => {
|
||||||
self.context = None;
|
self.context = None;
|
||||||
self.autoplay_context = None;
|
self.autoplay_context = None;
|
||||||
|
|
||||||
|
let player = self.player_mut();
|
||||||
|
player.context_uri.clear();
|
||||||
|
player.context_url.clear();
|
||||||
}
|
}
|
||||||
ResetContext::DefaultIndex => {
|
ResetContext::DefaultIndex => {
|
||||||
for ctx in [self.context.as_mut(), self.autoplay_context.as_mut()]
|
for ctx in [self.context.as_mut(), self.autoplay_context.as_mut()]
|
||||||
|
@ -141,14 +145,13 @@ impl ConnectState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_context_uri_from_context(context: &Context) -> Option<&str> {
|
pub fn find_valid_uri<'s>(
|
||||||
let uri = context.uri.as_deref().unwrap_or_default();
|
context_uri: Option<&'s str>,
|
||||||
Self::valid_resolve_uri(uri).or_else(|| {
|
first_page: Option<&'s ContextPage>,
|
||||||
context
|
) -> Option<&'s str> {
|
||||||
.pages
|
context_uri
|
||||||
.first()
|
.and_then(Self::valid_resolve_uri)
|
||||||
.and_then(|p| p.tracks.first().and_then(|t| t.uri.as_deref()))
|
.or_else(|| first_page.and_then(|p| p.tracks.first().and_then(|t| t.uri.as_deref())))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active_context(&mut self, new_context: ContextType) {
|
pub fn set_active_context(&mut self, new_context: ContextType) {
|
||||||
|
@ -157,7 +160,8 @@ impl ConnectState {
|
||||||
let player = self.player_mut();
|
let player = self.player_mut();
|
||||||
|
|
||||||
player.context_metadata = Default::default();
|
player.context_metadata = Default::default();
|
||||||
player.restrictions = Some(Default::default()).into();
|
player.context_restrictions = MessageField::some(Default::default());
|
||||||
|
player.restrictions = MessageField::some(Default::default());
|
||||||
|
|
||||||
let ctx = match self.get_context(new_context) {
|
let ctx = match self.get_context(new_context) {
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
|
@ -387,16 +391,10 @@ impl ConnectState {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_context(&mut self, context: Option<Context>) -> Option<()> {
|
pub fn merge_context(&mut self, new_page: Option<ContextPage>) -> Option<()> {
|
||||||
let mut context = context?;
|
|
||||||
if matches!(context.uri, Some(ref uri) if uri != self.context_uri()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_context = self.get_context_mut(ContextType::Default).ok()?;
|
let current_context = self.get_context_mut(ContextType::Default).ok()?;
|
||||||
let new_page = context.pages.pop()?;
|
|
||||||
|
|
||||||
for new_track in new_page.tracks {
|
for new_track in new_page?.tracks {
|
||||||
if new_track.uri.is_none() || matches!(new_track.uri, Some(ref uri) if uri.is_empty()) {
|
if new_track.uri.is_none() || matches!(new_track.uri, Some(ref uri) if uri.is_empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ impl ConnectState {
|
||||||
pub fn clear_restrictions(&mut self) {
|
pub fn clear_restrictions(&mut self) {
|
||||||
let player = self.player_mut();
|
let player = self.player_mut();
|
||||||
|
|
||||||
player.restrictions.clear();
|
player.context_restrictions = Some(Default::default()).into();
|
||||||
player.context_restrictions.clear();
|
player.restrictions = Some(Default::default()).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_restrictions(&mut self) {
|
pub fn update_restrictions(&mut self) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::context::Context;
|
use crate::{context::Context, context_page::ContextPage, context_track::ContextTrack};
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
@ -11,3 +11,27 @@ impl Hash for Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Context {}
|
impl Eq for Context {}
|
||||||
|
|
||||||
|
impl From<Vec<String>> for ContextPage {
|
||||||
|
fn from(value: Vec<String>) -> Self {
|
||||||
|
ContextPage {
|
||||||
|
tracks: value
|
||||||
|
.into_iter()
|
||||||
|
.map(|uri| ContextTrack {
|
||||||
|
uri: Some(uri),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<ContextTrack>> for ContextPage {
|
||||||
|
fn from(tracks: Vec<ContextTrack>) -> Self {
|
||||||
|
ContextPage {
|
||||||
|
tracks,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue