Add worldwide genre style selector
This commit is contained in:
@@ -594,6 +594,35 @@ public struct GenreStyle: Codable, Equatable, Identifiable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct GenreStyleCatalogItem: Codable, Equatable, Identifiable, Sendable {
|
||||
public let id: String
|
||||
public var name: String
|
||||
public var familyCategory: String
|
||||
public var regionOrigin: String?
|
||||
public var aliases: [String]
|
||||
public var searchTerms: [String]
|
||||
|
||||
public init(
|
||||
id: String,
|
||||
name: String,
|
||||
familyCategory: String,
|
||||
regionOrigin: String? = nil,
|
||||
aliases: [String] = [],
|
||||
searchTerms: [String] = []
|
||||
) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.familyCategory = familyCategory
|
||||
self.regionOrigin = regionOrigin
|
||||
self.aliases = aliases
|
||||
self.searchTerms = searchTerms
|
||||
}
|
||||
|
||||
public var genreStyle: GenreStyle {
|
||||
GenreStyle(id: id, name: name, aliases: aliases)
|
||||
}
|
||||
}
|
||||
|
||||
public struct MoodTag: Codable, Equatable, Identifiable, Sendable {
|
||||
public let id: String
|
||||
public var name: String
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
import Foundation
|
||||
|
||||
public struct LocalGenreStyleCatalog: Sendable {
|
||||
public let items: [GenreStyleCatalogItem]
|
||||
|
||||
public init(items: [GenreStyleCatalogItem] = LocalGenreStyleCatalog.worldwideItems) {
|
||||
self.items = items
|
||||
}
|
||||
|
||||
public var familyCategories: [String] {
|
||||
Array(Set(items.map(\.familyCategory)))
|
||||
.sorted { $0.localizedCaseInsensitiveCompare($1) == .orderedAscending }
|
||||
}
|
||||
|
||||
public var regionsOfOrigin: [String] {
|
||||
Array(Set(items.compactMap(\.regionOrigin)))
|
||||
.sorted { $0.localizedCaseInsensitiveCompare($1) == .orderedAscending }
|
||||
}
|
||||
|
||||
public func styles(
|
||||
matching query: String,
|
||||
familyCategory: String? = nil,
|
||||
regionOrigin: String? = nil
|
||||
) -> [GenreStyleCatalogItem] {
|
||||
let searchTokens = Self.searchTokens(for: query)
|
||||
let selectedFamilyCategory = familyCategory?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let selectedRegionOrigin = regionOrigin?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
return items
|
||||
.filter { item in
|
||||
let matchesSearch = searchTokens.isEmpty || searchTokens.allSatisfy { token in
|
||||
Self.searchableTerms(for: item).contains { $0.contains(token) }
|
||||
}
|
||||
let matchesFamily = selectedFamilyCategory?.isEmpty != false || item.familyCategory == selectedFamilyCategory
|
||||
let matchesRegion = selectedRegionOrigin?.isEmpty != false || item.regionOrigin == selectedRegionOrigin
|
||||
return matchesSearch && matchesFamily && matchesRegion
|
||||
}
|
||||
.sorted { $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending }
|
||||
}
|
||||
|
||||
public static let worldwideItems: [GenreStyleCatalogItem] =
|
||||
popAndContemporary + rockAndAlternative + electronicAndDance + urbanAndSoul + jazzAndBlues +
|
||||
countryFolkAndRoots + latinAndCaribbean + middleEasternAndNorthAfrican + southAsian + eastAsian +
|
||||
southeastAsianAndOceania + african + reggaeAndCaribbean + classicalAndCinematic
|
||||
|
||||
private static let popAndContemporary: [GenreStyleCatalogItem] = [
|
||||
item("pop", "Pop", "Pop & Contemporary", "Global"),
|
||||
item("adult-contemporary", "Adult Contemporary", "Pop & Contemporary", "Western"),
|
||||
item("art-pop", "Art Pop", "Pop & Contemporary", "Western"),
|
||||
item("baroque-pop", "Baroque Pop", "Pop & Contemporary", "Western"),
|
||||
item("chamber-pop", "Chamber Pop", "Pop & Contemporary", "Western"),
|
||||
item("dance-pop", "Dance Pop", "Pop & Contemporary", "Western"),
|
||||
item("dream-pop", "Dream Pop", "Pop & Contemporary", "Western"),
|
||||
item("electropop", "Electropop", "Pop & Contemporary", "Western"),
|
||||
item("hyperpop", "Hyperpop", "Pop & Contemporary", "Western"),
|
||||
item("indie-pop", "Indie Pop", "Pop & Contemporary", "Western"),
|
||||
item("power-pop", "Power Pop", "Pop & Contemporary", "Western"),
|
||||
item("synth-pop", "Synth Pop", "Pop & Contemporary", "Western"),
|
||||
item("teen-pop", "Teen Pop", "Pop & Contemporary", "Western"),
|
||||
item("soft-pop", "Soft Pop", "Pop & Contemporary", "Western"),
|
||||
item("singer-songwriter", "Singer-Songwriter", "Pop & Contemporary", "Western")
|
||||
]
|
||||
|
||||
private static let rockAndAlternative: [GenreStyleCatalogItem] = [
|
||||
item("rock", "Rock", "Rock & Alternative", "Western"),
|
||||
item("alternative-rock", "Alternative Rock", "Rock & Alternative", "Western", aliases: ["alt rock"]),
|
||||
item("classic-rock", "Classic Rock", "Rock & Alternative", "Western"),
|
||||
item("hard-rock", "Hard Rock", "Rock & Alternative", "Western"),
|
||||
item("indie-rock", "Indie Rock", "Rock & Alternative", "Western"),
|
||||
item("progressive-rock", "Progressive Rock", "Rock & Alternative", "Western", aliases: ["prog rock"]),
|
||||
item("psychedelic-rock", "Psychedelic Rock", "Rock & Alternative", "Western", aliases: ["psych rock"]),
|
||||
item("garage-rock", "Garage Rock", "Rock & Alternative", "Western"),
|
||||
item("surf-rock", "Surf Rock", "Rock & Alternative", "Western"),
|
||||
item("post-rock", "Post-Rock", "Rock & Alternative", "Western"),
|
||||
item("math-rock", "Math Rock", "Rock & Alternative", "Western"),
|
||||
item("grunge", "Grunge", "Rock & Alternative", "Western"),
|
||||
item("shoegaze", "Shoegaze", "Rock & Alternative", "Western"),
|
||||
item("emo", "Emo", "Rock & Alternative", "Western"),
|
||||
item("punk", "Punk", "Rock & Alternative", "Western"),
|
||||
item("pop-punk", "Pop Punk", "Rock & Alternative", "Western"),
|
||||
item("post-punk", "Post-Punk", "Rock & Alternative", "Western"),
|
||||
item("metal", "Metal", "Rock & Alternative", "Western"),
|
||||
item("heavy-metal", "Heavy Metal", "Rock & Alternative", "Western"),
|
||||
item("power-metal", "Power Metal", "Rock & Alternative", "Western"),
|
||||
item("progressive-metal", "Progressive Metal", "Rock & Alternative", "Western"),
|
||||
item("thrash-metal", "Thrash Metal", "Rock & Alternative", "Western"),
|
||||
item("death-metal", "Death Metal", "Rock & Alternative", "Western"),
|
||||
item("black-metal", "Black Metal", "Rock & Alternative", "Western"),
|
||||
item("doom-metal", "Doom Metal", "Rock & Alternative", "Western"),
|
||||
item("folk-rock", "Folk Rock", "Rock & Alternative", "Western"),
|
||||
item("blues-rock", "Blues Rock", "Rock & Alternative", "Western")
|
||||
]
|
||||
|
||||
private static let electronicAndDance: [GenreStyleCatalogItem] = [
|
||||
item("electronic", "Electronic", "Electronic & Dance", "Global"),
|
||||
item("edm", "EDM", "Electronic & Dance", "Global", aliases: ["electronic dance music"]),
|
||||
item("ambient", "Ambient", "Electronic & Dance", "Western"),
|
||||
item("downtempo", "Downtempo", "Electronic & Dance", "Western"),
|
||||
item("chillout", "Chillout", "Electronic & Dance", "Western"),
|
||||
item("lofi", "Lo-Fi", "Electronic & Dance", "Western", aliases: ["lofi"]),
|
||||
item("synthwave", "Synthwave", "Electronic & Dance", "Western"),
|
||||
item("vaporwave", "Vaporwave", "Electronic & Dance", "Western"),
|
||||
item("electro", "Electro", "Electronic & Dance", "Western"),
|
||||
item("industrial", "Industrial", "Electronic & Dance", "Western"),
|
||||
item("house", "House", "Electronic & Dance", "Western"),
|
||||
item("deep-house", "Deep House", "Electronic & Dance", "Western"),
|
||||
item("tech-house", "Tech House", "Electronic & Dance", "Western"),
|
||||
item("progressive-house", "Progressive House", "Electronic & Dance", "Western"),
|
||||
item("future-house", "Future House", "Electronic & Dance", "Western"),
|
||||
item("techno", "Techno", "Electronic & Dance", "Western"),
|
||||
item("minimal-techno", "Minimal Techno", "Electronic & Dance", "Western"),
|
||||
item("trance", "Trance", "Electronic & Dance", "Western"),
|
||||
item("progressive-trance", "Progressive Trance", "Electronic & Dance", "Western"),
|
||||
item("psytrance", "Psytrance", "Electronic & Dance", "Western"),
|
||||
item("drum-and-bass", "Drum and Bass", "Electronic & Dance", "UK", aliases: ["dnb"]),
|
||||
item("jungle", "Jungle", "Electronic & Dance", "UK"),
|
||||
item("dubstep", "Dubstep", "Electronic & Dance", "UK"),
|
||||
item("uk-garage", "UK Garage", "Electronic & Dance", "UK"),
|
||||
item("breakbeat", "Breakbeat", "Electronic & Dance", "Western"),
|
||||
item("hardstyle", "Hardstyle", "Electronic & Dance", "Europe"),
|
||||
item("moombahton", "Moombahton", "Electronic & Dance", "Latin America")
|
||||
]
|
||||
|
||||
private static let urbanAndSoul: [GenreStyleCatalogItem] = [
|
||||
item("hip-hop", "Hip Hop", "Hip Hop, R&B & Soul", "Global", aliases: ["hiphop"]),
|
||||
item("rap", "Rap", "Hip Hop, R&B & Soul", "Global"),
|
||||
item("boom-bap", "Boom Bap", "Hip Hop, R&B & Soul", "US"),
|
||||
item("trap", "Trap", "Hip Hop, R&B & Soul", "US"),
|
||||
item("drill", "Drill", "Hip Hop, R&B & Soul", "US/UK"),
|
||||
item("conscious-hip-hop", "Conscious Hip Hop", "Hip Hop, R&B & Soul", "US"),
|
||||
item("cloud-rap", "Cloud Rap", "Hip Hop, R&B & Soul", "US"),
|
||||
item("lofi-hip-hop", "Lo-Fi Hip Hop", "Hip Hop, R&B & Soul", "Global"),
|
||||
item("r-and-b", "R&B", "Hip Hop, R&B & Soul", "US", aliases: ["rhythm and blues"]),
|
||||
item("contemporary-r-and-b", "Contemporary R&B", "Hip Hop, R&B & Soul", "US"),
|
||||
item("soul", "Soul", "Hip Hop, R&B & Soul", "US"),
|
||||
item("neo-soul", "Neo Soul", "Hip Hop, R&B & Soul", "US"),
|
||||
item("funk", "Funk", "Hip Hop, R&B & Soul", "US"),
|
||||
item("disco", "Disco", "Hip Hop, R&B & Soul", "US"),
|
||||
item("nu-disco", "Nu Disco", "Hip Hop, R&B & Soul", "Western")
|
||||
]
|
||||
|
||||
private static let jazzAndBlues: [GenreStyleCatalogItem] = [
|
||||
item("jazz", "Jazz", "Jazz & Blues", "US"),
|
||||
item("swing", "Swing", "Jazz & Blues", "US"),
|
||||
item("bebop", "Bebop", "Jazz & Blues", "US"),
|
||||
item("cool-jazz", "Cool Jazz", "Jazz & Blues", "US"),
|
||||
item("hard-bop", "Hard Bop", "Jazz & Blues", "US"),
|
||||
item("modal-jazz", "Modal Jazz", "Jazz & Blues", "US"),
|
||||
item("jazz-fusion", "Jazz Fusion", "Jazz & Blues", "US"),
|
||||
item("smooth-jazz", "Smooth Jazz", "Jazz & Blues", "US"),
|
||||
item("vocal-jazz", "Vocal Jazz", "Jazz & Blues", "US"),
|
||||
item("big-band", "Big Band", "Jazz & Blues", "US"),
|
||||
item("blues", "Blues", "Jazz & Blues", "US"),
|
||||
item("delta-blues", "Delta Blues", "Jazz & Blues", "US"),
|
||||
item("chicago-blues", "Chicago Blues", "Jazz & Blues", "US"),
|
||||
item("gospel", "Gospel", "Jazz & Blues", "US")
|
||||
]
|
||||
|
||||
private static let countryFolkAndRoots: [GenreStyleCatalogItem] = [
|
||||
item("country", "Country", "Country, Folk & Roots", "US"),
|
||||
item("modern-country", "Modern Country", "Country, Folk & Roots", "US"),
|
||||
item("americana", "Americana", "Country, Folk & Roots", "US"),
|
||||
item("bluegrass", "Bluegrass", "Country, Folk & Roots", "US"),
|
||||
item("folk", "Folk", "Country, Folk & Roots", "Global"),
|
||||
item("indie-folk", "Indie Folk", "Country, Folk & Roots", "Western"),
|
||||
item("celtic", "Celtic", "Country, Folk & Roots", "Ireland/Scotland"),
|
||||
item("roots", "Roots", "Country, Folk & Roots", "Global"),
|
||||
item("traditional", "Traditional", "Country, Folk & Roots", "Global"),
|
||||
item("world", "World", "Country, Folk & Roots", "Global", aliases: ["world music"]),
|
||||
item("skiffle", "Skiffle", "Country, Folk & Roots", "UK")
|
||||
]
|
||||
|
||||
private static let latinAndCaribbean: [GenreStyleCatalogItem] = [
|
||||
item("latin-pop", "Latin Pop", "Latin & Caribbean", "Latin America"),
|
||||
item("reggaeton", "Reggaeton", "Latin & Caribbean", "Caribbean"),
|
||||
item("salsa", "Salsa", "Latin & Caribbean", "Caribbean"),
|
||||
item("bachata", "Bachata", "Latin & Caribbean", "Caribbean"),
|
||||
item("merengue", "Merengue", "Latin & Caribbean", "Caribbean"),
|
||||
item("cumbia", "Cumbia", "Latin & Caribbean", "Latin America"),
|
||||
item("bossa-nova", "Bossa Nova", "Latin & Caribbean", "Brazil"),
|
||||
item("samba", "Samba", "Latin & Caribbean", "Brazil"),
|
||||
item("tango", "Tango", "Latin & Caribbean", "Argentina/Uruguay"),
|
||||
item("bolero", "Bolero", "Latin & Caribbean", "Latin America"),
|
||||
item("mariachi", "Mariachi", "Latin & Caribbean", "Mexico"),
|
||||
item("norteno", "Norteno", "Latin & Caribbean", "Mexico"),
|
||||
item("banda", "Banda", "Latin & Caribbean", "Mexico"),
|
||||
item("corrido", "Corrido", "Latin & Caribbean", "Mexico"),
|
||||
item("baile-funk", "Baile Funk", "Latin & Caribbean", "Brazil"),
|
||||
item("dembow", "Dembow", "Latin & Caribbean", "Caribbean")
|
||||
]
|
||||
|
||||
private static let middleEasternAndNorthAfrican: [GenreStyleCatalogItem] = [
|
||||
item("arabic-pop", "Arabic Pop", "Middle East & North Africa", "Arab World", aliases: ["arab pop"], terms: ["بوب عربي"]),
|
||||
item("arabic-traditional", "Arabic Traditional", "Middle East & North Africa", "Arab World", terms: ["موسيقى عربية", "طرب"]),
|
||||
item("khaleeji", "Khaleeji", "Middle East & North Africa", "Gulf", aliases: ["gulf pop"], terms: ["خليجي"]),
|
||||
item("levantine-pop", "Levantine Pop", "Middle East & North Africa", "Levant", terms: ["شامي"]),
|
||||
item("egyptian-pop", "Egyptian Pop", "Middle East & North Africa", "Egypt", terms: ["مصري"]),
|
||||
item("iraqi-pop", "Iraqi Pop", "Middle East & North Africa", "Iraq", terms: ["عراقي"]),
|
||||
item("maghrebi-pop", "Maghrebi Pop", "Middle East & North Africa", "North Africa", terms: ["مغاربي"]),
|
||||
item("rai", "Rai", "Middle East & North Africa", "Algeria/Morocco"),
|
||||
item("chaabi", "Chaabi", "Middle East & North Africa", "North Africa"),
|
||||
item("gnawa", "Gnawa", "Middle East & North Africa", "Morocco"),
|
||||
item("andalusian", "Andalusian", "Middle East & North Africa", "North Africa"),
|
||||
item("turkish-pop", "Turkish Pop", "Middle East & North Africa", "Turkey"),
|
||||
item("turkish-folk", "Turkish Folk", "Middle East & North Africa", "Turkey"),
|
||||
item("persian-pop", "Persian Pop", "Middle East & North Africa", "Iran"),
|
||||
item("persian-traditional", "Persian Traditional", "Middle East & North Africa", "Iran"),
|
||||
item("kurdish", "Kurdish", "Middle East & North Africa", "Kurdistan"),
|
||||
item("armenian", "Armenian", "Middle East & North Africa", "Armenia")
|
||||
]
|
||||
|
||||
private static let southAsian: [GenreStyleCatalogItem] = [
|
||||
item("bollywood", "Bollywood", "South Asian", "India", aliases: ["filmi"]),
|
||||
item("hindustani-classical", "Hindustani Classical", "South Asian", "India"),
|
||||
item("carnatic", "Carnatic", "South Asian", "South India"),
|
||||
item("bhangra", "Bhangra", "South Asian", "Punjab"),
|
||||
item("punjabi-pop", "Punjabi Pop", "South Asian", "Punjab"),
|
||||
item("ghazal", "Ghazal", "South Asian", "South Asia"),
|
||||
item("qawwali", "Qawwali", "South Asian", "South Asia"),
|
||||
item("bhajan", "Bhajan", "South Asian", "India"),
|
||||
item("sufi", "Sufi", "South Asian", "South Asia"),
|
||||
item("pakistani-pop", "Pakistani Pop", "South Asian", "Pakistan"),
|
||||
item("bangladeshi-folk", "Bangladeshi Folk", "South Asian", "Bangladesh")
|
||||
]
|
||||
|
||||
private static let eastAsian: [GenreStyleCatalogItem] = [
|
||||
item("k-pop", "K-Pop", "East Asian", "Korea", aliases: ["kpop"]),
|
||||
item("korean-traditional", "Korean Traditional", "East Asian", "Korea"),
|
||||
item("j-pop", "J-Pop", "East Asian", "Japan", aliases: ["jpop"]),
|
||||
item("japanese-city-pop", "Japanese City Pop", "East Asian", "Japan", aliases: ["city pop"]),
|
||||
item("enka", "Enka", "East Asian", "Japan"),
|
||||
item("anime-music", "Anime Music", "East Asian", "Japan"),
|
||||
item("c-pop", "C-Pop", "East Asian", "China", aliases: ["cpop"]),
|
||||
item("mandopop", "Mandopop", "East Asian", "China/Taiwan"),
|
||||
item("cantopop", "Cantopop", "East Asian", "Hong Kong"),
|
||||
item("chinese-traditional", "Chinese Traditional", "East Asian", "China"),
|
||||
item("taiwanese-pop", "Taiwanese Pop", "East Asian", "Taiwan")
|
||||
]
|
||||
|
||||
private static let southeastAsianAndOceania: [GenreStyleCatalogItem] = [
|
||||
item("indonesian-pop", "Indonesian Pop", "Southeast Asia & Oceania", "Indonesia"),
|
||||
item("dangdut", "Dangdut", "Southeast Asia & Oceania", "Indonesia"),
|
||||
item("gamelan", "Gamelan", "Southeast Asia & Oceania", "Indonesia"),
|
||||
item("malay-pop", "Malay Pop", "Southeast Asia & Oceania", "Malaysia"),
|
||||
item("thai-pop", "Thai Pop", "Southeast Asia & Oceania", "Thailand"),
|
||||
item("luk-thung", "Luk Thung", "Southeast Asia & Oceania", "Thailand"),
|
||||
item("vietnamese-pop", "Vietnamese Pop", "Southeast Asia & Oceania", "Vietnam"),
|
||||
item("filipino-pop", "Filipino Pop", "Southeast Asia & Oceania", "Philippines"),
|
||||
item("pinoy-rock", "Pinoy Rock", "Southeast Asia & Oceania", "Philippines"),
|
||||
item("maori", "Maori", "Southeast Asia & Oceania", "New Zealand"),
|
||||
item("pacific", "Pacific", "Southeast Asia & Oceania", "Oceania"),
|
||||
item("australian-indigenous", "Australian Indigenous", "Southeast Asia & Oceania", "Australia")
|
||||
]
|
||||
|
||||
private static let african: [GenreStyleCatalogItem] = [
|
||||
item("afrobeats", "Afrobeats", "African", "West Africa"),
|
||||
item("afropop", "Afropop", "African", "Africa"),
|
||||
item("afro-house", "Afro House", "African", "Africa"),
|
||||
item("amapiano", "Amapiano", "African", "South Africa"),
|
||||
item("highlife", "Highlife", "African", "West Africa"),
|
||||
item("juju", "Juju", "African", "Nigeria"),
|
||||
item("fuji", "Fuji", "African", "Nigeria"),
|
||||
item("benga", "Benga", "African", "East Africa"),
|
||||
item("soukous", "Soukous", "African", "Central Africa"),
|
||||
item("kwaito", "Kwaito", "African", "South Africa"),
|
||||
item("mbalax", "Mbalax", "African", "Senegal"),
|
||||
item("taarab", "Taarab", "African", "East Africa"),
|
||||
item("ethiopian", "Ethiopian", "African", "Ethiopia"),
|
||||
item("sudanese", "Sudanese", "African", "Sudan"),
|
||||
item("desert-blues", "Desert Blues", "African", "Sahara")
|
||||
]
|
||||
|
||||
private static let reggaeAndCaribbean: [GenreStyleCatalogItem] = [
|
||||
item("reggae", "Reggae", "Reggae & Caribbean", "Jamaica"),
|
||||
item("roots-reggae", "Roots Reggae", "Reggae & Caribbean", "Jamaica"),
|
||||
item("dub", "Dub", "Reggae & Caribbean", "Jamaica"),
|
||||
item("dancehall", "Dancehall", "Reggae & Caribbean", "Jamaica"),
|
||||
item("ska", "Ska", "Reggae & Caribbean", "Jamaica"),
|
||||
item("rocksteady", "Rocksteady", "Reggae & Caribbean", "Jamaica"),
|
||||
item("lovers-rock", "Lovers Rock", "Reggae & Caribbean", "Jamaica"),
|
||||
item("calypso", "Calypso", "Reggae & Caribbean", "Caribbean"),
|
||||
item("soca", "Soca", "Reggae & Caribbean", "Caribbean")
|
||||
]
|
||||
|
||||
private static let classicalAndCinematic: [GenreStyleCatalogItem] = [
|
||||
item("classical", "Classical", "Classical & Cinematic", "Western"),
|
||||
item("baroque", "Baroque", "Classical & Cinematic", "Europe"),
|
||||
item("classical-period", "Classical Period", "Classical & Cinematic", "Europe"),
|
||||
item("romantic", "Romantic", "Classical & Cinematic", "Europe"),
|
||||
item("contemporary-classical", "Contemporary Classical", "Classical & Cinematic", "Global"),
|
||||
item("orchestral", "Orchestral", "Classical & Cinematic", "Western"),
|
||||
item("chamber-music", "Chamber Music", "Classical & Cinematic", "Western"),
|
||||
item("opera", "Opera", "Classical & Cinematic", "Europe"),
|
||||
item("choral", "Choral", "Classical & Cinematic", "Global"),
|
||||
item("cinematic", "Cinematic", "Classical & Cinematic", "Global"),
|
||||
item("soundtrack", "Soundtrack", "Classical & Cinematic", "Global"),
|
||||
item("musical-theater", "Musical Theater", "Classical & Cinematic", "Western"),
|
||||
item("new-age", "New Age", "Classical & Cinematic", "Western"),
|
||||
item("minimalism", "Minimalism", "Classical & Cinematic", "Western")
|
||||
]
|
||||
|
||||
private static func item(
|
||||
_ id: String,
|
||||
_ name: String,
|
||||
_ familyCategory: String,
|
||||
_ regionOrigin: String? = nil,
|
||||
aliases: [String] = [],
|
||||
terms: [String] = []
|
||||
) -> GenreStyleCatalogItem {
|
||||
GenreStyleCatalogItem(
|
||||
id: id,
|
||||
name: name,
|
||||
familyCategory: familyCategory,
|
||||
regionOrigin: regionOrigin,
|
||||
aliases: aliases,
|
||||
searchTerms: terms
|
||||
)
|
||||
}
|
||||
|
||||
private static func searchableTerms(for item: GenreStyleCatalogItem) -> [String] {
|
||||
searchTokens(for: [item.name, item.familyCategory, item.regionOrigin ?? ""] + item.aliases + item.searchTerms)
|
||||
}
|
||||
|
||||
private static func searchTokens(for query: String) -> [String] {
|
||||
searchTokens(for: [query])
|
||||
}
|
||||
|
||||
private static func searchTokens(for values: [String]) -> [String] {
|
||||
values
|
||||
.joined(separator: " ")
|
||||
.folding(
|
||||
options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive],
|
||||
locale: Locale(identifier: "en_US_POSIX")
|
||||
)
|
||||
.split(whereSeparator: { $0.isWhitespace || $0 == "-" || $0 == "/" })
|
||||
.map(String.init)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user