diff --git a/Cargo.lock b/Cargo.lock index 5c1a772..39efe91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1322,7 +1322,7 @@ dependencies = [ [[package]] name = "songparser" -version = "0.4.7" +version = "0.4.8" dependencies = [ "futures", "icarus_envy", diff --git a/Cargo.toml b/Cargo.toml index 595155f..e84cf61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "songparser" -version = "0.4.7" +version = "0.4.8" edition = "2024" rust-version = "1.90" diff --git a/src/api.rs b/src/api.rs index e11da54..01be8b9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -199,11 +199,10 @@ pub mod update_queued_song { println!("Queued song path: {:?}", queued_song.path); - // TODO: Make the filename random let form = reqwest::multipart::Form::new().part( "file", reqwest::multipart::Part::bytes(std::fs::read(&queued_song.path).unwrap()) - .file_name("track01.flac"), + .file_name(queued_song.song.filename.clone()), ); let url = format!("{}/api/v2/song/queue/{}", app.uri, queued_song.id); diff --git a/src/main.rs b/src/main.rs index 62c338e..3b4635b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ pub mod api; pub mod auth; pub mod config; pub mod metadata; +pub mod parser; +pub mod queue; pub mod queued_item; pub mod util; @@ -50,7 +52,7 @@ async fn main() -> Result<(), Box> { println!("Token did not expire"); } - match is_queue_empty(&app).await { + match queue::is_queue_empty(&app).await { Ok((empty, song_queue_item)) => { if !empty { println!("Queue is not empty"); @@ -59,11 +61,12 @@ async fn main() -> Result<(), Box> { let song_queue_id = song_queue_item.data[0].id; let user_id = song_queue_item.data[0].user_id; - match some_work(&app, &song_queue_id, &user_id).await { + match parser::some_work(&app, &song_queue_id, &user_id).await { Ok((song, coverart, _metadata, queued_song, queued_coverart)) => { - match wipe_data_from_queues(&app, &queued_song, &queued_coverart).await + match queue::wipe_data_from_queues(&app, &queued_song, &queued_coverart) + .await { - Ok(_) => match cleanup(&song, &coverart).await { + Ok(_) => match parser::cleanup(&song, &coverart).await { Ok(_) => { println!("Successful cleanup"); } @@ -93,327 +96,3 @@ async fn main() -> Result<(), Box> { tokio::time::sleep(tokio::time::Duration::from_secs(SECONDS_TO_SLEEP)).await; } } - -async fn wipe_data_from_queues( - app: &config::App, - queued_song: &crate::queued_item::QueuedSong, - queued_coverart: &crate::queued_item::QueuedCoverArt, -) -> Result<(), std::io::Error> { - match api::wipe_data::song_queue::wipe_data(app, queued_song).await { - Ok(response) => match response - .json::() - .await - { - Ok(_resp) => { - match api::wipe_data::coverart_queue::wipe_data(app, queued_coverart).await { - Ok(inner_response) => match inner_response - .json::() - .await - { - Ok(_inner_resp) => { - println!("Wiped data from CoverArt queue"); - println!("Resp: {_inner_resp:?}"); - Ok(()) - } - Err(err) => Err(std::io::Error::other(err.to_string())), - }, - Err(err) => Err(std::io::Error::other(err.to_string())), - } - } - Err(err) => Err(std::io::Error::other(err.to_string())), - }, - Err(err) => Err(std::io::Error::other(err.to_string())), - } -} - -async fn cleanup( - song: &icarus_models::song::Song, - coverart: &icarus_models::coverart::CoverArt, -) -> Result<(), std::io::Error> { - match song.remove_from_filesystem() { - Ok(_) => {} - Err(err) => { - eprintln!("Error: Problem cleaning up SongQueue files {err:?}"); - } - } - - match coverart.remove_from_filesystem() { - Ok(_) => Ok(()), - Err(err) => Err(err), - } -} - -async fn is_queue_empty( - app: &config::App, -) -> Result<(bool, api::fetch_next_queue_item::response::SongQueueItem), reqwest::Error> { - match api::fetch_next_queue_item::fetch_next_queue_item(app).await { - Ok(response) => { - match response - .json::() - .await - { - Ok(response) => { - if response.data.is_empty() { - Ok((true, response)) - } else { - Ok((false, response)) - } - } - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } -} - -async fn some_work( - app: &crate::config::App, - song_queue_id: &uuid::Uuid, - user_id: &uuid::Uuid, -) -> Result< - ( - icarus_models::song::Song, - icarus_models::coverart::CoverArt, - api::get_metadata_queue::response::Metadata, - queued_item::QueuedSong, - queued_item::QueuedCoverArt, - ), - std::io::Error, -> { - match prep_song(app, song_queue_id).await { - Ok((queued_song, queued_coverart, metadata)) => { - println!("Prepping song"); - - match metadata::apply_metadata(&queued_song, &queued_coverart, &metadata).await { - Ok(_applied) => { - match api::update_queued_song::update_queued_song(app, &queued_song).await { - Ok(response) => { - match response - .json::() - .await - { - Ok(_inner_response) => { - println!("Updated queued song"); - println!("Response: {_inner_response:?}"); - - let song_type = String::from( - icarus_meta::detection::song::constants::FLAC_TYPE, - ); - - match api::create_song::create( - app, &metadata, user_id, &song_type, - ) - .await - { - Ok(response) => match response - .json::() - .await - { - Ok(resp) => { - println!("Response: {resp:?}"); - - let mut song = resp.data[0].clone(); - song.directory = queued_song.song.directory.clone(); - song.filename = queued_song.song.filename.clone(); - - match api::create_coverart::create(app, &song, &queued_coverart).await { - Ok(response) => match response.json::().await { - Ok(resp) => { - println!("CoverArt sent and successfully parsed response"); - println!("json: {resp:?}"); - let mut coverart = resp.data[0].clone(); - coverart.directory = queued_coverart.coverart.directory.clone(); - coverart.filename = queued_coverart.coverart.filename.clone(); - - Ok((song.clone(), coverart.clone(), metadata, queued_song.clone(), queued_coverart.clone())) - } - Err(err) => { - Err(std::io::Error::other(err.to_string())) - } - } - Err(err) => { - Err(std::io::Error::other(err.to_string())) - } - } - } - Err(err) => Err(std::io::Error::other(err.to_string())), - }, - Err(err) => Err(std::io::Error::other(err.to_string())), - } - } - 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( - app: &crate::config::App, - song_queue_id: &uuid::Uuid, -) -> Result< - ( - queued_item::QueuedSong, - queued_item::QueuedCoverArt, - api::get_metadata_queue::response::Metadata, - ), - reqwest::Error, -> { - match api::fetch_song_queue_data::get_data(app, song_queue_id).await { - Ok(response) => { - // Process data here... - match api::parsing::parse_response_into_bytes(response).await { - Ok(song_bytes) => { - let song = icarus_models::song::Song { - directory: icarus_envy::environment::get_root_directory().await.value, - filename: icarus_models::song::generate_filename( - icarus_models::types::MusicTypes::FlacExtension, - true, - ), - data: song_bytes, - ..Default::default() - }; - let songpath = song.song_path().unwrap_or_default(); - - let queued_song: crate::queued_item::QueuedSong = - match song.save_to_filesystem() { - Ok(_) => queued_item::QueuedSong { - id: *song_queue_id, - song, - path: songpath, - }, - Err(err) => { - eprintln!("Error: {err:?}"); - queued_item::QueuedSong { - ..Default::default() - } - } - }; - - println!("Saved at: {:?}", queued_song.path); - - match api::get_metadata_queue::get(app, &queued_song.id).await { - Ok(response) => { - match response - .json::() - .await - { - Ok(response) => { - let id = &response.data[0].id; - 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:?}"); - - println!("Getting coverart queue"); - match api::get_coverart_queue::get(app, &queued_song.id).await { - Ok(response) => { - match response.json::().await { - Ok(response) => { - let coverart_queue = &response.data[0]; - let coverart_queue_id = coverart_queue.id; - println!("Coverart queue Id: {coverart_queue_id:?}"); - - match api::get_coverart_queue::get_data(app, &coverart_queue_id).await { - Ok(response) => match api::parsing::parse_response_into_bytes(response).await { - Ok(coverart_queue_bytes) => { - let (directory, filename) = generate_coverart_queue_dir_and_filename(&coverart_queue.file_type).await; - let coverart = icarus_models::coverart::CoverArt { - directory, - filename, - data: coverart_queue_bytes, - ..Default::default() - }; - coverart.save_to_filesystem().unwrap(); - let coverart_queue_fs_path = match coverart.get_path() { - Ok(path) => { - path - } - Err(err) => { - eprintln!("Error: {err:?}"); - std::process::exit(-1); - } - }; - - let queued_coverart = queued_item::QueuedCoverArt { - id: coverart_queue_id, - coverart, - path: coverart_queue_fs_path - }; - - println!("Saved coverart queue file at: {:?}", queued_coverart.path); - - Ok((queued_song, queued_coverart, metadata.clone())) - } - Err(err) => { - Err(err) - } - } - Err(err) => { - Err(err) - } - } - } - Err(err) => { - Err(err) - } - } - } - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } -} - -// TODO: Consider having something like this in icarus_models -pub async fn generate_coverart_queue_dir_and_filename(file_type: &str) -> (String, String) { - use rand::Rng; - - let mut filename: String = String::new(); - let filename_len = 10; - - let some_chars: String = String::from("abcdefghij0123456789"); - let mut rng = rand::rng(); - - for _ in 0..filename_len { - let random_number: i32 = rng.random_range(0..=19); - let index = random_number as usize; - let rando_char = some_chars.chars().nth(index); - - if let Some(c) = rando_char { - filename.push(c); - } - } - - filename += if file_type == icarus_meta::detection::coverart::constants::JPEG_TYPE - || file_type == icarus_meta::detection::coverart::constants::JPG_TYPE - { - icarus_models::constants::file_extensions::image::JPEGEXTENSION - } else if file_type == icarus_meta::detection::coverart::constants::PNG_TYPE { - icarus_models::constants::file_extensions::image::PNGEXTENSION - } else { - "" - }; - - // TODO: Consider separating song and coverart when saving to the filesystem - let directory = icarus_envy::environment::get_root_directory().await.value; - - (directory, filename) -} diff --git a/src/parser/mod.rs b/src/parser/mod.rs new file mode 100644 index 0000000..f4c8260 --- /dev/null +++ b/src/parser/mod.rs @@ -0,0 +1,234 @@ +pub async fn some_work( + app: &crate::config::App, + song_queue_id: &uuid::Uuid, + user_id: &uuid::Uuid, +) -> Result< + ( + icarus_models::song::Song, + icarus_models::coverart::CoverArt, + crate::api::get_metadata_queue::response::Metadata, + crate::queued_item::QueuedSong, + crate::queued_item::QueuedCoverArt, + ), + std::io::Error, +> { + match prep_song(app, song_queue_id).await { + Ok((queued_song, queued_coverart, metadata)) => { + println!("Prepping song"); + + match crate::metadata::apply_metadata(&queued_song, &queued_coverart, &metadata).await { + Ok(_applied) => { + match crate::api::update_queued_song::update_queued_song(app, &queued_song) + .await + { + Ok(response) => { + match response + .json::() + .await + { + Ok(_inner_response) => { + println!("Updated queued song"); + println!("Response: {_inner_response:?}"); + + let song_type = String::from( + icarus_meta::detection::song::constants::FLAC_TYPE, + ); + + match crate::api::create_song::create( + app, &metadata, user_id, &song_type, + ) + .await + { + Ok(response) => match response + .json::() + .await + { + Ok(resp) => { + println!("Response: {resp:?}"); + + let mut song = resp.data[0].clone(); + song.directory = queued_song.song.directory.clone(); + song.filename = queued_song.song.filename.clone(); + + match crate::api::create_coverart::create(app, &song, &queued_coverart).await { + Ok(response) => match response.json::().await { + Ok(resp) => { + println!("CoverArt sent and successfully parsed response"); + println!("json: {resp:?}"); + let mut coverart = resp.data[0].clone(); + coverart.directory = queued_coverart.coverart.directory.clone(); + coverart.filename = queued_coverart.coverart.filename.clone(); + + Ok((song.clone(), coverart.clone(), metadata, queued_song.clone(), queued_coverart.clone())) + } + Err(err) => { + Err(std::io::Error::other(err.to_string())) + } + } + Err(err) => { + Err(std::io::Error::other(err.to_string())) + } + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + }, + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } + 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())), + } +} + +pub async fn prep_song( + app: &crate::config::App, + song_queue_id: &uuid::Uuid, +) -> Result< + ( + crate::queued_item::QueuedSong, + crate::queued_item::QueuedCoverArt, + crate::api::get_metadata_queue::response::Metadata, + ), + reqwest::Error, +> { + match crate::api::fetch_song_queue_data::get_data(app, song_queue_id).await { + Ok(response) => { + // Process data here... + match crate::api::parsing::parse_response_into_bytes(response).await { + Ok(song_bytes) => { + let song = icarus_models::song::Song { + directory: icarus_envy::environment::get_root_directory().await.value, + filename: icarus_models::song::generate_filename( + icarus_models::types::MusicTypes::FlacExtension, + true, + ), + data: song_bytes, + ..Default::default() + }; + let songpath = song.song_path().unwrap_or_default(); + + let queued_song: crate::queued_item::QueuedSong = + match song.save_to_filesystem() { + Ok(_) => crate::queued_item::QueuedSong { + id: *song_queue_id, + song, + path: songpath, + }, + Err(err) => { + eprintln!("Error: {err:?}"); + crate::queued_item::QueuedSong { + ..Default::default() + } + } + }; + + println!("Saved at: {:?}", queued_song.path); + + match crate::api::get_metadata_queue::get(app, &queued_song.id).await { + Ok(response) => { + match response + .json::() + .await + { + Ok(response) => { + let id = &response.data[0].id; + 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:?}"); + + println!("Getting coverart queue"); + match crate::api::get_coverart_queue::get(app, &queued_song.id).await { + Ok(response) => { + match response.json::().await { + Ok(response) => { + let coverart_queue = &response.data[0]; + let coverart_queue_id = coverart_queue.id; + println!("Coverart queue Id: {coverart_queue_id:?}"); + + match crate::api::get_coverart_queue::get_data(app, &coverart_queue_id).await { + Ok(response) => match crate::api::parsing::parse_response_into_bytes(response).await { + Ok(coverart_queue_bytes) => { + let (directory, filename) = crate::util::generate_coverart_queue_dir_and_filename(&coverart_queue.file_type).await; + let coverart = icarus_models::coverart::CoverArt { + directory, + filename, + data: coverart_queue_bytes, + ..Default::default() + }; + coverart.save_to_filesystem().unwrap(); + let coverart_queue_fs_path = match coverart.get_path() { + Ok(path) => { + path + } + Err(err) => { + eprintln!("Error: {err:?}"); + std::process::exit(-1); + } + }; + + let queued_coverart = crate::queued_item::QueuedCoverArt { + id: coverart_queue_id, + coverart, + path: coverart_queue_fs_path + }; + + println!("Saved coverart queue file at: {:?}", queued_coverart.path); + + Ok((queued_song, queued_coverart, metadata.clone())) + } + Err(err) => { + Err(err) + } + } + Err(err) => { + Err(err) + } + } + } + Err(err) => { + Err(err) + } + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(err), + } +} + +pub async fn cleanup( + song: &icarus_models::song::Song, + coverart: &icarus_models::coverart::CoverArt, +) -> Result<(), std::io::Error> { + match song.remove_from_filesystem() { + Ok(_) => {} + Err(err) => { + eprintln!("Error: Problem cleaning up SongQueue files {err:?}"); + } + } + + match coverart.remove_from_filesystem() { + Ok(_) => Ok(()), + Err(err) => Err(err), + } +} diff --git a/src/queue/mod.rs b/src/queue/mod.rs new file mode 100644 index 0000000..8ce5c6a --- /dev/null +++ b/src/queue/mod.rs @@ -0,0 +1,60 @@ +pub async fn wipe_data_from_queues( + app: &crate::config::App, + queued_song: &crate::queued_item::QueuedSong, + queued_coverart: &crate::queued_item::QueuedCoverArt, +) -> Result<(), std::io::Error> { + match crate::api::wipe_data::song_queue::wipe_data(app, queued_song).await { + Ok(response) => match response + .json::() + .await + { + Ok(_resp) => { + match crate::api::wipe_data::coverart_queue::wipe_data(app, queued_coverart).await { + Ok(inner_response) => match inner_response + .json::() + .await + { + Ok(_inner_resp) => { + println!("Wiped data from CoverArt queue"); + println!("Resp: {_inner_resp:?}"); + Ok(()) + } + Err(err) => Err(std::io::Error::other(err.to_string())), + }, + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + }, + Err(err) => Err(std::io::Error::other(err.to_string())), + } +} + +pub async fn is_queue_empty( + app: &crate::config::App, +) -> Result< + ( + bool, + crate::api::fetch_next_queue_item::response::SongQueueItem, + ), + reqwest::Error, +> { + match crate::api::fetch_next_queue_item::fetch_next_queue_item(app).await { + Ok(response) => { + match response + .json::() + .await + { + Ok(response) => { + if response.data.is_empty() { + Ok((true, response)) + } else { + Ok((false, response)) + } + } + Err(err) => Err(err), + } + } + Err(err) => Err(err), + } +} diff --git a/src/util.rs b/src/util.rs index 3a873bc..57a2c60 100644 --- a/src/util.rs +++ b/src/util.rs @@ -4,3 +4,39 @@ pub fn path_buf_to_string(path: &std::path::Path) -> String { None => String::new(), } } + +// TODO: Consider having something like this in icarus_models +pub async fn generate_coverart_queue_dir_and_filename(file_type: &str) -> (String, String) { + use rand::Rng; + + let mut filename: String = String::new(); + let filename_len = 10; + + let some_chars: String = String::from("abcdefghij0123456789"); + let mut rng = rand::rng(); + + for _ in 0..filename_len { + let random_number: i32 = rng.random_range(0..=19); + let index = random_number as usize; + let rando_char = some_chars.chars().nth(index); + + if let Some(c) = rando_char { + filename.push(c); + } + } + + filename += if file_type == icarus_meta::detection::coverart::constants::JPEG_TYPE + || file_type == icarus_meta::detection::coverart::constants::JPG_TYPE + { + icarus_models::constants::file_extensions::image::JPEGEXTENSION + } else if file_type == icarus_meta::detection::coverart::constants::PNG_TYPE { + icarus_models::constants::file_extensions::image::PNGEXTENSION + } else { + "" + }; + + // TODO: Consider separating song and coverart when saving to the filesystem + let directory = icarus_envy::environment::get_root_directory().await.value; + + (directory, filename) +}