use teloxide::prelude::*; use crate::spotify::{PlayableKind, TrackInfo}; use spotify::SpotifyKind::Track; use crate::spotify::SpotifyKind::{Album, Episode, Playlist, Podcast}; use crate::utils::{human_readable_duration, truncate_with_dots}; mod spotify; mod utils; static MAX_ARTISTS_CHARS: usize = 140; #[tokio::main] async fn main() { teloxide::enable_logging!(); log::info!("Starting Songlify..."); let bot = Bot::from_env().auto_send(); teloxide::repl(bot, |message| async move { let text = message.update.text().and_then(spotify::get_entry_kind); match text { Some(spotify) => { let spotify_client = spotify::get_client().await; match spotify { Track(id) => { log::debug!("Parsing spotify song: {}", id); let track_info = spotify::get_track(spotify_client, &id).await; match track_info { Some(info) => { let reply = format!( "Track information:\n\ šŸŽµ Track name: {}\n\ šŸ§‘ā€šŸŽ¤ Artist(s): {}\n\ ā³ Duration: {}", info.name, truncate_with_dots(info.artists.join(", "), MAX_ARTISTS_CHARS), human_readable_duration(info.duration) ); Some(message.reply_to(reply).await?) } None => None, } } Album(id) => { log::debug!("Parsing spotify album: {}", id); let album_info = spotify::get_album(spotify_client, &id).await; match album_info { Some(info) => { let mut reply = format!( "Album information:\n\ šŸŽµ Album name: {}\n\ šŸ§‘ā€šŸŽ¤ {} artist(s): {}", info.name, info.artists.len(), truncate_with_dots(info.artists.join(", "), MAX_ARTISTS_CHARS) ); if !info.genres.is_empty() { reply.push_str( format!("\nšŸ’æ Genre(s): {}", info.genres.join(", ")) .as_str(), ); } Some( message .reply_to(add_track_section(info.tracks, reply)) .await?, ) } None => None, } } Playlist(id) => { log::debug!("Parsing spotify playlist: {}", id); let playlist_info = spotify::get_playlist(spotify_client, &id).await; match playlist_info { Some(info) => { let reply = format!( "Playlist information:\n\ āœ’ļø Playlist name: {}\n\ šŸ§‘ā€šŸŽ¤ {} artist(s): {}", info.name, info.artists.len(), truncate_with_dots(info.artists.join(", "), MAX_ARTISTS_CHARS) ); Some( message .reply_to(add_track_section_for_playlist(info.tracks, reply)) .await?, ) } None => None, } }, Episode(id) => { log::warn!("Support for episodes ({}) has not be implemented yet!", id); None } Podcast(id) => { log::warn!("Support for podcasts ({}) has not be implemented yet!", id); None } } } None => None, }; respond(()) }) .await; log::info!("Exiting..."); } fn add_track_section_for_playlist(tracks: Vec, reply: String) -> String { if !tracks.is_empty() { let songs = tracks .iter() .map(|x| match x { PlayableKind::Track(t) => t.name.clone(), PlayableKind::Podcast(e) => e.name.clone() } + "\n") .collect::(); reply .clone() .push_str(format!("\nšŸŽ¶ {} Track(s): {}", tracks.len(), songs).as_str()) } reply } fn add_track_section(tracks: Vec, reply: String) -> String { if !tracks.is_empty() { let songs = tracks .iter() .map(|x| x.name.clone() + "\n") .collect::(); reply .clone() .push_str(format!("\nšŸŽ¶ {} Track(s): {}", tracks.len(), songs).as_str()) } reply }