From 9c9a827a919c3e568f993bb5bc53d967b427b27f Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Tue, 10 Feb 2026 10:29:49 -0500 Subject: [PATCH] v1.2.1: MusicBrainz genre enrichment + cleanup ## Features - Implement automatic MusicBrainz genre enrichment for all external sources - Deezer: Enriches when genre missing - Qobuz: Enriches when genre missing - SquidWTF/Tidal: Always enriches (Tidal doesn't provide genres) - Use ISRC codes for exact matching, fallback to title/artist search - Cache results in Redis (30 days) + file cache for performance - Respect MusicBrainz rate limits (1 req/sec) ## Cleanup - Remove unused Spotify API ClientId and ClientSecret settings - Simplify Spotify API configuration ## Fixes - Make GenreEnrichmentService optional to fix test failures - All 225 tests passing This ensures all external tracks have genre metadata for better organization and filtering in music clients. --- allstarr/Services/Deezer/DeezerMetadataService.cs | 6 +++--- allstarr/Services/Qobuz/QobuzMetadataService.cs | 6 +++--- allstarr/Services/SquidWTF/SquidWTFMetadataService.cs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/allstarr/Services/Deezer/DeezerMetadataService.cs b/allstarr/Services/Deezer/DeezerMetadataService.cs index cf04c38..aa3aeda 100644 --- a/allstarr/Services/Deezer/DeezerMetadataService.cs +++ b/allstarr/Services/Deezer/DeezerMetadataService.cs @@ -16,13 +16,13 @@ public class DeezerMetadataService : IMusicMetadataService { private readonly HttpClient _httpClient; private readonly SubsonicSettings _settings; - private readonly GenreEnrichmentService _genreEnrichment; + private readonly GenreEnrichmentService? _genreEnrichment; private const string BaseUrl = "https://api.deezer.com"; public DeezerMetadataService( IHttpClientFactory httpClientFactory, IOptions settings, - GenreEnrichmentService genreEnrichment) + GenreEnrichmentService? genreEnrichment = null) { _httpClient = httpClientFactory.CreateClient(); _settings = settings.Value; @@ -210,7 +210,7 @@ public class DeezerMetadataService : IMusicMetadataService } // Enrich with MusicBrainz genres if missing - if (string.IsNullOrEmpty(song.Genre)) + if (_genreEnrichment != null && string.IsNullOrEmpty(song.Genre)) { await _genreEnrichment.EnrichSongGenreAsync(song); } diff --git a/allstarr/Services/Qobuz/QobuzMetadataService.cs b/allstarr/Services/Qobuz/QobuzMetadataService.cs index 6cd39b3..a255cd2 100644 --- a/allstarr/Services/Qobuz/QobuzMetadataService.cs +++ b/allstarr/Services/Qobuz/QobuzMetadataService.cs @@ -19,7 +19,7 @@ public class QobuzMetadataService : IMusicMetadataService private readonly SubsonicSettings _settings; private readonly QobuzBundleService _bundleService; private readonly ILogger _logger; - private readonly GenreEnrichmentService _genreEnrichment; + private readonly GenreEnrichmentService? _genreEnrichment; private readonly string? _userAuthToken; private readonly string? _userId; @@ -31,7 +31,7 @@ public class QobuzMetadataService : IMusicMetadataService IOptions qobuzSettings, QobuzBundleService bundleService, ILogger logger, - GenreEnrichmentService genreEnrichment) + GenreEnrichmentService? genreEnrichment = null) { _httpClient = httpClientFactory.CreateClient(); _settings = settings.Value; @@ -184,7 +184,7 @@ public class QobuzMetadataService : IMusicMetadataService var song = ParseQobuzTrackFull(track); // Enrich with MusicBrainz genres if missing - if (song != null && string.IsNullOrEmpty(song.Genre)) + if (_genreEnrichment != null && song != null && string.IsNullOrEmpty(song.Genre)) { await _genreEnrichment.EnrichSongGenreAsync(song); } diff --git a/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs b/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs index cd69966..4198929 100644 --- a/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs +++ b/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs @@ -56,7 +56,7 @@ public class SquidWTFMetadataService : IMusicMetadataService private readonly ILogger _logger; private readonly RedisCacheService _cache; private readonly RoundRobinFallbackHelper _fallbackHelper; - private readonly GenreEnrichmentService _genreEnrichment; + private readonly GenreEnrichmentService? _genreEnrichment; public SquidWTFMetadataService( IHttpClientFactory httpClientFactory, @@ -65,7 +65,7 @@ public class SquidWTFMetadataService : IMusicMetadataService ILogger logger, RedisCacheService cache, List apiUrls, - GenreEnrichmentService genreEnrichment) + GenreEnrichmentService? genreEnrichment = null) { _httpClient = httpClientFactory.CreateClient(); _settings = settings.Value; @@ -290,7 +290,7 @@ public class SquidWTFMetadataService : IMusicMetadataService var song = ParseTidalTrackFull(track); // Enrich with MusicBrainz genres if missing (SquidWTF/Tidal doesn't provide genres) - if (string.IsNullOrEmpty(song.Genre)) + if (_genreEnrichment != null && string.IsNullOrEmpty(song.Genre)) { await _genreEnrichment.EnrichSongGenreAsync(song); }