feat: add support for album links

- perform little code refactor, create new module spotify
pull/1/head
Davide Polonio 2021-09-28 15:20:28 +02:00
parent 34c294ef0f
commit cea5958e43
3 changed files with 117 additions and 38 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "songlify" name = "songlify"
version = "0.1.0" version = "0.2.0"
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,39 +1,13 @@
use crate::SpotifyURL::Track;
use aspotify::{Client, ClientCredentials};
use std::time::Duration; use std::time::Duration;
use aspotify::Client;
use teloxide::prelude::*; use teloxide::prelude::*;
enum SpotifyURL { use spotify::SpotifyKind::Track;
Track(String),
}
struct TrackInfo { use crate::spotify::SpotifyKind::Album;
name: String,
artist: Vec<String>,
duration: Duration,
}
fn get_spotify_entry(url: &str) -> Option<SpotifyURL> { mod spotify;
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<Client>, id: &String) -> Option<TrackInfo> {
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,
}
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -42,16 +16,14 @@ async fn main() {
let bot = Bot::from_env().auto_send(); let bot = Bot::from_env().auto_send();
teloxide::repl(bot, |message| async move { 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 { match text {
Some(spotify) => { Some(spotify) => {
let spotify_creds = let spotify_client = spotify::get_spotify_client();
ClientCredentials::from_env().expect("CLIENT_ID and CLIENT_SECRET not found.");
let spotify_client = Box::new(Client::new(spotify_creds));
match spotify { match spotify {
Track(id) => { Track(id) => {
log::debug!("Parsing spotify song: {}", 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 { match track_info {
Some(info) => { Some(info) => {
let reply = format!( let reply = format!(
@ -60,7 +32,7 @@ async fn main() {
🧑🎤 Artist(s): {}\n\ 🧑🎤 Artist(s): {}\n\
Duration: {} second(s)", Duration: {} second(s)",
info.name, info.name,
info.artist.join(", "), info.artists.join(", "),
info.duration.as_secs() info.duration.as_secs()
); );
Some(message.reply_to(reply).await?) Some(message.reply_to(reply).await?)
@ -68,6 +40,37 @@ async fn main() {
None => None, 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::<String>();
reply.push_str(format!("\n🎶 Song(s): {}", songs).as_str());
}
Some(message.reply_to(reply).await?)
}
None => None,
}
}
} }
} }
None => None, None => None,

76
src/spotify/mod.rs Normal file
View File

@ -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<SpotifyKind> {
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<Client> {
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<String>,
duration: Duration,
}
struct AlbumInfo {
pub(crate) name: String,
pub(crate) artists: Vec<String>,
pub(crate) genres: Vec<String>,
songs: Vec<TrackInfo>,
}
pub async fn get_spotify_track(spotify: Box<Client>, id: &String) -> Option<TrackInfo> {
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<Client>, id: &String) -> Option<AlbumInfo> {
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,
}
}