mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-30 03:38:26 -07:00
Fixed: Improve TrackMatching when title is slightly longer/shorter than DB (#491)
* improve TrackMatching * Add unit test for TrackMatching * rename NormalizeEpisodeTitle to NormalizeTrackTitle * correct typo
This commit is contained in:
parent
2af4a5004f
commit
9b0a7c60ed
4 changed files with 85 additions and 25 deletions
|
@ -0,0 +1,69 @@
|
||||||
|
using System.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NLog;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MusicTests.TitleMatchingTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TitleMatchingFixture : DbTest<TrackService, Track>
|
||||||
|
{
|
||||||
|
private TrackRepository _trackRepository;
|
||||||
|
private TrackService _trackService;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_trackRepository = Mocker.Resolve<TrackRepository>();
|
||||||
|
_trackService =
|
||||||
|
new TrackService(_trackRepository, Mocker.Resolve<ConfigService>(), Mocker.Resolve<Logger>());
|
||||||
|
|
||||||
|
_trackRepository.Insert(new Track
|
||||||
|
{
|
||||||
|
Title = "This is the short test title",
|
||||||
|
ForeignTrackId = "this is a fake id2",
|
||||||
|
AlbumId = 4321,
|
||||||
|
AbsoluteTrackNumber = 1,
|
||||||
|
MediumNumber = 1,
|
||||||
|
TrackFileId = 1
|
||||||
|
});
|
||||||
|
|
||||||
|
_trackRepository.Insert(new Track
|
||||||
|
{
|
||||||
|
Title = "This is the long test title",
|
||||||
|
ForeignTrackId = "this is a fake id",
|
||||||
|
AlbumId = 4321,
|
||||||
|
AbsoluteTrackNumber = 2,
|
||||||
|
MediumNumber = 1,
|
||||||
|
TrackFileId = 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_find_track_in_db_by_tracktitle_longer_then_relaeasetitle()
|
||||||
|
{
|
||||||
|
var track = _trackService.FindTrackByTitle(1234, 4321, 1, 1, "This is the short test title with some bla");
|
||||||
|
|
||||||
|
track.Title.Should().Be(_trackRepository.GetTracksByFileId(1).First().Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_find_track_in_db_by_tracktitle_shorter_then_relaeasetitle()
|
||||||
|
{
|
||||||
|
var track = _trackService.FindTrackByTitle(1234, 4321, 1, 2, "test title");
|
||||||
|
|
||||||
|
track.Title.Should().Be(_trackRepository.GetTracksByFileId(2).First().Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_find_track_in_db_by_wrong_title()
|
||||||
|
{
|
||||||
|
var track = _trackService.FindTrackByTitle(1234, 4321, 1, 1, "the short title");
|
||||||
|
|
||||||
|
track.Should().BeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -306,6 +306,7 @@
|
||||||
<Compile Include="MusicTests\ArtistServiceTests\UpdateMultipleArtistFixture.cs" />
|
<Compile Include="MusicTests\ArtistServiceTests\UpdateMultipleArtistFixture.cs" />
|
||||||
<Compile Include="MusicTests\RefreshAlbumServiceFixture.cs" />
|
<Compile Include="MusicTests\RefreshAlbumServiceFixture.cs" />
|
||||||
<Compile Include="MusicTests\ShouldRefreshAlbumFixture.cs" />
|
<Compile Include="MusicTests\ShouldRefreshAlbumFixture.cs" />
|
||||||
|
<Compile Include="MusicTests\TitleMatchingTests\TitleMatchingFixture.cs" />
|
||||||
<Compile Include="NotificationTests\NotificationBaseFixture.cs" />
|
<Compile Include="NotificationTests\NotificationBaseFixture.cs" />
|
||||||
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
|
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
|
||||||
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
|
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
|
||||||
|
|
|
@ -79,35 +79,25 @@ namespace NzbDrone.Core.Music
|
||||||
public Track FindTrackByTitle(int artistId, int albumId, int mediumNumber, int trackNumber, string releaseTitle)
|
public Track FindTrackByTitle(int artistId, int albumId, int mediumNumber, int trackNumber, string releaseTitle)
|
||||||
{
|
{
|
||||||
// TODO: can replace this search mechanism with something smarter/faster/better
|
// TODO: can replace this search mechanism with something smarter/faster/better
|
||||||
var normalizedReleaseTitle = Parser.Parser.NormalizeEpisodeTitle(releaseTitle).Replace(".", " ");
|
var normalizedReleaseTitle = Parser.Parser.NormalizeTrackTitle(releaseTitle).Replace(".", " ");
|
||||||
var tracks = _trackRepository.GetTracksByMedium(albumId, mediumNumber);
|
var tracks = _trackRepository.GetTracksByMedium(albumId, mediumNumber);
|
||||||
|
|
||||||
var matches = tracks.Select(
|
var matches = from track in tracks
|
||||||
track => new
|
//if we have a trackNumber use it
|
||||||
|
let trackNumCheck = (trackNumber == 0 || track.AbsoluteTrackNumber == trackNumber)
|
||||||
|
//if release title is longer than track title
|
||||||
|
let posReleaseTitle = normalizedReleaseTitle.IndexOf(Parser.Parser.NormalizeTrackTitle(track.Title), StringComparison.CurrentCultureIgnoreCase)
|
||||||
|
//if track title is longer than release title
|
||||||
|
let posTrackTitle = Parser.Parser.NormalizeTrackTitle(track.Title).IndexOf(normalizedReleaseTitle, StringComparison.CurrentCultureIgnoreCase)
|
||||||
|
where track.Title.Length > 0 && trackNumCheck && (posReleaseTitle >= 0 || posTrackTitle >= 0)
|
||||||
|
orderby posReleaseTitle, posTrackTitle
|
||||||
|
select new
|
||||||
{
|
{
|
||||||
Position = normalizedReleaseTitle.IndexOf(Parser.Parser.NormalizeEpisodeTitle(track.Title), StringComparison.CurrentCultureIgnoreCase),
|
NormalizedLength = Parser.Parser.NormalizeTrackTitle(track.Title).Length,
|
||||||
Length = Parser.Parser.NormalizeEpisodeTitle(track.Title).Length,
|
|
||||||
Track = track
|
Track = track
|
||||||
});
|
};
|
||||||
|
|
||||||
if (trackNumber == 0)
|
return matches.OrderByDescending(e => e.NormalizedLength).FirstOrDefault()?.Track;
|
||||||
{
|
|
||||||
matches = matches.Where(e => e.Track.Title.Length > 0 && e.Position >= 0);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
matches = matches.Where(e => e.Track.Title.Length > 0 && e.Position >= 0 && e.Track.AbsoluteTrackNumber == trackNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
matches.OrderBy(e => e.Position)
|
|
||||||
.ThenByDescending(e => e.Length)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (matches.Any())
|
|
||||||
{
|
|
||||||
return matches.First().Track;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Track> TracksWithFiles(int artistId)
|
public List<Track> TracksWithFiles(int artistId)
|
||||||
|
|
|
@ -529,7 +529,7 @@ namespace NzbDrone.Core.Parser
|
||||||
return NormalizeRegex.Replace(name, string.Empty).ToLower().RemoveAccent();
|
return NormalizeRegex.Replace(name, string.Empty).ToLower().RemoveAccent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string NormalizeEpisodeTitle(string title)
|
public static string NormalizeTrackTitle(string title)
|
||||||
{
|
{
|
||||||
title = SpecialEpisodeWordRegex.Replace(title, string.Empty);
|
title = SpecialEpisodeWordRegex.Replace(title, string.Empty);
|
||||||
title = PunctuationRegex.Replace(title, " ");
|
title = PunctuationRegex.Replace(title, " ");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue