From d52c0fc938de7f98322ba2f431223b1edf0b6883 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Fri, 6 Feb 2026 11:14:55 -0500 Subject: [PATCH] Add Spotify ID lookup for external tracks to enable Spotify lyrics - External tracks from playlists now look up their Spotify ID from matched tracks cache - Enables Spotify lyrics API to work for SquidWTF/Deezer/Qobuz tracks - Searches through all playlist matched tracks to find the Spotify ID - Falls back to LRCLIB if no Spotify ID found or lyrics unavailable --- allstarr/Controllers/JellyfinController.cs | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/allstarr/Controllers/JellyfinController.cs b/allstarr/Controllers/JellyfinController.cs index 4e1c0a3..93b91bb 100644 --- a/allstarr/Controllers/JellyfinController.cs +++ b/allstarr/Controllers/JellyfinController.cs @@ -1150,7 +1150,18 @@ public class JellyfinController : ControllerBase if (isExternal) { song = await _metadataService.GetSongAsync(provider!, externalId!); - // For Deezer tracks, we'll search Spotify by metadata + + // Try to find Spotify ID from matched tracks cache + // External tracks from playlists should have been matched and cached + if (song != null) + { + spotifyTrackId = await FindSpotifyIdForExternalTrackAsync(song); + if (!string.IsNullOrEmpty(spotifyTrackId)) + { + _logger.LogInformation("Found Spotify ID {SpotifyId} for external track {Provider}/{ExternalId}", + spotifyTrackId, provider, externalId); + } + } } else { @@ -4122,5 +4133,51 @@ public class JellyfinController : ControllerBase return (deviceId, client, device, version); } + + /// + /// Finds the Spotify ID for an external track by searching through all playlist matched tracks caches. + /// This allows us to get Spotify lyrics for external tracks that were matched from Spotify playlists. + /// + private async Task FindSpotifyIdForExternalTrackAsync(Song externalSong) + { + try + { + // Get all configured playlists + var playlists = _spotifySettings.Playlists; + + // Search through each playlist's matched tracks cache + foreach (var playlist in playlists) + { + var cacheKey = $"spotify:matched:ordered:{playlist.Name}"; + var matchedTracks = await _cache.GetAsync>(cacheKey); + + if (matchedTracks == null || matchedTracks.Count == 0) + continue; + + // Look for a match by external ID + var match = matchedTracks.FirstOrDefault(t => + t.MatchedSong != null && + t.MatchedSong.ExternalProvider == externalSong.ExternalProvider && + t.MatchedSong.ExternalId == externalSong.ExternalId); + + if (match != null && !string.IsNullOrEmpty(match.SpotifyId)) + { + _logger.LogDebug("Found Spotify ID {SpotifyId} for {Provider}/{ExternalId} in playlist {Playlist}", + match.SpotifyId, externalSong.ExternalProvider, externalSong.ExternalId, playlist.Name); + return match.SpotifyId; + } + } + + _logger.LogDebug("No Spotify ID found for external track {Provider}/{ExternalId}", + externalSong.ExternalProvider, externalSong.ExternalId); + return null; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error finding Spotify ID for external track"); + return null; + } + } } + // force rebuild Sun Jan 25 13:22:47 EST 2026