diff --git a/src/apis.rs b/src/apis.rs index dc11627..0c7f722 100644 --- a/src/apis.rs +++ b/src/apis.rs @@ -1,3 +1,4 @@ +pub mod azuracast; pub mod cobalt; pub mod craiyon; pub mod different_dimension_me; diff --git a/src/apis/azuracast.rs b/src/apis/azuracast.rs new file mode 100644 index 0000000..3c24706 --- /dev/null +++ b/src/apis/azuracast.rs @@ -0,0 +1,155 @@ +use serde::Deserialize; + +use crate::commands::CommandError; +use crate::utilities::api_utils::DetectServerError; +use crate::utilities::message_entities::{Entity, ToEntity, ToEntityOwned}; +use crate::utilities::text_utils; + +#[derive(Deserialize)] +pub struct PlayerState { + pub station: Station, + pub live: Live, + pub now_playing: Option, + pub playing_next: Option, + pub listeners: Listeners, +} + +#[derive(Deserialize)] +pub struct Station { + pub id: u32, + pub name: String, + pub public_player_url: String, +} + +#[derive(Deserialize)] +pub struct Listeners { + pub total: u32, + pub unique: u32, +} + +#[derive(Deserialize)] +pub struct Live { + pub is_live: bool, + pub streamer_name: String, +} + +#[derive(Deserialize)] +pub struct CurrentSong { + pub song: Song, + pub duration: u32, + pub elapsed: u32, +} + +#[derive(Deserialize)] +pub struct StationQueue { + pub song: Song, +} + +#[derive(Deserialize)] +pub struct Song { + pub title: String, + pub artist: String, + pub album: String, +} + +impl PlayerState { + pub fn format_entities(self, compact: bool) -> Vec> { + let mut entities = Vec::new(); + + if self.live.is_live { + entities.extend([ + "DJ ".text(), + self.live.streamer_name.bold_owned(), + " NA BEACIE!!!".text(), + ]); + } else { + entities.extend([ + self.station.name.text_url_owned(self.station.public_player_url), + " mówi:".text(), + ]); + } + + if let Some(now_playing) = self.now_playing { + entities.push("\n".text()); + entities.extend(format_song(now_playing.song)); + entities.extend([ + "\n".text(), + text_utils::progress_bar(now_playing.elapsed, now_playing.duration).code_owned(), + " ".text(), + text_utils::format_duration(now_playing.elapsed.into()).text_owned(), + " / ".text(), + text_utils::format_duration(now_playing.duration.into()).text_owned(), + ]); + } + + if !compact { + if let Some(playing_next) = self.playing_next { + entities.push("\n\nNastępnie:\n".text()); + entities.extend(format_song(playing_next.song)); + } + } + + if !compact || self.listeners.total > 0 { + if !compact { + entities.push("\n".text()); + } + + entities.extend(["\nSłucha: ".text(), self.listeners.total.to_string().text_owned()]); + + if self.listeners.total != self.listeners.unique { + entities.extend([ + "(tak naprawdę ".text(), + self.listeners.unique.to_string().text_owned(), + ")".text(), + ]); + } + } + + entities + } +} + +pub async fn now_playing( + http_client: reqwest::Client, + domain: &str, +) -> Result, CommandError> { + let now_playing = http_client + .get(format!("https://{domain}/api/nowplaying")) + .send() + .await? + .server_error()? + .json() + .await?; + + Ok(now_playing) +} + +pub async fn station_now_playing( + http_client: reqwest::Client, + domain: &str, + station_id: u32, +) -> Result { + let now_playing = http_client + .get(format!("https://{domain}/api/nowplaying/{station_id}")) + .send() + .await? + .server_error()? + .json() + .await?; + + Ok(now_playing) +} + +fn format_song(song: Song) -> Vec> { + let mut entities = vec![song.title.bold_owned()]; + + if !song.artist.is_empty() { + entities.extend(["\n".text(), song.artist.text_owned()]); + } + + if !song.album.is_empty() { + entities.extend([" • ".text(), song.album.text_owned()]); + } + + entities +} diff --git a/src/apis/poligon.rs b/src/apis/poligon.rs index 1ae54ee..e8f2109 100644 --- a/src/apis/poligon.rs +++ b/src/apis/poligon.rs @@ -19,64 +19,3 @@ pub async fn startit_joke(http_client: reqwest::Client) -> Result, - pub playing_next: Option, - pub listeners: Listeners, -} - -#[derive(Deserialize)] -pub struct Station { - pub name: String, - pub public_player_url: String, -} - -#[derive(Deserialize)] -pub struct Listeners { - pub total: u32, - pub unique: u32, -} - -#[derive(Deserialize)] -pub struct Live { - pub is_live: bool, - pub streamer_name: String, -} - -#[derive(Deserialize)] -pub struct CurrentSong { - pub song: Song, - pub duration: u32, - pub elapsed: u32, -} - -#[derive(Deserialize)] -pub struct StationQueue { - pub song: Song, -} - -#[derive(Deserialize)] -pub struct Song { - pub title: String, - pub artist: String, - pub album: String, -} - -pub async fn now_playing( - http_client: reqwest::Client, - station_id: u32, -) -> Result { - let now_playing = http_client - .get(format!("https://radio.poligon.lgbt/api/nowplaying/{station_id}")) - .send() - .await? - .server_error()? - .json::() - .await?; - - Ok(now_playing) -} diff --git a/src/commands.rs b/src/commands.rs index 2685f66..b0cd5f7 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -29,6 +29,7 @@ pub mod mevo; pub mod moveit_joke; pub mod ping; pub mod radio_poligon; +pub mod radio_sur; pub mod screenshot; pub mod sex; pub mod stablehorde; diff --git a/src/commands/radio_poligon.rs b/src/commands/radio_poligon.rs index cd5ea8a..8799401 100644 --- a/src/commands/radio_poligon.rs +++ b/src/commands/radio_poligon.rs @@ -1,84 +1,29 @@ use async_trait::async_trait; use super::{CommandResult, CommandTrait}; -use crate::apis::poligon::{self, Song}; +use crate::apis::azuracast; use crate::utilities::command_context::CommandContext; -use crate::utilities::message_entities::{self, Entity, ToEntity, ToEntityOwned}; -use crate::utilities::text_utils::{self}; +use crate::utilities::message_entities; pub struct RadioPoligon; #[async_trait] impl CommandTrait for RadioPoligon { fn command_names(&self) -> &[&str] { - &["radio_poligon", "radio", "poligon"] + &["radio_poligon", "poligon"] } async fn execute(&self, ctx: &CommandContext, _: String) -> CommandResult { - let now_playing = poligon::now_playing(ctx.bot_state.http_client.clone(), 1).await?; - let mut entities = Vec::new(); + let station = azuracast::station_now_playing( + ctx.bot_state.http_client.clone(), + "radio.poligon.lgbt", + 1, + ) + .await?; - if now_playing.live.is_live { - entities.extend([ - "DJ ".text(), - now_playing.live.streamer_name.bold(), - " NA BEACIE!!!".text(), - "\n".text(), - ]); - } else { - entities.extend([ - now_playing.station.name.text_url(now_playing.station.public_player_url), - " mówi:".text(), - "\n".text(), - ]); - } - - if let Some(now_playing) = now_playing.now_playing { - entities.extend(format_song(now_playing.song)); - entities.extend([ - "\n".text(), - text_utils::progress_bar(now_playing.elapsed, now_playing.duration).code_owned(), - " ".text(), - text_utils::format_duration(now_playing.elapsed.into()).text_owned(), - " / ".text(), - text_utils::format_duration(now_playing.duration.into()).text_owned(), - "\n".text(), - ]); - } - - if let Some(playing_next) = now_playing.playing_next { - entities.push("\nNastępnie:\n".text()); - entities.extend(format_song(playing_next.song)); - entities.push("\n".text()); - } - - entities - .extend(["\nSłucha: ".text(), now_playing.listeners.total.to_string().text_owned()]); - - if now_playing.listeners.total != now_playing.listeners.unique { - entities.extend([ - "(tak naprawdę ".text(), - now_playing.listeners.unique.to_string().text_owned(), - ")".text(), - ]); - } - - ctx.reply_formatted_text(message_entities::formatted_text(entities)).await?; + ctx.reply_formatted_text(message_entities::formatted_text(station.format_entities(false))) + .await?; Ok(()) } } - -fn format_song(song: Song) -> Vec> { - let mut entities = vec![song.title.bold_owned()]; - - if !song.artist.is_empty() { - entities.extend(["\n".text(), song.artist.text_owned()]); - } - - if !song.album.is_empty() { - entities.extend([" • ".text(), song.album.text_owned()]); - } - - entities -} diff --git a/src/commands/radio_sur.rs b/src/commands/radio_sur.rs new file mode 100644 index 0000000..db88427 --- /dev/null +++ b/src/commands/radio_sur.rs @@ -0,0 +1,33 @@ +use async_trait::async_trait; + +use super::{CommandResult, CommandTrait}; +use crate::apis::azuracast; +use crate::utilities::command_context::CommandContext; +use crate::utilities::message_entities::{self, ToEntity}; + +pub struct RadioSur; + +#[async_trait] +impl CommandTrait for RadioSur { + fn command_names(&self) -> &[&str] { + &["radio_sur", "sur"] + } + + async fn execute(&self, ctx: &CommandContext, _: String) -> CommandResult { + let mut stations = + azuracast::now_playing(ctx.bot_state.http_client.clone(), "stream.surradio.live") + .await?; + + stations.sort_unstable_by_key(|station| station.station.id); + + let entities = stations + .into_iter() + .map(|station| station.format_entities(true)) + .collect::>() + .join(&"\n\n".text()); + + ctx.reply_formatted_text(message_entities::formatted_text(entities)).await?; + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index fcadad1..93afcd1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ async fn main() { bot.add_command(commands::cobalt_download::CobaltDownload::auto()); bot.add_command(commands::cobalt_download::CobaltDownload::audio()); bot.add_command(commands::charinfo::CharInfo); + bot.add_command(commands::radio_sur::RadioSur); bot.add_command(commands::radio_poligon::RadioPoligon); bot.add_command(commands::autocomplete::Autocomplete); bot.add_command(commands::mevo::Mevo); diff --git a/src/utilities/message_entities.rs b/src/utilities/message_entities.rs index 4b84940..ccb79b7 100644 --- a/src/utilities/message_entities.rs +++ b/src/utilities/message_entities.rs @@ -16,6 +16,7 @@ impl Utf16Len for str { } } +#[derive(Clone)] pub enum Entity<'a> { Text(Cow<'a, str>), Bold(Vec>),