From 8a947926f7eaaf5f72dc1aec8dbba78c25326810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Czy=C5=BC?= Date: Fri, 16 Feb 2024 12:42:38 +0100 Subject: [PATCH] 0.5.1 refractor --- Cargo.lock | 3 +- Cargo.toml | 3 +- src/commands.rs | 2 +- src/commands/embeds.rs | 53 +++++++--- src/commands/music.rs | 10 +- src/commands/music/deafen.rs | 30 +++--- src/commands/music/join.rs | 34 +++---- src/commands/music/leave.rs | 27 +++-- src/commands/music/mute.rs | 34 +++---- src/commands/music/pause.rs | 33 +++--- src/commands/music/play.rs | 167 ++++++++++++++++++++++--------- src/commands/music/queue.rs | 47 ++++----- src/commands/music/repeat.rs | 64 ++++++++---- src/commands/music/resume.rs | 29 +++--- src/commands/music/seek.rs | 11 ++ src/commands/music/shuffle.rs | 11 ++ src/commands/music/skip.rs | 34 ++++--- src/commands/music/soundboard.rs | 11 ++ src/commands/music/stop.rs | 41 ++++---- src/commands/music/volume.rs | 11 ++ src/commands/tools.rs | 30 +++++- src/commands/tools/ai.rs | 50 +++++++++ src/commands/tools/dice.rs | 33 ++++++ src/commands/tools/dictionary.rs | 12 +++ src/commands/tools/ip.rs | 12 +++ src/commands/tools/metar.rs | 12 +++ src/commands/tools/owoify.rs | 12 +++ src/commands/tools/ping.rs | 13 +-- src/commands/tools/posix.rs | 29 ++++-- src/commands/tools/qr.rs | 12 +++ src/commands/tools/register.rs | 10 +- src/commands/tools/taf.rs | 12 +++ src/commands/tools/uptime.rs | 12 +++ src/commands/tools/verse.rs | 12 +++ src/commands/tools/weather.rs | 12 +++ src/http.rs | 2 +- src/main.rs | 45 +++++++-- 37 files changed, 694 insertions(+), 281 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a36326..60deb83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -959,12 +959,13 @@ dependencies = [ [[package]] name = "lyra" -version = "0.5.0" +version = "0.6.0" dependencies = [ "dotenv", "fancy-regex", "openssl", "poise", + "rand", "regex", "reqwest", "serenity", diff --git a/Cargo.toml b/Cargo.toml index 5c67ec3..95d9ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lyra" -version = "0.5.0" +version = "0.6.0" authors = ["Michał Czyż "] edition = "2021" description = "A featureful Discord bot written in Rust." @@ -16,6 +16,7 @@ dotenv = "0.15.0" fancy-regex = "0.13.0" openssl = { version = "0.10.63", features = ["vendored"] } poise = "0.6.1" +rand = "0.8.5" regex = "1.10.3" reqwest = "0.11.23" serenity = { version = "0.12.0", features = ["cache", "framework", "standard_framework", "voice"] } diff --git a/src/commands.rs b/src/commands.rs index 85ff9ea..6af7359 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,4 +1,4 @@ +pub mod embeds; pub mod kashi; pub mod music; pub mod tools; -pub mod embeds; diff --git a/src/commands/embeds.rs b/src/commands/embeds.rs index 887b8d2..6a5a825 100644 --- a/src/commands/embeds.rs +++ b/src/commands/embeds.rs @@ -1,37 +1,58 @@ use crate::{Context, Error}; -use serenity::{builder::{CreateEmbedAuthor, CreateEmbedFooter}, model::{Colour, Timestamp}}; use poise::serenity_prelude::CreateEmbed; use poise::CreateReply; +use serenity::{ + builder::{CreateEmbedAuthor, CreateEmbedFooter}, + model::{Colour, Timestamp}, +}; pub async fn fail(ctx: Context<'_>, err: String) -> Result<(), Error> { ctx.send( - CreateReply::default().embed(error_embed(ctx, &format!("Failed: {:?}", err)).await.unwrap()) - ).await?; + CreateReply::default().embed( + error_embed(ctx, &format!("Failed: {:?}", err)) + .await + .unwrap(), + ), + ) + .await?; Ok(()) } pub async fn error_embed(ctx: Context<'_>, msg: &str) -> Result { let embed = CreateEmbed::default() - .author(CreateEmbedAuthor::new("Something went wrong!").icon_url(ctx.author().clone().face())) - .colour(Colour::from_rgb(255, 58, 97)) - .title("Oopsie, Doopsie!") - .description(msg) - .timestamp(Timestamp::now()) - .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + .author( + CreateEmbedAuthor::new("Something went wrong!").icon_url(ctx.author().clone().face()), + ) + .colour(Colour::from_rgb(255, 58, 97)) + .title("Oopsie, Doopsie!") + .description(msg) + .timestamp(Timestamp::now()) + .footer( + CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()) + .icon_url(ctx.cache().current_user().face()), + ); Ok(embed) } -pub async fn embed(ctx: Context<'_>, author: &str, description: &str, title: &str) -> Result { +pub async fn embed( + ctx: Context<'_>, + author: &str, + description: &str, + title: &str, +) -> Result { let embed = CreateEmbed::default() - .author(CreateEmbedAuthor::new(author).icon_url(ctx.author().clone().face())) - .colour(Colour::from_rgb(255, 58, 97)) - .title(title) - .description(description) - .timestamp(Timestamp::now()) - .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + .author(CreateEmbedAuthor::new(author).icon_url(ctx.author().clone().face())) + .colour(Colour::from_rgb(255, 58, 97)) + .title(title) + .description(description) + .timestamp(Timestamp::now()) + .footer( + CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()) + .icon_url(ctx.cache().current_user().face()), + ); Ok(embed) } diff --git a/src/commands/music.rs b/src/commands/music.rs index 2272710..5c7c189 100644 --- a/src/commands/music.rs +++ b/src/commands/music.rs @@ -1,16 +1,20 @@ pub mod deafen; pub mod join; pub mod leave; -pub mod notifier; pub mod metadata; pub mod mute; +pub mod notifier; pub mod pause; pub mod play; pub mod queue; pub mod repeat; pub mod resume; +pub mod seek; +pub mod shuffle; pub mod skip; +pub mod soundboard; pub mod stop; +pub mod volume; pub use deafen::deafen; pub use join::join; @@ -21,5 +25,9 @@ pub use play::play; pub use queue::queue; pub use repeat::repeat; pub use resume::resume; +pub use seek::seek; +pub use shuffle::shuffle; pub use skip::skip; +pub use soundboard::soundboard; pub use stop::stop; +pub use volume::volume; diff --git a/src/commands/music/deafen.rs b/src/commands/music/deafen.rs index 0f4b6dd..e9a224c 100644 --- a/src/commands/music/deafen.rs +++ b/src/commands/music/deafen.rs @@ -1,4 +1,7 @@ -use crate::{commands::embeds::{error_embed, embed, fail}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed, fail}, + Context, Error, +}; use poise::CreateReply; /// Deafens itself while in a voice channel; \ @@ -9,9 +12,7 @@ use poise::CreateReply; aliases("shuush", "undeafen"), category = "Music" )] -pub async fn deafen( - ctx: Context<'_> -) -> Result<(), Error> { +pub async fn deafen(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -23,10 +24,9 @@ pub async fn deafen( Some(handler) => handler, None => { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; - + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; + return Ok(()); } }; @@ -38,17 +38,15 @@ pub async fn deafen( fail(ctx, err.to_string()).await.unwrap(); } - ctx.send( - CreateReply::default().embed(embed(ctx, "Undeafened!", "", "").await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(embed(ctx, "Undeafened!", "", "").await.unwrap())) + .await?; } else { - if let Err(err) = handler.deafen(true).await { + if let Err(err) = handler.deafen(true).await { fail(ctx, err.to_string()).await.unwrap(); } - - ctx.send( - CreateReply::default().embed(embed(ctx, "Deafened!", "", "").await.unwrap()) - ).await?; + + ctx.send(CreateReply::default().embed(embed(ctx, "Deafened!", "", "").await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/join.rs b/src/commands/music/join.rs index 4b87b3c..ad025a4 100644 --- a/src/commands/music/join.rs +++ b/src/commands/music/join.rs @@ -1,29 +1,28 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::commands::music::notifier::TrackErrorNotifier; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; use songbird::TrackEvent; -use crate::commands::music::notifier::TrackErrorNotifier; /// Joins your voice channel -#[poise::command( - prefix_command, - slash_command, - category = "Music" -)] -pub async fn join( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn join(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); - let channel_id = ctx.guild().unwrap() - .voice_states.get(&ctx.author().id) + let channel_id = ctx + .guild() + .unwrap() + .voice_states + .get(&ctx.author().id) .and_then(|voice_state| voice_state.channel_id); let connect_to = match channel_id { Some(channel) => channel, None => { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; return Ok(()); } }; @@ -38,9 +37,8 @@ pub async fn join( handler.add_global_event(TrackEvent::Error.into(), TrackErrorNotifier); } - ctx.send( - CreateReply::default().embed(embed(ctx, "Joined!", "Hi there!", "").await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(embed(ctx, "Joined!", "Hi there!", "").await.unwrap())) + .await?; Ok(()) } diff --git a/src/commands/music/leave.rs b/src/commands/music/leave.rs index 7b8ca45..284483d 100644 --- a/src/commands/music/leave.rs +++ b/src/commands/music/leave.rs @@ -1,5 +1,8 @@ +use crate::{ + commands::embeds::{embed, error_embed, fail}, + Context, Error, +}; use poise::CreateReply; -use crate::{commands::embeds::{error_embed, fail, embed}, Context, Error}; /// Leaves the voice channel; \ /// aliases: leave, qa! @@ -9,9 +12,7 @@ use crate::{commands::embeds::{error_embed, fail, embed}, Context, Error}; aliases("leave", "qa!"), category = "Music" )] -pub async fn leave( - ctx: Context<'_> -) -> Result<(), Error> { +pub async fn leave(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -21,20 +22,24 @@ pub async fn leave( if !manager.get(guild_id).is_some() { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; - return Ok(()) + return Ok(()); } - if let Err(err) = manager.remove(guild_id).await { + if let Err(err) = manager.remove(guild_id).await { fail(ctx, err.to_string()).await.unwrap(); } ctx.send( - CreateReply::default().embed(embed(ctx, "Left!", "I left the voice channel", "").await.unwrap()) - ).await?; + CreateReply::default().embed( + embed(ctx, "Left!", "I left the voice channel", "") + .await + .unwrap(), + ), + ) + .await?; Ok(()) } diff --git a/src/commands/music/mute.rs b/src/commands/music/mute.rs index c5b11bc..a80cb93 100644 --- a/src/commands/music/mute.rs +++ b/src/commands/music/mute.rs @@ -1,17 +1,18 @@ -use crate::{commands::embeds::{error_embed, embed, fail}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed, fail}, + Context, Error, +}; use poise::CreateReply; /// Mutes itself while in a voice channel; \ /// aliases: mute, unmute, shhh #[poise::command( - prefix_command, + prefix_command, slash_command, aliases("shhh", "unmute"), category = "Music" )] -pub async fn mute( - ctx: Context<'_> -) -> Result<(), Error> { +pub async fn mute(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -21,33 +22,30 @@ pub async fn mute( let handler_lock = match manager.get(guild_id) { Some(handler) => handler, - None => { + None => { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; return Ok(()); } }; let mut handler = handler_lock.lock().await; - if handler.is_mute() { + if handler.is_mute() { if let Err(err) = handler.mute(false).await { fail(ctx, err.to_string()).await.unwrap(); } - - ctx.send( - CreateReply::default().embed(embed(ctx, "Unmuted!", "", "").await.unwrap()) - ).await?; + + ctx.send(CreateReply::default().embed(embed(ctx, "Unmuted!", "", "").await.unwrap())) + .await?; } else { if let Err(err) = handler.mute(true).await { fail(ctx, err.to_string()).await.unwrap(); } - - ctx.send( - CreateReply::default().embed(embed(ctx, "Muted!", "", "").await.unwrap()) - ).await?; + + ctx.send(CreateReply::default().embed(embed(ctx, "Muted!", "", "").await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/pause.rs b/src/commands/music/pause.rs index 8a02993..e5a431a 100644 --- a/src/commands/music/pause.rs +++ b/src/commands/music/pause.rs @@ -1,15 +1,12 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; /// Pauses the currently playing song -#[poise::command( - prefix_command, - slash_command, - category = "Music" -)] -pub async fn pause( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn pause(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -21,15 +18,19 @@ pub async fn pause( let handler = handler_lock.lock().await; let queue = handler.queue(); let _ = queue.pause(); - + ctx.send( - CreateReply::default().embed(embed(ctx, "Paused!", "Currently playing song is now paused!", "").await.unwrap()) - ).await?; - } else { + CreateReply::default().embed( + embed(ctx, "Paused!", "Currently playing song is now paused!", "") + .await + .unwrap(), + ), + ) + .await?; + } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/play.rs b/src/commands/music/play.rs index 18a4002..58f9d08 100644 --- a/src/commands/music/play.rs +++ b/src/commands/music/play.rs @@ -1,20 +1,20 @@ -use crate::{commands::embeds::error_embed, Context, Error}; use crate::commands::music::metadata::Metadata; +use crate::{commands::embeds::error_embed, Context, Error}; use fancy_regex::Regex; +use poise::serenity_prelude::model::Timestamp; +use poise::serenity_prelude::Colour; +use poise::serenity_prelude::CreateEmbed; +use poise::CreateReply; use regex::Regex as Regex_Classic; +use serenity::builder::CreateEmbedAuthor; +use serenity::builder::CreateEmbedFooter; +use songbird::events::TrackEvent; +use songbird::input::AuxMetadata; +use songbird::input::{Compose, YoutubeDl}; use songbird::tracks::{TrackHandle, TrackQueue}; use std::process::Command; use std::time::Duration; -use poise::CreateReply; -use poise::serenity_prelude::CreateEmbed; -use poise::serenity_prelude::Colour; -use poise::serenity_prelude::model::Timestamp; -use serenity::builder::CreateEmbedAuthor; -use serenity::builder::CreateEmbedFooter; -use songbird::input::AuxMetadata; -use songbird::input::{Compose, YoutubeDl}; -use songbird::events::TrackEvent; use crate::commands::music::notifier::TrackErrorNotifier; use crate::http::HttpKey; @@ -23,33 +23,44 @@ use crate::http::HttpKey; /// you can search by query or paste an url; \ /// aliases: play, p, enqueue #[poise::command( - prefix_command, - slash_command, + prefix_command, + slash_command, aliases("p", "enqueue"), category = "Music" )] pub async fn play( - ctx: Context<'_>, - #[description = "Provide a query or an url"] #[rest] mut song: String, + ctx: Context<'_>, + #[description = "Provide a query or an url"] + #[rest] + mut song: String, ) -> Result<(), Error> { let regex_spotify = Regex::new(r"https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-)+)(?:(?=\?)(?:[?&]foo=(\d*)(?=[&#]|$)|(?![?&]foo=)[^#])+)?(?=#|$)").unwrap(); - let regex_youtube = Regex_Classic::new(r#""url": "(https://www.youtube.com/watch\?v=[A-Za-z0-9]{11})""#).unwrap(); - let regex_youtube_playlist = Regex::new(r"^((?:https?:)\/\/)?((?:www|m)\.)?((?:youtube\.com)).*(youtu.be\/|list=)([^#&?]*).*").unwrap(); + let regex_youtube = + Regex_Classic::new(r#""url": "(https://www.youtube.com/watch\?v=[A-Za-z0-9]{11})""#) + .unwrap(); + let regex_youtube_playlist = Regex::new( + r"^((?:https?:)\/\/)?((?:www|m)\.)?((?:youtube\.com)).*(youtu.be\/|list=)([^#&?]*).*", + ) + .unwrap(); let is_playlist = regex_youtube_playlist.is_match(&song).unwrap(); let is_spotify = regex_spotify.is_match(&song).unwrap(); let is_query = !song.starts_with("http"); let guild_id = ctx.guild_id().unwrap(); - let channel_id = ctx.guild().unwrap().voice_states.get(&ctx.author().id).and_then(|voice_state| voice_state.channel_id); + let channel_id = ctx + .guild() + .unwrap() + .voice_states + .get(&ctx.author().id) + .and_then(|voice_state| voice_state.channel_id); let connect_to = match channel_id { Some(channel) => channel, - None => { + None => { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; return Ok(()); } @@ -77,17 +88,24 @@ pub async fn play( .args(["-j", "--flat-playlist", &song]) .output() .expect("failed to execute process") - .stdout; + .stdout; let list = String::from_utf8(raw_list.clone()).expect("Invalid UTF-8"); - let urls: Vec = regex_youtube.captures_iter(&list).map(|capture| capture[1].to_string()).collect(); - - for (index, url) in urls.clone().iter().enumerate() { + let urls: Vec = regex_youtube + .captures_iter(&list) + .map(|capture| capture[1].to_string()) + .collect(); + + for (index, url) in urls.clone().iter().enumerate() { let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client.clone(), url.to_string()); let aux_metadata = src.clone().aux_metadata().await.unwrap(); let track = handler.enqueue_input(src.clone().into()).await; - let _ = track.typemap().write().await.insert::(aux_metadata); + let _ = track + .typemap() + .write() + .await + .insert::(aux_metadata); if index == 0 { let embed = generate_playlist_embed(ctx, track, urls.len()).await; @@ -95,43 +113,61 @@ pub async fn play( ctx.send(response).await?; } } - } else { if is_spotify { let exec = format!("node ./src/spotify --url {}", song); - let query = Command::new("sh").arg("-c").arg(exec).output().expect("failed to execute process").stdout; + let query = Command::new("sh") + .arg("-c") + .arg(exec) + .output() + .expect("failed to execute process") + .stdout; let query_str = String::from_utf8(query.clone()).expect("Invalid UTF-8"); song = format!("ytsearch:{}", query_str.to_string()); - } if is_query { song = format!("ytsearch:{}", song); } - let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client, song); + let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client, song); let embed = generate_embed(ctx, src.clone(), handler.queue()).await; let response = CreateReply::default().embed(embed.unwrap()); ctx.send(response).await?; - + let aux_metadata = src.clone().aux_metadata().await.unwrap(); - + let track = handler.enqueue_input(src.clone().into()).await; - let _ = track.typemap().write().await.insert::(aux_metadata); + let _ = track + .typemap() + .write() + .await + .insert::(aux_metadata); } } Ok(()) } -async fn generate_embed(ctx: Context<'_>, src: YoutubeDl, queue: &TrackQueue) -> Result { +async fn generate_embed( + ctx: Context<'_>, + src: YoutubeDl, + queue: &TrackQueue, +) -> Result { let metadata = src.clone().aux_metadata().await.unwrap(); - let AuxMetadata {title, thumbnail, source_url, artist, duration, ..} = metadata; + let AuxMetadata { + title, + thumbnail, + source_url, + artist, + duration, + .. + } = metadata; let timestamp = Timestamp::now(); let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; let mut description = format!("Song added to queue @ {}", queue.len()); - + if queue.len() == 0 { description = format!("Playing now!"); } @@ -142,24 +178,46 @@ async fn generate_embed(ctx: Context<'_>, src: YoutubeDl, queue: &TrackQueue) -> .title(title.unwrap()) .url(source_url.unwrap()) .thumbnail(thumbnail.unwrap_or(ctx.cache().current_user().face())) - .field("Artist", artist.unwrap_or("Unknown Artist".to_string()), true) - .field("Duration", format!("{:02}:{:02}", duration_minutes, duration_seconds), true) + .field( + "Artist", + artist.unwrap_or("Unknown Artist".to_string()), + true, + ) + .field( + "Duration", + format!("{:02}:{:02}", duration_minutes, duration_seconds), + true, + ) .field("DJ", ctx.author().name.clone(), true) .description(description) .timestamp(timestamp) - .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + .footer( + CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()) + .icon_url(ctx.cache().current_user().face()), + ); Ok(embed) } -async fn generate_playlist_embed(ctx: Context<'_>, track: TrackHandle, queue_length: usize) -> Result { +async fn generate_playlist_embed( + ctx: Context<'_>, + track: TrackHandle, + queue_length: usize, +) -> Result { let meta_typemap = track.typemap().read().await; - let metadata = meta_typemap.get::().unwrap(); - let AuxMetadata {title, thumbnail, source_url, artist, duration, ..} = metadata; + let metadata = meta_typemap.get::().unwrap(); + let AuxMetadata { + title, + thumbnail, + source_url, + artist, + duration, + .. + } = metadata; let timestamp = Timestamp::now(); let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; - + let description = format!("Enqueued tracks: {}", queue_length - 1); let embed = CreateEmbed::default() @@ -167,13 +225,28 @@ async fn generate_playlist_embed(ctx: Context<'_>, track: TrackHandle, queue_len .colour(Colour::from_rgb(255, 58, 97)) .title(title.as_ref().unwrap()) .url(source_url.as_ref().unwrap()) - .thumbnail(thumbnail.as_ref().unwrap_or(&ctx.cache().current_user().face())) - .field("Artist", artist.as_ref().unwrap_or(&"Unknown Artist".to_string()), true) - .field("Duration", format!("{:02}:{:02}", duration_minutes, duration_seconds), true) + .thumbnail( + thumbnail + .as_ref() + .unwrap_or(&ctx.cache().current_user().face()), + ) + .field( + "Artist", + artist.as_ref().unwrap_or(&"Unknown Artist".to_string()), + true, + ) + .field( + "Duration", + format!("{:02}:{:02}", duration_minutes, duration_seconds), + true, + ) .field("DJ", ctx.author().name.clone(), true) .description(description) .timestamp(timestamp) - .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + .footer( + CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()) + .icon_url(ctx.cache().current_user().face()), + ); Ok(embed) } diff --git a/src/commands/music/queue.rs b/src/commands/music/queue.rs index c94f691..3603c11 100644 --- a/src/commands/music/queue.rs +++ b/src/commands/music/queue.rs @@ -1,23 +1,19 @@ use std::time::Duration; -use crate::{commands::embeds::error_embed, Context, Error}; use crate::commands::music::metadata::Metadata; -use poise::CreateReply; -use serenity::{builder::{CreateEmbedAuthor, CreateEmbedFooter}, model::{Colour, Timestamp}}; +use crate::{commands::embeds::error_embed, Context, Error}; use poise::serenity_prelude::CreateEmbed; +use poise::CreateReply; +use serenity::{ + builder::{CreateEmbedAuthor, CreateEmbedFooter}, + model::{Colour, Timestamp}, +}; use songbird::input::AuxMetadata; /// Shows next tracks in queue; \ /// aliases: queue, q -#[poise::command( - prefix_command, - slash_command, - aliases("q"), - category = "Music" -)] -pub async fn queue( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, aliases("q"), category = "Music")] +pub async fn queue(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -33,12 +29,17 @@ pub async fn queue( for (index, song) in queue.current_queue().iter().enumerate() { let meta_typemap = song.typemap().read().await; let metadata = meta_typemap.get::().unwrap(); - let AuxMetadata { title, artist, duration, ..} = metadata; + let AuxMetadata { + title, + artist, + duration, + .. + } = metadata; let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; - // println!("{:?}", metadata.clone()); + // println!("{:?}", metadata.clone()); queue_res.push_str(&format!( "{}. {} - {} [{:02}:{:02}] \n", @@ -50,31 +51,31 @@ pub async fn queue( )); } - ctx.send( - CreateReply::default().embed(embed(ctx, queue_res).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(embed(ctx, queue_res).await.unwrap())) + .await?; } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } Ok(()) } async fn embed(ctx: Context<'_>, queue: String) -> Result { - let title = "Now playing"; let timestamp = Timestamp::now(); - + let embed = CreateEmbed::default() .author(CreateEmbedAuthor::new("Queue").icon_url(ctx.author().clone().face())) .colour(Colour::from_rgb(255, 58, 97)) .title(title) .description(queue) .timestamp(timestamp) - .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + .footer( + CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()) + .icon_url(ctx.cache().current_user().face()), + ); Ok(embed) } diff --git a/src/commands/music/repeat.rs b/src/commands/music/repeat.rs index 4bdf053..ee282d2 100644 --- a/src/commands/music/repeat.rs +++ b/src/commands/music/repeat.rs @@ -1,18 +1,23 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; use songbird::tracks::LoopState; /// Loops currently playing song provided amount of times; \ /// aliases: repeat, loop, while, for #[poise::command( - prefix_command, + prefix_command, slash_command, aliases("loop", "while", "for"), category = "Music" )] pub async fn repeat( - ctx: Context<'_>, - #[description = "How many times"] #[rest] times: usize + ctx: Context<'_>, + #[description = "How many times"] + #[rest] + times: usize, ) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); @@ -21,7 +26,6 @@ pub async fn repeat( .expect("Songbird client placed at init") .clone(); - if let Some(handler_lock) = manager.get(guild_id) { let handler = handler_lock.lock().await; let queue = handler.queue(); @@ -34,36 +38,52 @@ pub async fn repeat( let _ = queue.current().unwrap().disable_loop(); ctx.send( - CreateReply::default().embed(embed(ctx, "Song Unlooped!", "", "").await.unwrap()) - ).await?; + CreateReply::default() + .embed(embed(ctx, "Song Unlooped!", "", "").await.unwrap()), + ) + .await?; } - LoopState::Finite(_) => { + LoopState::Finite(_) => { if times == 0 { let _ = queue.current().unwrap().disable_loop(); ctx.send( - CreateReply::default().embed(embed(ctx, "Song Unlooped!", "", "").await.unwrap()) - ).await?; - } - else if times < 100 { + CreateReply::default() + .embed(embed(ctx, "Song Unlooped!", "", "").await.unwrap()), + ) + .await?; + } else if times < 100 { let _ = queue.current().unwrap().loop_for(times); ctx.send( - CreateReply::default().embed(embed(ctx, &format!("Song looped {} times!", times), "You definitelly love this song!", "").await.unwrap()) - ).await?; - } - else { + CreateReply::default().embed( + embed( + ctx, + &format!("Song looped {} times!", times), + "You definitelly love this song!", + "", + ) + .await + .unwrap(), + ), + ) + .await?; + } else { let _ = queue.current().unwrap().enable_loop(); ctx.send( - CreateReply::default().embed(embed(ctx, "Song looped forever!", "A very long time!", "").await.unwrap()) - ).await?; + CreateReply::default().embed( + embed(ctx, "Song looped forever!", "A very long time!", "") + .await + .unwrap(), + ), + ) + .await?; } } } - } else { + } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/resume.rs b/src/commands/music/resume.rs index 31236b4..1fd1be0 100644 --- a/src/commands/music/resume.rs +++ b/src/commands/music/resume.rs @@ -1,15 +1,12 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; /// Resumes currently paused song -#[poise::command( - prefix_command, - slash_command, - category = "Music" -)] -pub async fn resume( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn resume(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -24,13 +21,17 @@ pub async fn resume( ctx.say(format!("Song resumed.")).await?; ctx.send( - CreateReply::default().embed(embed(ctx, "Resumed!", "Currently paused song is now resumed!", "").await.unwrap()) - ).await?; + CreateReply::default().embed( + embed(ctx, "Resumed!", "Currently paused song is now resumed!", "") + .await + .unwrap(), + ), + ) + .await?; } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/seek.rs b/src/commands/music/seek.rs index e69de29..edee2c4 100644 --- a/src/commands/music/seek.rs +++ b/src/commands/music/seek.rs @@ -0,0 +1,11 @@ +use crate::{commands::embeds::embed, Context, Error}; +use poise::CreateReply; + +/// Seeks a track by provided seconds +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn seek(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/music/shuffle.rs b/src/commands/music/shuffle.rs index e69de29..e17028c 100644 --- a/src/commands/music/shuffle.rs +++ b/src/commands/music/shuffle.rs @@ -0,0 +1,11 @@ +use crate::{commands::embeds::embed, Context, Error}; +use poise::CreateReply; + +/// Shuffles the playlist +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn shuffle(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/music/skip.rs b/src/commands/music/skip.rs index 2256783..49cd4ad 100644 --- a/src/commands/music/skip.rs +++ b/src/commands/music/skip.rs @@ -1,15 +1,12 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; /// Skips the currently playing song -#[poise::command( - prefix_command, - slash_command, - category = "Music" -)] -pub async fn skip( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn skip(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); let manager = songbird::get(&ctx.serenity_context()) @@ -23,13 +20,22 @@ pub async fn skip( let _ = queue.skip(); ctx.send( - CreateReply::default().embed(embed(ctx, "Skipped!", "Next song: {song}", &format!("Songs left in queue: {}", queue.len())).await.unwrap()) - ).await?; + CreateReply::default().embed( + embed( + ctx, + "Skipped!", + "Next song: {song}", + &format!("Songs left in queue: {}", queue.len()), + ) + .await + .unwrap(), + ), + ) + .await?; } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } Ok(()) diff --git a/src/commands/music/soundboard.rs b/src/commands/music/soundboard.rs index e69de29..e0ae2f6 100644 --- a/src/commands/music/soundboard.rs +++ b/src/commands/music/soundboard.rs @@ -0,0 +1,11 @@ +use crate::{commands::embeds::embed, Context, Error}; +use poise::CreateReply; + +/// A better soundboard +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn soundboard(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/music/stop.rs b/src/commands/music/stop.rs index d1c15b9..ca13883 100644 --- a/src/commands/music/stop.rs +++ b/src/commands/music/stop.rs @@ -1,19 +1,15 @@ -use crate::{commands::embeds::{error_embed, embed}, Context, Error}; +use crate::{ + commands::embeds::{embed, error_embed}, + Context, Error, +}; use poise::CreateReply; /// Stops playback and destroys the queue; \ /// aliases: stop, end -#[poise::command( - prefix_command, - slash_command, - aliases("end"), - category = "Music" -)] -pub async fn stop( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, aliases("end"), category = "Music")] +pub async fn stop(ctx: Context<'_>) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); - + let manager = songbird::get(&ctx.serenity_context()) .await .expect("Songbird client placed at init") @@ -25,14 +21,23 @@ pub async fn stop( queue.stop(); ctx.send( - CreateReply::default().embed(embed(ctx, "Stopped!", "Playback stopped!", "Queue destroyed! Bot will stay and chill with you in a vc").await.unwrap()) - ).await?; - } else { + CreateReply::default().embed( + embed( + ctx, + "Stopped!", + "Playback stopped!", + "Queue destroyed! Bot will stay and chill with you in a vc", + ) + .await + .unwrap(), + ), + ) + .await?; + } else { let msg = "I am not in a voice channel!"; - ctx.send( - CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()) - ).await?; + ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap())) + .await?; } - + Ok(()) } diff --git a/src/commands/music/volume.rs b/src/commands/music/volume.rs index e69de29..77dc48a 100644 --- a/src/commands/music/volume.rs +++ b/src/commands/music/volume.rs @@ -0,0 +1,11 @@ +use crate::{commands::embeds::embed, Context, Error}; +use poise::CreateReply; + +/// Changes output volume +#[poise::command(prefix_command, slash_command, category = "Music")] +pub async fn volume(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools.rs b/src/commands/tools.rs index 75d982d..40721f2 100644 --- a/src/commands/tools.rs +++ b/src/commands/tools.rs @@ -1,9 +1,31 @@ -pub mod ping; -pub mod register; +pub mod ai; +pub mod dice; +pub mod dictionary; pub mod help; +pub mod ip; +pub mod metar; +pub mod owoify; +pub mod ping; pub mod posix; +pub mod qr; +pub mod register; +pub mod taf; +pub mod uptime; +pub mod verse; +pub mod weather; -pub use ping::ping; -pub use register::register; +pub use ai::ai; +pub use dice::dice; +pub use dictionary::dictionary; pub use help::help; +pub use ip::ip; +pub use metar::metar; +pub use owoify::owoify; +pub use ping::ping; pub use posix::posix; +pub use qr::qr; +pub use register::register; +pub use taf::taf; +pub use uptime::uptime; +pub use verse::verse; +pub use weather::weather; diff --git a/src/commands/tools/ai.rs b/src/commands/tools/ai.rs index e69de29..22e32c2 100644 --- a/src/commands/tools/ai.rs +++ b/src/commands/tools/ai.rs @@ -0,0 +1,50 @@ +use rand::Rng; + +use std::thread::sleep; +use std::time::Duration; + +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Asks AI +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn ai( + ctx: Context<'_>, + #[description = "prompt to ask"] + #[rest] + prompt: String, +) -> Result<(), Error> { + let iamsorry = vec![ + "I'm sorry, but as an AI language model, I must follow ethical guidelines, and I cannot engage in harmful, malicious, or offensive behavior.", + "I'm sorry, but as an AI language model, I may not always be perfect and can make mistakes or provide inaccurate information. Please verify important details from reliable sources.", + "I'm sorry, but as an AI language model, I can't engage in real-time conversations or remember previous interactions with users.", + "I'm sorry, but as an AI language model, I don't have personal opinions or feelings; I can only provide information based on patterns in the data I was trained on.", + "I'm sorry, but as an AI language model, I don't have access to real-time information or updates beyond my last training data in September 2021.", + "I'm sorry, but as an AI language model, I don't have the ability to recall specific personal data or information about individuals.", + "I'm sorry, but as an AI language model, I don't have consciousness or self-awareness. I'm simply a program designed to process and generate human-like text." + ]; + + println!("Funny prompts: {}", prompt); + + let response; + + let _ = { + let mut rng = rand::thread_rng(); + + response = rng.gen_range(0..iamsorry.len()); + }; + + sleep(Duration::from_secs(3)); + + ctx.send( + CreateReply::default().embed( + embed(ctx, "AI Response:", "", &format!("{}", iamsorry[response])) + .await + .unwrap(), + ), + ) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/dice.rs b/src/commands/tools/dice.rs index e69de29..fb81c45 100644 --- a/src/commands/tools/dice.rs +++ b/src/commands/tools/dice.rs @@ -0,0 +1,33 @@ +use rand::Rng; + +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Rolls a dice +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn dice(ctx: Context<'_>) -> Result<(), Error> { + let dice; + + let _ = { + let mut rng = rand::thread_rng(); + + dice = rng.gen_range(1..7); + }; + + ctx.send( + CreateReply::default().embed( + embed( + ctx, + "Let's roll the dice!", + "", + &format!("Your number is: {}", dice), + ) + .await + .unwrap(), + ), + ) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/dictionary.rs b/src/commands/tools/dictionary.rs index e69de29..aab5b04 100644 --- a/src/commands/tools/dictionary.rs +++ b/src/commands/tools/dictionary.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Explains provided query +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn dictionary(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/ip.rs b/src/commands/tools/ip.rs index e69de29..1a3600b 100644 --- a/src/commands/tools/ip.rs +++ b/src/commands/tools/ip.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Shows IP information +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn ip(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/metar.rs b/src/commands/tools/metar.rs index e69de29..cf012ca 100644 --- a/src/commands/tools/metar.rs +++ b/src/commands/tools/metar.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Prints metar for provided airport +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn metar(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/owoify.rs b/src/commands/tools/owoify.rs index e69de29..e676faa 100644 --- a/src/commands/tools/owoify.rs +++ b/src/commands/tools/owoify.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Owoifies whatever you want uwu +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn owoify(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/ping.rs b/src/commands/tools/ping.rs index b1bbfff..ddc04d1 100644 --- a/src/commands/tools/ping.rs +++ b/src/commands/tools/ping.rs @@ -2,17 +2,12 @@ use crate::{Context, Error}; use std::time::SystemTime; /// Pings you backs with a response time -#[poise::command( - prefix_command, - slash_command, - category = "Tools" -)] -pub async fn ping( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn ping(ctx: Context<'_>) -> Result<(), Error> { let system_now = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .unwrap().as_millis() as i64; + .unwrap() + .as_millis() as i64; let message_now = ctx.created_at().timestamp_millis(); diff --git a/src/commands/tools/posix.rs b/src/commands/tools/posix.rs index 2d89683..d9a92b3 100644 --- a/src/commands/tools/posix.rs +++ b/src/commands/tools/posix.rs @@ -5,19 +5,26 @@ use poise::CreateReply; use crate::{commands::embeds::embed, Context, Error}; /// Prints current time in POSIX format -#[poise::command( - prefix_command, - slash_command, - category = "Tools" -)] -pub async fn posix( - ctx: Context<'_> -) -> Result<(), Error> { - let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis(); +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn posix(ctx: Context<'_>) -> Result<(), Error> { + let time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_millis(); ctx.send( - CreateReply::default().embed(embed(ctx, "The time is", &format!("{} ms", time), "since Jan 1st 1970").await.unwrap()) - ).await?; + CreateReply::default().embed( + embed( + ctx, + "The time is", + "since Jan 1st 1970", + &format!("{} ms", time), + ) + .await + .unwrap(), + ), + ) + .await?; Ok(()) } diff --git a/src/commands/tools/qr.rs b/src/commands/tools/qr.rs index e69de29..a27bfba 100644 --- a/src/commands/tools/qr.rs +++ b/src/commands/tools/qr.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Creates a qr code from text +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn qr(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/register.rs b/src/commands/tools/register.rs index 9bf1f08..b252af5 100644 --- a/src/commands/tools/register.rs +++ b/src/commands/tools/register.rs @@ -1,13 +1,7 @@ use crate::{Context, Error}; -#[poise::command( - prefix_command, - hide_in_help, - owners_only -)] -pub async fn register( - ctx: Context<'_> -) -> Result<(), Error> { +#[poise::command(prefix_command, hide_in_help, owners_only)] +pub async fn register(ctx: Context<'_>) -> Result<(), Error> { poise::builtins::register_application_commands_buttons(ctx).await?; Ok(()) } diff --git a/src/commands/tools/taf.rs b/src/commands/tools/taf.rs index e69de29..d9f6f5a 100644 --- a/src/commands/tools/taf.rs +++ b/src/commands/tools/taf.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Returns taf for provided airport +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn taf(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/uptime.rs b/src/commands/tools/uptime.rs index e69de29..975eaf4 100644 --- a/src/commands/tools/uptime.rs +++ b/src/commands/tools/uptime.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Checks how long the bot has been running +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn uptime(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/verse.rs b/src/commands/tools/verse.rs index e69de29..8598c73 100644 --- a/src/commands/tools/verse.rs +++ b/src/commands/tools/verse.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Reference Bible by verse +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn verse(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/commands/tools/weather.rs b/src/commands/tools/weather.rs index e69de29..9bf5039 100644 --- a/src/commands/tools/weather.rs +++ b/src/commands/tools/weather.rs @@ -0,0 +1,12 @@ +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Shows weather for provided location +#[poise::command(prefix_command, slash_command, category = "Tools")] +pub async fn weather(ctx: Context<'_>) -> Result<(), Error> { + ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap())) + .await?; + + Ok(()) +} diff --git a/src/http.rs b/src/http.rs index e2b18b0..819e750 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,5 +1,5 @@ -use reqwest::Client as HttpClient; use poise::serenity_prelude::prelude::TypeMapKey; +use reqwest::Client as HttpClient; pub struct HttpKey; diff --git a/src/main.rs b/src/main.rs index 1bda848..afc3cfa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ +use poise::serenity_prelude::{self as serenity, ActivityData}; +use reqwest::Client as HttpClient; +use songbird::SerenityInit; use std::sync::Arc; use std::time::Duration; -use tracing::{info, warn, error}; -use poise::serenity_prelude::{self as serenity, ActivityData}; -use songbird::SerenityInit; -use reqwest::Client as HttpClient; +use tracing::{error, info, warn}; mod commands; mod http; @@ -37,7 +37,8 @@ async fn main() { tracing_subscriber::fmt::init(); dotenv::dotenv().expect("Failed to load .env file."); - let token = std::env::var("DISCORD_TOKEN").expect("Environment variable `DISCORD_TOKEN` not found!"); + let token = + std::env::var("DISCORD_TOKEN").expect("Environment variable `DISCORD_TOKEN` not found!"); let prefix = std::env::var("PREFIX").expect("Environment variable `PREFIX` not found!"); let commands = vec![ @@ -45,18 +46,33 @@ async fn main() { music::deafen(), music::join(), music::leave(), - music::repeat(), music::mute(), music::pause(), music::play(), music::queue(), + music::repeat(), music::resume(), + music::seek(), + music::shuffle(), music::skip(), + music::soundboard(), music::stop(), - tools::ping(), - tools::register(), + music::volume(), + tools::ai(), + tools::dice(), + tools::dictionary(), tools::help(), + tools::ip(), + tools::metar(), + tools::owoify(), + tools::ping(), tools::posix(), + tools::qr(), + tools::register(), + tools::taf(), + tools::uptime(), + tools::verse(), + tools::weather(), ]; let options = poise::FrameworkOptions { @@ -96,7 +112,10 @@ async fn main() { skip_checks_for_owners: false, event_handler: |_ctx, event, _framework, _data| { Box::pin(async move { - info!("Got an event in event handler: {:?}", event.snake_case_name()); + info!( + "Got an event in event handler: {:?}", + event.snake_case_name() + ); Ok(()) }) }, @@ -106,7 +125,10 @@ async fn main() { let framework = poise::Framework::builder() .setup(move |ctx, ready, _framework| { Box::pin(async move { - info!("{} [{}] connected successfully!", ready.user.name, ready.user.id); + info!( + "{} [{}] connected successfully!", + ready.user.name, ready.user.id + ); ctx.set_activity(Some(ActivityData::listening(prefix + "help"))); // poise::builtins::register_globally(ctx, &framework.options().commands).await?; @@ -116,7 +138,8 @@ async fn main() { .options(options) .build(); - let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; + let intents = + serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; let mut client = serenity::ClientBuilder::new(token, intents) .framework(framework)