diff --git a/Cargo.lock b/Cargo.lock index 663a929..a2f85d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,7 @@ dependencies = [ [[package]] name = "icarus_meta" -version = "0.4.4" +version = "0.4.5" dependencies = [ "imghdr", "infer", diff --git a/Cargo.toml b/Cargo.toml index b98b2eb..38c59e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus_meta" -version = "0.4.4" +version = "0.4.5" edition = "2024" rust-version = "1.90" diff --git a/src/lib.rs b/src/lib.rs index dd4820b..cb40592 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,10 +19,7 @@ pub mod test_util { Err(err) => Err(err), } } - pub fn get_full_path( - directory: &String, - filename: &String, - ) -> Result { + pub fn get_full_path(directory: &str, filename: &str) -> Result { match path_buf(directory, filename) { Ok(pf) => Ok(pf.display().to_string()), Err(err) => Err(err), @@ -39,6 +36,12 @@ pub mod test_util { std::fs::copy(src_path, dest_path) } + pub fn remove_file(filepath: &str) -> Result<(), std::io::Error> { + let f_path = std::path::Path::new(filepath); + + std::fs::remove_file(f_path) + } + pub fn get_data_from_file(source_path: &str) -> Result, std::io::Error> { match std::fs::File::open(source_path) { Ok(mut file) => { @@ -52,13 +55,23 @@ pub mod test_util { } } - pub fn file_exists(directory: &String, filename: &String) -> Result { + pub fn file_exists(directory: &str, filename: &str) -> Result { match path_buf(directory, filename) { Ok(pf) => Ok(pf.exists()), Err(err) => Err(err), } } + pub fn generate_newfilepath(directory: &str) -> Result { + match generate_filename() { + Ok(filename) => match get_full_path(directory, &filename) { + Ok(filepath) => Ok(filepath), + Err(err) => Err(err), + }, + Err(err) => Err(err), + } + } + pub fn generate_filename() -> Result { let mut filename = String::from("track-"); let length = 20; @@ -78,10 +91,7 @@ pub mod test_util { Ok(format!("{filename}.flac")) } - fn path_buf( - directory: &String, - filename: &String, - ) -> Result { + fn path_buf(directory: &str, filename: &str) -> Result { let dir_path = std::path::Path::new(&directory); Ok(dir_path.join(filename)) } diff --git a/src/properties.rs b/src/properties.rs deleted file mode 100644 index 3e28031..0000000 --- a/src/properties.rs +++ /dev/null @@ -1,51 +0,0 @@ -use lofty::file::AudioFile; - -pub fn get_duration(song_path: &String) -> Result { - match std::fs::File::open(song_path) { - Ok(mut content) => { - match lofty::flac::FlacFile::read_from(&mut content, lofty::config::ParseOptions::new()) - { - Ok(flac_file) => { - let properties = flac_file.properties(); - Ok(properties.duration()) - } - Err(err) => Err(std::io::Error::other(err.to_string())), - } - } - Err(err) => Err(err), - } -} - -#[cfg(test)] -mod tests { - use crate::test_util; - - #[test] - fn test_get_duration() { - let filename = test_util::util::get_filename(1); - let dir = String::from(test_util::util::TESTFILEDIRECTORY); - - match test_util::util::file_exists(&dir, &filename) { - Ok(_) => { - let filepath = test_util::util::get_full_path(&dir, &filename).unwrap(); - match super::get_duration(&filepath) { - Ok(duration) => { - let song_duration: u64 = 41; - let fetched_song_duration = duration.as_secs(); - - assert_eq!( - song_duration, fetched_song_duration, - "Durations should match, but they don't {song_duration} {fetched_song_duration} ({duration:?})" - ); - } - Err(err) => { - assert!(false, "Error: {err:?}"); - } - } - } - Err(err) => { - assert!(false, "Error: {err:?}"); - } - } - } -} diff --git a/src/properties/audio.rs b/src/properties/audio.rs new file mode 100644 index 0000000..e74034d --- /dev/null +++ b/src/properties/audio.rs @@ -0,0 +1,14 @@ +use lofty::file::AudioFile; + +pub fn get_properties(songpath: &str) -> Result { + match std::fs::File::open(songpath) { + Ok(mut content) => { + match lofty::flac::FlacFile::read_from(&mut content, lofty::config::ParseOptions::new()) + { + Ok(flac_file) => Ok(*flac_file.properties()), + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } + Err(err) => Err(err), + } +} diff --git a/src/properties/mod.rs b/src/properties/mod.rs new file mode 100644 index 0000000..69f08f6 --- /dev/null +++ b/src/properties/mod.rs @@ -0,0 +1,139 @@ +pub mod audio; + +#[derive(Clone, Debug, Default)] +pub struct SongProperties { + pub duration: std::time::Duration, + pub sample_rate: u32, + pub bitrate: u32, + pub overall_bitrate: u32, + pub bit_depth: u8, + pub channels: u8, +} + +pub fn get_song_properties(song_path: &str) -> Result { + match audio::get_properties(song_path) { + Ok(flac_properties) => Ok(SongProperties { + duration: flac_properties.duration(), + sample_rate: flac_properties.sample_rate(), + bitrate: flac_properties.audio_bitrate(), + overall_bitrate: flac_properties.overall_bitrate(), + bit_depth: flac_properties.bit_depth(), + channels: flac_properties.channels(), + }), + Err(err) => Err(err), + } +} + +pub fn get_duration(song_path: &str) -> Result { + match get_song_properties(song_path) { + Ok(song_properties) => Ok(song_properties.duration), + Err(err) => Err(err), + } +} + +#[cfg(test)] +mod tests { + use crate::test_util; + + #[test] + fn test_get_duration() { + let filename = test_util::util::get_filename(1); + let dir = String::from(test_util::util::TESTFILEDIRECTORY); + + match test_util::util::file_exists(&dir, &filename) { + Ok(_) => { + let filepath = test_util::util::get_full_path(&dir, &filename).unwrap(); + let new_filepath = test_util::util::generate_newfilepath(&dir).unwrap(); + + match test_util::util::copy_file(&filepath, &new_filepath) { + Ok(_) => match super::get_duration(&new_filepath) { + Ok(duration) => { + test_util::util::remove_file(&new_filepath).unwrap(); + + let song_duration: u64 = 41; + let fetched_song_duration = duration.as_secs(); + + assert_eq!( + song_duration, fetched_song_duration, + "Durations should match, but they don't {song_duration} {fetched_song_duration} ({duration:?})" + ); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + }, + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } + + #[test] + fn test_song_properties() { + let filename = test_util::util::get_filename(1); + let dir = String::from(test_util::util::TESTFILEDIRECTORY); + + match test_util::util::file_exists(&dir, &filename) { + Ok(_) => { + let filepath = test_util::util::get_full_path(&dir, &filename).unwrap(); + let new_filepath = test_util::util::generate_newfilepath(&dir).unwrap(); + + match test_util::util::copy_file(&filepath, &new_filepath) { + Ok(_) => match super::get_song_properties(&new_filepath) { + Ok(song_properties) => { + test_util::util::remove_file(&new_filepath).unwrap(); + + let song_duration: u64 = 41; + let bitrate: u32 = 1; + let overall_bitrate: u32 = 3; + let bit_depth: u8 = 24; + let channels: u8 = 2; + + let fetched_song_duration = song_properties.duration.as_secs(); + let fetched_bitrate = song_properties.bitrate; + let fetched_overall_bitrate = song_properties.overall_bitrate; + let fetched_bit_depth = song_properties.bit_depth; + let fetched_channels = song_properties.channels; + + assert_eq!( + song_duration, fetched_song_duration, + "Durations should match, but they don't {song_duration} {fetched_song_duration} ({song_properties:?})" + ); + + assert_eq!( + bitrate, fetched_bitrate, + "Bitrates do not match {bitrate:?} {fetched_bitrate:?} {song_properties:?}" + ); + assert_eq!( + overall_bitrate, fetched_overall_bitrate, + "Overall bitrates do not match {overall_bitrate:?} {fetched_overall_bitrate:?} {song_properties:?}" + ); + assert_eq!( + bit_depth, fetched_bit_depth, + "Bit depth do not match {bit_depth:?} {fetched_bit_depth:?} {song_properties:?}" + ); + assert_eq!( + channels, fetched_channels, + "Channels do not match {channels:?} {fetched_channels:?} {song_properties:?}" + ); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + }, + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } +}