Skip to content

Commit

Permalink
Fixed parsing (duplicate) releases for series with multiple season nu…
Browse files Browse the repository at this point in the history
…mber mappings
  • Loading branch information
Taloth committed Jan 16, 2021
1 parent 6c17b4b commit e10cff5
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void should_get_mappings_for_all_providers()
[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());
Expand All @@ -130,7 +130,7 @@ public void should_not_refresh_cache_if_cache_is_not_empty_when_looking_for_tvdb
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());
Expand Down Expand Up @@ -195,7 +195,7 @@ public void should_return_single_match(string parseTitle, string title, int expe

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);
Expand Down Expand Up @@ -328,8 +328,8 @@ public void should_filter_by_regex()

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]
Expand All @@ -343,7 +343,7 @@ public void should_throw_if_multiple_mappings()

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]
Expand All @@ -357,7 +357,21 @@ public void should_not_throw_if_multiple_mappings_with_same_tvdbid()

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()
Expand All @@ -376,7 +390,7 @@ private void AssertMappingUpdated()
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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public void should_return_unknown_series_rejection_if_series_title_is_an_alias_f
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ public void should_use_tvdb_season_number_when_available_and_a_scene_source()
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);

Expand All @@ -342,8 +342,8 @@ public void should_not_use_tvdb_season_number_when_available_for_a_different_sea
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);

Expand Down Expand Up @@ -374,7 +374,7 @@ public void should_not_use_tvdb_season_when_tvdb_season_number_is_less_than_zero
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void should_parse_concatenated_title()
{
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");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void should_not_use_tvrageid_when_scene_naming_exception_exists()
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);
Expand Down Expand Up @@ -199,7 +199,7 @@ public void should_FindByTvRageId_when_search_criteria_and_FindByTitle_matching_
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);
Expand Down
44 changes: 33 additions & 11 deletions src/NzbDrone.Core/DataAugmentation/Scene/SceneMappingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -65,14 +65,9 @@ public List<string> GetSceneNames(int tvdbId, List<int> seasonNumbers, List<int>
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)
Expand All @@ -92,7 +87,7 @@ public List<SceneMapping> FindByTvdbId(int tvdbId)
return mappings;
}

public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle)
public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle, int sceneSeasonNumber)
{
var mappings = FindMappings(seriesTitle, releaseTitle);

Expand All @@ -101,6 +96,8 @@ public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle)
return null;
}

mappings = FilterSceneMappings(mappings, sceneSeasonNumber);

var distinctMappings = mappings.DistinctBy(v => v.TvdbId).ToList();

if (distinctMappings.Count == 0)
Expand All @@ -120,7 +117,7 @@ public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle)

public int? GetSceneSeasonNumber(string seriesTitle, string releaseTitle)
{
return FindSceneMapping(seriesTitle, releaseTitle)?.SceneSeasonNumber;
return FindSceneMapping(seriesTitle, releaseTitle, -1)?.SceneSeasonNumber;
}

private void UpdateMappings()
Expand Down Expand Up @@ -239,6 +236,31 @@ private List<SceneMapping> FilterSceneMappings(List<SceneMapping> candidates, st
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);
Expand Down
2 changes: 1 addition & 1 deletion src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, Se
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)
{
Expand Down
4 changes: 2 additions & 2 deletions src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,9 @@ private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>>

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();
}
}
}
6 changes: 3 additions & 3 deletions src/NzbDrone.Core/Parser/ParsingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public Series GetSeries(string title)
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)
{
Expand Down Expand Up @@ -85,7 +85,7 @@ private Series GetSeriesByAllTitles(ParsedEpisodeInfo parsedEpisodeInfo)

if (series == null)
{
tvdbId = _sceneMappingService.FindTvdbId(title, parsedEpisodeInfo.ReleaseTitle);
tvdbId = _sceneMappingService.FindTvdbId(title, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
}

if (!tvdbId.HasValue)
Expand Down Expand Up @@ -137,7 +137,7 @@ public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnu

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
{
Expand Down

0 comments on commit e10cff5

Please sign in to comment.