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.
This commit is contained in:
Chris Cochrun 2024-01-23 14:47:28 -06:00
parent 27dc1d1bc8
commit e000f4458a
4 changed files with 120 additions and 2 deletions

5
Cargo.lock generated
View file

@ -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",

View file

@ -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

View file

@ -1,2 +1,3 @@
pub mod song_editor;
pub mod song_lyrics;
pub mod song_model;

View file

@ -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<String>,
lyrics: Option<String>,
id: Option<u32>,
artist_names: Option<String>,
}
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<Vec<Song>, 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<Song> = 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);
}
}