WIP: code compiles now, connects to VC, does not play audio yet
This commit is contained in:
parent
6685163c96
commit
880e81646d
7 changed files with 280 additions and 138 deletions
176
Cargo.lock
generated
176
Cargo.lock
generated
|
@ -78,20 +78,10 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-tungstenite"
|
name = "atomic-waker"
|
||||||
version = "0.24.0"
|
version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
dependencies = [
|
|
||||||
"futures-io",
|
|
||||||
"futures-util",
|
|
||||||
"log",
|
|
||||||
"native-tls",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
"tokio-native-tls",
|
|
||||||
"tungstenite 0.21.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "audiopus"
|
name = "audiopus"
|
||||||
|
@ -719,6 +709,25 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"http 1.1.0",
|
||||||
|
"indexmap",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
|
@ -764,6 +773,29 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body-util"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"http 1.1.0",
|
||||||
|
"http-body 1.0.0",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -786,9 +818,9 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.3.26",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"http-body",
|
"http-body 0.4.6",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -800,6 +832,26 @@ dependencies = [
|
||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.4.5",
|
||||||
|
"http 1.1.0",
|
||||||
|
"http-body 1.0.0",
|
||||||
|
"httparse",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.24.2"
|
version = "0.24.2"
|
||||||
|
@ -808,7 +860,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"hyper",
|
"hyper 0.14.28",
|
||||||
"rustls 0.21.12",
|
"rustls 0.21.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.24.1",
|
"tokio-rustls 0.24.1",
|
||||||
|
@ -821,12 +873,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"hyper",
|
"hyper 0.14.28",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper 1.3.1",
|
||||||
|
"hyper-util",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-util"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"http 1.1.0",
|
||||||
|
"http-body 1.0.0",
|
||||||
|
"hyper 1.3.1",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.60"
|
version = "0.1.60"
|
||||||
|
@ -902,25 +990,29 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lavalink-rs"
|
name = "lavalink-rs"
|
||||||
version = "0.10.0"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87676c01f7c63f255899cc2672f11a1d7d6848787cf0e6abbc6b79c839cf9f24"
|
checksum = "4ba892eecbfb64bfa0e4fca87462a33fa8616915a6532d38026267147dd62cdb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-tungstenite",
|
"bytes",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"futures",
|
"futures",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper 1.3.1",
|
||||||
|
"hyper-tls 0.6.0",
|
||||||
|
"hyper-util",
|
||||||
"oneshot",
|
"oneshot",
|
||||||
"reqwest",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_qs",
|
"serde_qs",
|
||||||
"serenity",
|
"serenity",
|
||||||
"songbird",
|
"songbird",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-tungstenite 0.21.0",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"urlencoding",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1515,12 +1607,12 @@ dependencies = [
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.3.26",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"http-body",
|
"http-body 0.4.6",
|
||||||
"hyper",
|
"hyper 0.14.28",
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
"hyper-tls",
|
"hyper-tls 0.5.0",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1874,9 +1966,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_qs"
|
name = "serde_qs"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c"
|
checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -2530,6 +2622,28 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"pin-project",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-layer"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2813,6 +2927,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urlencoding"
|
||||||
|
version = "2.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf-8"
|
name = "utf-8"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
|
|
|
@ -14,7 +14,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
confy = "0.6.0"
|
confy = "0.6.0"
|
||||||
songbird = { version = "0.4", features = ["gateway", "serenity", "native", "driver"], default-features = false }
|
songbird = { version = "0.4", features = ["gateway", "serenity", "native", "driver"], default-features = false }
|
||||||
lavalink-rs = { version = "0.10", features = ["songbird", "serenity-native", "native-tls"], default-features = false }
|
lavalink-rs = { version = "0.12", features = ["songbird", "serenity", "native-tls"], default-features = false }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
reqwest = "0.11"
|
reqwest = "0.11"
|
||||||
symphonia = "0.5"
|
symphonia = "0.5"
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::music::preview::Preview;
|
||||||
use crate::util::embed::Embed;
|
use crate::util::embed::Embed;
|
||||||
use lavalink_rs::client::LavalinkClient;
|
use lavalink_rs::client::LavalinkClient;
|
||||||
use serenity::all::{CommandInteraction, Context};
|
use serenity::all::{CommandInteraction, Context, GuildId};
|
||||||
use serenity::builder::{CreateCommand, CreateEmbed};
|
use serenity::builder::{CreateCommand, CreateEmbed};
|
||||||
|
|
||||||
pub async fn run(ctx: &Context, command: &CommandInteraction, llc: &LavalinkClient) -> CreateEmbed {
|
pub async fn run(ctx: &Context, command: &CommandInteraction, llc: &LavalinkClient) -> CreateEmbed {
|
||||||
|
@ -17,47 +20,27 @@ pub async fn run(ctx: &Context, command: &CommandInteraction, llc: &LavalinkClie
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let now_plaing = match music_queue::get_now_playing(&guild_id).await {
|
let Some(player_context) = llc.get_player_context(guild_id.get()) else {
|
||||||
Some(ytdl) => ytdl,
|
return Embed::create_error_respose(username, "Not playing", "There is no player context and therefore there is nothing playing.");
|
||||||
None => {
|
|
||||||
return Embed::create_error_respose(
|
|
||||||
username,
|
|
||||||
"Not playing",
|
|
||||||
"I'm not playing anything!",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let now_handle = match music_queue::get_now_playing_track_handle(&guild_id).await {
|
let Ok(player) = player_context.get_player().await else {
|
||||||
Some(handle) => handle,
|
return Embed::create_error_respose(username, "Can't get player", "Cannot get player from player context.");
|
||||||
None => {
|
|
||||||
return Embed::create_error_respose(
|
|
||||||
username,
|
|
||||||
"Cannot get TrackHandle",
|
|
||||||
"The TrackHandle is empty.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let manager = songbird::get(ctx)
|
|
||||||
.await
|
|
||||||
.expect("Cannot get Songbird")
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let _ = match manager.get(*guild_id) {
|
if let Some(npt) = player.track {
|
||||||
Some(handler) => handler,
|
let npti = npt.info;
|
||||||
None => {
|
let preview_data = Preview {
|
||||||
return Embed::create_error_respose(
|
title: npti.title,
|
||||||
username,
|
artist: Some(npti.author.to_string()),
|
||||||
"Error",
|
duration: Some(npti.length),
|
||||||
"Error while getting the audio handler.",
|
thumbnail: npti.artwork_url,
|
||||||
);
|
link: npti.uri
|
||||||
}
|
};
|
||||||
};
|
let position = Duration::from_millis(player_context.get_player().await.expect("Can't get player").state.position);
|
||||||
|
|
||||||
let position = now_handle.get_info().await.unwrap().position;
|
return Embed::create_playing(preview_data, username, "Now playing")
|
||||||
|
|
||||||
Embed::create_playing(now_plaing, username, "Currently playing")
|
|
||||||
.await
|
.await
|
||||||
.field(
|
.field(
|
||||||
"Position",
|
"Position",
|
||||||
|
@ -66,8 +49,11 @@ pub async fn run(ctx: &Context, command: &CommandInteraction, llc: &LavalinkClie
|
||||||
position.as_secs() / 60,
|
position.as_secs() / 60,
|
||||||
position.as_secs() % 60
|
position.as_secs() % 60
|
||||||
),
|
),
|
||||||
true,
|
true
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Embed::create_error_respose(username, "Not playing", "I'm currently not playing anything.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register() -> CreateCommand {
|
pub fn register() -> CreateCommand {
|
||||||
|
|
|
@ -8,22 +8,22 @@ pub async fn ready_event(client: LavalinkClient, _session_id: String, event: &ev
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hook]
|
#[hook]
|
||||||
pub async fn track_start(client: LavalinkClient, _session_id: String, event: &events::TrackStart) {
|
pub async fn track_start(_client: LavalinkClient, _session_id: String, _event: &events::TrackStart) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hook]
|
#[hook]
|
||||||
pub async fn track_end_event(client: LavalinkClient, _session_id: String, event: &events::TrackEnd) {
|
pub async fn track_end_event(_client: LavalinkClient, _session_id: String, _event: &events::TrackEnd) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hook]
|
#[hook]
|
||||||
pub async fn track_exception(client: LavalinkClient, _session_id: String, event: &events::TrackException) {
|
pub async fn track_exception(_client: LavalinkClient, _session_id: String, _event: &events::TrackException) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hook]
|
#[hook]
|
||||||
pub async fn track_stuck(client: LavalinkClient, _session_id: String, event: &events::TrackStuck) {
|
pub async fn track_stuck(_client: LavalinkClient, _session_id: String, _event: &events::TrackStuck) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/main.rs
32
src/main.rs
|
@ -3,8 +3,12 @@ mod music;
|
||||||
mod util;
|
mod util;
|
||||||
mod events;
|
mod events;
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use lavalink_rs::client::LavalinkClient;
|
use lavalink_rs::client::LavalinkClient;
|
||||||
|
use lavalink_rs::model::client::NodeDistributionStrategy;
|
||||||
use lavalink_rs::model::events::Events;
|
use lavalink_rs::model::events::Events;
|
||||||
|
use lavalink_rs::model::UserId;
|
||||||
use lavalink_rs::node::NodeBuilder;
|
use lavalink_rs::node::NodeBuilder;
|
||||||
use serenity::all::{
|
use serenity::all::{
|
||||||
CommandInteraction, CreateInteractionResponseFollowup, OnlineStatus, VoiceState,
|
CommandInteraction, CreateInteractionResponseFollowup, OnlineStatus, VoiceState,
|
||||||
|
@ -29,7 +33,7 @@ use crate::events::lavalink_event_handler;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
struct Handler {
|
struct Handler {
|
||||||
llc: LavalinkClient
|
pub llc: LavalinkClient
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -120,26 +124,26 @@ async fn main() {
|
||||||
let status = OnlineStatus::DoNotDisturb;
|
let status = OnlineStatus::DoNotDisturb;
|
||||||
let activity = ActivityData::streaming("music", "https://twitch.tv/moonleaytv").unwrap();
|
let activity = ActivityData::streaming("music", "https://twitch.tv/moonleaytv").unwrap();
|
||||||
|
|
||||||
|
let event = Events {
|
||||||
|
ready: Some(lavalink_event_handler::ready_event),
|
||||||
|
// track_start: Some(lavalink_event_handler::track_start),
|
||||||
|
// track_end: Some(lavalink_event_handler::track_end_event),
|
||||||
|
// track_exception: Some(lavalink_event_handler::track_exception),
|
||||||
|
// track_stuck: Some(lavalink_event_handler::track_stuck),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let node_builder = NodeBuilder {
|
let node_builder = NodeBuilder {
|
||||||
hostname: config.lavalink_address,
|
hostname: config.lavalink_address,
|
||||||
password: config.lavalink_password,
|
password: config.lavalink_password,
|
||||||
|
user_id: UserId(config.user_id),
|
||||||
is_ssl: false,
|
is_ssl: false,
|
||||||
..Default::default()
|
events: event.clone(),
|
||||||
|
session_id: None
|
||||||
};
|
};
|
||||||
|
|
||||||
let event = Events {
|
|
||||||
ready: Some(lavalink_event_handler::ready_event),
|
|
||||||
track_start: Some(lavalink_event_handler::track_start),
|
|
||||||
track_end: Some(lavalink_event_handler::track_end_event),
|
|
||||||
track_exception: Some(lavalink_event_handler::track_exception),
|
|
||||||
track_stuck: Some(lavalink_event_handler::track_stuck),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let lavalink_client = LavalinkClient::new(event, vec![node_builder]);
|
let lavalink_client = LavalinkClient::new(event, vec![node_builder], NodeDistributionStrategy::round_robin()).await;
|
||||||
tokio::spawn(async move {
|
|
||||||
lavalink_client.start().await;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Build the client
|
// Build the client
|
||||||
let mut client = Client::builder(config.discord_token, GatewayIntents::empty())
|
let mut client = Client::builder(config.discord_token, GatewayIntents::empty())
|
||||||
|
|
|
@ -2,11 +2,12 @@ use crate::util::embed::Embed;
|
||||||
use crate::util::user_util;
|
use crate::util::user_util;
|
||||||
use crate::util::user_util::get_vc_id;
|
use crate::util::user_util::get_vc_id;
|
||||||
use crate::music::preview::Preview;
|
use crate::music::preview::Preview;
|
||||||
use lavalink_rs::client::LavalinkClient;
|
use lavalink_rs::{client::LavalinkClient, player_context::QueueMessage};
|
||||||
use lavalink_rs::model::search::SearchEngines;
|
use lavalink_rs::model::search::SearchEngines;
|
||||||
use lavalink_rs::model::track::TrackLoadData;
|
use lavalink_rs::model::track::TrackLoadData;
|
||||||
use lavalink_rs::player_context::TrackInQueue;
|
use lavalink_rs::player_context::TrackInQueue;
|
||||||
use serenity::all::{Context, CreateEmbed, GuildId, UserId};
|
use serenity::all::{Context, CreateEmbed, GuildId, UserId};
|
||||||
|
use songbird::error::JoinError;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Either queues the song, or start playing it instantly, depending on if there is already a song playing
|
/// Either queues the song, or start playing it instantly, depending on if there is already a song playing
|
||||||
|
@ -56,7 +57,7 @@ pub async fn attempt_to_queue_song(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(why) => {
|
Err(_) => {
|
||||||
return Embed::create_error_respose(username, "Cannot join", "Could not join the channel.");
|
return Embed::create_error_respose(username, "Cannot join", "Could not join the channel.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +80,7 @@ pub async fn attempt_to_queue_song(
|
||||||
let search_query = if do_search {
|
let search_query = if do_search {
|
||||||
match SearchEngines::YouTube.to_query(&query) {
|
match SearchEngines::YouTube.to_query(&query) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(why) => {
|
Err(_) => {
|
||||||
return Embed::create_error_respose(username, "Cannot generate query", "Could not generate a seach query..");
|
return Embed::create_error_respose(username, "Cannot generate query", "Could not generate a seach query..");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,13 +140,17 @@ pub async fn attempt_to_queue_song(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut q = match player.get_queue().await {
|
|
||||||
Ok(q) => q,
|
let q = player.get_queue();
|
||||||
Err(why) => {
|
q.append(tracks.into());
|
||||||
return Embed::create_error_respose(username, "Cannont get queue", "Could not get queue.");
|
|
||||||
|
if let Ok(player_data) = player.get_player().await {
|
||||||
|
if player_data.track.is_none() && q.get_track(0).await.is_ok_and(|x| x.is_some()) {
|
||||||
|
player.skip();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
q.append(&mut tracks.into());
|
|
||||||
|
|
||||||
|
|
||||||
Embed::create_playing(preview_data.unwrap(), username, &response_title).await
|
Embed::create_playing(preview_data.unwrap(), username, &response_title).await
|
||||||
}
|
}
|
||||||
|
@ -166,54 +171,76 @@ pub async fn attempt_to_skip_current_song(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let connect_to = match get_vc_id(ctx, guild_id, user_id).await {
|
let user_channel = match get_vc_id(ctx, guild_id, user_id).await {
|
||||||
Some(channel_id) => channel_id,
|
Some(channel_id) => channel_id,
|
||||||
None => {
|
None => {
|
||||||
return Embed::create_error_respose(username, "Error", "Cannot find channel_id.");
|
return Embed::create_error_respose(username, "Error", "Cannot find channel_id.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let manager: &Arc<songbird::Songbird> = &songbird::get(ctx) // TODO match
|
|
||||||
.await
|
|
||||||
.expect("Cannot get Songbird.")
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let self_channel = user_util::get_self_vc_id(ctx, guild_id).await;
|
let self_channel = user_util::get_self_vc_id(ctx, guild_id).await;
|
||||||
if !user_util::is_self_connected_to_vc(ctx, guild_id).await {
|
if !user_util::is_self_connected_to_vc(ctx, guild_id).await {
|
||||||
// self is connected to vc, check if user is in same vc
|
// Self is not connected to vc, cannot skip.
|
||||||
|
|
||||||
if self_channel.is_none() {
|
return Embed::create_error_respose(username, "Not connected", "I am not connected and I am not playing anything, therefore you cannot skip.");
|
||||||
// Connect to VC
|
|
||||||
manager // TODO match
|
|
||||||
.join(*guild_id, connect_to)
|
|
||||||
.await
|
|
||||||
.expect("Cannot connect>...");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let self_channel = self_channel.expect("Cannot get self channel"); // TODO: match
|
let self_channel = self_channel.expect("Cannot get self channel");
|
||||||
|
|
||||||
// Check if user is in the same VC as the bot
|
// Check if user is in the same VC as the bot
|
||||||
if self_channel != connect_to {
|
if self_channel != user_channel {
|
||||||
return Embed::create_error_respose(
|
return Embed::create_error_respose(
|
||||||
username,
|
username,
|
||||||
"You are not in my VC",
|
"You are not in my VC",
|
||||||
"You have to be in my VC in order to controll the music.",
|
"You have to be in my VC in order to control the music.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = music_queue::next(guild_id).await; // TODO match
|
let Some(player_context) = llc.get_player_context(guild_id.get()) else {
|
||||||
if head.is_none() {
|
return Embed::create_error_respose(username, "Not playing", "There is no player context and therefore there is nothing playing.");
|
||||||
return Embed::create_error_respose(
|
};
|
||||||
username,
|
|
||||||
"Cannot find a song to play",
|
let Ok(player) = player_context.get_player().await else {
|
||||||
"The queue is empty.",
|
return Embed::create_error_respose(username, "Can't get player", "Cannot get player from player context.");
|
||||||
);
|
};
|
||||||
}
|
|
||||||
let head = head.unwrap();
|
|
||||||
play_song(ctx, guild_id, llc, &head).await;
|
if let Some(_) = player.track {
|
||||||
|
let Ok(_) = player_context.skip() else {
|
||||||
|
return Embed::create_error_respose(username, "Cannot skip", "Could not skip track.");
|
||||||
|
};
|
||||||
|
let ct = match player_context.get_player().await.expect("Can't get player").track {
|
||||||
|
Some(data) => data.info,
|
||||||
|
None => { // Disconnect
|
||||||
|
let songbird = songbird::get(ctx).await.unwrap().clone();
|
||||||
|
|
||||||
|
let Ok(_) = llc.delete_player(guild_id.get()).await else {
|
||||||
|
return Embed::create_error_respose(username, "Cannot delete player", "Could not delete player.");
|
||||||
|
};
|
||||||
|
if songbird.get(GuildId::new(guild_id.get())).is_some() {
|
||||||
|
let Ok(_) = songbird.remove(GuildId::new(guild_id.get())).await else {
|
||||||
|
return Embed::create_error_respose(username, "Cannot remove ref", "Cannot remove songbird ref.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Embed::create_error_respose(username, "No track to skip to", "Therefore I am leaving the channel.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let preview_data = Preview {
|
||||||
|
title: ct.title,
|
||||||
|
artist: Some(ct.author.to_string()),
|
||||||
|
duration: Some(ct.length),
|
||||||
|
thumbnail: ct.artwork_url,
|
||||||
|
link: ct.uri
|
||||||
|
};
|
||||||
|
|
||||||
|
return Embed::create_playing(preview_data, username, "Skipped; Now playing").await;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Embed::create_error_respose(username, "Not playing", "I'm currently not playing anything.");
|
||||||
|
|
||||||
|
|
||||||
Embed::create_playing(head, username, "Song skipped; Now playing").await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to clear the queue and stop playing. Also leave the vc
|
/// Try to clear the queue and stop playing. Also leave the vc
|
||||||
|
@ -248,6 +275,9 @@ pub async fn attempt_to_stop(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let player = llc.get_player_context(guild_id.get()).expect("Can't get player context.");
|
||||||
|
player.get_queue().clear();
|
||||||
|
|
||||||
let stopped = match leave(ctx, llc, guild_id).await {
|
let stopped = match leave(ctx, llc, guild_id).await {
|
||||||
Ok(stopped) => stopped,
|
Ok(stopped) => stopped,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -267,26 +297,26 @@ pub async fn attempt_to_stop(
|
||||||
"I am not connected.\nI cant stop doing something, when I'm not doing it.",
|
"I am not connected.\nI cant stop doing something, when I'm not doing it.",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
music_queue::delete_queue(guild_id).await; // Clear queue
|
|
||||||
|
|
||||||
Embed::create_success_response(username, "I stopped and left", "Just like you girlfriend.")
|
Embed::create_success_response(username, "I stopped and left", "Just like you girlfriend.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong.
|
/// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong.
|
||||||
pub async fn leave(ctx: &Context, llc: &LavalinkClient, guild_id: &GuildId) -> Result<bool, JoinError> {
|
pub async fn leave(ctx: &Context, llc: &LavalinkClient, guild_id: &GuildId) -> Result<bool, JoinError> {
|
||||||
let manager = songbird::get(ctx)
|
let Some(songbird) = songbird::get(ctx)
|
||||||
.await
|
.await.clone() else {
|
||||||
.expect("Cannot get Songbird")
|
return Err(JoinError::NoSender);
|
||||||
.clone();
|
};
|
||||||
|
|
||||||
let handler = manager.get(*guild_id);
|
let Ok(_) = llc.delete_player(guild_id.get()).await else {
|
||||||
let has_handler = handler.is_some();
|
return Err(JoinError::Dropped);
|
||||||
|
};
|
||||||
|
|
||||||
if has_handler {
|
if songbird.get(GuildId::new(guild_id.get())).is_some() {
|
||||||
handler.unwrap().lock().await.stop();
|
let Ok(_) = songbird.remove(GuildId::new(guild_id.get())).await else {
|
||||||
manager.remove(*guild_id).await?;
|
return Err(JoinError::Dropped);
|
||||||
return Ok(true); // Handler removed
|
};
|
||||||
}
|
}
|
||||||
Ok(false) // No handler, so it's already stopped
|
|
||||||
|
return Ok(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ use std::error::Error;
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub discord_token: String,
|
pub discord_token: String,
|
||||||
pub lavalink_address: String,
|
pub lavalink_address: String,
|
||||||
pub lavalink_password: String
|
pub lavalink_password: String,
|
||||||
|
pub user_id: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONFIG_FILE: &str = "./data/config.json";
|
const CONFIG_FILE: &str = "./data/config.json";
|
||||||
|
@ -26,7 +27,8 @@ fn create_empty() -> fs::File {
|
||||||
let example_config = Config {
|
let example_config = Config {
|
||||||
discord_token: "paste_your_token".to_string(),
|
discord_token: "paste_your_token".to_string(),
|
||||||
lavalink_address: "paste_your_lavalink_address".to_string(),
|
lavalink_address: "paste_your_lavalink_address".to_string(),
|
||||||
lavalink_password: "paste_your_lavalink_password".to_string()
|
lavalink_password: "paste_your_lavalink_password".to_string(),
|
||||||
|
user_id: 976119987330777168
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut config_file = fs::File::create(CONFIG_FILE).unwrap();
|
let mut config_file = fs::File::create(CONFIG_FILE).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue