mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
refactor: use token-based fuzzy matching for flexible search
Some checks failed
CI / build-and-test (push) Has been cancelled
Some checks failed
CI / build-and-test (push) Has been cancelled
This commit is contained in:
@@ -1785,45 +1785,39 @@ public class JellyfinController : ControllerBase
|
||||
var artist = artistField(item) ?? "";
|
||||
var album = albumField(item) ?? "";
|
||||
|
||||
var scores = new List<int>();
|
||||
// Token-based fuzzy matching: split query and fields into words
|
||||
var queryTokens = query.ToLower()
|
||||
.Split(new[] { ' ', '-', '_' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToList();
|
||||
|
||||
// Individual field scores
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, title));
|
||||
if (!string.IsNullOrEmpty(artist))
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, artist));
|
||||
if (!string.IsNullOrEmpty(album))
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, album));
|
||||
var fieldText = $"{title} {artist} {album}".ToLower();
|
||||
var fieldTokens = fieldText
|
||||
.Split(new[] { ' ', '-', '_' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToList();
|
||||
|
||||
// Two-field combinations
|
||||
if (!string.IsNullOrEmpty(artist))
|
||||
if (queryTokens.Count == 0) return (item, 0);
|
||||
|
||||
// Count how many query tokens match field tokens (with fuzzy tolerance)
|
||||
var matchedTokens = 0;
|
||||
foreach (var queryToken in queryTokens)
|
||||
{
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{title} {artist}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{artist} {title}"));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(album))
|
||||
{
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{title} {album}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{album} {title}"));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(artist) && !string.IsNullOrEmpty(album))
|
||||
{
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{artist} {album}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{album} {artist}"));
|
||||
// Check if any field token matches this query token
|
||||
var hasMatch = fieldTokens.Any(fieldToken =>
|
||||
{
|
||||
// Exact match or substring match
|
||||
if (fieldToken.Contains(queryToken) || queryToken.Contains(fieldToken))
|
||||
return true;
|
||||
|
||||
// Fuzzy match with Levenshtein distance
|
||||
var similarity = FuzzyMatcher.CalculateSimilarity(queryToken, fieldToken);
|
||||
return similarity >= 70; // 70% similarity threshold for individual words
|
||||
});
|
||||
|
||||
if (hasMatch) matchedTokens++;
|
||||
}
|
||||
|
||||
// Three-field combinations (all permutations)
|
||||
if (!string.IsNullOrEmpty(artist) && !string.IsNullOrEmpty(album))
|
||||
{
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{title} {artist} {album}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{title} {album} {artist}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{artist} {title} {album}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{artist} {album} {title}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{album} {title} {artist}"));
|
||||
scores.Add(FuzzyMatcher.CalculateSimilarity(query, $"{album} {artist} {title}"));
|
||||
}
|
||||
|
||||
// Use the best score from all attempts
|
||||
var baseScore = scores.Max();
|
||||
// Score = percentage of query tokens that matched
|
||||
var baseScore = (matchedTokens * 100) / queryTokens.Count;
|
||||
|
||||
// Give external results a small boost (+5 points) to prioritize the larger catalog
|
||||
var finalScore = isExternal ? Math.Min(100, baseScore + 5) : baseScore;
|
||||
|
||||
Reference in New Issue
Block a user