From e000f4458a4ed14d5ec78c70528e6f98b33d58dc Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Tue, 23 Jan 2024 14:47:28 -0600 Subject: [PATCH] adding song_lyrics.rs This module will allow for searching and finding songs in genius lyrics and giving me the ability to get the lyrics from those songs. The main function implemented is search_song first. From here we can get the id of the songs we are looking for and then add the lyrics into Lumina. --- Cargo.lock | 5 +- Cargo.toml | 1 + src/rust/songs/mod.rs | 1 + src/rust/songs/song_lyrics.rs | 115 ++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 src/rust/songs/song_lyrics.rs diff --git a/Cargo.lock b/Cargo.lock index f68911f..865380d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,6 +1498,7 @@ dependencies = [ "obws", "qt-build-utils", "quote", + "reqwest", "rfd", "serde", "serde_derive", @@ -2224,9 +2225,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64", "bytes", diff --git a/Cargo.toml b/Cargo.toml index d7a3127..7c84cce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ tracing-subscriber = { version = "0.3.17", features = ["fmt", "std", "time", "lo tracing = "0.1.37" time = { version = "0.3.29", features = ["formatting", "macros"] } obws = "0.11.5" +reqwest = "0.11.23" # ffmpeg-next = "6.0.0" # cxx-qt-build generates C++ code from the `#[cxx_qt::bridge]` module diff --git a/src/rust/songs/mod.rs b/src/rust/songs/mod.rs index 4e25172..2c17f14 100644 --- a/src/rust/songs/mod.rs +++ b/src/rust/songs/mod.rs @@ -1,2 +1,3 @@ pub mod song_editor; +pub mod song_lyrics; pub mod song_model; diff --git a/src/rust/songs/song_lyrics.rs b/src/rust/songs/song_lyrics.rs new file mode 100644 index 0000000..0531f27 --- /dev/null +++ b/src/rust/songs/song_lyrics.rs @@ -0,0 +1,115 @@ +use reqwest::Error; +use serde_derive::Deserialize; +use serde_json::Value; +use tracing::debug; + +#[derive(PartialEq, Debug, Eq, Deserialize)] +pub struct Song { + title: String, + lyrics: String, + id: u32, + artist_names: String, +} + +#[derive(Debug)] +pub struct SongBuilder { + title: Option, + lyrics: Option, + id: Option, + artist_names: Option, +} + +impl Song { + fn builder() -> SongBuilder { + SongBuilder { + title: None, + lyrics: None, + id: None, + artist_names: None, + } + } +} + +impl SongBuilder { + fn title(mut self, s: &str) -> SongBuilder { + self.title = Some(s.to_owned()); + self + } + + fn artist(mut self, s: &str) -> SongBuilder { + self.artist_names = Some(s.to_owned()); + self + } + + fn id(mut self, id: u32) -> SongBuilder { + self.id = Some(id); + self + } + + fn build(self) -> Song { + Song { + title: self.title.unwrap_or_default(), + lyrics: self.lyrics.unwrap_or_default(), + id: self.id.unwrap_or_default(), + artist_names: self.artist_names.unwrap_or_default(), + } + } + +} + +pub fn search_song(s: &str) -> Result, Error> { + let url = String::from("https://api.genius.com/search?"); + tokio::runtime::Runtime::new().unwrap().block_on(async { + let req = reqwest::Client::new() + .get(url) + .query(&[("access_token", "R0Y0ZW50Il9LSh5su3LKfdyfmQRx41NpVvLFJ0VxMo-hQ_4H1OVg_IE0Q-UUoFQx"), ("q", s)]) + .send().await? + .text().await?; + + let json: Value = serde_json::from_str(req.as_str()).unwrap(); + let mut songs: Vec = vec![]; + let collection = json["response"]["hits"].as_array(); + if let Some(col) = collection { + for result in col { + let result = &result["result"]; + let song = Song::builder() + .title(result["title"].as_str().unwrap_or_default()) + .artist(result["artist_names"].as_str().unwrap_or_default()) + .id(result["id"].as_u64().unwrap_or_default() as u32).build(); + // debug!(title = ?result["title"], artist = ?result["artist_names"]); + songs.push(song); + } + } + debug!(?songs); + Ok(songs) + }) +} + +#[cfg(test)] +mod tests { + use tracing_subscriber::EnvFilter; + + use super::*; + + #[test] + fn test_search() { + // Uncomment to see debug info + tracing_subscriber::FmtSubscriber::builder() + .pretty() + .with_line_number(true) + .with_level(true) + .with_target(true) + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let song = "Perfect"; + let res = search_song(song).unwrap().into_iter().next().unwrap(); + let song = Song { + title: String::from("Perfect"), + lyrics: String::from(""), + id: 2953761, + artist_names: String::from("Ed Sheeran"), + }; + assert_eq!(song, res); + } +}