1
0
Fork 0
mirror of https://github.com/librespot-org/librespot.git synced 2025-10-05 02:39:53 +02:00

Shuffle tracks in place (#1445)

* connect: add shuffle_vec.rs

* connect: shuffle in place

* add shuffle with seed option

* reduce complexity to add new metadata fields

* add context index to metadata

* use seed for shuffle

When losing the connection and restarting the dealer, the seed is now stored in the context metadata. So on transfer we can pickup the seed again and shuffle the context as it was previously

* add log for shuffle seed

* connect: use small_rng, derive Default

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Felix Prillwitz 2025-02-02 22:58:30 +01:00 committed by GitHub
parent 471735aa5a
commit 34762f2274
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 314 additions and 170 deletions

View file

@ -4,13 +4,10 @@ use crate::{
autoplay_context_request::AutoplayContextRequest, context::Context,
transfer_state::TransferState,
},
state::{
context::{ContextType, UpdateContext},
ConnectState,
},
state::{context::ContextType, ConnectState},
};
use std::cmp::PartialEq;
use std::{
cmp::PartialEq,
collections::{HashMap, VecDeque},
fmt::{Display, Formatter},
hash::Hash,
@ -35,7 +32,7 @@ pub(super) enum ContextAction {
pub(super) struct ResolveContext {
resolve: Resolve,
fallback: Option<String>,
update: UpdateContext,
update: ContextType,
action: ContextAction,
}
@ -44,7 +41,7 @@ impl ResolveContext {
Self {
resolve: Resolve::Uri(uri.into()),
fallback: None,
update: UpdateContext::Default,
update: ContextType::Default,
action: ContextAction::Append,
}
}
@ -52,7 +49,7 @@ impl ResolveContext {
pub fn from_uri(
uri: impl Into<String>,
fallback: impl Into<String>,
update: UpdateContext,
update: ContextType,
action: ContextAction,
) -> Self {
let fallback_uri = fallback.into();
@ -64,7 +61,7 @@ impl ResolveContext {
}
}
pub fn from_context(context: Context, update: UpdateContext, action: ContextAction) -> Self {
pub fn from_context(context: Context, update: ContextType, action: ContextAction) -> Self {
Self {
resolve: Resolve::Context(context),
fallback: None,
@ -214,7 +211,7 @@ impl ContextResolver {
let (next, resolve_uri, _) = self.find_next().ok_or(ContextResolverError::NoNext)?;
match next.update {
UpdateContext::Default => {
ContextType::Default => {
let mut ctx = self.session.spclient().get_context(resolve_uri).await;
if let Ok(ctx) = ctx.as_mut() {
ctx.uri = Some(next.context_uri().to_string());
@ -223,7 +220,7 @@ impl ContextResolver {
ctx
}
UpdateContext::Autoplay => {
ContextType::Autoplay => {
if resolve_uri.contains("spotify:show:") || resolve_uri.contains("spotify:episode:")
{
// autoplay is not supported for podcasts
@ -304,13 +301,13 @@ impl ContextResolver {
}
match (next.update, state.active_context) {
(UpdateContext::Default, ContextType::Default) | (UpdateContext::Autoplay, _) => {
(ContextType::Default, ContextType::Default) | (ContextType::Autoplay, _) => {
debug!(
"last item of type <{:?}>, finishing state setup",
next.update
);
}
(UpdateContext::Default, _) => {
(ContextType::Default, _) => {
debug!("skipped finishing default, because it isn't the active context");
return false;
}
@ -320,7 +317,7 @@ impl ContextResolver {
let res = if let Some(transfer_state) = transfer_state.take() {
state.finish_transfer(transfer_state)
} else if state.shuffling_context() {
state.shuffle()
state.shuffle(None)
} 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