Genres fix
This commit is contained in:
@@ -24,6 +24,8 @@ final class MALibraryManager {
|
||||
private(set) var playlists: [MAPlaylist] = []
|
||||
private(set) var podcasts: [MAPodcast] = []
|
||||
private(set) var genres: [MAGenre] = []
|
||||
/// Deduplicated, non-empty genres ready for display. Populated after loadGenres completes.
|
||||
private(set) var displayGenres: [MAGenre] = []
|
||||
|
||||
// Pagination
|
||||
private var artistsOffset = 0
|
||||
@@ -413,12 +415,72 @@ final class MALibraryManager {
|
||||
logger.info("Loading genres")
|
||||
let loaded = try await service.getGenres()
|
||||
genres = loaded.sorted { $0.name < $1.name }
|
||||
logger.info("Loaded \(loaded.count) genres")
|
||||
logger.info("Loaded \(loaded.count) genres, filtering empty ones…")
|
||||
let filtered = await filterNonEmptyGenres(service: service)
|
||||
displayGenres = filtered
|
||||
logger.info("Displaying \(filtered.count) non-empty genres")
|
||||
}
|
||||
|
||||
func browseGenre(genreUri: String) async throws -> [MAMediaItem] {
|
||||
/// Returns deduplicated genres that have at least one artist or album.
|
||||
private func filterNonEmptyGenres(service: MAService) async -> [MAGenre] {
|
||||
// Deduplicate by name and collect all IDs for each unique name
|
||||
var seenNames = Set<String>()
|
||||
var uniqueGenres: [MAGenre] = []
|
||||
for genre in genres where seenNames.insert(genre.name.lowercased()).inserted {
|
||||
uniqueGenres.append(genre)
|
||||
}
|
||||
|
||||
// Pre-compute genre IDs per unique name before entering the task group
|
||||
let genreWithIds: [(MAGenre, [Int])] = uniqueGenres.map { genre in
|
||||
let ids = genres
|
||||
.filter { $0.name.caseInsensitiveCompare(genre.name) == .orderedSame }
|
||||
.compactMap { Int($0.uri.components(separatedBy: "/").last ?? "") }
|
||||
return (genre, ids)
|
||||
}
|
||||
|
||||
return await withTaskGroup(of: MAGenre?.self) { group in
|
||||
for (genre, ids) in genreWithIds where !ids.isEmpty {
|
||||
group.addTask {
|
||||
do {
|
||||
let artists = try await service.getArtistsByGenre(genreIds: ids, limit: 1)
|
||||
if !artists.isEmpty { return genre }
|
||||
let albums = try await service.getAlbumsByGenre(genreIds: ids, limit: 1)
|
||||
return albums.isEmpty ? nil : genre
|
||||
} catch {
|
||||
return genre // Don't hide on network error
|
||||
}
|
||||
}
|
||||
}
|
||||
var result: [MAGenre] = []
|
||||
for await genre in group {
|
||||
if let genre { result.append(genre) }
|
||||
}
|
||||
return result.sorted { $0.name < $1.name }
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch all artists and albums that belong to the given genre name.
|
||||
/// Extracts database IDs from matching genre URIs and uses the native
|
||||
/// `genre` parameter of MA Server's library_items endpoints.
|
||||
func browseGenresByName(_ name: String) async throws -> [MAMediaItem] {
|
||||
guard let service else { throw MAWebSocketClient.ClientError.notConnected }
|
||||
return try await service.browseGenre(genreUri: genreUri)
|
||||
|
||||
// Genre URIs look like "library://genre/26". Extract the integer IDs.
|
||||
let genreIds = genres
|
||||
.filter { $0.name.caseInsensitiveCompare(name) == .orderedSame }
|
||||
.compactMap { Int($0.uri.components(separatedBy: "/").last ?? "") }
|
||||
|
||||
guard !genreIds.isEmpty else { return [] }
|
||||
|
||||
async let artists = service.getArtistsByGenre(genreIds: genreIds)
|
||||
async let albums = service.getAlbumsByGenre(genreIds: genreIds)
|
||||
let (artistResults, albumResults) = try await (artists, albums)
|
||||
|
||||
var seen = Set<String>()
|
||||
let allItems = (artistResults + albumResults)
|
||||
.filter { seen.insert($0.uri).inserted }
|
||||
.sorted { $0.name < $1.name }
|
||||
return allItems
|
||||
}
|
||||
|
||||
func getPodcastEpisodes(podcastUri: String) async throws -> [MAMediaItem] {
|
||||
|
||||
Reference in New Issue
Block a user