Fixed parsing (duplicate) releases for series with multiple season number mappings

This commit is contained in:
Taloth Saldono 2021-01-16 21:13:32 +01:00
parent 6c17b4bb86
commit e10cff5414
9 changed files with 70 additions and 34 deletions

View File

@ -109,7 +109,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
[Test]
public void should_refresh_cache_if_cache_is_empty_when_looking_for_tvdb_id()
{
Subject.FindTvdbId("title");
Subject.FindTvdbId("title", null, -1);
Mocker.GetMock<ISceneMappingRepository>()
.Verify(v => v.All(), Times.Once());
@ -130,7 +130,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
Mocker.GetMock<ISceneMappingRepository>()
.Verify(v => v.All(), Times.Once());
Subject.FindTvdbId("title");
Subject.FindTvdbId("title", null, -1);
Mocker.GetMock<ISceneMappingRepository>()
.Verify(v => v.All(), Times.Once());
@ -195,7 +195,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(mappings);
var tvdbId = Subject.FindTvdbId(parseTitle);
var tvdbId = Subject.FindTvdbId(parseTitle, null, -1);
var seasonNumber = Subject.GetSceneSeasonNumber(parseTitle, null);
tvdbId.Should().Be(100);
@ -328,8 +328,8 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(mappings);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva").Should().Be(101);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-DMO").Should().Be(100);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva", -1).Should().Be(101);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-DMO", -1).Should().Be(100);
}
[Test]
@ -343,7 +343,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(mappings);
Assert.Throws<InvalidSceneMappingException>(() => Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva"));
Assert.Throws<InvalidSceneMappingException>(() => Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva", -1));
}
[Test]
@ -357,7 +357,21 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(mappings);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva").Should().Be(100);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva", -1).Should().Be(100);
}
[Test]
public void should_pick_best_season()
{
var mappings = new List<SceneMapping>
{
new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", SceneSeasonNumber = 2, SeasonNumber = 3, TvdbId = 100 },
new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", SceneSeasonNumber = 3, SeasonNumber = 3, TvdbId = 101 }
};
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(mappings);
Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva", 4).Should().Be(101);
}
private void AssertNoUpdate()
@ -376,7 +390,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene
foreach (var sceneMapping in _fakeMappings)
{
Subject.GetSceneNames(sceneMapping.TvdbId, _fakeMappings.Select(m => m.SeasonNumber.Value).Distinct().ToList(), new List<int>()).Should().Contain(sceneMapping.SearchTerm);
Subject.FindTvdbId(sceneMapping.ParseTerm).Should().Be(sceneMapping.TvdbId);
Subject.FindTvdbId(sceneMapping.ParseTerm, null, sceneMapping.SceneSeasonNumber ?? -1).Should().Be(sceneMapping.TvdbId);
}
}
}

View File

@ -336,7 +336,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenSpecifications(_pass1, _pass2, _pass3);
Mocker.GetMock<ISceneMappingService>()
.Setup(s => s.FindTvdbId(It.IsAny<string>(), It.IsAny<string>()))
.Setup(s => s.FindTvdbId(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns(12345);
_remoteEpisode.Series = null;

View File

@ -324,8 +324,8 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
const int tvdbSeasonNumber = 5;
Mocker.GetMock<ISceneMappingService>()
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>()))
.Returns<string, string>((s, r) => new SceneMapping { SceneSeasonNumber = 1, SeasonNumber = tvdbSeasonNumber });
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns<string, string, int>((s, r, sn) => new SceneMapping { SceneSeasonNumber = 1, SeasonNumber = tvdbSeasonNumber });
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
@ -342,8 +342,8 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
const int tvdbSeasonNumber = 5;
Mocker.GetMock<ISceneMappingService>()
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>()))
.Returns<string, string>((s, r) => new SceneMapping { SceneSeasonNumber = 101, SeasonNumber = tvdbSeasonNumber });
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns<string, string, int>((s, r, sn) => new SceneMapping { SceneSeasonNumber = 101, SeasonNumber = tvdbSeasonNumber });
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
@ -374,7 +374,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
const int tvdbSeasonNumber = -1;
Mocker.GetMock<ISceneMappingService>()
.Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle, It.IsAny<string>()))
.Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle, It.IsAny<string>(), It.IsAny<int>()))
.Returns(new SceneMapping { SeasonNumber = tvdbSeasonNumber, SceneSeasonNumber = _parsedEpisodeInfo.SeasonNumber });
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);

View File

