mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 07:58:39 -05:00
Fix: Match local Jellyfin tracks by ISRC instead of Spotify ID
- Local Jellyfin tracks don't have Spotify IDs (only plugin-added tracks do) - Now matches by ISRC first (most reliable), then falls back to Spotify ID - Builds dictionaries for fast lookup: existingBySpotifyId and existingByIsrc - Prioritizes local tracks over external matches - Logs: 'X tracks (Y with Spotify IDs, Z with ISRCs)' - This fixes all tracks showing [S] - now uses local files when available
This commit is contained in:
@@ -2862,29 +2862,36 @@ public class JellyfinController : ControllerBase
|
||||
Request.Headers);
|
||||
|
||||
var existingTracks = new List<Song>();
|
||||
var existingSpotifyIds = new HashSet<string>();
|
||||
var existingPositions = new Dictionary<string, int>(); // SpotifyId -> position from Jellyfin
|
||||
var existingBySpotifyId = new Dictionary<string, Song>(); // SpotifyId -> Song
|
||||
var existingByIsrc = new Dictionary<string, Song>(); // ISRC -> Song
|
||||
|
||||
if (existingTracksResponse != null &&
|
||||
existingTracksResponse.RootElement.TryGetProperty("Items", out var items))
|
||||
{
|
||||
var position = 0;
|
||||
foreach (var item in items.EnumerateArray())
|
||||
{
|
||||
var song = _modelMapper.ParseSong(item);
|
||||
existingTracks.Add(song);
|
||||
|
||||
// Track Spotify IDs and their positions
|
||||
// Index by Spotify ID if available (from Jellyfin Spotify Import plugin)
|
||||
if (item.TryGetProperty("ProviderIds", out var providerIds) &&
|
||||
providerIds.TryGetProperty("Spotify", out var spotifyId))
|
||||
providerIds.TryGetProperty("Spotify", out var spotifyIdElement))
|
||||
{
|
||||
var id = spotifyId.GetString() ?? "";
|
||||
existingSpotifyIds.Add(id);
|
||||
existingPositions[id] = position;
|
||||
var spotifyId = spotifyIdElement.GetString();
|
||||
if (!string.IsNullOrEmpty(spotifyId))
|
||||
{
|
||||
existingBySpotifyId[spotifyId] = song;
|
||||
}
|
||||
}
|
||||
|
||||
// Index by ISRC for matching (most reliable)
|
||||
if (!string.IsNullOrEmpty(song.Isrc))
|
||||
{
|
||||
existingByIsrc[song.Isrc] = song;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
_logger.LogInformation("Found {Count} existing local tracks in Jellyfin playlist", existingTracks.Count);
|
||||
_logger.LogInformation("Found {Count} existing tracks in Jellyfin playlist ({SpotifyIds} with Spotify IDs, {Isrcs} with ISRCs)",
|
||||
existingTracks.Count, existingBySpotifyId.Count, existingByIsrc.Count);
|
||||
}
|
||||
|
||||
// Get the full playlist from Spotify to know the correct order
|
||||
@@ -2897,28 +2904,39 @@ public class JellyfinController : ControllerBase
|
||||
|
||||
// Build the final track list in correct Spotify order
|
||||
var finalTracks = new List<Song>();
|
||||
var localUsed = new HashSet<int>(); // Track which local tracks we've placed
|
||||
var localUsedCount = 0;
|
||||
var externalUsedCount = 0;
|
||||
|
||||
foreach (var spotifyTrack in spotifyTracks.OrderBy(t => t.Position))
|
||||
{
|
||||
// Check if this track exists locally
|
||||
if (existingSpotifyIds.Contains(spotifyTrack.SpotifyId))
|
||||
Song? localTrack = null;
|
||||
|
||||
// Try to find local track by Spotify ID first (fastest)
|
||||
if (existingBySpotifyId.TryGetValue(spotifyTrack.SpotifyId, out var trackBySpotifyId))
|
||||
{
|
||||
// Use the local version
|
||||
if (existingPositions.TryGetValue(spotifyTrack.SpotifyId, out var localIndex) &&
|
||||
localIndex < existingTracks.Count)
|
||||
{
|
||||
finalTracks.Add(existingTracks[localIndex]);
|
||||
localUsed.Add(localIndex);
|
||||
continue;
|
||||
}
|
||||
localTrack = trackBySpotifyId;
|
||||
}
|
||||
// Try to find by ISRC (most reliable for matching)
|
||||
else if (!string.IsNullOrEmpty(spotifyTrack.Isrc) &&
|
||||
existingByIsrc.TryGetValue(spotifyTrack.Isrc, out var trackByIsrc))
|
||||
{
|
||||
localTrack = trackByIsrc;
|
||||
}
|
||||
|
||||
// Check if we have a matched external track
|
||||
// If we found a local track, use it
|
||||
if (localTrack != null)
|
||||
{
|
||||
finalTracks.Add(localTrack);
|
||||
localUsedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// No local track - check if we have a matched external track
|
||||
var matched = orderedTracks.FirstOrDefault(t => t.SpotifyId == spotifyTrack.SpotifyId);
|
||||
if (matched != null)
|
||||
{
|
||||
finalTracks.Add(matched.MatchedSong);
|
||||
externalUsedCount++;
|
||||
}
|
||||
// If no match, the track is simply omitted (not available from any source)
|
||||
}
|
||||
@@ -2931,8 +2949,8 @@ public class JellyfinController : ControllerBase
|
||||
_logger.LogInformation(
|
||||
"Final ordered playlist: {Total} tracks ({Local} local + {External} external) for {Playlist}",
|
||||
finalTracks.Count,
|
||||
localUsed.Count,
|
||||
finalTracks.Count - localUsed.Count,
|
||||
localUsedCount,
|
||||
externalUsedCount,
|
||||
spotifyPlaylistName);
|
||||
|
||||
return _responseBuilder.CreateItemsResponse(finalTracks);
|
||||
|
||||
Reference in New Issue
Block a user