1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-11-24 08:42:19 +02:00

New: Match search releases using IMDb ID if available

This commit is contained in:
Bogdan 2024-08-11 18:46:46 +03:00 committed by GitHub
parent 0877a6718d
commit 363f8fc347
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 181 additions and 66 deletions

View File

@ -64,7 +64,7 @@ public void Setup()
};
Mocker.GetMock<IParsingService>()
.Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
.Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()))
.Returns(_remoteEpisode);
}
@ -154,7 +154,7 @@ public void should_not_attempt_to_map_episode_if_not_parsable()
Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
@ -169,7 +169,7 @@ public void should_not_attempt_to_map_episode_if_series_title_is_blank()
var results = Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
@ -186,7 +186,7 @@ public void should_return_rejected_result_for_unparsable_search()
Subject.GetSearchDecision(_reports, new SingleEpisodeSearchCriteria()).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
@ -212,7 +212,7 @@ public void broken_report_shouldnt_blowup_the_process()
{
GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()))
.Throws<TestException>();
_reports = new List<ReleaseInfo>
@ -224,7 +224,7 @@ public void broken_report_shouldnt_blowup_the_process()
Subject.GetRssDecision(_reports);
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Exactly(_reports.Count));
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()), Times.Exactly(_reports.Count));
ExceptionVerification.ExpectedErrors(3);
}
@ -263,8 +263,8 @@ public void should_only_include_reports_for_requested_episodes()
}).ToList();
Mocker.GetMock<IParsingService>()
.Setup(v => v.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
.Returns<ParsedEpisodeInfo, int, int, SearchCriteriaBase>((p, tvdbid, tvrageid, c) =>
.Setup(v => v.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()))
.Returns<ParsedEpisodeInfo, int, int, string, SearchCriteriaBase>((p, _, _, _, _) =>
new RemoteEpisode
{
DownloadAllowed = true,
@ -318,7 +318,7 @@ public void should_return_a_decision_when_exception_is_caught()
{
GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()))
.Throws<TestException>();
_reports = new List<ReleaseInfo>

View File

@ -10,7 +10,6 @@
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@ -35,7 +34,7 @@ public void SetupBase()
.Returns(30);
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), (SearchCriteriaBase)null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(() => CreateRemoteEpisode());
Mocker.GetMock<IHttpClient>()

View File

@ -118,7 +118,7 @@ public void should_parse_as_special_when_source_title_parsing_fails()
.Returns(remoteEpisode);
Mocker.GetMock<IParsingService>()
.Setup(s => s.ParseSpecialEpisodeTitle(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.ParseSpecialEpisodeTitle(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(remoteEpisode.ParsedEpisodeInfo);
var client = new DownloadClientDefinition()
@ -169,7 +169,7 @@ public void should_unmap_tracked_download_if_episode_deleted()
};
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(remoteEpisode);
Mocker.GetMock<IHistoryService>()
@ -199,7 +199,7 @@ public void should_unmap_tracked_download_if_episode_deleted()
Subject.GetTrackedDownloads().Should().HaveCount(1);
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(default(RemoteEpisode));
Subject.Handle(new EpisodeInfoRefreshedEvent(remoteEpisode.Series, new List<Episode>(), new List<Episode>(), remoteEpisode.Episodes));
@ -228,7 +228,7 @@ public void should_not_throw_when_processing_deleted_episodes()
};
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(default(RemoteEpisode));
Mocker.GetMock<IHistoryService>()
@ -258,7 +258,7 @@ public void should_not_throw_when_processing_deleted_episodes()
Subject.GetTrackedDownloads().Should().HaveCount(1);
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(default(RemoteEpisode));
Subject.Handle(new EpisodeInfoRefreshedEvent(remoteEpisode.Series, new List<Episode>(), new List<Episode>(), remoteEpisode.Episodes));
@ -287,7 +287,7 @@ public void should_not_throw_when_processing_deleted_series()
};
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(default(RemoteEpisode));
Mocker.GetMock<IHistoryService>()
@ -317,7 +317,7 @@ public void should_not_throw_when_processing_deleted_series()
Subject.GetTrackedDownloads().Should().HaveCount(1);
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), null))
.Returns(default(RemoteEpisode));
Subject.Handle(new SeriesDeletedEvent(new List<Series> { remoteEpisode.Series }, true, true));

