From 2f05c20d4ece14a82eacd0c789de8075cd78653a Mon Sep 17 00:00:00 2001 From: phoenix Date: Sat, 28 Jun 2025 23:23:41 +0000 Subject: [PATCH] update queued song (#28) Reviewed-on: https://git.kundeng.us/phoenix/songparser/pulls/28 Co-authored-by: phoenix Co-committed-by: phoenix --- Cargo.lock | 17 +++++ Cargo.toml | 2 +- src/main.rs | 138 +++++++++++++++++++++----------------- src/the_rest.rs | 6 ++ src/update_queued_song.rs | 35 ++++++++++ src/util.rs | 6 ++ 6 files changed, 142 insertions(+), 62 deletions(-) create mode 100644 src/the_rest.rs create mode 100644 src/update_queued_song.rs create mode 100644 src/util.rs diff --git a/Cargo.lock b/Cargo.lock index a2cd917..fc99adf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -749,6 +749,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.8.8" @@ -1023,6 +1033,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", @@ -1512,6 +1523,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index 9ec7ef6..9cf368d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ rust-version = "1.86" [dependencies] tokio = { version = "1.44.1", features = ["full"] } futures = { version = "0.3.31" } -reqwest = { version = "0.12.19", features = ["json", "stream"] } +reqwest = { version = "0.12.19", features = ["json", "stream", "multipart"] } serde = { version = "1.0.218", features = ["derive"] } serde_json = { version = "1.0.139" } time = { version = "0.3.41", features = ["macros", "serde"] } diff --git a/src/main.rs b/src/main.rs index b29bc69..429eac7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +pub mod the_rest; +pub mod update_queued_song; +pub mod util; + use std::io::Write; pub const SECONDS_TO_SLEEP: u64 = 5; @@ -17,7 +21,12 @@ async fn main() -> Result<(), Box> { let song_queue_id = song_queue_item.data[0].id; // TODO: Do something with the result later - let _ = process_song(&app_base_url, &song_queue_id).await; + match some_work(&app_base_url, &song_queue_id).await { + Ok(_) => {} + Err(err) => { + eprintln!("Error: {:?}", err); + } + } } else { println!("Queue is empty"); } @@ -55,7 +64,47 @@ async fn is_queue_empty( } } -async fn process_song(api_url: &String, song_queue_id: &uuid::Uuid) -> Result<(), reqwest::Error> { +async fn some_work( + app_base_url: &String, + song_queue_id: &uuid::Uuid, +) -> Result<(), std::io::Error> { + match prep_song(app_base_url, song_queue_id).await { + Ok((song_queue_path, coverart_queue_path, metadata)) => { + match apply_metadata(&song_queue_path, &coverart_queue_path, &metadata).await { + Ok(_applied) => { + match update_queued_song::update_queued_song( + app_base_url, + &song_queue_path, + song_queue_id, + ) + .await + { + Ok(response) => { + match response + .json::() + .await + { + Ok(_inner_response) => { + println!("Response: {:?}", _inner_response); + Ok(()) + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } +} + +async fn prep_song( + api_url: &String, + song_queue_id: &uuid::Uuid, +) -> Result<(String, String, api::get_metadata_queue::response::Metadata), reqwest::Error> { match api::fetch_song_queue_data::get_data(api_url, song_queue_id).await { Ok(response) => { // Process data here... @@ -74,8 +123,8 @@ async fn process_song(api_url: &String, song_queue_id: &uuid::Uuid) -> Result<() { Ok(response) => { let id = &response.data[0].id; - let metadata = &response.data[0].metadata; let created_at = &response.data[0].created_at; + let metadata = &response.data[0].metadata; println!("Id: {:?}", id); println!("Metadata: {:?}", metadata); println!("Created at: {:?}", created_at); @@ -97,49 +146,31 @@ async fn process_song(api_url: &String, song_queue_id: &uuid::Uuid) -> Result<() println!("Saved coverart queue file at: {:?}", coverart_queue_path); - match apply_metadata(song_queue_path, coverart_queue_path, metadata).await { - Ok(_) => { - // TODO: Update the queued song with the updated queued song - // TODO: Create song - // TODO: Create coverart - // TODO: Wipe data from queued song - // TODO: Wipe data from queued coverart - } - Err(err) => { - eprintln!("Error: {:?}", err); - } - } + let c_path = util::path_buf_to_string(&coverart_queue_path); + let s_path = util::path_buf_to_string(&song_queue_path); + Ok((s_path, c_path, metadata.clone())) } Err(err) => { - eprintln!("Error: {:?}", err); + Err(err) } } Err(err) => { - eprintln!("Error: {:?}", err); + Err(err) } } } Err(err) => { - eprintln!("Error: {:?}", err); + Err(err) } } } - Err(err) => { - eprintln!("Error: {:?}", err); - } + Err(err) => Err(err), } - Ok(()) - } - Err(err) => { - eprintln!("Error: {:?}", err); - Err(err) } + Err(err) => Err(err), } } - Err(err) => { - eprintln!("Error: {:?}", err); - Err(err) - } + Err(err) => Err(err), } } Err(err) => Err(err), @@ -206,21 +237,11 @@ pub async fn save_file_to_fs( } pub async fn apply_metadata( - song_queue_path: std::path::PathBuf, - coverart_queue_path: std::path::PathBuf, + song_queue_path: &String, + coverart_queue_path: &String, metadata: &api::get_metadata_queue::response::Metadata, ) -> Result { // Apply metadata fields - let s_path = match song_queue_path.to_str() { - Some(val) => String::from(val), - None => String::new(), - }; - - if s_path.is_empty() { - println!("Song queue path is empty"); - return Ok(false); - } - let types = icarus_meta::types::all_metadata_types(); for t in types { @@ -228,7 +249,7 @@ pub async fn apply_metadata( icarus_meta::types::Type::Album => { let meta_type = icarus_meta::types::MetadataType::from_string(metadata.album.clone()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -238,7 +259,7 @@ pub async fn apply_metadata( icarus_meta::types::Type::AlbumArtist => { let meta_type = icarus_meta::types::MetadataType::from_string(metadata.album_artist.clone()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -248,7 +269,7 @@ pub async fn apply_metadata( icarus_meta::types::Type::Artist => { let meta_type = icarus_meta::types::MetadataType::from_string(metadata.artist.clone()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -259,7 +280,7 @@ pub async fn apply_metadata( // TODO: Do something about this discrepancy let meta_type = icarus_meta::types::MetadataType::from_string(metadata.year.to_string()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -268,7 +289,7 @@ pub async fn apply_metadata( } icarus_meta::types::Type::Disc => { let meta_type = icarus_meta::types::MetadataType::from_int(metadata.disc); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -278,7 +299,7 @@ pub async fn apply_metadata( icarus_meta::types::Type::Genre => { let meta_type = icarus_meta::types::MetadataType::from_string(metadata.genre.clone()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -288,7 +309,7 @@ pub async fn apply_metadata( icarus_meta::types::Type::Title => { let meta_type = icarus_meta::types::MetadataType::from_string(metadata.title.clone()); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -297,7 +318,7 @@ pub async fn apply_metadata( } icarus_meta::types::Type::Track => { let meta_type = icarus_meta::types::MetadataType::from_int(metadata.track); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -306,7 +327,7 @@ pub async fn apply_metadata( } icarus_meta::types::Type::TrackCount => { let meta_type = icarus_meta::types::MetadataType::from_int(metadata.track_count); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -315,7 +336,7 @@ pub async fn apply_metadata( } icarus_meta::types::Type::DiscCount => { let meta_type = icarus_meta::types::MetadataType::from_int(metadata.disc_count); - match icarus_meta::meta::metadata::set_meta_value(t, &s_path, meta_type) { + match icarus_meta::meta::metadata::set_meta_value(t, song_queue_path, meta_type) { Ok(_) => {} Err(_err) => { return Err(_err); @@ -326,16 +347,11 @@ pub async fn apply_metadata( } // Apply coverart - let c_path: String = match coverart_queue_path.to_str() { - Some(val) => String::from(val), - None => String::new(), - }; - - match icarus_meta::meta::coverart::contains_coverart(&s_path) { + match icarus_meta::meta::coverart::contains_coverart(song_queue_path) { Ok((exists, size)) => { if exists { println!("Coverart exists: {:?} size", size); - match icarus_meta::meta::coverart::remove_coverart(&s_path) { + match icarus_meta::meta::coverart::remove_coverart(song_queue_path) { Ok(_data) => {} Err(err) => { return Err(err); @@ -343,7 +359,7 @@ pub async fn apply_metadata( } } - match icarus_meta::meta::coverart::set_coverart(&s_path, &c_path) { + match icarus_meta::meta::coverart::set_coverart(song_queue_path, coverart_queue_path) { Ok(_data) => { if _data.is_empty() { println!("There was an issue"); @@ -439,7 +455,7 @@ mod api { pub mod response { use serde::{Deserialize, Serialize}; - #[derive(Debug, Deserialize, Serialize)] + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Metadata { pub song_queue_id: uuid::Uuid, pub album: String, diff --git a/src/the_rest.rs b/src/the_rest.rs new file mode 100644 index 0000000..ae021fd --- /dev/null +++ b/src/the_rest.rs @@ -0,0 +1,6 @@ +// TODO: Refactor this file when this app is functional + +// TODO: Create song +// TODO: Create coverart +// TODO: Wipe data from queued song +// TODO: Wipe data from queued coverart diff --git a/src/update_queued_song.rs b/src/update_queued_song.rs new file mode 100644 index 0000000..ba51eeb --- /dev/null +++ b/src/update_queued_song.rs @@ -0,0 +1,35 @@ +pub async fn update_queued_song( + base_url: &String, + song_path: &String, + song_queue_id: &uuid::Uuid, +) -> Result { + let client = reqwest::Client::builder().build()?; + + println!("Song path: {:?}", song_path); + + // TODO: Make the filename random + let form = reqwest::multipart::Form::new().part( + "file", + reqwest::multipart::Part::bytes(std::fs::read(song_path).unwrap()) + .file_name("track01.flac"), + ); + + let url = format!("{}/api/v2/song/queue/{}", base_url, song_queue_id); + println!("Url: {:?}", url); + + let request = client.patch(url).multipart(form); + + let response = request.send().await?; + + Ok(response) +} + +pub mod response { + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Deserialize, Serialize)] + pub struct Response { + pub message: String, + pub data: Vec, + } +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..3a873bc --- /dev/null +++ b/src/util.rs @@ -0,0 +1,6 @@ +pub fn path_buf_to_string(path: &std::path::Path) -> String { + match path.to_str() { + Some(val) => String::from(val), + None => String::new(), + } +}