@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
{
var series = new Series { TvdbId = 100 };
Mocker.GetMock<ISeriesService>().Setup(v => v.FindByTitle("Welcome")).Returns(series);
Mocker.GetMock<ISceneMappingService>().Setup(v => v.FindTvdbId("Mairimashita", It.IsAny<string>())).Returns(100);
Mocker.GetMock<ISceneMappingService>().Setup(v => v.FindTvdbId("Mairimashita", It.IsAny<string>(), It.IsAny<int>())).Returns(100);
var result = Subject.GetSeries("Welcome (Mairimashita).S01E01.720p.WEB-DL-Viva");

View File

@ -118,7 +118,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
GivenMatchByTvRageId();
Mocker.GetMock<ISceneMappingService>()
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>()))
.Setup(v => v.FindSceneMapping(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns(new SceneMapping { TvdbId = 10 });
var result = Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
@ -199,7 +199,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
public void should_use_tvdbid_matching_when_alias_is_found()
{
Mocker.GetMock<ISceneMappingService>()
.Setup(s => s.FindTvdbId(It.IsAny<string>(), It.IsAny<string>()))
.Setup(s => s.FindTvdbId(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns(_series.TvdbId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);

View File

@ -15,9 +15,9 @@ namespace NzbDrone.Core.DataAugmentation.Scene
public interface ISceneMappingService
{
List<string> GetSceneNames(int tvdbId, List<int> seasonNumbers, List<int> sceneSeasonNumbers);
int? FindTvdbId(string sceneTitle, string releaseTitle);
int? FindTvdbId(string sceneTitle, string releaseTitle, int sceneSeasonNumber);
List<SceneMapping> FindByTvdbId(int tvdbId);
SceneMapping FindSceneMapping(string sceneTitle, string releaseTitle);
SceneMapping FindSceneMapping(string sceneTitle, string releaseTitle, int sceneSeasonNumber);
int? GetSceneSeasonNumber(string seriesTitle, string releaseTitle);
}
@ -65,14 +65,9 @@ namespace NzbDrone.Core.DataAugmentation.Scene
return names;
}
public int? FindTvdbId(string seriesTitle)
public int? FindTvdbId(string seriesTitle, string releaseTitle, int sceneSeasonNumber)
{
return FindTvdbId(seriesTitle, null);
}
public int? FindTvdbId(string seriesTitle, string releaseTitle)
{
return FindSceneMapping(seriesTitle, releaseTitle)?.TvdbId;
return FindSceneMapping(seriesTitle, releaseTitle, sceneSeasonNumber)?.TvdbId;
}
public List<SceneMapping> FindByTvdbId(int tvdbId)
@ -92,7 +87,7 @@ namespace NzbDrone.Core.DataAugmentation.Scene
return mappings;
}
public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle)
public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle, int sceneSeasonNumber)
{
var mappings = FindMappings(seriesTitle, releaseTitle);
@ -101,6 +96,8 @@ namespace NzbDrone.Core.DataAugmentation.Scene
return null;
}
mappings = FilterSceneMappings(mappings, sceneSeasonNumber);
var distinctMappings = mappings.DistinctBy(v => v.TvdbId).ToList();
if (distinctMappings.Count == 0)
@ -120,7 +117,7 @@ namespace NzbDrone.Core.DataAugmentation.Scene
public int? GetSceneSeasonNumber(string seriesTitle, string releaseTitle)
{
return FindSceneMapping(seriesTitle, releaseTitle)?.SceneSeasonNumber;
return FindSceneMapping(seriesTitle, releaseTitle, -1)?.SceneSeasonNumber;
}
private void UpdateMappings()
@ -239,6 +236,31 @@ namespace NzbDrone.Core.DataAugmentation.Scene
return normalCandidates;
}
private List<SceneMapping> FilterSceneMappings(List<SceneMapping> candidates, int sceneSeasonNumber)
{
var filteredCandidates = candidates.Where(v => (v.SceneSeasonNumber ?? -1) != -1 && (v.SeasonNumber ?? -1) != -1).ToList();
var normalCandidates = candidates.Except(filteredCandidates).ToList();
if (sceneSeasonNumber == -1)
{
return normalCandidates;
}
if (filteredCandidates.Any())
{
filteredCandidates = filteredCandidates.Where(v => v.SceneSeasonNumber <= sceneSeasonNumber)
.GroupBy(v => v.Title)
.Select(d => d.OrderByDescending(v => v.SceneSeasonNumber)
.ThenByDescending(v => v.SeasonNumber)
.First())
.ToList();
return filteredCandidates;
}
return normalCandidates;
}
private bool IsEnglish(string title)
{
return title.All(c => c <= 255);

View File

@ -93,7 +93,7 @@ namespace NzbDrone.Core.DecisionEngine
if (remoteEpisode.Series == null)
{
var reason = "Unknown Series";
var matchingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle);
var matchingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
if (matchingTvdbId.HasValue)
{

View File

@ -523,9 +523,9 @@ namespace NzbDrone.Core.IndexerSearch
private List<DownloadDecision> DeDupeDecisions(List<DownloadDecision> decisions)
{
// De-dupe reports by guid so duplicate results aren't returned.
// De-dupe reports by guid so duplicate results aren't returned. Pick the one with the least rejections.
return decisions.DistinctBy(d => d.RemoteEpisode.Release.Guid).ToList();
return decisions.GroupBy(d => d.RemoteEpisode.Release.Guid).Select(d => d.OrderBy(v => v.Rejections.Count()).First()).ToList();
}
}
}

View File

@ -49,7 +49,7 @@ namespace NzbDrone.Core.Parser
return _seriesService.FindByTitle(title);
}
var tvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle);
var tvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
if (tvdbId.HasValue)
{
@ -85,7 +85,7 @@ namespace NzbDrone.Core.Parser
if (series == null)
{
tvdbId = _sceneMappingService.FindTvdbId(title, parsedEpisodeInfo.ReleaseTitle);
tvdbId = _sceneMappingService.FindTvdbId(title, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
}
if (!tvdbId.HasValue)
@ -137,7 +137,7 @@ namespace NzbDrone.Core.Parser
private RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, Series series, SearchCriteriaBase searchCriteria)
{
var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle);
var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
var remoteEpisode = new RemoteEpisode
{