use deunicode::deunicode;
use serde::{Deserialize, Serialize};
use crate::brainz::{ArtistCredit, ArtistReference, GenreReference, Tag};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ReleaseGroup {
pub id: String,
pub title: String,
#[serde(default, alias = "primary-type-id")]
pub primary_type_id: Option<String>,
#[serde(default, alias = "primary-type")]
pub primary_type: Option<String>,
#[serde(default, alias = "first-release-date")]
pub first_release_date: Option<String>,
#[serde(default, alias = "artist-credit")]
pub artist_credit: Vec<ArtistCredit>,
#[serde(default)]
pub genres: Vec<GenreReference>,
#[serde(default)]
pub tags: Vec<Tag>,
#[serde(default, alias = "secondary-types")]
pub secondary_types: Vec<String>,
}
fn primary_release_group_type_to_priority(release_group_type: &str) -> i64 {
let lowered = release_group_type.to_lowercase();
match lowered.as_str() {
"album" => 5,
"ep" => 4,
"live" => 3,
_ => 2,
}
}
fn secondary_release_group_type_to_priority(release_group_type: &str) -> i64 {
let lowered = release_group_type.to_lowercase();
match lowered.as_str() {
"album" => 2,
"ep" => 3,
"live" => 4,
_ => 1,
}
}
impl ReleaseGroup {
pub fn priority(&self) -> i64 {
if let Some(primary_type) = self.primary_type.as_ref() {
let mut priority = primary_release_group_type_to_priority(primary_type);
if !self.genres.is_empty() {
priority += 1;
}
if !self.tags.is_empty() {
priority += 1;
}
let release_date_priority = self
.first_release_date
.as_ref()
.map(|release_date| {
if !release_date.trim().is_empty() {
1
} else {
0
}
})
.unwrap_or(0);
priority += release_date_priority;
if self.secondary_types.is_empty() {
priority * 10
} else {
for secondary_type in self.secondary_types.iter() {
priority -= secondary_release_group_type_to_priority(secondary_type);
}
if priority <= 0 {
priority = 1
}
priority * 5
}
} else {
1
}
}
pub fn artist_ids(&self) -> Vec<String> {
self.artist_credit
.iter()
.filter_map(|artist_credit| artist_credit.artist.clone())
.map(|artist| artist.id.clone())
.collect()
}
pub fn artist_content(&self) -> String {
self.artist_credit
.iter()
.flat_map(|artist_credit| {
if let Some(artist) = artist_credit.artist.as_ref() {
Some(artist.name.clone())
} else {
artist_credit.name.clone()
}
})
.map(|name| {
let normal = deunicode(&name);
if name.contains(".") {
format!("{} {}", normal, normal.replace(".", ""))
} else {
normal
}
})
.collect::<Vec<_>>()
.join("; ")
}
pub fn artist_references(&self) -> Vec<ArtistReference> {
self.artist_credit
.iter()
.flat_map(|artist_credit| artist_credit.artist.clone())
.collect::<Vec<_>>()
}
pub fn title_content(&self) -> String {
deunicode(&self.title)
}
pub fn genres_content(&self) -> String {
self.genres
.iter()
.map(|genre| genre.name.clone())
.collect::<Vec<_>>()
.join("; ")
}
pub fn matches_types(&self, release_types: &[String]) -> bool {
if let Some(primary_type) = self.primary_type.as_ref() {
if !release_types.contains(primary_type) {
false
} else if self.secondary_types.is_empty() {
true
} else {
release_types
.iter()
.any(|release_type| self.secondary_types.contains(release_type))
}
} else {
false
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct SearchReleaseGroup {
pub id: String,
pub title: String,
pub artists: Vec<String>,
pub genres: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct ReleaseGroupReference {
pub id: String,
}