From 750ee7d0dccc2bf1e2cf1f7a2bd6807ab55468ff Mon Sep 17 00:00:00 2001 From: trivernis Date: Fri, 9 Apr 2021 13:55:54 +0200 Subject: [PATCH] Add lyrics command and format playlists list differently Signed-off-by: trivernis --- Cargo.lock | 1 + Cargo.toml | 3 ++- src/commands/music/lyrics.rs | 45 +++++++++++++++++++++++++++++++++ src/commands/music/mod.rs | 5 +++- src/commands/music/playlists.rs | 9 +++++-- src/providers/music/lyrics.rs | 24 ++++++++++++++++++ src/providers/music/mod.rs | 1 + src/utils/error.rs | 3 +++ 8 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/commands/music/lyrics.rs create mode 100644 src/providers/music/lyrics.rs diff --git a/Cargo.lock b/Cargo.lock index a1659cf..03788da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2109,6 +2109,7 @@ dependencies = [ "minecraft-data-rs", "rand 0.8.3", "regex", + "reqwest", "rusqlite", "serde", "serde_derive", diff --git a/Cargo.toml b/Cargo.toml index bd68c2d..671b6d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,4 +28,5 @@ fern = "0.6.0" chrono = "0.4.19" colored = "2.0.0" sysinfo = "0.16.5" -database = {path="./database"} \ No newline at end of file +database = {path="./database"} +reqwest = "0.11.2" \ No newline at end of file diff --git a/src/commands/music/lyrics.rs b/src/commands/music/lyrics.rs new file mode 100644 index 0000000..3fa7595 --- /dev/null +++ b/src/commands/music/lyrics.rs @@ -0,0 +1,45 @@ +use serenity::client::Context; +use serenity::framework::standard::macros::command; +use serenity::framework::standard::CommandResult; +use serenity::model::channel::Message; + +use crate::commands::music::get_queue_for_guild; +use crate::providers::music::lyrics::get_lyrics; + +#[command] +#[only_in(guilds)] +#[description("Shows the lyrics for the currently playing song")] +#[usage("")] +async fn lyrics(ctx: &Context, msg: &Message) -> CommandResult { + let guild = msg.guild(&ctx.cache).await.unwrap(); + log::debug!("Fetching lyrics for song playing in {}", guild.id); + + let queue = get_queue_for_guild(ctx, &guild.id).await?; + let queue_lock = queue.lock().await; + + if let Some(current) = queue_lock.current() { + log::debug!("Playing music. Fetching lyrics for currently playing song..."); + let metadata = current.metadata(); + let title = metadata.title.clone().unwrap(); + let author = metadata.artist.clone().unwrap(); + + if let Some(lyrics) = get_lyrics(&*author, &*title).await? { + log::trace!("Lyrics for '{}' are {}", title, lyrics); + + msg.channel_id + .send_message(ctx, |m| { + m.embed(|e| e.title(format!("Lyrics for {}", title)).description(lyrics)) + }) + .await?; + } else { + log::debug!("No lyrics found"); + msg.channel_id.say(ctx, "No lyrics found").await?; + } + } else { + msg.channel_id + .say(ctx, "I'm not playing music right now") + .await?; + } + + Ok(()) +} diff --git a/src/commands/music/mod.rs b/src/commands/music/mod.rs index 8a6d081..c5b5529 100644 --- a/src/commands/music/mod.rs +++ b/src/commands/music/mod.rs @@ -16,6 +16,7 @@ use clear::CLEAR_COMMAND; use current::CURRENT_COMMAND; use join::JOIN_COMMAND; use leave::LEAVE_COMMAND; +use lyrics::LYRICS_COMMAND; use pause::PAUSE_COMMAND; use play::PLAY_COMMAND; use play_next::PLAY_NEXT_COMMAND; @@ -39,6 +40,7 @@ mod clear; mod current; mod join; mod leave; +mod lyrics; mod pause; mod play; mod play_next; @@ -61,7 +63,8 @@ mod skip; clear, pause, save_playlist, - playlists + playlists, + lyrics )] #[prefixes("m", "music")] pub struct Music; diff --git a/src/commands/music/playlists.rs b/src/commands/music/playlists.rs index c032147..03ae07a 100644 --- a/src/commands/music/playlists.rs +++ b/src/commands/music/playlists.rs @@ -17,8 +17,13 @@ async fn playlists(ctx: &Context, msg: &Message) -> CommandResult { msg.channel_id .send_message(ctx, |m| { m.embed(|e| { - e.title("Saved Playlists") - .fields(playlists.into_iter().map(|p| (p.name, p.url, true))) + e.title("Saved Playlists").description( + playlists + .into_iter() + .map(|p| format!("[{}]({})", p.name, p.url)) + .collect::>() + .join("\n"), + ) }) }) .await?; diff --git a/src/providers/music/lyrics.rs b/src/providers/music/lyrics.rs new file mode 100644 index 0000000..4d9d306 --- /dev/null +++ b/src/providers/music/lyrics.rs @@ -0,0 +1,24 @@ +use crate::utils::error::BotResult; +use regex::Regex; +use serde_derive::Deserialize; + +const API_ENDPOINT: &str = "https://api.lyrics.ovh/v1/"; + +pub async fn get_lyrics(artist: &str, title: &str) -> BotResult> { + lazy_static::lazy_static! { static ref DOUBLE_LB_REGEX: Regex = Regex::new(r"\n\n").unwrap(); } + log::debug!("Requesting lyrics for '{}' by '{}'", title, artist); + let request_url = format!("{}{}/{}", API_ENDPOINT, artist, title); + log::trace!("Request url is {}", request_url); + let response = reqwest::get(request_url).await?; + let response_text = response.text().await?; + log::trace!("Lyrics Response is {}", response_text); + + let lyrics: Option = serde_json::from_str(&*response_text).ok(); + + Ok(lyrics.map(|l| DOUBLE_LB_REGEX.replace_all(&*l.lyrics, "\n").to_string())) +} + +#[derive(Deserialize, Clone, Debug)] +struct Lyrics { + lyrics: String, +} diff --git a/src/providers/music/mod.rs b/src/providers/music/mod.rs index dd604c4..16e337c 100644 --- a/src/providers/music/mod.rs +++ b/src/providers/music/mod.rs @@ -10,6 +10,7 @@ use std::time::Duration; use tokio::io::AsyncReadExt; use tokio::process::Command; +pub(crate) mod lyrics; pub(crate) mod queue; pub(crate) mod responses; pub(crate) mod spotify; diff --git a/src/utils/error.rs b/src/utils/error.rs index 31ce166..8445d8e 100644 --- a/src/utils/error.rs +++ b/src/utils/error.rs @@ -25,6 +25,9 @@ pub enum BotError { #[error("Spotify API Error: {0}")] SpotifyError(#[from] aspotify::Error), + #[error("Reqwest Error: {0}")] + Reqwest(#[from] reqwest::Error), + #[error("{0}")] Msg(String), }