diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index df423ea..0d8531d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,8 @@ extract_version: script: - apk add --no-cache jq - VERSION=$(grep 'version = "' Cargo.toml | awk -F'"' '{print $2}' | head -n 1) + - VER_HASH=${CI_COMMIT_SHA:0:10} + - VERSION="$VERSION-$VER_HASH" - if [ $? -ne 0 ]; then echo "Error extracting version"; exit 1; fi - echo "Extracted version is" - echo "$VERSION" diff --git a/Cargo.toml b/Cargo.toml index cf7fc91..17a7f14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus-models" -version = "0.1.7" +version = "0.1.10" edition = "2024" description = "models used for the icarus project" license = "MIT" diff --git a/src/song.rs b/src/song.rs index 9b5357a..1a0fdd6 100644 --- a/src/song.rs +++ b/src/song.rs @@ -5,69 +5,303 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Song { + #[serde(skip_serializing_if = "is_zero")] #[serde(alias = "id")] - pub id: Option, - pub title: Option, - pub artist: Option, - pub album: Option, - pub album_artist: Option, - pub genre: Option, - pub year: Option, - pub duration: Option, - pub track: Option, - pub disc: Option, - pub disc_count: Option, - pub track_count: Option, - pub audio_type: Option, - pub date_created: Option, - pub filename: Option, - pub user_id: Option, + pub id: i32, + #[serde(skip_serializing_if = "String::is_empty")] + pub title: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub artist: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub album: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub album_artist: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub genre: String, + #[serde(skip_serializing_if = "is_zero")] + pub year: i32, + #[serde(skip_serializing_if = "is_dur_not_set")] + pub duration: i32, + #[serde(skip_serializing_if = "is_zero")] + pub track: i32, + #[serde(skip_serializing_if = "is_zero")] + pub disc: i32, + #[serde(skip_serializing_if = "is_zero")] + pub disc_count: i32, + #[serde(skip_serializing_if = "is_zero")] + pub track_count: i32, + #[serde(skip_serializing_if = "String::is_empty")] + pub audio_type: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub date_created: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub filename: String, + #[serde(skip_serializing_if = "is_zero")] + pub user_id: i32, #[serde(skip)] - pub data: Option>, + pub data: Vec, #[serde(skip)] - pub directory: Option, + pub directory: String, #[serde(skip)] - pub album_id: Option, + pub album_id: i32, #[serde(skip)] - pub artist_id: Option, + pub artist_id: i32, #[serde(skip)] - pub genre_id: Option, + pub genre_id: i32, #[serde(skip)] - pub coverart_id: Option, + pub coverart_id: i32, +} + +fn is_zero(num: &i32) -> bool { + *num == 0 +} + +fn is_dur_not_set(num: &i32) -> bool { + *num == 0 } impl Default for Song { fn default() -> Self { Song { - id: None, - title: None, - artist: None, - album: None, - album_artist: None, - genre: None, - year: None, - duration: None, - track: None, - disc: None, - disc_count: None, - track_count: None, - audio_type: None, - date_created: None, - filename: None, - user_id: None, - data: None, - directory: None, - album_id: None, - artist_id: None, - genre_id: None, - coverart_id: None, + id: 0, + title: String::new(), + artist: String::new(), + album: String::new(), + album_artist: String::new(), + genre: String::new(), + year: 0, + duration: 0, + track: 0, + disc: 0, + disc_count: 0, + track_count: 0, + audio_type: String::new(), + date_created: String::new(), + filename: String::new(), + user_id: 0, + data: Vec::new(), + directory: String::new(), + album_id: 0, + artist_id: 0, + genre_id: 0, + coverart_id: 0, } } } impl Song { - // TODO: Implement - pub fn to_metadata_json(&self) -> Result { - return serde_json::to_string_pretty(&self); + pub fn to_metadata_json(&self, pretty: bool) -> Result { + if pretty { + return serde_json::to_string_pretty(&self); + } else { + return serde_json::to_string(&self); + } + } + + pub fn song_path(&self) -> Result { + if self.directory.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Directory does not exist", + )); + } + + let directory = &self.directory; + let mut buffer: String = String::from(directory.clone()); + let lastIndex = directory.len() - 1; + + if let Some(character) = directory.chars().nth(lastIndex) { + if character != '/' { + buffer += "/"; + } + + buffer += &self.filename.clone(); + + return Ok(buffer); + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not access last character of directory", + )); + } + } + + pub fn to_data(&self) -> Result, std::io::Error> { + let pathResult = self.song_path(); + + match pathResult { + Ok(path) => { + let mut file = std::fs::File::open(path)?; + let mut buffer: Vec = Vec::new(); + file.read_to_end(&mut buffer)?; + + if buffer.len() == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "File is empty", + )); + } else { + return Ok(buffer); + } + } + Err(er) => { + return Err(er); + } + } + } +} + +mod embedded { + use std::io::Read; + + use serde::{Deserialize, Serialize}; + + impl Song { + pub fn to_metadata_json(&self, pretty: bool) -> Result { + if pretty { + return serde_json::to_string_pretty(&self); + } else { + return serde_json::to_string(&self); + } + } + + pub fn song_path(&self) -> Result { + if self.directory.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Directory does not exist", + )); + } + + let directory = &self.directory; + let mut buffer: String = String::from(directory.clone()); + let lastIndex = directory.len() - 1; + + if let Some(character) = directory.chars().nth(lastIndex) { + if character != '/' { + buffer += "/"; + } + + buffer += &self.filename.clone(); + + return Ok(buffer); + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not access last character of directory", + )); + } + } + + pub fn to_data(&self) -> Result, std::io::Error> { + let pathResult = self.song_path(); + + match pathResult { + Ok(path) => { + let mut file = std::fs::File::open(path)?; + let mut buffer: Vec = Vec::new(); + file.read_to_end(&mut buffer)?; + + if buffer.len() == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "File is empty", + )); + } else { + return Ok(buffer); + } + } + Err(er) => { + return Err(er); + } + } + } + } + + // The song's duration is a floating point in seconds + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct Song { + #[serde(skip_serializing_if = "is_embed_zero")] + #[serde(alias = "id")] + pub id: i32, + #[serde(skip_serializing_if = "String::is_empty")] + pub title: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub artist: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub album: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub album_artist: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub genre: String, + #[serde(skip_serializing_if = "is_embed_zero")] + pub year: i32, + #[serde(skip_serializing_if = "is_embed_dur_not_set")] + pub duration: f64, + #[serde(skip_serializing_if = "is_embed_zero")] + pub track: i32, + #[serde(skip_serializing_if = "is_embed_zero")] + pub disc: i32, + #[serde(skip_serializing_if = "is_embed_zero")] + pub disc_count: i32, + #[serde(skip_serializing_if = "is_embed_zero")] + pub track_count: i32, + #[serde(skip_serializing_if = "String::is_empty")] + pub audio_type: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub date_created: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub filename: String, + #[serde(skip_serializing_if = "is_embed_zero")] + pub user_id: i32, + #[serde(skip)] + pub data: Vec, + #[serde(skip)] + pub directory: String, + #[serde(skip)] + pub album_id: i32, + #[serde(skip)] + pub artist_id: i32, + #[serde(skip)] + pub genre_id: i32, + #[serde(skip)] + pub coverart_id: i32, + } + + fn is_embed_zero(num: &i32) -> bool { + *num == 0 + } + + fn is_embed_dur_not_set(num: &f64) -> bool { + *num == 0.0 + } + + impl Default for Song { + fn default() -> Self { + Song { + id: 0, + title: String::new(), + artist: String::new(), + album: String::new(), + album_artist: String::new(), + genre: String::new(), + year: 0, + duration: 0.0, + track: 0, + disc: 0, + disc_count: 0, + track_count: 0, + audio_type: String::new(), + date_created: String::new(), + filename: String::new(), + user_id: 0, + data: Vec::new(), + directory: String::new(), + album_id: 0, + artist_id: 0, + genre_id: 0, + coverart_id: 0, + } + } } }