mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 16:08:39 -05:00
fix: sort search results by individual match scores instead of source averages
Local tracks now properly appear first when they match better, even if there are many external results. Each track is scored individually with +10 boost for local tracks, then all results are sorted by score.
This commit is contained in:
@@ -279,54 +279,50 @@ public class JellyfinController : ControllerBase
|
|||||||
// Parse Jellyfin results into domain models
|
// Parse Jellyfin results into domain models
|
||||||
var (localSongs, localAlbums, localArtists) = _modelMapper.ParseItemsResponse(jellyfinResult);
|
var (localSongs, localAlbums, localArtists) = _modelMapper.ParseItemsResponse(jellyfinResult);
|
||||||
|
|
||||||
// Respect source ordering (SquidWTF/Tidal has better search ranking than our fuzzy matching)
|
// Sort all results by match score (local tracks get +10 boost)
|
||||||
// Just interleave local and external results based on which source has better overall match
|
// This ensures best matches appear first regardless of source
|
||||||
|
var allSongs = localSongs.Concat(externalResult.Songs)
|
||||||
// Calculate average match score for each source to determine which should come first
|
.Select(s => new { Song = s, Score = FuzzyMatcher.CalculateSimilarity(cleanQuery, s.Title) + (s.IsLocal ? 10.0 : 0.0) })
|
||||||
// Give local tracks a +10 boost to prioritize them
|
.OrderByDescending(x => x.Score)
|
||||||
var localSongsAvgScore = localSongs.Any()
|
.Select(x => x.Song)
|
||||||
? localSongs.Average(s => FuzzyMatcher.CalculateSimilarity(cleanQuery, s.Title) + 10.0)
|
.ToList();
|
||||||
: 0.0;
|
|
||||||
var externalSongsAvgScore = externalResult.Songs.Any()
|
|
||||||
? externalResult.Songs.Average(s => FuzzyMatcher.CalculateSimilarity(cleanQuery, s.Title))
|
|
||||||
: 0.0;
|
|
||||||
|
|
||||||
var localAlbumsAvgScore = localAlbums.Any()
|
var allAlbums = localAlbums.Concat(externalResult.Albums)
|
||||||
? localAlbums.Average(a => FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Title) + 10.0)
|
.Select(a => new { Album = a, Score = FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Title) + (a.IsLocal ? 10.0 : 0.0) })
|
||||||
: 0.0;
|
.OrderByDescending(x => x.Score)
|
||||||
var externalAlbumsAvgScore = externalResult.Albums.Any()
|
.Select(x => x.Album)
|
||||||
? externalResult.Albums.Average(a => FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Title))
|
.ToList();
|
||||||
: 0.0;
|
|
||||||
|
|
||||||
var localArtistsAvgScore = localArtists.Any()
|
var allArtists = localArtists.Concat(externalResult.Artists)
|
||||||
? localArtists.Average(a => FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Name) + 10.0)
|
.Select(a => new { Artist = a, Score = FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Name) + (a.IsLocal ? 10.0 : 0.0) })
|
||||||
: 0.0;
|
.OrderByDescending(x => x.Score)
|
||||||
var externalArtistsAvgScore = externalResult.Artists.Any()
|
.Select(x => x.Artist)
|
||||||
? externalResult.Artists.Average(a => FuzzyMatcher.CalculateSimilarity(cleanQuery, a.Name))
|
.ToList();
|
||||||
: 0.0;
|
|
||||||
|
|
||||||
// Interleave results: put better-matching source first, preserve original ordering within each source
|
// Log top results for debugging
|
||||||
var allSongs = localSongsAvgScore >= externalSongsAvgScore
|
|
||||||
? localSongs.Concat(externalResult.Songs).ToList()
|
|
||||||
: externalResult.Songs.Concat(localSongs).ToList();
|
|
||||||
|
|
||||||
var allAlbums = localAlbumsAvgScore >= externalAlbumsAvgScore
|
|
||||||
? localAlbums.Concat(externalResult.Albums).ToList()
|
|
||||||
: externalResult.Albums.Concat(localAlbums).ToList();
|
|
||||||
|
|
||||||
var allArtists = localArtistsAvgScore >= externalArtistsAvgScore
|
|
||||||
? localArtists.Concat(externalResult.Artists).ToList()
|
|
||||||
: externalResult.Artists.Concat(localArtists).ToList();
|
|
||||||
|
|
||||||
// Log results for debugging
|
|
||||||
if (_logger.IsEnabled(LogLevel.Debug))
|
if (_logger.IsEnabled(LogLevel.Debug))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("🎵 Songs: Local avg score={LocalScore:F2}, External avg score={ExtScore:F2}, Local first={LocalFirst}",
|
if (allSongs.Any())
|
||||||
localSongsAvgScore, externalSongsAvgScore, localSongsAvgScore >= externalSongsAvgScore);
|
{
|
||||||
_logger.LogDebug("💿 Albums: Local avg score={LocalScore:F2}, External avg score={ExtScore:F2}, Local first={LocalFirst}",
|
var topSong = allSongs.First();
|
||||||
localAlbumsAvgScore, externalAlbumsAvgScore, localAlbumsAvgScore >= externalAlbumsAvgScore);
|
var topScore = FuzzyMatcher.CalculateSimilarity(cleanQuery, topSong.Title) + (topSong.IsLocal ? 10.0 : 0.0);
|
||||||
_logger.LogDebug("🎤 Artists: Local avg score={LocalScore:F2}, External avg score={ExtScore:F2}, Local first={LocalFirst}",
|
_logger.LogDebug("🎵 Top song: '{Title}' (local={IsLocal}, score={Score:F2})",
|
||||||
localArtistsAvgScore, externalArtistsAvgScore, localArtistsAvgScore >= externalArtistsAvgScore);
|
topSong.Title, topSong.IsLocal, topScore);
|
||||||
|
}
|
||||||
|
if (allAlbums.Any())
|
||||||
|
{
|
||||||
|
var topAlbum = allAlbums.First();
|
||||||
|
var topScore = FuzzyMatcher.CalculateSimilarity(cleanQuery, topAlbum.Title) + (topAlbum.IsLocal ? 10.0 : 0.0);
|
||||||
|
_logger.LogDebug("💿 Top album: '{Title}' (local={IsLocal}, score={Score:F2})",
|
||||||
|
topAlbum.Title, topAlbum.IsLocal, topScore);
|
||||||
|
}
|
||||||
|
if (allArtists.Any())
|
||||||
|
{
|
||||||
|
var topArtist = allArtists.First();
|
||||||
|
var topScore = FuzzyMatcher.CalculateSimilarity(cleanQuery, topArtist.Name) + (topArtist.IsLocal ? 10.0 : 0.0);
|
||||||
|
_logger.LogDebug("🎤 Top artist: '{Name}' (local={IsLocal}, score={Score:F2})",
|
||||||
|
topArtist.Name, topArtist.IsLocal, topScore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to Jellyfin format
|
// Convert to Jellyfin format
|
||||||
@@ -344,7 +340,7 @@ public class JellyfinController : ControllerBase
|
|||||||
mergedAlbums.AddRange(playlistItems);
|
mergedAlbums.AddRange(playlistItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Merged results (preserving source order): Songs={Songs}, Albums={Albums}, Artists={Artists}",
|
_logger.LogInformation("Merged and sorted results by score: Songs={Songs}, Albums={Albums}, Artists={Artists}",
|
||||||
mergedSongs.Count, mergedAlbums.Count, mergedArtists.Count);
|
mergedSongs.Count, mergedAlbums.Count, mergedArtists.Count);
|
||||||
|
|
||||||
// Pre-fetch lyrics for top 3 songs in background (don't await)
|
// Pre-fetch lyrics for top 3 songs in background (don't await)
|
||||||
|
|||||||
Reference in New Issue
Block a user