mirror of
https://github.com/eRgo35/lyra.git
synced 2026-02-04 12:26:10 +01:00
soundboard and some tools
This commit is contained in:
@@ -10,7 +10,6 @@ pub mod queue;
|
||||
pub mod repeat;
|
||||
pub mod resume;
|
||||
pub mod seek;
|
||||
pub mod shuffle;
|
||||
pub mod skip;
|
||||
pub mod soundboard;
|
||||
pub mod stop;
|
||||
@@ -26,7 +25,6 @@ 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 stop::stop;
|
||||
pub use volume::volume;
|
||||
|
||||
@@ -19,7 +19,6 @@ pub async fn resume(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let queue = handler.queue();
|
||||
let _ = queue.resume();
|
||||
|
||||
ctx.say(format!("Song resumed.")).await?;
|
||||
ctx.send(
|
||||
CreateReply::default().embed(
|
||||
embed(ctx, "Resumed!", "Currently paused song is now resumed!", "")
|
||||
|
||||
@@ -1,11 +1,51 @@
|
||||
use crate::{commands::embeds::embed, Context, Error};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{
|
||||
commands::embeds::{embed, error_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()))
|
||||
pub async fn seek(
|
||||
ctx: Context<'_>,
|
||||
#[description = "How many seconds shall I seek"] seek: u64,
|
||||
) -> Result<(), Error> {
|
||||
let guild_id = ctx.guild_id().unwrap();
|
||||
|
||||
let manager = songbird::get(&ctx.serenity_context())
|
||||
.await
|
||||
.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();
|
||||
|
||||
let seek_duration = Duration::from_secs(seek);
|
||||
|
||||
let track = queue.current().unwrap();
|
||||
let _ = track.seek(seek_duration);
|
||||
|
||||
ctx.send(
|
||||
CreateReply::default().embed(
|
||||
embed(
|
||||
ctx,
|
||||
"Track seeked!",
|
||||
&format!("Track seeked by: {} seconds", seek),
|
||||
"",
|
||||
)
|
||||
.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?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
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(())
|
||||
}
|
||||
@@ -1,11 +1,117 @@
|
||||
use crate::{commands::embeds::embed, Context, Error};
|
||||
use crate::{commands::embeds::error_embed, Context, Error};
|
||||
|
||||
use poise::serenity_prelude::model::Timestamp;
|
||||
use poise::serenity_prelude::Colour;
|
||||
use poise::serenity_prelude::CreateEmbed;
|
||||
use poise::CreateReply;
|
||||
use serenity::builder::CreateEmbedAuthor;
|
||||
use serenity::builder::CreateEmbedFooter;
|
||||
use songbird::events::TrackEvent;
|
||||
use songbird::input::AuxMetadata;
|
||||
use songbird::input::{Compose, YoutubeDl};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::commands::music::notifier::TrackErrorNotifier;
|
||||
use crate::http::HttpKey;
|
||||
|
||||
/// Plays one of available audio effects
|
||||
#[poise::command(prefix_command, slash_command, category = "Music")]
|
||||
pub async fn effect(ctx: Context<'_>) -> Result<(), Error> {
|
||||
ctx.send(CreateReply::default().embed(embed(ctx, "Playing an effect", "", "").await.unwrap()))
|
||||
.await?;
|
||||
pub async fn effect(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Shall output pause?"]
|
||||
#[flag]
|
||||
pause: bool,
|
||||
#[description = "Provide a query or an url"]
|
||||
#[rest]
|
||||
mut song: String,
|
||||
) -> Result<(), Error> {
|
||||
let is_query = !song.starts_with("http");
|
||||
|
||||
let guild_id = ctx.guild_id().unwrap();
|
||||
|
||||
let http_client = {
|
||||
let data = ctx.serenity_context().data.read().await;
|
||||
data.get::<HttpKey>()
|
||||
.cloned()
|
||||
.expect("Guaranteed to exist in the typemap.")
|
||||
};
|
||||
|
||||
let manager = songbird::get(&ctx.serenity_context())
|
||||
.await
|
||||
.expect("Songbird Voice placed at init")
|
||||
.clone();
|
||||
|
||||
if pause {
|
||||
if let Some(handler_lock) = manager.get(guild_id) {
|
||||
let handler = handler_lock.lock().await;
|
||||
let queue = handler.queue();
|
||||
let _ = queue.pause();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(handler_lock) = manager.get(guild_id) {
|
||||
let mut handler = handler_lock.lock().await;
|
||||
|
||||
handler.add_global_event(TrackEvent::Error.into(), TrackErrorNotifier);
|
||||
|
||||
if is_query {
|
||||
song = format!("ytsearch:{}", song);
|
||||
}
|
||||
|
||||
let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client, song);
|
||||
let embed = generate_embed(ctx, src.clone()).await;
|
||||
let response = CreateReply::default().embed(embed.unwrap());
|
||||
ctx.send(response).await?;
|
||||
|
||||
let _ = handler.play_input(src.clone().into());
|
||||
} else {
|
||||
let msg = "I am not in a voice channel!";
|
||||
ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn generate_embed(ctx: Context<'_>, src: YoutubeDl) -> Result<CreateEmbed, Error> {
|
||||
let metadata = src.clone().aux_metadata().await.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!("Playing now!");
|
||||
|
||||
let embed = CreateEmbed::default()
|
||||
.author(CreateEmbedAuthor::new("Playing an effect!").icon_url(ctx.author().clone().face()))
|
||||
.colour(Colour::from_rgb(255, 58, 97))
|
||||
.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("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()),
|
||||
);
|
||||
|
||||
Ok(embed)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,126 @@
|
||||
use crate::{commands::embeds::embed, Context, Error};
|
||||
use poise::CreateReply;
|
||||
use crate::{commands::embeds::error_embed, Context, Error};
|
||||
|
||||
/// Hijacks current audio output and plays selected audio
|
||||
#[poise::command(prefix_command, slash_command, aliases("override"), category = "Music")]
|
||||
pub async fn stream(ctx: Context<'_>) -> Result<(), Error> {
|
||||
ctx.send(CreateReply::default().embed(embed(ctx, "Playing audio", "", "").await.unwrap()))
|
||||
.await?;
|
||||
use poise::serenity_prelude::model::Timestamp;
|
||||
use poise::serenity_prelude::Colour;
|
||||
use poise::serenity_prelude::CreateEmbed;
|
||||
use poise::CreateReply;
|
||||
use serenity::builder::CreateEmbedAuthor;
|
||||
use serenity::builder::CreateEmbedFooter;
|
||||
use songbird::events::TrackEvent;
|
||||
use songbird::input::AuxMetadata;
|
||||
use songbird::input::{Compose, YoutubeDl};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::commands::music::notifier::TrackErrorNotifier;
|
||||
use crate::http::HttpKey;
|
||||
|
||||
/// Hijacks output and plays audio; \
|
||||
/// search by query or paste an url; \
|
||||
/// aliases: stream, override, hijack
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
aliases("override", "hijack"),
|
||||
category = "Music"
|
||||
)]
|
||||
pub async fn stream(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Shall output pause?"]
|
||||
#[flag]
|
||||
pause: bool,
|
||||
#[description = "Provide a query or an url"]
|
||||
#[rest]
|
||||
mut song: String,
|
||||
) -> Result<(), Error> {
|
||||
let is_query = !song.starts_with("http");
|
||||
|
||||
let guild_id = ctx.guild_id().unwrap();
|
||||
|
||||
let http_client = {
|
||||
let data = ctx.serenity_context().data.read().await;
|
||||
data.get::<HttpKey>()
|
||||
.cloned()
|
||||
.expect("Guaranteed to exist in the typemap.")
|
||||
};
|
||||
|
||||
let manager = songbird::get(&ctx.serenity_context())
|
||||
.await
|
||||
.expect("Songbird Voice placed at init")
|
||||
.clone();
|
||||
|
||||
if pause {
|
||||
if let Some(handler_lock) = manager.get(guild_id) {
|
||||
let handler = handler_lock.lock().await;
|
||||
let queue = handler.queue();
|
||||
let _ = queue.pause();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(handler_lock) = manager.get(guild_id) {
|
||||
let mut handler = handler_lock.lock().await;
|
||||
|
||||
handler.add_global_event(TrackEvent::Error.into(), TrackErrorNotifier);
|
||||
|
||||
if is_query {
|
||||
song = format!("ytsearch:{}", song);
|
||||
}
|
||||
|
||||
let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client, song);
|
||||
let embed = generate_embed(ctx, src.clone()).await;
|
||||
let response = CreateReply::default().embed(embed.unwrap());
|
||||
ctx.send(response).await?;
|
||||
|
||||
let _ = handler.play_input(src.clone().into());
|
||||
} else {
|
||||
let msg = "I am not in a voice channel!";
|
||||
ctx.send(CreateReply::default().embed(error_embed(ctx, msg).await.unwrap()))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn generate_embed(ctx: Context<'_>, src: YoutubeDl) -> Result<CreateEmbed, Error> {
|
||||
let metadata = src.clone().aux_metadata().await.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!("Playing now!");
|
||||
|
||||
let embed = CreateEmbed::default()
|
||||
.author(
|
||||
CreateEmbedAuthor::new("Audio output hijacked!").icon_url(ctx.author().clone().face()),
|
||||
)
|
||||
.colour(Colour::from_rgb(255, 58, 97))
|
||||
.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("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()),
|
||||
);
|
||||
|
||||
Ok(embed)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,44 @@
|
||||
use crate::{commands::embeds::embed, Context, Error};
|
||||
use crate::{
|
||||
commands::embeds::{embed, error_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()))
|
||||
pub async fn volume(ctx: Context<'_>, #[description = "Volume"] volume: f32) -> Result<(), Error> {
|
||||
let guild_id = ctx.guild_id().unwrap();
|
||||
|
||||
let manager = songbird::get(&ctx.serenity_context())
|
||||
.await
|
||||
.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();
|
||||
|
||||
let track = queue.current().unwrap();
|
||||
let _ = track.set_volume(volume / 100.0);
|
||||
|
||||
ctx.send(
|
||||
CreateReply::default().embed(
|
||||
embed(
|
||||
ctx,
|
||||
"Volume changed",
|
||||
"",
|
||||
&format!("Set volume to {}%", volume),
|
||||
)
|
||||
.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?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,72 @@
|
||||
use poise::CreateReply;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::form_urlencoded;
|
||||
|
||||
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?;
|
||||
#[poise::command(prefix_command, slash_command, aliases("dict"), category = "Tools")]
|
||||
pub async fn dictionary(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Word you're looking for"]
|
||||
#[rest]
|
||||
word: String,
|
||||
) -> Result<(), Error> {
|
||||
let data: String = form_urlencoded::byte_serialize(word.as_bytes()).collect();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let response = client
|
||||
.get(format!(
|
||||
"https://api.dictionaryapi.dev/api/v2/entries/en/{}",
|
||||
data
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match response.status() {
|
||||
reqwest::StatusCode::OK => match response.json::<Vec<Word>>().await {
|
||||
Ok(parsed) => {
|
||||
println!("{:?}", parsed);
|
||||
|
||||
ctx.send(CreateReply::default().embed(embed(ctx, "", "", "").await.unwrap()))
|
||||
.await?;
|
||||
}
|
||||
Err(err) => println!("Something is messed up! {:?}", err),
|
||||
},
|
||||
reqwest::StatusCode::UNAUTHORIZED => {
|
||||
println!("Unauthorized.. Uoops!!");
|
||||
}
|
||||
error => {
|
||||
println!("Something went wrong: {:?}", error);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Definition {
|
||||
definition: String,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Meaning {
|
||||
partOfSpeech: String,
|
||||
definitions: Vec<Definition>,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Phonetic {
|
||||
text: Option<String>,
|
||||
audio: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Word {
|
||||
word: String,
|
||||
phonetics: Vec<Phonetic>,
|
||||
meanings: Vec<Meaning>,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
use owoify::OwOifiable;
|
||||
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()))
|
||||
pub async fn owoify(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Text to owoify w-woify OwO"]
|
||||
#[rest]
|
||||
text: String,
|
||||
) -> Result<(), Error> {
|
||||
ctx.send(CreateReply::default().embed(embed(ctx, "OwO", &text.owoify(), "").await.unwrap()))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -53,7 +53,6 @@ async fn main() {
|
||||
music::repeat(),
|
||||
music::resume(),
|
||||
music::seek(),
|
||||
music::shuffle(),
|
||||
music::skip(),
|
||||
music::stop(),
|
||||
music::volume(),
|
||||
|
||||
Reference in New Issue
Block a user