View File

@ -233,11 +233,11 @@ public void should_be_accepted_if_both_file_and_folder_info_map_to_same_special(
GivenEpisodes(actualInfo, actualInfo.EpisodeNumbers);
Mocker.GetMock<IParsingService>()
.Setup(v => v.ParseSpecialEpisodeTitle(fileInfo, It.IsAny<string>(), 0, 0, null))
.Setup(v => v.ParseSpecialEpisodeTitle(fileInfo, It.IsAny<string>(), 0, 0, null, null))
.Returns(actualInfo);
Mocker.GetMock<IParsingService>()
.Setup(v => v.ParseSpecialEpisodeTitle(folderInfo, It.IsAny<string>(), 0, 0, null))
.Setup(v => v.ParseSpecialEpisodeTitle(folderInfo, It.IsAny<string>(), 0, 0, null, null))
.Returns(actualInfo);
Subject.IsSatisfiedBy(localEpisode, null).Accepted.Should().BeTrue();

View File

@ -91,7 +91,7 @@ public void should_get_daily_episode_episode_when_search_criteria_is_null()
GivenDailySeries();
GivenDailyParseResult();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Once());
@ -103,7 +103,7 @@ public void should_use_search_criteria_episode_when_it_matches_daily()
GivenDailySeries();
GivenDailyParseResult();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Never());
@ -115,7 +115,7 @@ public void should_fallback_to_daily_episode_lookup_when_search_criteria_episode
GivenDailySeries();
_parsedEpisodeInfo.AirDate = DateTime.Today.AddDays(-5).ToString(Episode.AIR_DATE_FORMAT);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Once());
@ -128,7 +128,7 @@ public void should_get_daily_episode_episode_should_lookup_including_daily_part(
GivenDailyParseResult();
_parsedEpisodeInfo.DailyPart = 1;
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), 1), Times.Once());
@ -143,7 +143,7 @@ public void should_use_search_criteria_episode_when_it_matches_absolute()
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<int>(), It.IsAny<int>()))
.Returns(new List<Episode>());
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Never());
@ -154,7 +154,7 @@ public void should_use_scene_numbering_when_series_uses_scene_numbering()
{
GivenSceneNumberingSeries();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once());
@ -165,7 +165,7 @@ public void should_match_search_criteria_by_scene_numbering()
{
GivenSceneNumberingSeries();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never());
@ -177,7 +177,7 @@ public void should_fallback_to_findEpisode_when_search_criteria_match_fails_for_
GivenSceneNumberingSeries();
_episodes.First().SceneEpisodeNumber = 10;
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once());
@ -186,7 +186,7 @@ public void should_fallback_to_findEpisode_when_search_criteria_match_fails_for_
[Test]
public void should_find_episode()
{
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once());
@ -195,7 +195,7 @@ public void should_find_episode()
[Test]
public void should_match_episode_with_search_criteria()
{
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never());
@ -206,7 +206,7 @@ public void should_fallback_to_findEpisode_when_search_criteria_match_fails()
{
_episodes.First().EpisodeNumber = 10;
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once());
@ -537,7 +537,7 @@ public void should_use_season_zero_when_looking_up_is_partial_special_episode_fo
.With(e => e.EpisodeNumber = 1)
.Build());
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(_series.TvdbId, 0, 1), Times.Once());
@ -555,7 +555,7 @@ public void should_use_original_parse_result_when_special_episode_lookup_by_titl
.Setup(s => s.FindEpisodeByTitle(_series.TvdbId, 0, _parsedEpisodeInfo.ReleaseTitle))
.Returns((Episode)null);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(_series.TvdbId, _parsedEpisodeInfo.SeasonNumber, _parsedEpisodeInfo.EpisodeNumbers.First()), Times.Once());

View File

