From a424ee44ae068b4c4d7c2f136839ec21f0a9a716 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Wed, 11 Jun 2025 20:00:35 -0400 Subject: [PATCH 1/9] Added dependencies --- Cargo.lock | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8be8125..2a0118a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,6 +187,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -194,6 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -202,6 +218,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -220,10 +264,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -398,6 +448,14 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "icarus_envy" +version = "0.2.0" +source = "git+ssh://git@git.kundeng.us/phoenix/icarus_envy.git?tag=v0.2.0#3ee8c1e573ba9637769aa0538d2c11335e39ed9f" +dependencies = [ + "dotenvy", +] + [[package]] name = "icarus_models" version = "0.4.3" @@ -851,6 +909,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", + "futures-util", "h2", "http", "http-body", @@ -874,12 +933,14 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", ] @@ -1088,6 +1149,8 @@ name = "songparser" version = "0.1.0" dependencies = [ "dotenvy", + "futures", + "icarus_envy", "icarus_models", "reqwest", "serde", @@ -1488,6 +1551,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.77" diff --git a/Cargo.toml b/Cargo.toml index 6999867..ed00706 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,11 @@ rust-version = "1.86" [dependencies] tokio = { version = "1.44.1", features = ["full"] } -reqwest = { version = "0.12.19", features = ["json"] } +futures = { version = "0.3.31" } +reqwest = { version = "0.12.19", features = ["json", "stream"] } serde = { version = "1.0.218", features = ["derive"] } serde_json = { version = "1.0.139" } uuid = { version = "1.16.0", features = ["v4", "serde"] } dotenvy = { version = "0.15.7" } icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.3" } +icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.2.0" } -- 2.43.0 From 5c71504686dea71d66b07c12e5c4cba20959bcdb Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Wed, 11 Jun 2025 20:00:48 -0400 Subject: [PATCH 2/9] Added code to fetch song queue data --- src/main.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8a0e0ab..adbe5f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +use std::io::Write; + +use futures::StreamExt; + #[tokio::main] async fn main() -> Result<(), Box> { let app_base_url = get_icarus_url().await; @@ -15,19 +19,53 @@ async fn main() -> Result<(), Box> { if !song_queue_item.data.is_empty() { println!("Song queue item: {:?}", song_queue_item); - // Process data here... + match api::fetch_song_queue_data::get_data(&app_base_url, &song_queue_item.data[0].id).await { + Ok(response) => { + // TODO: At some point, handle the flow if the size is small or + // large + let mut byte_stream = response.bytes_stream(); + let mut all_bytes = Vec::new(); + + while let Some(chunk) = byte_stream.next().await { + let chunk = chunk?; + all_bytes.extend_from_slice(&chunk); + } + + let mut song = icarus_models::song::Song::default(); + song.data = all_bytes; + song.filename = song.generate_filename(icarus_models::types::MusicTypes::FlacExtension, true); + + // TODO: Add function to save bytes to a file in icarus_models + + song.directory = icarus_envy::environment::get_root_directory().await; + + let dir = std::path::Path::new(&song.directory); + let save_path = dir.join(&song.filename); + + let mut file = std::fs::File::create(&save_path).unwrap(); + file.write_all(&song.data).unwrap(); + println!("File saved to: {:?}", save_path); + +// Process data here... + +// TODO: Parse the response body to a struct +// TODO: Get queued song data +// TODO: Get queued song's metadata +// TODO: Get queued coverart +// TODO: Get queued coverart's data +// TODO: Apply metadata to the queued song +// 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 fetching song queue data: {:?}", err); + } + } - // TODO: Parse the response body to a struct - // TODO: Get queued song data - // TODO: Get queued song's metadata - // TODO: Get queued coverart - // TODO: Get queued coverart's data - // TODO: Apply metadata to the queued song - // 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 } else { println!("No data to fetch"); } @@ -73,6 +111,21 @@ mod api { let api_url = format!("{}/{}", base_url, fetch_endpoint); client.get(api_url).send().await } + + pub mod fetch_song_queue_data { + pub async fn get_data(base_url: &String, id: &uuid::Uuid) -> Result { + let client = reqwest::Client::new(); + let endpoint = String::from("api/v2/song/queue"); + let api_url = format!("{}/{}/{}", base_url, endpoint, id); + client.get(api_url).send().await + } + + pub mod response { + // use serde::{Deserialize, Serialize}; + // pub struct Response { + // } + } + } } async fn get_icarus_url() -> String { -- 2.43.0 From 38950d2e873ca6a02507f1279ae6674ba4d7eef8 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Wed, 11 Jun 2025 20:02:34 -0400 Subject: [PATCH 3/9] Some cleanup --- src/main.rs | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index adbe5f5..3056e41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,12 @@ async fn main() -> Result<(), Box> { if !song_queue_item.data.is_empty() { println!("Song queue item: {:?}", song_queue_item); - match api::fetch_song_queue_data::get_data(&app_base_url, &song_queue_item.data[0].id).await { + match api::fetch_song_queue_data::get_data( + &app_base_url, + &song_queue_item.data[0].id, + ) + .await + { Ok(response) => { // TODO: At some point, handle the flow if the size is small or // large @@ -33,11 +38,16 @@ async fn main() -> Result<(), Box> { let mut song = icarus_models::song::Song::default(); song.data = all_bytes; - song.filename = song.generate_filename(icarus_models::types::MusicTypes::FlacExtension, true); + song.filename = song.generate_filename( + icarus_models::types::MusicTypes::FlacExtension, + true, + ); // TODO: Add function to save bytes to a file in icarus_models + // repo - song.directory = icarus_envy::environment::get_root_directory().await; + song.directory = + icarus_envy::environment::get_root_directory().await; let dir = std::path::Path::new(&song.directory); let save_path = dir.join(&song.filename); @@ -46,26 +56,22 @@ async fn main() -> Result<(), Box> { file.write_all(&song.data).unwrap(); println!("File saved to: {:?}", save_path); -// Process data here... - -// TODO: Parse the response body to a struct -// TODO: Get queued song data -// TODO: Get queued song's metadata -// TODO: Get queued coverart -// TODO: Get queued coverart's data -// TODO: Apply metadata to the queued song -// 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 + // Process data here... + // TODO: Get queued song's metadata + // TODO: Get queued coverart + // TODO: Get queued coverart's data + // TODO: Apply metadata to the queued song + // 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 fetching song queue data: {:?}", err); } } - } else { println!("No data to fetch"); } @@ -113,7 +119,10 @@ mod api { } pub mod fetch_song_queue_data { - pub async fn get_data(base_url: &String, id: &uuid::Uuid) -> Result { + pub async fn get_data( + base_url: &String, + id: &uuid::Uuid, + ) -> Result { let client = reqwest::Client::new(); let endpoint = String::from("api/v2/song/queue"); let api_url = format!("{}/{}/{}", base_url, endpoint, id); -- 2.43.0 From e67b7d32db87cb6472d044da5a31f601bbcb67d0 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:17:14 -0400 Subject: [PATCH 4/9] Simplify code --- src/main.rs | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3056e41..ea96083 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,24 +37,18 @@ async fn main() -> Result<(), Box> { } let mut song = icarus_models::song::Song::default(); - song.data = all_bytes; + // song.data = all_bytes; song.filename = song.generate_filename( icarus_models::types::MusicTypes::FlacExtension, true, ); - // TODO: Add function to save bytes to a file in icarus_models - // repo song.directory = icarus_envy::environment::get_root_directory().await; + let (directory, filename) = generate_song_queue_dir_and_filename().await; + let _ = save_song_to_fs(&directory, &filename, &all_bytes).await; - let dir = std::path::Path::new(&song.directory); - let save_path = dir.join(&song.filename); - - let mut file = std::fs::File::create(&save_path).unwrap(); - file.write_all(&song.data).unwrap(); - println!("File saved to: {:?}", save_path); // Process data here... @@ -89,6 +83,32 @@ async fn main() -> Result<(), Box> { } } +// TODO: Consider having something like this in icarus_models +pub async fn generate_song_queue_dir_and_filename() -> (String, String) { + let mut song = icarus_models::song::Song::default(); + song.filename = song.generate_filename( + icarus_models::types::MusicTypes::FlacExtension, + true, + ); + + song.directory = icarus_envy::environment::get_root_directory().await; + + (song.directory, song.filename) +} + +// TODO: Check to see if this is available in icarus_models +pub async fn save_song_to_fs(directory: &String, filename: &String, data: &Vec) -> std::path::PathBuf { + // TODO: Add function to save bytes to a file in icarus_models + // repo + let dir = std::path::Path::new(directory); + let save_path = dir.join(filename); + + let mut file = std::fs::File::create(&save_path).unwrap(); + file.write_all(data).unwrap(); + + save_path +} + mod responses { pub mod fetch_next_queue_item { use serde::{Deserialize, Serialize}; -- 2.43.0 From 83fc701d24255c3cf48865062315cd100a565b0b Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:30:48 -0400 Subject: [PATCH 5/9] Making code more simpler --- src/main.rs | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/main.rs b/src/main.rs index ea96083..205f1dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ use std::io::Write; -use futures::StreamExt; #[tokio::main] async fn main() -> Result<(), Box> { @@ -26,31 +25,14 @@ async fn main() -> Result<(), Box> { .await { Ok(response) => { - // TODO: At some point, handle the flow if the size is small or - // large - let mut byte_stream = response.bytes_stream(); - let mut all_bytes = Vec::new(); - - while let Some(chunk) = byte_stream.next().await { - let chunk = chunk?; - all_bytes.extend_from_slice(&chunk); - } - - let mut song = icarus_models::song::Song::default(); - // song.data = all_bytes; - song.filename = song.generate_filename( - icarus_models::types::MusicTypes::FlacExtension, - true, - ); - - - song.directory = - icarus_envy::environment::get_root_directory().await; - let (directory, filename) = generate_song_queue_dir_and_filename().await; - let _ = save_song_to_fs(&directory, &filename, &all_bytes).await; - - // Process data here... + let all_bytes = api::fetch_song_queue_data::response::parse_response(response).await?; + + let (directory, filename) = generate_song_queue_dir_and_filename().await; + let save_path = save_song_to_fs(&directory, &filename, &all_bytes).await; + + println!("Saved at: {:?}", save_path); + // TODO: Get queued song's metadata // TODO: Get queued coverart @@ -109,6 +91,7 @@ pub async fn save_song_to_fs(directory: &String, filename: &String, data: &Vec Result, reqwest::Error> { + + // TODO: At some point, handle the flow if the size is small or + // large + let mut byte_stream = response.bytes_stream(); + let mut all_bytes = Vec::new(); + + while let Some(chunk) = byte_stream.next().await { + let chunk = chunk?; + all_bytes.extend_from_slice(&chunk); + } + + Ok(all_bytes) + } } } } -- 2.43.0 From 488c20202320e5eab9e147d994b22b9d0905fe74 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:38:48 -0400 Subject: [PATCH 6/9] Using constant and adding print statement --- src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 205f1dd..88d42eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::io::Write; +pub const SECONDS_TO_SLEEP: u64 = 5; #[tokio::main] async fn main() -> Result<(), Box> { @@ -18,6 +19,7 @@ async fn main() -> Result<(), Box> { if !song_queue_item.data.is_empty() { println!("Song queue item: {:?}", song_queue_item); + println!("Fetching song queue data"); match api::fetch_song_queue_data::get_data( &app_base_url, &song_queue_item.data[0].id, @@ -33,7 +35,6 @@ async fn main() -> Result<(), Box> { println!("Saved at: {:?}", save_path); - // TODO: Get queued song's metadata // TODO: Get queued coverart // TODO: Get queued coverart's data @@ -61,7 +62,7 @@ async fn main() -> Result<(), Box> { } println!("Sleeping"); - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + tokio::time::sleep(tokio::time::Duration::from_secs(SECONDS_TO_SLEEP)).await; } } -- 2.43.0 From dba7cae1802de276db23982c66adac9238bb5a31 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:39:10 -0400 Subject: [PATCH 7/9] Code formatting --- src/main.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 88d42eb..4dc98ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,10 +28,16 @@ async fn main() -> Result<(), Box> { { Ok(response) => { // Process data here... - let all_bytes = api::fetch_song_queue_data::response::parse_response(response).await?; + let all_bytes = + api::fetch_song_queue_data::response::parse_response( + response, + ) + .await?; - let (directory, filename) = generate_song_queue_dir_and_filename().await; - let save_path = save_song_to_fs(&directory, &filename, &all_bytes).await; + let (directory, filename) = + generate_song_queue_dir_and_filename().await; + let save_path = + save_song_to_fs(&directory, &filename, &all_bytes).await; println!("Saved at: {:?}", save_path); @@ -69,10 +75,7 @@ async fn main() -> Result<(), Box> { // TODO: Consider having something like this in icarus_models pub async fn generate_song_queue_dir_and_filename() -> (String, String) { let mut song = icarus_models::song::Song::default(); - song.filename = song.generate_filename( - icarus_models::types::MusicTypes::FlacExtension, - true, - ); + song.filename = song.generate_filename(icarus_models::types::MusicTypes::FlacExtension, true); song.directory = icarus_envy::environment::get_root_directory().await; @@ -80,7 +83,11 @@ pub async fn generate_song_queue_dir_and_filename() -> (String, String) { } // TODO: Check to see if this is available in icarus_models -pub async fn save_song_to_fs(directory: &String, filename: &String, data: &Vec) -> std::path::PathBuf { +pub async fn save_song_to_fs( + directory: &String, + filename: &String, + data: &Vec, +) -> std::path::PathBuf { // TODO: Add function to save bytes to a file in icarus_models // repo let dir = std::path::Path::new(directory); @@ -92,7 +99,6 @@ pub async fn save_song_to_fs(directory: &String, filename: &String, data: &Vec Result, reqwest::Error> { - + pub async fn parse_response( + response: reqwest::Response, + ) -> Result, reqwest::Error> { // TODO: At some point, handle the flow if the size is small or // large let mut byte_stream = response.bytes_stream(); -- 2.43.0 From 4df0fd12f882dcdc32ba4c8ebd472528b8aafe7a Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:42:45 -0400 Subject: [PATCH 8/9] Removing code --- src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4dc98ee..e059769 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,9 +141,7 @@ mod api { pub mod response { use futures::StreamExt; - // use serde::{Deserialize, Serialize}; - // pub struct Response { - // } + pub async fn parse_response( response: reqwest::Response, ) -> Result, reqwest::Error> { -- 2.43.0 From f9facacfb4b756c6bfe1ae772a0c122f758be307 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Thu, 12 Jun 2025 14:46:18 -0400 Subject: [PATCH 9/9] Warning fixes --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index e059769..efbb604 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,7 +86,7 @@ pub async fn generate_song_queue_dir_and_filename() -> (String, String) { pub async fn save_song_to_fs( directory: &String, filename: &String, - data: &Vec, + data: &[u8], ) -> std::path::PathBuf { // TODO: Add function to save bytes to a file in icarus_models // repo -- 2.43.0