124 lines
4.7 KiB
Rust
124 lines
4.7 KiB
Rust
mod commands;
|
|
mod util;
|
|
mod music;
|
|
|
|
use serenity::all::{CommandInteraction, CreateInteractionResponseFollowup, OnlineStatus, VoiceState};
|
|
use serenity::async_trait;
|
|
use serenity::builder::{CreateEmbed};
|
|
use serenity::gateway::ActivityData;
|
|
use serenity::model::application::{Command, Interaction};
|
|
use serenity::model::gateway::Ready;
|
|
use serenity::prelude::*;
|
|
use util::{config, embed::Embed, user_util};
|
|
|
|
// This trait adds the `register_songbird` and `register_songbird_with` methods
|
|
// to the client builder below, making it easy to install this voice client.
|
|
// The voice client can be retrieved in any command using `songbird::get(ctx).await`.
|
|
use songbird::SerenityInit;
|
|
|
|
// YtDl requests need an HTTP client to operate -- we'll create and store our own.
|
|
use reqwest::Client as HttpClient;
|
|
|
|
struct HttpKey;
|
|
impl TypeMapKey for HttpKey {
|
|
type Value = HttpClient;
|
|
}
|
|
|
|
struct Handler;
|
|
|
|
#[async_trait]
|
|
impl EventHandler for Handler {
|
|
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
|
unsafe {
|
|
if let Interaction::Command(command) = interaction {
|
|
let _ = &command.defer(&ctx.http()).await.expect("Cannot defer");
|
|
|
|
let content = Some(match command.data.name.as_str() {
|
|
"info" => commands::info::run(&ctx, &command).await,
|
|
"play" => commands::play::run(&ctx, &command).await,
|
|
"stop" => commands::stop::run(&ctx, &command).await,
|
|
_ => respond_with_error(&ctx, &command).await,
|
|
});
|
|
|
|
if let Some(embed) = content {
|
|
let followup = CreateInteractionResponseFollowup::new().embed(embed);
|
|
if let Err(why) = command.create_followup(&ctx.http, followup).await {
|
|
println!("Cannot followup to slash command: {why}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn ready(&self, ctx: Context, ready: Ready) {
|
|
println!("{} is connected!", ready.user.name);
|
|
|
|
let _command = Command::create_global_command(&ctx.http, commands::info::register()).await;
|
|
let _command = Command::create_global_command(&ctx.http, commands::stop::register()).await;
|
|
let _command = Command::create_global_command(&ctx.http, commands::play::register()).await;
|
|
println!("Commands are registered and Rustendo is ready for Freddy.");
|
|
}
|
|
|
|
async fn voice_state_update(&self, ctx: Context, old: Option<VoiceState>, new: VoiceState) { // FIXME: This does not work, when switching channels
|
|
if new.channel_id.is_some() {
|
|
return; // User did not leave, ignore
|
|
}
|
|
if let Some(old) = old {
|
|
if !user_util::is_self_connected_to_vc(&ctx, &old.guild_id.unwrap()).await {
|
|
return; // Bot is not connected to a VC, ignore
|
|
}
|
|
if user_util::get_amount_of_members_in_vc(&ctx, &old.guild_id.unwrap(), &old.channel_id.unwrap()).await < 2 {
|
|
let manager = songbird::get(&ctx).await.expect("Cannot get Songbird");
|
|
if let Err(e) = manager.remove(old.guild_id.unwrap()).await {
|
|
println!("Failed to remove handler: {:?}", e);
|
|
}
|
|
}
|
|
} // else: new user joined, ignore
|
|
}
|
|
}
|
|
|
|
pub async fn respond_with_error(_ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
|
|
Embed::create(
|
|
command.user.name.to_owned(),
|
|
"Command not found",
|
|
"Cannot find the executed command",
|
|
)
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
println!(
|
|
r"__________ __ .___
|
|
\______ \__ __ _______/ |_ ____ ____ __| _/____
|
|
| _/ | | ___/\ __\_/ __ \ / \ / __ |/ _ \
|
|
| | \ | |___ \ | | \ ___/ | | | /_/ ( <_> )
|
|
|____|_ /____/____ > |__| \___ >|___| |____ |\____/
|
|
\/ \/ \/ \/ \/
|
|
"
|
|
);
|
|
|
|
// Load config
|
|
let config = config::load().unwrap();
|
|
// Set status
|
|
let status = OnlineStatus::DoNotDisturb;
|
|
let activity = ActivityData::streaming("music", "https://twitch.tv/moonleaytv").unwrap();
|
|
|
|
// Build the client
|
|
let mut client = Client::builder(config.discord_token, GatewayIntents::empty())
|
|
.event_handler(Handler)
|
|
.status(status)
|
|
.activity(activity)
|
|
.register_songbird()
|
|
.type_map_insert::<HttpKey>(HttpClient::new())
|
|
.intents(GatewayIntents::all())
|
|
.await
|
|
.expect("Error creating client");
|
|
|
|
// Finally, start a single shard, and start listening to events.
|
|
//
|
|
// Shards will automatically attempt to reconnect, and will perform exponential backoff until
|
|
// it reconnects.
|
|
if let Err(why) = client.start().await {
|
|
println!("Client error: {why:?}");
|
|
}
|
|
}
|