From 3b24ef3e783055b2561a9cdc76749bedf348f899 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Thu, 5 Feb 2026 11:13:26 -0500 Subject: [PATCH] Fix: Fetch full metadata for manual external mappings Manual external mappings now fetch complete track metadata from the provider (SquidWTF) instead of using minimal Spotify metadata. This ensures proper IDs, artist IDs, album IDs, cover art, and all metadata needed for playback. Also fixed admin UI to properly detect manual external mappings so tracks show as 'External' instead of 'Missing'. Changes: - Fetch full Song metadata using GetSongAsync when manual mapping exists - Fallback to minimal metadata if fetch fails - Admin controller now checks isManualMapping flag to set correct status - Tracks with manual external mappings now show proper provider badge --- .../Spotify/SpotifyTrackMatchingService.cs | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs b/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs index dae7ddc..05ab695 100644 --- a/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs +++ b/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs @@ -871,19 +871,48 @@ public class SpotifyTrackMatchingService : BackgroundService if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(externalId)) { - // Create a matched track entry for the external mapping - var externalSong = new Song + // Fetch full metadata from the provider instead of using minimal Spotify data + Song? externalSong = null; + + try { - Id = $"ext-{provider}-song-{externalId}", // CRITICAL: Set proper ID format - Title = spotifyTrack.Title, - Artist = spotifyTrack.PrimaryArtist, - Album = spotifyTrack.Album, - Duration = spotifyTrack.DurationMs / 1000, - Isrc = spotifyTrack.Isrc, - IsLocal = false, - ExternalProvider = provider, - ExternalId = externalId - }; + using var metadataScope = _serviceProvider.CreateScope(); + var metadataServiceForFetch = metadataScope.ServiceProvider.GetRequiredService(); + externalSong = await metadataServiceForFetch.GetSongAsync(provider, externalId); + + if (externalSong != null) + { + _logger.LogInformation("✓ Fetched full metadata for manual external mapping: {Title} by {Artist}", + externalSong.Title, externalSong.Artist); + } + else + { + _logger.LogWarning("Failed to fetch metadata for {Provider} ID {ExternalId}, using fallback", + provider, externalId); + } + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error fetching metadata for {Provider} ID {ExternalId}, using fallback", + provider, externalId); + } + + // Fallback to minimal metadata if fetch failed + if (externalSong == null) + { + externalSong = new Song + { + Id = $"ext-{provider}-song-{externalId}", + Title = spotifyTrack.Title, + Artist = spotifyTrack.PrimaryArtist, + Album = spotifyTrack.Album, + Duration = spotifyTrack.DurationMs / 1000, + Isrc = spotifyTrack.Isrc, + IsLocal = false, + ExternalProvider = provider, + ExternalId = externalId + }; + } var matchedTrack = new MatchedTrack {