mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-10-30 15:32:31 +01:00
Fixed: Search results from trakt are now sorted based on similarity with the search query.
Using a Levenshtein distance algorithm.
This commit is contained in:
parent
50303ce470
commit
e28123eefd
50
src/NzbDrone.Common.Test/LevenshteinDistanceFixture.cs
Normal file
50
src/NzbDrone.Common.Test/LevenshteinDistanceFixture.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Common.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class LevenshteinDistanceFixture : TestBase
|
||||
{
|
||||
[TestCase("", "", 0)]
|
||||
[TestCase("abc", "abc", 0)]
|
||||
[TestCase("abc", "abcd", 1)]
|
||||
[TestCase("abcd", "abc", 1)]
|
||||
[TestCase("abc", "abd", 1)]
|
||||
[TestCase("abc", "adc", 1)]
|
||||
[TestCase("abcdefgh", "abcghdef", 4)]
|
||||
[TestCase("a.b.c.", "abc", 3)]
|
||||
[TestCase("Agents Of SHIELD", "Marvel's Agents Of S.H.I.E.L.D.", 15)]
|
||||
[TestCase("Agents of cracked", "Agents of shield", 6)]
|
||||
[TestCase("ABCxxx", "ABC1xx", 1)]
|
||||
[TestCase("ABC1xx", "ABCxxx", 1)]
|
||||
public void LevenshteinDistance(String text, String other, Int32 expected)
|
||||
{
|
||||
text.LevenshteinDistance(other).Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase("", "", 0)]
|
||||
[TestCase("abc", "abc", 0)]
|
||||
[TestCase("abc", "abcd", 1)]
|
||||
[TestCase("abcd", "abc", 3)]
|
||||
[TestCase("abc", "abd", 3)]
|
||||
[TestCase("abc", "adc", 3)]
|
||||
[TestCase("abcdefgh", "abcghdef", 8)]
|
||||
[TestCase("a.b.c.", "abc", 0)]
|
||||
[TestCase("Agents of shield", "Marvel's Agents Of S.H.I.E.L.D.", 9)]
|
||||
[TestCase("Agents of shield", "Agents of cracked", 14)]
|
||||
[TestCase("Agents of shield", "the shield", 24)]
|
||||
[TestCase("ABCxxx", "ABC1xx", 3)]
|
||||
[TestCase("ABC1xx", "ABCxxx", 3)]
|
||||
public void LevenshteinDistanceClean(String text, String other, Int32 expected)
|
||||
{
|
||||
text.ToLower().LevenshteinDistanceClean(other.ToLower()).Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@
|
||||
<Compile Include="EnsureTest\PathExtensionFixture.cs" />
|
||||
<Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" />
|
||||
<Compile Include="EnvironmentTests\EnvironmentProviderTest.cs" />
|
||||
<Compile Include="LevenshteinDistanceFixture.cs" />
|
||||
<Compile Include="ReflectionExtensions.cs" />
|
||||
<Compile Include="PathExtensionFixture.cs" />
|
||||
<Compile Include="DiskProviderTests\DiskProviderFixtureBase.cs" />
|
||||
|
55
src/NzbDrone.Common/LevenstheinExtensions.cs
Normal file
55
src/NzbDrone.Common/LevenstheinExtensions.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
|
||||
namespace NzbDrone.Common
|
||||
{
|
||||
public static class LevenstheinExtensions
|
||||
{
|
||||
public static Int32 LevenshteinDistance(this String text, String other, Int32 costInsert = 1, Int32 costDelete = 1, Int32 costSubstitute = 1)
|
||||
{
|
||||
if (text == other) return 0;
|
||||
if (text.Length == 0) return other.Length * costInsert;
|
||||
if (other.Length == 0) return text.Length * costDelete;
|
||||
|
||||
Int32[] matrix = new Int32[other.Length + 1];
|
||||
|
||||
for (var i = 1; i < matrix.Length; i++)
|
||||
{
|
||||
matrix[i] = i * costInsert;
|
||||
}
|
||||
|
||||
for (var i = 0; i < text.Length; i++)
|
||||
{
|
||||
Int32 topLeft = matrix[0];
|
||||
matrix[0] = matrix[0] + costDelete;
|
||||
|
||||
for (var j = 0; j < other.Length; j++)
|
||||
{
|
||||
Int32 top = matrix[j];
|
||||
Int32 left = matrix[j + 1];
|
||||
|
||||
var sumIns = top + costInsert;
|
||||
var sumDel = left + costDelete;
|
||||
var sumSub = topLeft + (text[i] == other[j] ? 0 : costSubstitute);
|
||||
|
||||
topLeft = matrix[j + 1];
|
||||
matrix[j + 1] = Math.Min(Math.Min(sumIns, sumDel), sumSub);
|
||||
}
|
||||
}
|
||||
|
||||
return matrix[other.Length];
|
||||
}
|
||||
|
||||
public static Int32 LevenshteinDistanceClean(this String expected, String other)
|
||||
{
|
||||
expected = expected.ToLower().Replace(".", "");
|
||||
other = other.ToLower().Replace(".", "");
|
||||
|
||||
return expected.LevenshteinDistance(other, 1, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
@ -114,6 +114,7 @@
|
||||
<Compile Include="Serializer\IntConverter.cs" />
|
||||
<Compile Include="Services.cs" />
|
||||
<Compile Include="Extensions\StreamExtensions.cs" />
|
||||
<Compile Include="LevenstheinExtensions.cs" />
|
||||
<Compile Include="TPL\LimitedConcurrencyLevelTaskScheduler.cs" />
|
||||
<Compile Include="Security\IgnoreCertErrorPolicy.cs" />
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
|
@ -35,7 +35,9 @@ namespace NzbDrone.Core.MetadataSource
|
||||
var restRequest = new RestRequest(GetSearchTerm(title) + "/30/seasons");
|
||||
var response = client.ExecuteAndValidate<List<Show>>(restRequest);
|
||||
|
||||
return response.Select(MapSeries).ToList();
|
||||
return response.Select(MapSeries)
|
||||
.OrderBy(v => title.LevenshteinDistanceClean(v.Title))
|
||||
.ToList();
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user