@ -86,7 +86,7 @@ public void should_lookup_series_by_name()
{
GivenMatchBySeriesTitle();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>()), Times.Once());
@ -97,7 +97,7 @@ public void should_use_tvdbid_when_series_title_lookup_fails()
{
GivenMatchByTvdbId();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvdbId(It.IsAny<int>()), Times.Once());
@ -108,7 +108,7 @@ public void should_use_tvrageid_when_series_title_lookup_fails()
{
GivenMatchByTvRageId();
Subject.Map(_parsedEpisodeInfo, 0, _series.TvRageId);
Subject.Map(_parsedEpisodeInfo, 0, _series.TvRageId, null);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvRageId(It.IsAny<int>()), Times.Once());
@ -123,7 +123,7 @@ public void should_not_use_tvrageid_when_scene_naming_exception_exists()
.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);
var result = Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvRageId(It.IsAny<int>()), Times.Never());
@ -136,7 +136,7 @@ public void should_use_search_criteria_series_title()
{
GivenMatchBySeriesTitle();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>()), Times.Never());
@ -147,7 +147,7 @@ public void should_FindByTitle_when_search_criteria_matching_fails()
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 10, 10, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, 10, 10, null, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>()), Times.Once());
@ -169,7 +169,7 @@ public void should_FindByTitle_using_year_when_FindByTitle_matching_fails()
.Setup(s => s.FindByTitle(_parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, _parsedEpisodeInfo.SeriesTitleInfo.Year))
.Returns(_series);
Subject.Map(_parsedEpisodeInfo, 10, 10, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, 10, 10, null, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>(), It.IsAny<int>()), Times.Once());
@ -180,7 +180,7 @@ public void should_FindByTvdbId_when_search_criteria_and_FindByTitle_matching_fa
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 10, 10, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, 10, 10, null, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvdbId(It.IsAny<int>()), Times.Once());
@ -191,7 +191,7 @@ public void should_FindByTvRageId_when_search_criteria_and_FindByTitle_matching_
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 0, 10, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, 0, 10, null, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvRageId(It.IsAny<int>()), Times.Once());
@ -202,12 +202,34 @@ public void should_not_FindByTvRageId_when_search_criteria_and_FindByTitle_match
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 10, 10, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, 10, 10, null, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTvRageId(It.IsAny<int>()), Times.Never());
}
[Test]
public void should_FindByImdbId_when_search_criteria_and_FindByTitle_matching_fails()
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 0, 0, "tt12345", _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByImdbId(It.IsAny<string>()), Times.Once());
}
[Test]
public void should_not_FindByImdbId_when_search_criteria_and_FindByTitle_matching_fails_and_tvdb_id_is_specified()
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, 10, 10, "tt12345", _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByImdbId(It.IsAny<string>()), Times.Never());
}
[Test]
public void should_use_tvdbid_matching_when_alias_is_found()
{
@ -215,7 +237,7 @@ public void should_use_tvdbid_matching_when_alias_is_found()
.Setup(s => s.FindTvdbId(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
.Returns(_series.TvdbId);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>()), Times.Never());
@ -226,7 +248,7 @@ public void should_use_tvrageid_match_from_search_criteria_when_title_match_fail
{
GivenParseResultSeriesDoesntMatchSearchCriteria();
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, _singleEpisodeSearchCriteria);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.FindByTitle(It.IsAny<string>()), Times.Never());

View File

@ -80,7 +80,7 @@ private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, bo
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
{
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, report.Title, report.TvdbId, report.TvRageId, searchCriteria);
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, report.Title, report.TvdbId, report.TvRageId, report.ImdbId, searchCriteria);
if (specialEpisodeInfo != null)
{
@ -90,7 +90,7 @@ private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, bo
if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
{
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, searchCriteria);
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, report.ImdbId, searchCriteria);
remoteEpisode.Release = report;
if (remoteEpisode.Series == null)

View File

@ -119,7 +119,7 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do
if (parsedEpisodeInfo != null)
{
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0, null);
_aggregationService.Augment(trackedDownload.RemoteEpisode);
}
@ -147,7 +147,7 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do
// Try parsing the original source title and if that fails, try parsing it as a special
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ??
_parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0);
_parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0, null);
if (parsedEpisodeInfo != null)
{
@ -234,7 +234,7 @@ private void UpdateCachedItem(TrackedDownload trackedDownload)
{
var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title);
trackedDownload.RemoteEpisode = parsedEpisodeInfo == null ? null : _parsingService.Map(parsedEpisodeInfo, 0, 0);
trackedDownload.RemoteEpisode = parsedEpisodeInfo == null ? null : _parsingService.Map(parsedEpisodeInfo, 0, 0, null);
_aggregationService.Augment(trackedDownload.RemoteEpisode);
}

View File

@ -165,6 +165,7 @@ public void Handle(EpisodeGrabbedEvent message)
history.Data.Add("Guid", message.Episode.Release.Guid);
history.Data.Add("TvdbId", message.Episode.Release.TvdbId.ToString());
history.Data.Add("TvRageId", message.Episode.Release.TvRageId.ToString());
history.Data.Add("ImdbId", message.Episode.Release.ImdbId);
history.Data.Add("Protocol", ((int)message.Episode.Release.DownloadProtocol).ToString());
history.Data.Add("CustomFormatScore", message.Episode.CustomFormatScore.ToString());
history.Data.Add("SeriesMatchType", message.Episode.SeriesMatchType.ToString());

View File

@ -95,6 +95,11 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
torrentInfo.TvRageId = torrent.TvrageID.Value;
}
if (torrent.ImdbID.IsNotNullOrWhiteSpace() && int.TryParse(torrent.ImdbID, out var imdbId) && imdbId > 0)
{
torrentInfo.ImdbId = $"tt{imdbId:D7}";
}
results.Add(torrentInfo);
}

View File

@ -38,7 +38,7 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var id = result.Id;
torrentInfos.Add(new TorrentInfo
var torrentInfo = new TorrentInfo
{
Guid = $"FileList-{id}",
Title = result.Name,
@ -48,9 +48,15 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
Seeders = result.Seeders,
Peers = result.Leechers + result.Seeders,
PublishDate = result.UploadDate.ToUniversalTime(),
ImdbId = result.ImdbId,
IndexerFlags = GetIndexerFlags(result)
});
};
if (result.ImdbId is { Length: > 2 } && int.TryParse(result.ImdbId.TrimStart('t'), out var imdbId) && imdbId > 0)
{
torrentInfo.ImdbId = $"tt{imdbId:D7}";
}
torrentInfos.Add(torrentInfo);
}
return torrentInfos.ToArray();

View File

@ -90,6 +90,7 @@ protected override ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInf
releaseInfo.TvdbId = GetTvdbId(item);
releaseInfo.TvRageId = GetTvRageId(item);
releaseInfo.ImdbId = GetImdbId(item);
return releaseInfo;
}
@ -182,6 +183,18 @@ protected virtual int GetTvRageId(XElement item)
return 0;
}
protected virtual string GetImdbId(XElement item)
{
var imdbIdString = TryGetNewznabAttribute(item, "imdb");
if (!imdbIdString.IsNullOrWhiteSpace() && int.TryParse(imdbIdString, out var imdbId) && imdbId > 0)
{
return $"tt{imdbId:D7}";
}
return null;
}
protected string TryGetNewznabAttribute(XElement item, string key, string defaultValue = "")
{
var attrElement = item.Elements(ns + "attr").FirstOrDefault(e => e.Attribute("name").Value.Equals(key, StringComparison.OrdinalIgnoreCase));

View File

@ -83,6 +83,7 @@ protected override ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInf
{
torrentInfo.TvdbId = GetTvdbId(item);
torrentInfo.TvRageId = GetTvRageId(item);
releaseInfo.ImdbId = GetImdbId(item);
torrentInfo.IndexerFlags = GetFlags(item);
}
@ -177,6 +178,18 @@ protected virtual int GetTvRageId(XElement item)
return 0;
}
protected virtual string GetImdbId(XElement item)
{
var imdbIdString = TryGetTorznabAttribute(item, "imdb");
if (!imdbIdString.IsNullOrWhiteSpace() && int.TryParse(imdbIdString, out var imdbId) && imdbId > 0)
{
return $"tt{imdbId:D7}";
}
return null;
}
protected override string GetInfoHash(XElement item)
{
return TryGetTorznabAttribute(item, "infohash");

View File

@ -33,12 +33,12 @@ public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem down
if (fileInfo != null && fileInfo.IsPossibleSceneSeasonSpecial)
{
fileInfo = _parsingService.ParseSpecialEpisodeTitle(fileInfo, fileInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0);
fileInfo = _parsingService.ParseSpecialEpisodeTitle(fileInfo, fileInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0, null);
}
if (folderInfo != null && folderInfo.IsPossibleSceneSeasonSpecial)
{
folderInfo = _parsingService.ParseSpecialEpisodeTitle(folderInfo, folderInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0);
folderInfo = _parsingService.ParseSpecialEpisodeTitle(folderInfo, folderInfo.ReleaseTitle, localEpisode.Series.TvdbId, 0, null);
}
if (folderInfo == null)

View File

@ -103,6 +103,7 @@ public virtual string ToString(string format)
stringBuilder.AppendLine("DownloadProtocol: " + DownloadProtocol ?? "Empty");
stringBuilder.AppendLine("TvdbId: " + TvdbId ?? "Empty");
stringBuilder.AppendLine("TvRageId: " + TvRageId ?? "Empty");
stringBuilder.AppendLine("ImdbId: " + ImdbId ?? "Empty");
stringBuilder.AppendLine("PublishDate: " + PublishDate ?? "Empty");
return stringBuilder.ToString();
default:

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
@ -13,11 +14,11 @@ namespace NzbDrone.Core.Parser
public interface IParsingService
{
Series GetSeries(string title);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, string imdbId, SearchCriteriaBase searchCriteria = null);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, Series series);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, string imdbId, SearchCriteriaBase searchCriteria = null);
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, Series series);
}
@ -115,14 +116,14 @@ private Series GetSeriesByAllTitles(ParsedEpisodeInfo parsedEpisodeInfo)
return foundSeries;
}
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, string imdbId, SearchCriteriaBase searchCriteria = null)
{
return Map(parsedEpisodeInfo, tvdbId, tvRageId, null, searchCriteria);
return Map(parsedEpisodeInfo, tvdbId, tvRageId, imdbId, null, searchCriteria);
}
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, Series series)
{
return Map(parsedEpisodeInfo, 0, 0, series, null);
return Map(parsedEpisodeInfo, 0, 0, null, series, null);
}
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds)
@ -135,7 +136,7 @@ public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnu
};
}
private RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, Series series, SearchCriteriaBase searchCriteria)
private RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, string imdbId, Series series, SearchCriteriaBase searchCriteria)
{
var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);
@ -171,7 +172,7 @@ private RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int t
if (series == null)
{
var seriesMatch = FindSeries(parsedEpisodeInfo, tvdbId, tvRageId, sceneMapping, searchCriteria);
var seriesMatch = FindSeries(parsedEpisodeInfo, tvdbId, tvRageId, imdbId, sceneMapping, searchCriteria);
if (seriesMatch != null)
{
@ -210,7 +211,7 @@ public List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series ser
{
if (sceneSource)
{
var remoteEpisode = Map(parsedEpisodeInfo, 0, 0, series, searchCriteria);
var remoteEpisode = Map(parsedEpisodeInfo, 0, 0, null, series, searchCriteria);
return remoteEpisode.Episodes;
}
@ -272,7 +273,7 @@ private List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series se
return GetStandardEpisodes(series, parsedEpisodeInfo, mappedSeasonNumber, sceneSource, searchCriteria);
}
public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, string imdbId, SearchCriteriaBase searchCriteria = null)
{
if (searchCriteria != null)
{
@ -285,6 +286,11 @@ public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisod
{
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, searchCriteria.Series);
}
if (imdbId.IsNotNullOrWhiteSpace() && imdbId.Equals(searchCriteria.Series.ImdbId, StringComparison.Ordinal))
{
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, searchCriteria.Series);
}
}
var series = GetSeries(releaseTitle);
@ -304,6 +310,11 @@ public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisod
series = _seriesService.FindByTvRageId(tvRageId);
}
if (series == null && imdbId.IsNotNullOrWhiteSpace())
{
series = _seriesService.FindByImdbId(imdbId);
}
if (series == null)
{
_logger.Debug("No matching series {0}", releaseTitle);
@ -354,7 +365,7 @@ public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisod
return null;
}
private FindSeriesResult FindSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SceneMapping sceneMapping, SearchCriteriaBase searchCriteria)
private FindSeriesResult FindSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, string imdbId, SceneMapping sceneMapping, SearchCriteriaBase searchCriteria)
{
Series series = null;
@ -406,6 +417,18 @@ private FindSeriesResult FindSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvd
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Id);
}
if (imdbId.IsNotNullOrWhiteSpace() && imdbId.Equals(searchCriteria.Series.ImdbId, StringComparison.Ordinal) && tvdbId <= 0)
{
_logger.Debug()
.Message("Found matching series by IMDb ID {0}, an alias may be needed for: {1}", imdbId, parsedEpisodeInfo.SeriesTitle)
.Property("ImdbId", imdbId)
.Property("ParsedEpisodeInfo", parsedEpisodeInfo)
.WriteSentryWarn("ImdbIdMatch", imdbId, parsedEpisodeInfo.SeriesTitle)
.Write();
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Id);
}
}
var matchType = SeriesMatchType.Unknown;
@ -462,6 +485,23 @@ private FindSeriesResult FindSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvd
}
}
if (series == null && imdbId.IsNotNullOrWhiteSpace() && tvdbId <= 0)
{
series = _seriesService.FindByImdbId(imdbId);
if (series != null)
{
_logger.Debug()
.Message("Found matching series by IMDb ID {0}, an alias may be needed for: {1}", imdbId, parsedEpisodeInfo.SeriesTitle)
.Property("ImdbId", imdbId)
.Property("ParsedEpisodeInfo", parsedEpisodeInfo)
.WriteSentryWarn("ImdbIdMatch", imdbId, parsedEpisodeInfo.SeriesTitle)
.Write();
matchType = SeriesMatchType.Id;
}
}
if (series == null)
{
_logger.Debug("No matching series {0}", parsedEpisodeInfo.SeriesTitle);

View File

@ -14,6 +14,7 @@ public interface ISeriesRepository : IBasicRepository<Series>
List<Series> FindByTitleInexact(string cleanTitle);
Series FindByTvdbId(int tvdbId);
Series FindByTvRageId(int tvRageId);
Series FindByImdbId(string imdbId);
Series FindByPath(string path);
List<int> AllSeriesTvdbIds();
Dictionary<int, string> AllSeriesPaths();
@ -73,6 +74,11 @@ public Series FindByTvRageId(int tvRageId)
return Query(s => s.TvRageId == tvRageId).SingleOrDefault();
}
public Series FindByImdbId(string imdbId)
{
return Query(s => s.ImdbId == imdbId).SingleOrDefault();
}
public Series FindByPath(string path)
{
return Query(s => s.Path == path)

View File

@ -17,6 +17,7 @@ public interface ISeriesService
List<Series> AddSeries(List<Series> newSeries);
Series FindByTvdbId(int tvdbId);
Series FindByTvRageId(int tvRageId);
Series FindByImdbId(string imdbId);
Series FindByTitle(string title);
Series FindByTitle(string title, int year);
Series FindByTitleInexact(string title);
@ -94,6 +95,11 @@ public Series FindByTvRageId(int tvRageId)
return _seriesRepository.FindByTvRageId(tvRageId);
}
public Series FindByImdbId(string imdbId)
{
return _seriesRepository.FindByImdbId(imdbId);
}
public Series FindByTitle(string title)
{
return _seriesRepository.FindByTitle(title.CleanSeriesTitle());

View File

@ -48,6 +48,7 @@ public class ReleaseResource : RestResource
public bool Rejected { get; set; }
public int TvdbId { get; set; }
public int TvRageId { get; set; }
public string ImdbId { get; set; }
public IEnumerable<string> Rejections { get; set; }
public DateTime PublishDate { get; set; }
public string CommentUrl { get; set; }
@ -136,6 +137,7 @@ public static ReleaseResource ToResource(this DownloadDecision model)
Rejected = model.Rejected,
TvdbId = releaseInfo.TvdbId,
TvRageId = releaseInfo.TvRageId,
ImdbId = releaseInfo.ImdbId,
Rejections = model.Rejections.Select(r => r.Reason).ToList(),
PublishDate = releaseInfo.PublishDate,
CommentUrl = releaseInfo.CommentUrl,
@ -194,6 +196,7 @@ public static ReleaseInfo ToModel(this ReleaseResource resource)
model.DownloadProtocol = resource.Protocol;
model.TvdbId = resource.TvdbId;
model.TvRageId = resource.TvRageId;
model.ImdbId = resource.ImdbId;
model.PublishDate = resource.PublishDate.ToUniversalTime();
return model;

View File

@ -45,7 +45,7 @@ public ParseResource Parse(string title, string path)
};
}
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0, null);
if (remoteEpisode != null)
{