WIP: code compiles now, connects to VC, does not play audio yet

This commit is contained in:
moonleay 2024-05-20 04:07:10 +02:00
parent 6685163c96
commit 880e81646d
Signed by: moonleay
GPG key ID: 82667543CCD715FB
7 changed files with 280 additions and 138 deletions

176
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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 {

View file

@ -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) {
} }

View file

@ -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())

View file

@ -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)
} }

View file

@ -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();