diff --git a/genres/genres_to_meta.py b/genres/genres_to_meta.py index 85ebce7..474fac5 100644 --- a/genres/genres_to_meta.py +++ b/genres/genres_to_meta.py @@ -453,23 +453,6 @@ def package(out_dir: Path): with open(util.TRANSLATION_FILE_EN) as f: tl_en = json.load(f) - # Remove redundant tags - def remove_redundant_tags(gid: str, parent: str): - genre = metadata[gid] - pg = metadata[parent] - if pg.language and pg.language == genre.language: - metadata[gid].language = None - if pg.country and pg.country == genre.country: - metadata[gid].country = None - if pg.region and pg.region == genre.region: - metadata[gid].region = None - if pg.parent: - remove_redundant_tags(gid, pg.parent) - - for genre_id, genre in metadata.items(): - if genre.parent: - remove_redundant_tags(genre_id, genre.parent) - # Genre database db = { g_id: model.GenreMetadataDB.conv(genre, tl_en.get(g_id)) diff --git a/libs/rust/Cargo.toml b/libs/rust/Cargo.toml index b3ed6a6..0081e66 100644 --- a/libs/rust/Cargo.toml +++ b/libs/rust/Cargo.toml @@ -2,10 +2,6 @@ name = "spotify-genrebase" version = "0.1.0" edition = "2021" -authors = ["ThetaDev "] -license = "MIT" -description = "Lookup Spotify genre metadata" -repository = "https://code.thetadev.de/Tiraya/spotify-genres" [features] playlists = [] @@ -19,5 +15,4 @@ serde_with = { version = "3.0", default-features = false, features = [ "macros", ] } serde_json = "1.0" -serde_plain = "1.0" thiserror = "1.0" diff --git a/libs/rust/src/lib.rs b/libs/rust/src/lib.rs index b3e7176..76cfa5a 100644 --- a/libs/rust/src/lib.rs +++ b/libs/rust/src/lib.rs @@ -6,7 +6,7 @@ use path_macro::path; use model::{GenreEntry, GenreMeta}; -pub use model::{Genre, Region}; +pub use model::Genre; type Translation = HashMap; @@ -55,11 +55,6 @@ impl GenreDb { }) } - /// Return a list of supported languages - pub fn languages(&self) -> Vec<&str> { - self.translations.keys().map(String::as_str).collect() - } - /// Select a supported language from a list of given languages (for example from the /// Accept-Language http headere). pub fn select_lang<'a, S: AsRef>(&self, langs: &'a [S]) -> Option<&'a str> { @@ -130,64 +125,33 @@ impl GenreDb { GenreEntry::Alias { alias } => self.get_localized(alias, lang), GenreEntry::Meta(genre) => { if let Some(lang) = lang { - Some( - self.conv_genre( - id, - self.get_translated_name(id, lang) - .unwrap_or_else(|| genre.name.to_owned()), - genre, - ), - ) + Some(conv_genre( + id, + self.get_translated_name(id, lang) + .unwrap_or_else(|| genre.name.to_owned()), + genre, + )) } else { - Some(self.conv_genre(id, genre.name.to_owned(), genre)) + Some(conv_genre(id, genre.name.to_owned(), genre)) } } } } - - fn conv_genre<'a>(&self, id: &str, name: String, gm: &GenreMeta) -> Genre { - let mut genre = Genre { - id: id.to_owned(), - name: name, - parent: gm.parent.to_owned(), - language: gm.language.to_owned(), - country: gm.country.to_owned(), - region: gm.region, - rank: gm.rank, - deprecated: gm.deprecated, - metagenre: gm.metagenre, - #[cfg(feature = "playlists")] - playlists: gm.playlists.clone(), - }; - self.inherit_parent(&mut genre, gm.parent.as_deref()); - genre - } - - fn inherit_parent(&self, genre: &mut Genre, parent: Option<&str>) { - if let Some(GenreEntry::Meta(g2)) = parent.and_then(|p| self.genres.get(p)) { - merge_genre_data(genre, g2); - self.inherit_parent(genre, g2.parent.as_deref()); - } - } - - /// Get the path of the genre tree - pub fn tree_path(&self, lang: Option<&str>) -> PathBuf { - match lang.filter(|l| self.translations.contains_key(*l)) { - Some(lang) => path!(self.path / "tree" / format!("tree.{lang}.json")), - None => path!(self.path / "tree" / "tree.en.json"), - } - } } -fn merge_genre_data(genre: &mut Genre, g2: &GenreMeta) { - if genre.language.is_none() { - genre.language = g2.language.clone(); - } - if genre.country.is_none() { - genre.country = g2.country.clone(); - } - if genre.region.is_none() { - genre.region = g2.region.clone(); +fn conv_genre<'a>(id: &str, name: String, gm: &GenreMeta) -> Genre { + Genre { + id: id.to_owned(), + name: name, + parent: gm.parent.to_owned(), + language: gm.language.to_owned(), + country: gm.country.to_owned(), + region: gm.region, + rank: gm.rank, + deprecated: gm.deprecated, + metagenre: gm.metagenre, + #[cfg(feature = "playlists")] + playlists: gm.playlists.clone(), } } @@ -213,25 +177,14 @@ mod tests { let genre = db.get_localized(id, lang).unwrap(); assert_eq!(genre.id, id); assert_eq!(genre.name, expect); - assert_eq!(genre.language.unwrap(), "sqi"); - assert_eq!(genre.country.unwrap(), "AL"); let localized_name = db.get_localized_name(id, lang).unwrap(); assert_eq!(localized_name, expect) } - #[test] - /// Genres should inherit parent parameters - fn get_subgenre() { - let db = GenreDb::new(genre_db_path()).unwrap(); - let genre = db.get("k-pop girl group").unwrap(); - assert_eq!(genre.language.unwrap(), "kor"); - assert_eq!(genre.country.unwrap(), "KR"); - } - #[test] fn select_lang() { - let languages = vec!["xy".to_owned(), "de".to_owned(), "en-GB".to_owned()]; + let languages = vec!["es".to_owned(), "de".to_owned(), "en-GB".to_owned()]; let db = GenreDb::new(genre_db_path()).unwrap(); let lang = db.select_lang(&languages); @@ -246,18 +199,4 @@ mod tests { let lang = db.select_lang(&languages); assert_eq!(lang, None); } - - #[test] - fn tree_path() { - let db_path = genre_db_path(); - let db = GenreDb::new(&db_path).unwrap(); - - let expect_en = path!(&db_path / "tree" / "tree.en.json"); - let expect_de = path!(&db_path / "tree" / "tree.de.json"); - - assert_eq!(db.tree_path(None), expect_en); - assert_eq!(db.tree_path(Some("en")), expect_en); - assert_eq!(db.tree_path(Some("xy")), expect_en); - assert_eq!(db.tree_path(Some("de")), expect_de); - } } diff --git a/libs/rust/src/model.rs b/libs/rust/src/model.rs index 86cf295..fb5e1aa 100644 --- a/libs/rust/src/model.rs +++ b/libs/rust/src/model.rs @@ -4,9 +4,8 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DefaultOnError}; -/// Region for describing genres from multiple countrie +/// Region for describing genres from multiple countries #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] pub enum Region { /// Africa AF, @@ -58,7 +57,28 @@ pub enum Region { WF, } -serde_plain::derive_display_from_serialize!(Region); +#[cfg(feature = "playlists")] +#[serde_as] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum PlaylistKind { + Sound, + Intro, + Pulse, + Edge, + #[serde(rename = "2018")] + Y2018, + #[serde(rename = "2019")] + Y2019, + #[serde(rename = "2020")] + Y2020, + #[serde(rename = "2021")] + Y2021, + #[serde(rename = "2022")] + Y2022, + #[serde(rename = "2023")] + Y2023, +} #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -81,7 +101,7 @@ pub struct GenreMeta { pub rank: Option, #[cfg(feature = "playlists")] #[serde(default)] - pub playlists: HashMap, + pub playlists: HashMap, #[serde(default)] pub deprecated: bool, #[serde(default)] @@ -90,51 +110,21 @@ pub struct GenreMeta { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -#[non_exhaustive] pub struct Genre { - /// Spotify genre ID pub id: String, - /// Localized genre name pub name: String, - /// ID of the parent genre if this is a subgenre - #[serde(skip_serializing_if = "Option::is_none")] pub parent: Option, - /// ISO-639-3 language code if the genre implies lyrics in a specific language - #[serde(skip_serializing_if = "Option::is_none")] pub language: Option, - /// ISO-3166-1 country code if the genre is dominant in a specific country - #[serde(skip_serializing_if = "Option::is_none")] pub country: Option, - /// Region code if the genre is dominant in a specific region - /// - /// Region codes are not standardized, refer to the documentation for a definition. - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] #[serde_as(deserialize_as = "DefaultOnError")] pub region: Option, - /// Position in the popularity ranking (1: most popular) - #[serde(skip_serializing_if = "Option::is_none")] pub rank: Option, - /// Spotify playlist IDs #[cfg(feature = "playlists")] - #[serde(skip_serializing_if = "Option::is_none")] - pub playlists: Option>, - /// True if the genre is no longer part of Spotify's catalog - #[serde(default, skip_serializing_if = "is_default")] + #[serde(default)] + pub playlists: HashMap, + #[serde(default)] pub deprecated: bool, - /// True if the genre is a metagenre - /// - /// Metagenres do not exist at Spotify but are used to group other genres together. - #[serde(default, skip_serializing_if = "is_default")] + #[serde(default)] pub metagenre: bool, } - -impl PartialEq for Genre { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} -impl Eq for Genre {} - -fn is_default(t: &T) -> bool { - t == &T::default() -} diff --git a/schema/genre_db.json b/schema/genre_db.json index 6b5744d..78c2c0c 100644 --- a/schema/genre_db.json +++ b/schema/genre_db.json @@ -34,7 +34,7 @@ "pattern": "^[A-Z]{2}$" }, "region": { - "description": "Region code if the genre is dominant in a specific region\nRegion codes are not standardized, refer to the documentation for a definition.", + "description": "Region code if the genre is dominant in a specific region", "type": "string", "enum": [ "AF", diff --git a/schema/genre_metadata.json b/schema/genre_metadata.json index eab53d9..f0e7ccf 100644 --- a/schema/genre_metadata.json +++ b/schema/genre_metadata.json @@ -36,7 +36,7 @@ "pattern": "^[A-Z]{2}$" }, "region": { - "description": "Region code if the genre is dominant in a specific region\nRegion codes are not standardized, refer to the documentation for a definition.", + "description": "Region code if the genre is dominant in a specific region", "type": "string", "enum": [ "AF", @@ -112,7 +112,7 @@ "pattern": "^[a-z0-9\\-+: '&]+$" }, "deprecated": { - "description": "True if the genre is no longer part of Spotify's catalog", + "description": "True if the genre is no longer part of Spotify's catalogue", "type": "boolean" }, "metagenre": { diff --git a/schema/genre_tree.json b/schema/genre_tree.json index 8b90fb5..a3f8891 100644 --- a/schema/genre_tree.json +++ b/schema/genre_tree.json @@ -32,7 +32,7 @@ "pattern": "^[A-Z]{2}$" }, "region": { - "description": "Region code if the genre is dominant in a specific region\nRegion codes are not standardized, refer to the documentation for a definition.", + "description": "Region code if the genre is dominant in a specific region", "type": "string", "enum": [ "AF",