From cea5958e43e92c089096667bcb414bbacc5f24d4 Mon Sep 17 00:00:00 2001 From: Davide Polonio Date: Tue, 28 Sep 2021 15:20:28 +0200 Subject: [PATCH] feat: add support for album links - perform little code refactor, create new module spotify --- Cargo.toml | 2 +- src/main.rs | 77 ++++++++++++++++++++++++---------------------- src/spotify/mod.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/spotify/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 37f1f2b..7a80f6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "songlify" -version = "0.1.0" +version = "0.2.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/main.rs b/src/main.rs index 492b240..501a043 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,39 +1,13 @@ -use crate::SpotifyURL::Track; -use aspotify::{Client, ClientCredentials}; use std::time::Duration; + +use aspotify::Client; use teloxide::prelude::*; -enum SpotifyURL { - Track(String), -} +use spotify::SpotifyKind::Track; -struct TrackInfo { - name: String, - artist: Vec, - duration: Duration, -} +use crate::spotify::SpotifyKind::Album; -fn get_spotify_entry(url: &str) -> Option { - if url.contains("https://open.spotify.com/track/") { - let track_id = url.rsplit('/').next().and_then(|x| x.split('?').next()); - return match track_id { - Some(id) => Some(SpotifyURL::Track(id.to_string())), - None => None, - }; - } - return None; -} - -async fn get_spotify_track(spotify: Box, id: &String) -> Option { - match spotify.tracks().get_track(id.as_str(), None).await { - Ok(track) => Some(TrackInfo { - name: track.data.name, - artist: track.data.artists.iter().map(|x| x.name.clone()).collect(), - duration: track.data.duration, - }), - Err(_e) => None, - } -} +mod spotify; #[tokio::main] async fn main() { @@ -42,16 +16,14 @@ async fn main() { let bot = Bot::from_env().auto_send(); teloxide::repl(bot, |message| async move { - let text = message.update.text().and_then(get_spotify_entry); + let text = message.update.text().and_then(spotify::get_spotify_entry); match text { Some(spotify) => { - let spotify_creds = - ClientCredentials::from_env().expect("CLIENT_ID and CLIENT_SECRET not found."); - let spotify_client = Box::new(Client::new(spotify_creds)); + let spotify_client = spotify::get_spotify_client(); match spotify { Track(id) => { log::debug!("Parsing spotify song: {}", id); - let track_info = get_spotify_track(spotify_client, &id).await; + let track_info = spotify::get_spotify_track(spotify_client, &id).await; match track_info { Some(info) => { let reply = format!( @@ -60,7 +32,7 @@ async fn main() { šŸ§‘ā€šŸŽ¤ Artist(s): {}\n\ ā³ Duration: {} second(s)", info.name, - info.artist.join(", "), + info.artists.join(", "), info.duration.as_secs() ); Some(message.reply_to(reply).await?) @@ -68,6 +40,37 @@ async fn main() { None => None, } } + Album(id) => { + log::debug!("Parsing spotify album: {}", id); + let album_info = spotify::get_spotify_album(spotify_client, &id).await; + match album_info { + Some(info) => { + let mut reply = format!( + "Album information:\n\ + šŸŽµ Album name name: {}\n\ + šŸ§‘ā€šŸŽ¤ Artist(s): {}", + info.name, + info.artists.join(", ") + ); + if !info.genres.is_empty() { + reply.push_str( + format!("\nšŸ’æ Genre(s): {}", info.genres.join(", ")) + .as_str(), + ); + } + if !info.songs.is_empty() { + let songs = info + .songs + .iter() + .map(|x| x.name.clone() + "\n") + .collect::(); + reply.push_str(format!("\nšŸŽ¶ Song(s): {}", songs).as_str()); + } + Some(message.reply_to(reply).await?) + } + None => None, + } + } } } None => None, diff --git a/src/spotify/mod.rs b/src/spotify/mod.rs new file mode 100644 index 0000000..e56f36b --- /dev/null +++ b/src/spotify/mod.rs @@ -0,0 +1,76 @@ +use std::time::Duration; + +use aspotify::{Client, ClientCredentials}; + +pub enum SpotifyKind { + Track(String), + Album(String), +} + +fn get_id_in_url(url: &str) -> Option<&str> { + url.rsplit('/') + .next() + .and_then(|x| x.split(' ').next()) + .and_then(|x| x.split('?').next()) +} + +pub fn get_spotify_entry(url: &str) -> Option { + if url.contains("https://open.spotify.com/track/") { + let track_id = get_id_in_url(url); + return match track_id { + Some(id) => Some(SpotifyKind::Track(id.to_string())), + None => None, + }; + } + if url.contains("https://open.spotify.com/album/") { + let album_id = get_id_in_url(url); + return match album_id { + Some(id) => Some(SpotifyKind::Album(id.to_string())), + None => None, + }; + } + return None; +} + +pub fn get_spotify_client() -> Box { + let spotify_creds = + ClientCredentials::from_env().expect("CLIENT_ID and CLIENT_SECRET not found."); + let spotify_client = Box::new(Client::new(spotify_creds)); + spotify_client +} + +struct TrackInfo { + name: String, + artists: Vec, + duration: Duration, +} + +struct AlbumInfo { + pub(crate) name: String, + pub(crate) artists: Vec, + pub(crate) genres: Vec, + songs: Vec, +} + +pub async fn get_spotify_track(spotify: Box, id: &String) -> Option { + match spotify.tracks().get_track(id.as_str(), None).await { + Ok(track) => Some(TrackInfo { + name: track.data.name, + artists: track.data.artists.iter().map(|x| x.name.clone()).collect(), + duration: track.data.duration, + }), + Err(_e) => None, + } +} + +pub async fn get_spotify_album(spotify: Box, id: &String) -> Option { + match spotify.albums().get_album(id.as_str(), None).await { + Ok(album) => Some(AlbumInfo { + name: album.data.name, + artists: album.data.artists.iter().map(|x| x.name.clone()).collect(), + genres: album.data.genres, + songs: vec![], // TODO we could lookup songs and put them here! + }), + Err(_e) => None, + } +}