mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Add fuzzy name matching as fallback for local tracks + better error logging
- Add fuzzy matching by title+artist as fallback (like Jellyfin Spotify Import plugin) - Add clear error messages when JELLYFIN_USER_ID is not configured - Add emoji logging for easier debugging (🔍 📌 ✅ ❌) - Check HTTP status code when fetching playlist items - This should fix the issue where all tracks show [S] even when they exist locally
This commit is contained in:
@@ -2860,20 +2860,26 @@ public class JellyfinController : ControllerBase
|
||||
var userId = _settings.UserId;
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
_logger.LogWarning("No UserId configured - attempting to fetch existing playlist tracks may fail");
|
||||
_logger.LogError("❌ JELLYFIN_USER_ID is NOT configured! Cannot fetch playlist tracks. Set it in .env or admin UI.");
|
||||
return null; // Fall back to legacy mode
|
||||
}
|
||||
|
||||
var playlistItemsUrl = $"Playlists/{playlistId}/Items";
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
playlistItemsUrl += $"?UserId={userId}";
|
||||
}
|
||||
var playlistItemsUrl = $"Playlists/{playlistId}/Items?UserId={userId}";
|
||||
|
||||
var (existingTracksResponse, _) = await _proxyService.GetJsonAsync(
|
||||
_logger.LogInformation("🔍 Fetching existing tracks from Jellyfin playlist {PlaylistId} with UserId {UserId}",
|
||||
playlistId, userId);
|
||||
|
||||
var (existingTracksResponse, statusCode) = await _proxyService.GetJsonAsync(
|
||||
playlistItemsUrl,
|
||||
null,
|
||||
Request.Headers);
|
||||
|
||||
if (statusCode != 200)
|
||||
{
|
||||
_logger.LogError("❌ Failed to fetch Jellyfin playlist items: HTTP {StatusCode}. Check JELLYFIN_USER_ID is correct.", statusCode);
|
||||
return null;
|
||||
}
|
||||
|
||||
var existingTracks = new List<Song>();
|
||||
var existingBySpotifyId = new Dictionary<string, Song>(); // SpotifyId -> Song
|
||||
var existingByIsrc = new Dictionary<string, Song>(); // ISRC -> Song
|
||||
@@ -2894,7 +2900,7 @@ public class JellyfinController : ControllerBase
|
||||
if (!string.IsNullOrEmpty(spotifyId))
|
||||
{
|
||||
existingBySpotifyId[spotifyId] = song;
|
||||
_logger.LogDebug("Indexed local track by Spotify ID: {SpotifyId} -> {Title}", spotifyId, song.Title);
|
||||
_logger.LogDebug(" 📌 Indexed local track by Spotify ID: {SpotifyId} -> {Title}", spotifyId, song.Title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2902,15 +2908,16 @@ public class JellyfinController : ControllerBase
|
||||
if (!string.IsNullOrEmpty(song.Isrc))
|
||||
{
|
||||
existingByIsrc[song.Isrc] = song;
|
||||
_logger.LogDebug("Indexed local track by ISRC: {Isrc} -> {Title}", song.Isrc, song.Title);
|
||||
_logger.LogDebug(" 📌 Indexed local track by ISRC: {Isrc} -> {Title}", song.Isrc, song.Title);
|
||||
}
|
||||
}
|
||||
_logger.LogInformation("Found {Count} existing tracks in Jellyfin playlist ({SpotifyIds} with Spotify IDs, {Isrcs} with ISRCs)",
|
||||
_logger.LogInformation("✅ Found {Count} existing tracks in Jellyfin playlist ({SpotifyIds} with Spotify IDs, {Isrcs} with ISRCs)",
|
||||
existingTracks.Count, existingBySpotifyId.Count, existingByIsrc.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No existing tracks found in Jellyfin playlist {PlaylistId} - may need UserId parameter", playlistId);
|
||||
_logger.LogError("❌ No existing tracks found in Jellyfin playlist {PlaylistId} - Jellyfin Spotify Import plugin may not have run yet", playlistId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the full playlist from Spotify to know the correct order
|
||||
@@ -2930,7 +2937,7 @@ public class JellyfinController : ControllerBase
|
||||
{
|
||||
Song? localTrack = null;
|
||||
|
||||
// Try to find local track by Spotify ID first (fastest)
|
||||
// Try to find local track by Spotify ID first (fastest and most reliable)
|
||||
if (existingBySpotifyId.TryGetValue(spotifyTrack.SpotifyId, out var trackBySpotifyId))
|
||||
{
|
||||
localTrack = trackBySpotifyId;
|
||||
@@ -2945,6 +2952,34 @@ public class JellyfinController : ControllerBase
|
||||
_logger.LogDebug("#{Pos} {Title} - Found LOCAL by ISRC: {Isrc}",
|
||||
spotifyTrack.Position, spotifyTrack.Title, spotifyTrack.Isrc);
|
||||
}
|
||||
// Fallback: Match by title + artist name (like Jellyfin Spotify Import plugin does)
|
||||
else
|
||||
{
|
||||
var bestMatch = existingTracks
|
||||
.Select(song => new
|
||||
{
|
||||
Song = song,
|
||||
TitleScore = FuzzyMatcher.CalculateSimilarity(spotifyTrack.Title, song.Title),
|
||||
ArtistScore = FuzzyMatcher.CalculateSimilarity(spotifyTrack.PrimaryArtist, song.Artist)
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
x.Song,
|
||||
x.TitleScore,
|
||||
x.ArtistScore,
|
||||
TotalScore = (x.TitleScore * 0.7) + (x.ArtistScore * 0.3) // Weight title more
|
||||
})
|
||||
.OrderByDescending(x => x.TotalScore)
|
||||
.FirstOrDefault();
|
||||
|
||||
// Only use if match is good enough (>75% combined score)
|
||||
if (bestMatch != null && bestMatch.TotalScore >= 75)
|
||||
{
|
||||
localTrack = bestMatch.Song;
|
||||
_logger.LogDebug("#{Pos} {Title} - Found LOCAL by fuzzy match: {MatchTitle} (score: {Score:F1})",
|
||||
spotifyTrack.Position, spotifyTrack.Title, bestMatch.Song.Title, bestMatch.TotalScore);
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a local track, use it
|
||||
if (localTrack != null)
|
||||
|
||||
Reference in New Issue
Block a user