Compare commits

..

2 Commits
main ... api

Author SHA1 Message Date
Joey Hines f360e253b8
Added more control fields for playback control 2024-10-14 20:44:48 -06:00
Joey Hines 10a13d3daa
initial api impl 2024-10-12 12:15:31 -06:00
14 changed files with 511 additions and 17 deletions

279
Cargo.lock generated
View File

@ -236,6 +236,61 @@ dependencies = [
"paste", "paste",
] ]
[[package]]
name = "axum"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
dependencies = [
"async-trait",
"axum-core",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.4.1",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper 1.0.1",
"tokio",
"tower 0.5.1",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.1",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper 1.0.1",
"tower-layer",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.74"
@ -652,7 +707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"hashbrown", "hashbrown 0.14.5",
"lock_api", "lock_api",
"once_cell", "once_cell",
"parking_lot_core", "parking_lot_core",
@ -1251,7 +1306,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http 0.2.12", "http 0.2.12",
"indexmap", "indexmap 2.5.0",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1270,7 +1325,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"http 1.1.0", "http 1.1.0",
"indexmap", "indexmap 2.5.0",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1283,10 +1338,16 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f"
dependencies = [ dependencies = [
"hashbrown", "hashbrown 0.14.5",
"serde", "serde",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.14.5"
@ -1596,6 +1657,19 @@ dependencies = [
"webpki-roots 0.26.6", "webpki-roots 0.26.6",
] ]
[[package]]
name = "hyper-timeout"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
dependencies = [
"hyper 1.4.1",
"hyper-util",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.9" version = "0.1.9"
@ -1664,6 +1738,16 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.5.0" version = "2.5.0"
@ -1671,7 +1755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown 0.14.5",
] ]
[[package]] [[package]]
@ -2108,6 +2192,12 @@ dependencies = [
"regex-automata 0.1.10", "regex-automata 0.1.10",
] ]
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]] [[package]]
name = "maybe-async" name = "maybe-async"
version = "0.2.10" version = "0.2.10"
@ -2517,7 +2607,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [ dependencies = [
"fixedbitset", "fixedbitset",
"indexmap", "indexmap 2.5.0",
] ]
[[package]] [[package]]
@ -2753,7 +2843,7 @@ checksum = "714c75db297bc88a63783ffc6ab9f830698a6705aa0201416931759ef4c8183d"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"equivalent", "equivalent",
"indexmap", "indexmap 2.5.0",
] ]
[[package]] [[package]]
@ -2765,6 +2855,59 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "prost"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15"
dependencies = [
"bytes",
"heck 0.5.0",
"itertools",
"log",
"multimap",
"once_cell",
"petgraph",
"prettyplease",
"prost",
"prost-types",
"regex",
"syn 2.0.79",
"tempfile",
]
[[package]]
name = "prost-derive"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]]
name = "prost-types"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670"
dependencies = [
"prost",
]
[[package]] [[package]]
name = "protobuf" name = "protobuf"
version = "3.5.1" version = "3.5.1"
@ -2798,7 +2941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b0e9b447d099ae2c4993c0cbb03c7a9d6c937b17f2d56cfc0b1550e6fcfdb76" checksum = "1b0e9b447d099ae2c4993c0cbb03c7a9d6c937b17f2d56cfc0b1550e6fcfdb76"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap 2.5.0",
"log", "log",
"protobuf", "protobuf",
"protobuf-support", "protobuf-support",
@ -3976,6 +4119,8 @@ dependencies = [
"rustls 0.23.13", "rustls 0.23.13",
"serenity", "serenity",
"songbird", "songbird",
"spoticord_api",
"spoticord_api_grpc",
"spoticord_config", "spoticord_config",
"spoticord_database", "spoticord_database",
"spoticord_player", "spoticord_player",
@ -3983,6 +4128,35 @@ dependencies = [
"spoticord_stats", "spoticord_stats",
"spoticord_utils", "spoticord_utils",
"tokio", "tokio",
"tonic",
]
[[package]]
name = "spoticord_api"
version = "0.1.0"
dependencies = [
"axum",
"env_logger",
"log",
"prost",
"spoticord_api_grpc",
"spoticord_database",
"spoticord_player",
"spoticord_session",
"thiserror",
"tokio",
"tonic",
]
[[package]]
name = "spoticord_api_grpc"
version = "0.1.0"
dependencies = [
"bytes",
"prost",
"tokio",
"tonic",
"tonic-build",
] ]
[[package]] [[package]]
@ -4025,6 +4199,7 @@ dependencies = [
"hex", "hex",
"librespot", "librespot",
"log", "log",
"rand",
"songbird", "songbird",
"spoticord_audio", "spoticord_audio",
"spoticord_utils", "spoticord_utils",
@ -4645,6 +4820,92 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tonic"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
dependencies = [
"async-stream",
"async-trait",
"axum",
"base64 0.22.1",
"bytes",
"h2 0.4.6",
"http 1.1.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.4.1",
"hyper-timeout",
"hyper-util",
"percent-encoding",
"pin-project",
"prost",
"socket2",
"tokio",
"tokio-stream",
"tower 0.4.13",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tonic-build"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
dependencies = [
"prettyplease",
"proc-macro2",
"prost-build",
"prost-types",
"quote",
"syn 2.0.79",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand",
"slab",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper 0.1.2",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.3" version = "0.3.3"
@ -4870,7 +5131,7 @@ checksum = "5dece5c06268af6a9ff4541788601e560a4284ffebfb357f713d676f13b964db"
dependencies = [ dependencies = [
"chrono", "chrono",
"dashmap", "dashmap",
"hashbrown", "hashbrown 0.14.5",
"mini-moka", "mini-moka",
"parking_lot", "parking_lot",
"secrecy", "secrecy",

View File

@ -17,6 +17,8 @@ members = [
"spoticord_session", "spoticord_session",
"spoticord_utils", "spoticord_utils",
"spoticord_stats", "spoticord_stats",
"spoticord_api",
"spoticord_api_grpc",
] ]
[features] [features]
@ -30,6 +32,8 @@ spoticord_player = { path = "./spoticord_player" }
spoticord_session = { path = "./spoticord_session" } spoticord_session = { path = "./spoticord_session" }
spoticord_utils = { path = "./spoticord_utils" } spoticord_utils = { path = "./spoticord_utils" }
spoticord_stats = { path = "./spoticord_stats", optional = true } spoticord_stats = { path = "./spoticord_stats", optional = true }
spoticord_api = { path = "./spoticord_api"}
spoticord_api_grpc = { path = "./spoticord_api_grpc"}
anyhow = "1.0.86" anyhow = "1.0.86"
dotenvy = "0.15.7" dotenvy = "0.15.7"
@ -40,6 +44,7 @@ serenity = "0.12.2"
songbird = { version = "0.4.3", features = ["simd-json"] } songbird = { version = "0.4.3", features = ["simd-json"] }
tokio = { version = "1.39.3", features = ["full"] } tokio = { version = "1.39.3", features = ["full"] }
rustls = { version = "0.23.13", features = ["aws-lc-rs"] } rustls = { version = "0.23.13", features = ["aws-lc-rs"] }
tonic = "0.12.3"
[profile.release] [profile.release]
opt-level = 3 opt-level = 3

View File

@ -0,0 +1,17 @@
[package]
name = "spoticord_api"
version = "0.1.0"
edition = "2021"
[dependencies]
spoticord_database = { path = "../spoticord_database" }
spoticord_session = { path = "../spoticord_session" }
spoticord_api_grpc = { path = "../spoticord_api_grpc"}
spoticord_player = { path = "../spoticord_player"}
prost = "0.13.3"
tokio = {version = "1.38.0", features = ["io-util", "net", "rt-multi-thread"]}
axum = "0.7.5"
env_logger = "0.11.3"
log = "0.4.21"
thiserror = "1.0.61"
tonic = "0.12.3"

View File

@ -0,0 +1,52 @@
use log::info;
use spoticord_api_grpc::spoticord_api::service::{PlayModes, PlayPlaylistRequest};
use spoticord_player::playback_control::{PlayPlaylist, StartAt};
use spoticord_session::manager::{SessionManager, SessionQuery};
use tonic::{Request, Response, Status};
pub struct SpoticordApi {
pub session: SessionManager,
}
#[tonic::async_trait]
impl spoticord_api_grpc::spoticord_api::service::spoticord_api_server::SpoticordApi
for SpoticordApi
{
async fn play_playlist(
&self,
request: Request<PlayPlaylistRequest>,
) -> Result<Response<spoticord_api_grpc::spoticord_api::service::Response>, Status> {
let playlist = request.into_inner();
info!(
"Playing {} for {}",
playlist.playlist_uri, playlist.discord_user_id
);
let session = self
.session
.get_session(SessionQuery::Owner(playlist.discord_user_id.into()))
.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 {
resp: Option::from(
spoticord_api_grpc::spoticord_api::service::response::Resp::Success(true),
),
};
Ok(Response::new(response))
}
}

View File

@ -0,0 +1,13 @@
[package]
name = "spoticord_api_grpc"
version = "0.1.0"
edition = "2021"
[dependencies]
bytes = "1.6.0"
tonic = "0.12.3"
prost = "0.13.3"
tokio = {version = "1.38.0", features = ["io-util", "test-util"]}
[build-dependencies]
tonic-build = "0.12.3"

View File

@ -0,0 +1,6 @@
use std::io::Result;
fn main() -> Result<()> {
tonic_build::configure().compile_protos(&["src/service.proto"], &["src/"])?;
Ok(())
}

View File

@ -0,0 +1,21 @@
pub mod spoticord_api {
pub mod service {
include!(concat!(env!("OUT_DIR"), "/spoticord_api.service.rs"));
}
}
#[cfg(test)]
mod test {
use crate::spoticord_api::service::{PlayModes, PlayPlaylistRequest};
#[test]
fn test_build_play_playlist() {
let play_playlist = PlayPlaylistRequest {
order: PlayModes::InOrder.into(),
playlist_uri: "test".to_string(),
};
assert_eq!(play_playlist.playlist_uri, "test");
assert_eq!(play_playlist.order, PlayModes::InOrder.into());
}
}

View File

@ -0,0 +1,32 @@
syntax = "proto3";
package spoticord_api.service;
enum PlayModes {
SHUFFLE = 0;
IN_ORDER = 1;
}
message PlayPlaylistRequest {
uint64 discord_user_id = 1;
PlayModes order = 2;
string playlist_uri = 3;
}
enum Error {
SpotifyError = 0;
BotError = 1;
UserNotRegistered = 2;
}
message Response {
oneof resp {
bool success = 1;
Error error = 2;
}
}
service SpoticordApi {
rpc PlayPlaylist(PlayPlaylistRequest) returns (Response);
}

View File

@ -35,8 +35,4 @@ diesel::table! {
diesel::joinable!(account -> user (user_id)); diesel::joinable!(account -> user (user_id));
diesel::joinable!(link_request -> user (user_id)); diesel::joinable!(link_request -> user (user_id));
diesel::allow_tables_to_appear_in_same_query!( diesel::allow_tables_to_appear_in_same_query!(account, link_request, user,);
account,
link_request,
user,
);

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,7 +1,13 @@
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::core::SpotifyId;
use librespot::metadata::{Metadata, Playlist};
use librespot::protocol::spirc::TrackRef;
use librespot::{ use librespot::{
connect::{config::ConnectConfig, spirc::Spirc}, connect::{config::ConnectConfig, spirc::Spirc},
core::{http_client::HttpClientError, Session as SpotifySession, SessionConfig}, core::{http_client::HttpClientError, Session as SpotifySession, SessionConfig},
@ -14,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},
@ -34,6 +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(PlayPlaylist),
Shutdown, Shutdown,
} }
@ -213,6 +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(play_playlist) => self.queue_playlist(play_playlist).await,
}; };
} }
@ -300,6 +309,42 @@ impl Player {
_ = tx.send(Some(lyrics)); _ = tx.send(Some(lyrics));
} }
async fn queue_playlist(&self, playlist_control: PlayPlaylist) {
let playlist = Playlist::get(
&self.session,
&SpotifyId::from_uri(&playlist_control.uri).unwrap(),
)
.await
.unwrap();
let tracks: Vec<_> = playlist
.tracks()
.map(|track_id| {
let mut track = TrackRef::new();
track.set_gid(Vec::from(track_id.to_raw()));
track
})
.collect();
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
.load(SpircLoadCommand {
context_uri: playlist_control.uri,
start_playing: true,
shuffle: playlist_control.shuffle,
repeat: playlist_control.repeat,
playing_track_index: start_ndx,
tracks,
})
.unwrap();
}
} }
impl Drop for Player { impl Drop for Player {
@ -354,4 +399,11 @@ impl PlayerHandle {
pub async fn shutdown(&self) { pub async fn shutdown(&self) {
_ = self.commands.send(PlayerCommand::Shutdown).await; _ = self.commands.send(PlayerCommand::Shutdown).await;
} }
pub async fn queue_playlist(&self, play_playlist: PlayPlaylist) {
self.commands
.send(PlayerCommand::QueuePlaylist(play_playlist))
.await
.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,6 +43,7 @@ pub enum SessionCommand {
ShutdownPlayer, ShutdownPlayer,
Disconnect, Disconnect,
DisconnectTimedOut, DisconnectTimedOut,
QueuePlaylist(PlayPlaylist),
} }
pub struct Session { pub struct Session {
@ -236,7 +238,6 @@ impl Session {
SessionCommand::GetOwner(sender) => _ = sender.send(self.owner), SessionCommand::GetOwner(sender) => _ = sender.send(self.owner),
SessionCommand::GetPlayer(sender) => _ = sender.send(self.player.clone()), SessionCommand::GetPlayer(sender) => _ = sender.send(self.player.clone()),
SessionCommand::GetActive(sender) => _ = sender.send(self.active), SessionCommand::GetActive(sender) => _ = sender.send(self.active),
SessionCommand::CreatePlaybackEmbed(handle, interaction, behavior) => { SessionCommand::CreatePlaybackEmbed(handle, interaction, behavior) => {
match PlaybackEmbed::create(self, handle, interaction, behavior).await { match PlaybackEmbed::create(self, handle, interaction, behavior).await {
Ok(opt_handle) => { Ok(opt_handle) => {
@ -290,6 +291,9 @@ impl Session {
return ControlFlow::Break(()); return ControlFlow::Break(());
} }
SessionCommand::QueuePlaylist(play_playlist) => {
self.player.queue_playlist(play_playlist).await;
}
}; };
ControlFlow::Continue(()) ControlFlow::Continue(())
@ -551,6 +555,14 @@ impl SessionHandle {
error!("Failed to send command: {why}"); error!("Failed to send command: {why}");
} }
} }
pub async fn queue_playlist(&self, play_playlist: PlayPlaylist) -> Result<()> {
self.commands
.send(SessionCommand::QueuePlaylist(play_playlist))
.await?;
Ok(())
}
} }
#[async_trait] #[async_trait]

View File

@ -4,6 +4,7 @@ use anyhow::{anyhow, Result};
use log::{debug, info}; use log::{debug, info};
use poise::{serenity_prelude, Framework, FrameworkContext, FrameworkOptions}; use poise::{serenity_prelude, Framework, FrameworkContext, FrameworkOptions};
use serenity::all::{ActivityData, FullEvent, Ready, ShardManager}; use serenity::all::{ActivityData, FullEvent, Ready, ShardManager};
use spoticord_api::SpoticordApi;
use spoticord_database::Database; use spoticord_database::Database;
use spoticord_session::manager::SessionManager; use spoticord_session::manager::SessionManager;
@ -84,7 +85,7 @@ async fn event_handler(
ctx: &serenity_prelude::Context, ctx: &serenity_prelude::Context,
event: &FullEvent, event: &FullEvent,
_framework: FrameworkContext<'_, Data, anyhow::Error>, _framework: FrameworkContext<'_, Data, anyhow::Error>,
_data: &Data, data: &Data,
) -> Result<()> { ) -> Result<()> {
if let FullEvent::Ready { data_about_bot } = event { if let FullEvent::Ready { data_about_bot } = event {
if let Some(shard) = data_about_bot.shard { if let Some(shard) = data_about_bot.shard {
@ -95,7 +96,19 @@ async fn event_handler(
} }
ctx.set_activity(Some(ActivityData::listening(spoticord_config::MOTD))); ctx.set_activity(Some(ActivityData::listening(spoticord_config::MOTD)));
}
let api_server = SpoticordApi {
session: data.clone(),
};
tokio::spawn(async move {
tonic::transport::Server::builder()
.add_service(spoticord_api_grpc::spoticord_api::service::spoticord_api_server::SpoticordApiServer::new(api_server))
.serve("127.0.0.1:8080".parse().unwrap())
.await
.unwrap();
});
};
Ok(()) Ok(())
} }