Added more control fields for playback control

api
Joey Hines 2024-10-14 20:44:48 -06:00
parent 10a13d3daa
commit f360e253b8
Signed by: joeyahines
GPG Key ID: 995E531F7A569DDB
7 changed files with 63 additions and 23 deletions

2
Cargo.lock generated
View File

@ -4141,6 +4141,7 @@ dependencies = [
"prost", "prost",
"spoticord_api_grpc", "spoticord_api_grpc",
"spoticord_database", "spoticord_database",
"spoticord_player",
"spoticord_session", "spoticord_session",
"thiserror", "thiserror",
"tokio", "tokio",
@ -4198,6 +4199,7 @@ dependencies = [
"hex", "hex",
"librespot", "librespot",
"log", "log",
"rand",
"songbird", "songbird",
"spoticord_audio", "spoticord_audio",
"spoticord_utils", "spoticord_utils",

View File

@ -7,6 +7,7 @@ edition = "2021"
spoticord_database = { path = "../spoticord_database" } spoticord_database = { path = "../spoticord_database" }
spoticord_session = { path = "../spoticord_session" } spoticord_session = { path = "../spoticord_session" }
spoticord_api_grpc = { path = "../spoticord_api_grpc"} spoticord_api_grpc = { path = "../spoticord_api_grpc"}
spoticord_player = { path = "../spoticord_player"}
prost = "0.13.3" prost = "0.13.3"
tokio = {version = "1.38.0", features = ["io-util", "net", "rt-multi-thread"]} tokio = {version = "1.38.0", features = ["io-util", "net", "rt-multi-thread"]}
axum = "0.7.5" axum = "0.7.5"

View File

@ -1,5 +1,6 @@
use log::info; use log::info;
use spoticord_api_grpc::spoticord_api::service::PlayPlaylistRequest; use spoticord_api_grpc::spoticord_api::service::{PlayModes, PlayPlaylistRequest};
use spoticord_player::playback_control::{PlayPlaylist, StartAt};
use spoticord_session::manager::{SessionManager, SessionQuery}; use spoticord_session::manager::{SessionManager, SessionQuery};
use tonic::{Request, Response, Status}; use tonic::{Request, Response, Status};
@ -26,7 +27,19 @@ impl spoticord_api_grpc::spoticord_api::service::spoticord_api_server::Spoticord
.get_session(SessionQuery::Owner(playlist.discord_user_id.into())) .get_session(SessionQuery::Owner(playlist.discord_user_id.into()))
.unwrap(); .unwrap();
session.queue_playlist(playlist.playlist_uri).await.unwrap(); let shuffle = match playlist.order() {
PlayModes::Shuffle => true,
PlayModes::InOrder => false,
};
let play_playlist = PlayPlaylist {
uri: playlist.playlist_uri,
shuffle,
repeat: true,
start_at: StartAt::FirstSong,
};
session.queue_playlist(play_playlist).await.unwrap();
let response = spoticord_api_grpc::spoticord_api::service::Response { let response = spoticord_api_grpc::spoticord_api::service::Response {
resp: Option::from( resp: Option::from(

View File

@ -16,3 +16,4 @@ anyhow = "1.0.86"
log = "0.4.22" log = "0.4.22"
symphonia = { version = "0.5.4", default-features = false, features = ["pcm"] } symphonia = { version = "0.5.4", default-features = false, features = ["pcm"] }
hex = "0.4.3" hex = "0.4.3"
rand = "0.8.5"

View File

@ -1,5 +1,7 @@
pub mod info; pub mod info;
pub mod playback_control;
use crate::playback_control::{PlayPlaylist, StartAt};
use anyhow::Result; use anyhow::Result;
use info::PlaybackInfo; use info::PlaybackInfo;
use librespot::connect::spirc::SpircLoadCommand; use librespot::connect::spirc::SpircLoadCommand;
@ -18,6 +20,7 @@ use librespot::{
}, },
}; };
use log::{error, trace}; use log::{error, trace};
use rand::{thread_rng, Rng};
use songbird::{input::RawAdapter, tracks::TrackHandle, Call}; use songbird::{input::RawAdapter, tracks::TrackHandle, Call};
use spoticord_audio::{ use spoticord_audio::{
sink::{SinkEvent, StreamSink}, sink::{SinkEvent, StreamSink},
@ -38,7 +41,7 @@ enum PlayerCommand {
GetPlaybackInfo(oneshot::Sender<Option<PlaybackInfo>>), GetPlaybackInfo(oneshot::Sender<Option<PlaybackInfo>>),
GetLyrics(oneshot::Sender<Option<Lyrics>>), GetLyrics(oneshot::Sender<Option<Lyrics>>),
QueuePlaylist { uri: String }, QueuePlaylist(PlayPlaylist),
Shutdown, Shutdown,
} }
@ -218,7 +221,7 @@ impl Player {
PlayerCommand::GetLyrics(tx) => self.get_lyrics(tx).await, PlayerCommand::GetLyrics(tx) => self.get_lyrics(tx).await,
PlayerCommand::Shutdown => self.commands.close(), PlayerCommand::Shutdown => self.commands.close(),
PlayerCommand::QueuePlaylist { uri } => self.queue_playlist(uri).await, PlayerCommand::QueuePlaylist(play_playlist) => self.queue_playlist(play_playlist).await,
}; };
} }
@ -307,12 +310,15 @@ impl Player {
_ = tx.send(Some(lyrics)); _ = tx.send(Some(lyrics));
} }
async fn queue_playlist(&self, playlist_uri: String) { async fn queue_playlist(&self, playlist_control: PlayPlaylist) {
let playlist = Playlist::get(&self.session, &SpotifyId::from_uri(&playlist_uri).unwrap()) let playlist = Playlist::get(
&self.session,
&SpotifyId::from_uri(&playlist_control.uri).unwrap(),
)
.await .await
.unwrap(); .unwrap();
let tracks = playlist let tracks: Vec<_> = playlist
.tracks() .tracks()
.map(|track_id| { .map(|track_id| {
let mut track = TrackRef::new(); let mut track = TrackRef::new();
@ -323,13 +329,18 @@ impl Player {
self.spirc.activate().unwrap(); self.spirc.activate().unwrap();
let start_ndx = match playlist_control.start_at {
StartAt::FirstSong => 0u32,
StartAt::Random => thread_rng().gen_range(0..tracks.len()) as u32,
};
self.spirc self.spirc
.load(SpircLoadCommand { .load(SpircLoadCommand {
context_uri: playlist_uri, context_uri: playlist_control.uri,
start_playing: true, start_playing: true,
shuffle: true, shuffle: playlist_control.shuffle,
repeat: true, repeat: playlist_control.repeat,
playing_track_index: 0, playing_track_index: start_ndx,
tracks, tracks,
}) })
.unwrap(); .unwrap();
@ -389,9 +400,9 @@ impl PlayerHandle {
_ = self.commands.send(PlayerCommand::Shutdown).await; _ = self.commands.send(PlayerCommand::Shutdown).await;
} }
pub async fn queue_playlist(&self, playlist_uri: String) { pub async fn queue_playlist(&self, play_playlist: PlayPlaylist) {
self.commands self.commands
.send(PlayerCommand::QueuePlaylist { uri: playlist_uri }) .send(PlayerCommand::QueuePlaylist(play_playlist))
.await .await
.unwrap() .unwrap()
} }

View File

@ -0,0 +1,13 @@
#[derive(Debug, Clone)]
pub enum StartAt {
FirstSong,
Random,
}
#[derive(Debug, Clone)]
pub struct PlayPlaylist {
pub uri: String,
pub shuffle: bool,
pub repeat: bool,
pub start_at: StartAt,
}

View File

@ -17,6 +17,7 @@ use serenity::{
}; };
use songbird::{model::payload::ClientDisconnect, Call, CoreEvent, Event, EventContext}; use songbird::{model::payload::ClientDisconnect, Call, CoreEvent, Event, EventContext};
use spoticord_database::Database; use spoticord_database::Database;
use spoticord_player::playback_control::PlayPlaylist;
use spoticord_player::{Player, PlayerEvent, PlayerHandle}; use spoticord_player::{Player, PlayerEvent, PlayerHandle};
use spoticord_utils::{discord::Colors, spotify}; use spoticord_utils::{discord::Colors, spotify};
use std::{ops::ControlFlow, sync::Arc, time::Duration}; use std::{ops::ControlFlow, sync::Arc, time::Duration};
@ -42,9 +43,7 @@ pub enum SessionCommand {
ShutdownPlayer, ShutdownPlayer,
Disconnect, Disconnect,
DisconnectTimedOut, DisconnectTimedOut,
QueuePlaylist { QueuePlaylist(PlayPlaylist),
playlist_uri: String,
},
} }
pub struct Session { pub struct Session {
@ -292,8 +291,8 @@ impl Session {
return ControlFlow::Break(()); return ControlFlow::Break(());
} }
SessionCommand::QueuePlaylist { playlist_uri } => { SessionCommand::QueuePlaylist(play_playlist) => {
self.player.queue_playlist(playlist_uri).await; self.player.queue_playlist(play_playlist).await;
} }
}; };
@ -557,9 +556,9 @@ impl SessionHandle {
} }
} }
pub async fn queue_playlist(&self, playlist_uri: String) -> Result<()> { pub async fn queue_playlist(&self, play_playlist: PlayPlaylist) -> Result<()> {
self.commands self.commands
.send(SessionCommand::QueuePlaylist { playlist_uri }) .send(SessionCommand::QueuePlaylist(play_playlist))
.await?; .await?;
Ok(()) Ok(())