mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
fix: show both local and external artists with same name
- Artists with same name now appear separately (local + external [S]) - Fixed deduplication to keep one local AND one external per name - Added logging to SquidWTF artist search to show actual URLs - External artists get [S] suffix to distinguish from local - Allows users to browse external artist albums not in local library - TIDAL image URLs already correctly implemented with UUID splitting
This commit is contained in:
@@ -294,14 +294,58 @@ public class JellyfinController : ControllerBase
|
||||
.Select(x => x.Item)
|
||||
.ToList();
|
||||
|
||||
// Dedupe artists by name, keeping highest scored version
|
||||
var artistScores = scoredLocalArtists.Concat(scoredExternalArtists)
|
||||
.GroupBy(x => x.Item.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => g.OrderByDescending(x => x.Score).First())
|
||||
.OrderByDescending(x => x.Score)
|
||||
.Select(x => x.Item)
|
||||
// Dedupe artists by name, but KEEP both local and external versions
|
||||
// Group by name, then for each name keep ONE local and ONE external (if both exist)
|
||||
var artistsByName = scoredLocalArtists.Concat(scoredExternalArtists)
|
||||
.GroupBy(x => x.Item.Name, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var artistScores = new List<Artist>();
|
||||
foreach (var group in artistsByName)
|
||||
{
|
||||
// Get best local artist (if any)
|
||||
var bestLocal = group
|
||||
.Where(x => x.Item.IsLocal)
|
||||
.OrderByDescending(x => x.Score)
|
||||
.FirstOrDefault();
|
||||
|
||||
// Get best external artist (if any)
|
||||
var bestExternal = group
|
||||
.Where(x => !x.Item.IsLocal)
|
||||
.OrderByDescending(x => x.Score)
|
||||
.FirstOrDefault();
|
||||
|
||||
// Add both (if they exist)
|
||||
if (bestLocal.Item != null)
|
||||
{
|
||||
artistScores.Add(bestLocal.Item);
|
||||
}
|
||||
if (bestExternal.Item != null)
|
||||
{
|
||||
artistScores.Add(bestExternal.Item);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by score
|
||||
artistScores = artistScores
|
||||
.OrderByDescending(a => {
|
||||
// Find the score for this artist
|
||||
var scored = scoredLocalArtists.Concat(scoredExternalArtists)
|
||||
.FirstOrDefault(x => x.Item.Id == a.Id);
|
||||
return scored.Score;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// Log deduplication details for debugging
|
||||
if (_logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
var localArtistNames = scoredLocalArtists.Select(x => $"{x.Item.Name} (local, score: {x.Score:F2})").ToList();
|
||||
var externalArtistNames = scoredExternalArtists.Select(x => $"{x.Item.Name} ({x.Item.ExternalProvider}, score: {x.Score:F2})").ToList();
|
||||
_logger.LogDebug("🎤 Artist deduplication: Local={LocalArtists}, External={ExternalArtists}, Final={FinalCount}",
|
||||
string.Join(", ", localArtistNames),
|
||||
string.Join(", ", externalArtistNames),
|
||||
artistScores.Count);
|
||||
}
|
||||
|
||||
// Convert to Jellyfin format
|
||||
var mergedSongs = allSongs.Select(s => _responseBuilder.ConvertSongToJellyfinItem(s)).ToList();
|
||||
var mergedAlbums = allAlbums.Select(a => _responseBuilder.ConvertAlbumToJellyfinItem(a)).ToList();
|
||||
@@ -680,27 +724,30 @@ public class JellyfinController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
// Merge and deduplicate by name
|
||||
// Merge and deduplicate by name, but KEEP both local and external versions
|
||||
// This allows users to see both their local "Taylor Swift" and external "Taylor Swift [S]"
|
||||
var artistNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var mergedArtists = new List<Artist>();
|
||||
|
||||
// Add all local artists first
|
||||
foreach (var artist in localArtists)
|
||||
{
|
||||
if (artistNames.Add(artist.Name))
|
||||
if (artistNames.Add(artist.Name + ":local"))
|
||||
{
|
||||
mergedArtists.Add(artist);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all external artists (even if name matches local)
|
||||
foreach (var artist in externalArtists)
|
||||
{
|
||||
if (artistNames.Add(artist.Name))
|
||||
if (artistNames.Add(artist.Name + ":external"))
|
||||
{
|
||||
mergedArtists.Add(artist);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Returning {Count} merged artists", mergedArtists.Count);
|
||||
_logger.LogInformation("Returning {Count} merged artists (local + external)", mergedArtists.Count);
|
||||
|
||||
// Convert to Jellyfin format
|
||||
var artistItems = mergedArtists.Select(a => _responseBuilder.ConvertArtistToJellyfinItem(a)).ToList();
|
||||
|
||||
@@ -176,10 +176,13 @@ public class SquidWTFMetadataService : IMusicMetadataService
|
||||
return await TryWithFallbackAsync(async (baseUrl) =>
|
||||
{
|
||||
var url = $"{baseUrl}/search/?a={Uri.EscapeDataString(query)}";
|
||||
_logger.LogInformation("🔍 SQUIDWTF: Searching artists with URL: {Url}", url);
|
||||
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogWarning("⚠️ SQUIDWTF: Artist search failed with status {StatusCode}", response.StatusCode);
|
||||
return new List<Artist>();
|
||||
}
|
||||
|
||||
@@ -196,11 +199,14 @@ public class SquidWTFMetadataService : IMusicMetadataService
|
||||
{
|
||||
if (count >= limit) break;
|
||||
|
||||
artists.Add(ParseTidalArtist(artist));
|
||||
var parsedArtist = ParseTidalArtist(artist);
|
||||
artists.Add(parsedArtist);
|
||||
_logger.LogDebug("🎤 SQUIDWTF: Found artist: {Name} (ID: {Id})", parsedArtist.Name, parsedArtist.ExternalId);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("✓ SQUIDWTF: Artist search returned {Count} results", artists.Count);
|
||||
return artists;
|
||||
}, new List<Artist>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user