diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/DownloadDecisionMakerFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/DownloadDecisionMakerFixture.cs index ad49ae791..a7d57ab7a 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/DownloadDecisionMakerFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/DownloadDecisionMakerFixture.cs @@ -19,7 +19,7 @@ public class DownloadDecisionMakerFixture : CoreTest { private List _reports; private RemoteMovie _remoteEpisode; - private MappingResult _mappingResult; + private FindMovieResult _mappingResult; private Mock _pass1; private Mock _pass2; @@ -57,11 +57,10 @@ public void Setup() ParsedMovieInfo = new ParsedMovieInfo() }; - _mappingResult = new MappingResult { Movie = new Movie(), MappingResultType = MappingResultType.Success }; - _mappingResult.RemoteMovie = _remoteEpisode; + _mappingResult = new FindMovieResult(new Movie(), MovieMatchType.Title); Mocker.GetMock() - .Setup(c => c.Map(It.IsAny(), It.IsAny(), It.IsAny())).Returns(_mappingResult); + .Setup(c => c.Map(It.IsAny(), It.IsAny(), It.IsAny())).Returns(_remoteEpisode); } private void GivenSpecifications(params Mock[] mocks) @@ -128,7 +127,6 @@ public void should_not_attempt_to_map_episode_if_not_parsable() { GivenSpecifications(_pass1, _pass2, _pass3); _reports[0].Title = "Not parsable"; - _mappingResult.MappingResultType = MappingResultType.NotParsable; Subject.GetRssDecision(_reports).ToList(); @@ -144,7 +142,6 @@ public void should_not_attempt_to_map_episode_if_series_title_is_blank() { GivenSpecifications(_pass1, _pass2, _pass3); _reports[0].Title = "1937 - Snow White and the Seven Dwarves"; - _mappingResult.MappingResultType = MappingResultType.NotParsable; var results = Subject.GetRssDecision(_reports).ToList(); @@ -162,7 +159,6 @@ public void should_return_rejected_result_for_unparsable_search() { GivenSpecifications(_pass1, _pass2, _pass3); _reports[0].Title = "1937 - Snow White and the Seven Dwarves"; - _mappingResult.MappingResultType = MappingResultType.NotParsable; Subject.GetSearchDecision(_reports, new MovieSearchCriteria()).ToList(); @@ -179,7 +175,6 @@ public void should_not_attempt_to_make_decision_if_series_is_unknown() GivenSpecifications(_pass1, _pass2, _pass3); _remoteEpisode.Movie = null; - _mappingResult.MappingResultType = MappingResultType.TitleNotFound; Subject.GetRssDecision(_reports); @@ -228,7 +223,6 @@ public void should_not_allow_download_if_series_is_unknown() GivenSpecifications(_pass1, _pass2, _pass3); _remoteEpisode.Movie = null; - _mappingResult.MappingResultType = MappingResultType.TitleNotFound; var result = Subject.GetRssDecision(_reports); diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs index da738a7c8..63dcc449c 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs @@ -33,7 +33,7 @@ public void SetupBase() Mocker.GetMock() .Setup(s => s.Map(It.IsAny(), It.IsAny(), (SearchCriteriaBase)null)) - .Returns(() => new MappingResult { RemoteMovie = CreateRemoteMovie(), MappingResultType = MappingResultType.Success }); + .Returns(() => CreateRemoteMovie()); Mocker.GetMock() .Setup(s => s.Get(It.IsAny())) diff --git a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs index 3c1ec3fc9..4bf161c96 100644 --- a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs @@ -43,7 +43,7 @@ public void should_track_downloads_using_the_source_title_if_it_cannot_be_found_ { GivenDownloadHistory(); - var remoteEpisode = new RemoteMovie + var remoteMovie = new RemoteMovie { Movie = new Movie() { Id = 3 }, @@ -56,7 +56,7 @@ public void should_track_downloads_using_the_source_title_if_it_cannot_be_found_ Mocker.GetMock() .Setup(s => s.Map(It.Is(i => i.PrimaryMovieTitle == "A Movie"), It.IsAny(), null)) - .Returns(new MappingResult { RemoteMovie = remoteEpisode }); + .Returns(remoteMovie); ParseMovieTitle(); @@ -104,7 +104,7 @@ public void should_unmap_tracked_download_if_movie_deleted() Mocker.GetMock() .Setup(s => s.Map(It.IsAny(), It.IsAny(), null)) - .Returns(new MappingResult { RemoteMovie = remoteMovie }); + .Returns(remoteMovie); Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) @@ -136,7 +136,7 @@ public void should_unmap_tracked_download_if_movie_deleted() Mocker.GetMock() .Setup(s => s.Map(It.IsAny(), It.IsAny(), null)) - .Returns(new MappingResult { MappingResultType = MappingResultType.Unknown }); + .Returns(default(RemoteMovie)); Subject.Handle(new MoviesDeletedEvent(new List { remoteMovie.Movie }, false, false)); @@ -163,7 +163,7 @@ public void should_not_throw_when_processing_deleted_movie() Mocker.GetMock() .Setup(s => s.Map(It.IsAny(), It.IsAny(), null)) - .Returns(new MappingResult { MappingResultType = MappingResultType.Unknown }); + .Returns(default(RemoteMovie)); Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) @@ -195,7 +195,7 @@ public void should_not_throw_when_processing_deleted_movie() Mocker.GetMock() .Setup(s => s.Map(It.IsAny(), It.IsAny(), null)) - .Returns(new MappingResult { MappingResultType = MappingResultType.Unknown }); + .Returns(default(RemoteMovie)); Subject.Handle(new MoviesDeletedEvent(new List { remoteMovie.Movie }, false, false)); diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs index 080e33959..06c901040 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs @@ -146,30 +146,6 @@ public void should_use_search_criteria_movie_title() .Verify(v => v.FindByTitle(It.IsAny()), Times.Never()); } - [Test] - public void should_not_match_with_wrong_year() - { - GivenMatchByMovieTitle(); - Subject.Map(_wrongYearInfo, "", _movieSearchCriteria).MappingResultType.Should().Be(MappingResultType.WrongYear); - } - - [Test] - public void should_not_match_wrong_title() - { - GivenMatchByMovieTitle(); - Subject.Map(_wrongTitleInfo, "", _movieSearchCriteria).MappingResultType.Should().Be(MappingResultType.WrongTitle); - } - - [Test] - public void should_return_title_not_found_when_all_is_null() - { - Mocker.GetMock() - .Setup(s => s.FindByTitle(It.IsAny())) - .Returns((Movie)null); - Subject.Map(_parsedMovieInfo, "", null).MappingResultType.Should() - .Be(MappingResultType.TitleNotFound); - } - [Test] public void should_match_alternative_title() { diff --git a/src/NzbDrone.Core/Datastore/Migration/218_add_additional_info_to_pending_releases.cs b/src/NzbDrone.Core/Datastore/Migration/218_add_additional_info_to_pending_releases.cs new file mode 100644 index 000000000..0b3ca3414 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/218_add_additional_info_to_pending_releases.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(218)] + public class add_additional_info_to_pending_releases : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("PendingReleases").AddColumn("AdditionalInfo").AsString().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index b6287c09a..004092f49 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -197,6 +197,7 @@ private static void RegisterMappers() SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter(new QualityIntConverter(), new LanguageIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); + SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter>()); diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs index c7b48c407..c8055aae0 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs @@ -10,10 +10,8 @@ using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Download.Aggregation; using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Languages; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Qualities; namespace NzbDrone.Core.DecisionEngine { @@ -80,51 +78,50 @@ private IEnumerable GetDecisions(List reports, Se { var parsedMovieInfo = _parsingService.ParseMovieInfo(report.Title, new List { report }); - MappingResult result = null; - - if (parsedMovieInfo == null || parsedMovieInfo.PrimaryMovieTitle.IsNullOrWhiteSpace()) + if (parsedMovieInfo != null && !parsedMovieInfo.PrimaryMovieTitle.IsNullOrWhiteSpace()) { - _logger.Debug("{0} could not be parsed :(.", report.Title); - parsedMovieInfo = new ParsedMovieInfo - { - MovieTitles = new List() { report.Title }, - SimpleReleaseTitle = report.Title.SimplifyReleaseTitle(), - Year = 1290, - Languages = new List { Language.Unknown }, - Quality = new QualityModel(), - }; + var remoteMovie = _parsingService.Map(parsedMovieInfo, report.ImdbId.ToString(), searchCriteria); + remoteMovie.Release = report; - if (result == null) + if (remoteMovie.Movie == null) { - result = new MappingResult { MappingResultType = MappingResultType.NotParsable }; - result.Movie = null; // To ensure we have a remote movie, else null exception on next line! - result.RemoteMovie.ParsedMovieInfo = parsedMovieInfo; + var reason = "Unknown Movie"; + + decision = new DownloadDecision(remoteMovie, new Rejection(reason)); + } + else + { + _aggregationService.Augment(remoteMovie); + + remoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(remoteMovie, remoteMovie.Release.Size); + remoteMovie.CustomFormatScore = remoteMovie?.Movie?.Profile?.CalculateCustomFormatScore(remoteMovie.CustomFormats) ?? 0; + + remoteMovie.DownloadAllowed = remoteMovie.Movie != null; + decision = GetDecisionForReport(remoteMovie, searchCriteria); } } - else + + if (searchCriteria != null) { - result = _parsingService.Map(parsedMovieInfo, report.ImdbId.ToString(), searchCriteria); - } + if (parsedMovieInfo == null) + { + parsedMovieInfo = new ParsedMovieInfo + { + Languages = LanguageParser.ParseLanguages(report.Title), + Quality = QualityParser.ParseQuality(report.Title) + }; + } - result.ReleaseName = report.Title; - var remoteMovie = result.RemoteMovie; - remoteMovie.Release = report; - remoteMovie.MappingResult = result.MappingResultType; + if (parsedMovieInfo.PrimaryMovieTitle.IsNullOrWhiteSpace()) + { + var remoteMovie = new RemoteMovie + { + Release = report, + ParsedMovieInfo = parsedMovieInfo, + }; - _aggregationService.Augment(remoteMovie); - - if (result.MappingResultType != MappingResultType.Success) - { - var rejection = result.ToRejection(); - decision = new DownloadDecision(remoteMovie, rejection); - } - else - { - remoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(remoteMovie, remoteMovie.Release.Size); - remoteMovie.CustomFormatScore = remoteMovie?.Movie?.Profile?.CalculateCustomFormatScore(remoteMovie.CustomFormats) ?? 0; - - remoteMovie.DownloadAllowed = remoteMovie.Movie != null; - decision = GetDecisionForReport(remoteMovie, searchCriteria); + decision = new DownloadDecision(remoteMovie, new Rejection("Unable to parse release")); + } } } catch (Exception e) diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs index 7ca42a7a5..772f8e681 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionPriorizationService.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Parser; using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Qualities; @@ -27,13 +26,13 @@ public DownloadDecisionPriorizationService(IConfigService configService, IDelayP public List PrioritizeDecisionsForMovies(List decisions) { - return decisions.Where(c => c.RemoteMovie.MappingResult == MappingResultType.Success) + return decisions.Where(c => c.RemoteMovie.Movie != null) .GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) => { return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_configService, _delayProfileService, _qualityDefinitionService)); }) .SelectMany(c => c) - .Union(decisions.Where(c => c.RemoteMovie.MappingResult != MappingResultType.Success)) + .Union(decisions.Where(c => c.RemoteMovie.Movie == null)) .ToList(); } } diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index 4adc31972..c026d957b 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -13,6 +14,7 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Movies; using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download { @@ -92,13 +94,17 @@ public void Check(TrackedDownload trackedDownload) if (movie == null) { - trackedDownload.Warn("Movie title mismatch, automatic import is not possible."); + trackedDownload.Warn("Movie title mismatch, Manual Import required."); return; } - trackedDownload.Warn("Found matching movie via grab history, but release title doesn't match movie title. Automatic import is not possible."); + Enum.TryParse(historyItem.Data.GetValueOrDefault(MovieHistory.MOVIE_MATCH_TYPE, MovieMatchType.Unknown.ToString()), out MovieMatchType movieMatchType); - return; + if (movieMatchType == MovieMatchType.Id) + { + trackedDownload.Warn("Found matching movie via grab history, but release was matched to movie by ID. Manual Import required."); + return; + } } trackedDownload.State = TrackedDownloadState.ImportPending; diff --git a/src/NzbDrone.Core/Download/Pending/PendingRelease.cs b/src/NzbDrone.Core/Download/Pending/PendingRelease.cs index da86e76b7..032558130 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingRelease.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingRelease.cs @@ -12,8 +12,14 @@ public class PendingRelease : ModelBase public ParsedMovieInfo ParsedMovieInfo { get; set; } public ReleaseInfo Release { get; set; } public PendingReleaseReason Reason { get; set; } + public PendingReleaseAdditionalInfo AdditionalInfo { get; set; } // Not persisted public RemoteMovie RemoteMovie { get; set; } } + + public class PendingReleaseAdditionalInfo + { + public MovieMatchType MovieMatchType { get; set; } + } } diff --git a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs index 80e0a3313..9c05fce98 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs @@ -293,6 +293,7 @@ private List IncludeRemoteMovies(List releases, release.RemoteMovie = new RemoteMovie { Movie = movie, + MovieMatchType = release.AdditionalInfo?.MovieMatchType ?? MovieMatchType.Unknown, ParsedMovieInfo = release.ParsedMovieInfo, Release = release.Release }; @@ -315,7 +316,11 @@ private void Insert(DownloadDecision decision, PendingReleaseReason reason) Release = decision.RemoteMovie.Release, Title = decision.RemoteMovie.Release.Title, Added = DateTime.UtcNow, - Reason = reason + Reason = reason, + AdditionalInfo = new PendingReleaseAdditionalInfo + { + MovieMatchType = decision.RemoteMovie.MovieMatchType + } }; if (release.ParsedMovieInfo == null) diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs index 243f77f1b..15ee14cc0 100644 --- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs +++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs @@ -121,7 +121,7 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do if (parsedMovieInfo != null) { - trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null).RemoteMovie; + trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null); _aggregationService.Augment(trackedDownload.RemoteMovie); } @@ -149,7 +149,7 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do if (parsedMovieInfo != null) { - trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null).RemoteMovie; + trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null); } } } @@ -197,7 +197,7 @@ private void UpdateCachedItem(TrackedDownload trackedDownload) { var parsedMovieInfo = Parser.Parser.ParseMovieTitle(trackedDownload.DownloadItem.Title); - trackedDownload.RemoteMovie = parsedMovieInfo == null ? null : _parsingService.Map(parsedMovieInfo, "", null).RemoteMovie; + trackedDownload.RemoteMovie = parsedMovieInfo == null ? null : _parsingService.Map(parsedMovieInfo, "", null); _aggregationService.Augment(trackedDownload.RemoteMovie); } diff --git a/src/NzbDrone.Core/History/History.cs b/src/NzbDrone.Core/History/History.cs index 3d5c37539..5426582ae 100644 --- a/src/NzbDrone.Core/History/History.cs +++ b/src/NzbDrone.Core/History/History.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.History public class MovieHistory : ModelBase { public const string DOWNLOAD_CLIENT = "downloadClient"; + public const string MOVIE_MATCH_TYPE = "movieMatchType"; public MovieHistory() { diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 8c25c7826..c31d37f56 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -153,6 +153,7 @@ public void Handle(MovieGrabbedEvent message) history.Data.Add("TmdbId", message.Movie.Release.TmdbId.ToString()); history.Data.Add("Protocol", ((int)message.Movie.Release.DownloadProtocol).ToString()); history.Data.Add("CustomFormatScore", message.Movie.CustomFormatScore.ToString()); + history.Data.Add("MovieMatchType", message.Movie.MovieMatchType.ToString()); history.Data.Add("IndexerFlags", message.Movie.Release.IndexerFlags.ToString()); history.Data.Add("IndexerId", message.Movie.Release.IndexerId.ToString()); diff --git a/src/NzbDrone.Core/Parser/Model/FindMovieResult.cs b/src/NzbDrone.Core/Parser/Model/FindMovieResult.cs new file mode 100644 index 000000000..f551d79d5 --- /dev/null +++ b/src/NzbDrone.Core/Parser/Model/FindMovieResult.cs @@ -0,0 +1,24 @@ +using NzbDrone.Core.Movies; + +namespace NzbDrone.Core.Parser.Model +{ + public class FindMovieResult + { + public Movie Movie { get; set; } + public MovieMatchType MatchType { get; set; } + + public FindMovieResult(Movie movie, MovieMatchType matchType) + { + Movie = movie; + MatchType = matchType; + } + } + + public enum MovieMatchType + { + Unknown = 0, + Title = 1, + Alias = 2, + Id = 3 + } +} diff --git a/src/NzbDrone.Core/Parser/Model/RemoteMovie.cs b/src/NzbDrone.Core/Parser/Model/RemoteMovie.cs index 58ba9d647..5ef4c8e8d 100644 --- a/src/NzbDrone.Core/Parser/Model/RemoteMovie.cs +++ b/src/NzbDrone.Core/Parser/Model/RemoteMovie.cs @@ -12,8 +12,8 @@ public class RemoteMovie public ParsedMovieInfo ParsedMovieInfo { get; set; } public List CustomFormats { get; set; } public int CustomFormatScore { get; set; } + public MovieMatchType MovieMatchType { get; set; } public Movie Movie { get; set; } - public MappingResultType MappingResult { get; set; } public bool DownloadAllowed { get; set; } public TorrentSeedConfiguration SeedConfiguration { get; set; } public List Languages { get; set; } diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 021719121..4daec475e 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Parser public interface IParsingService { Movie GetMovie(string title); - MappingResult Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null); + RemoteMovie Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null); ParsedMovieInfo ParseMovieInfo(string title, List helpers); ParsedMovieInfo ParseMinimalMovieInfo(string path, bool isDir = false); ParsedMovieInfo ParseMinimalPathMovieInfo(string path); @@ -85,7 +85,7 @@ public Movie GetMovie(string title) return _movieService.FindByTitle(title); } - if (TryGetMovieByTitleAndOrYear(parsedMovieInfo, out var result) && result.MappingResultType == MappingResultType.Success) + if (TryGetMovieByTitleAndOrYear(parsedMovieInfo, out var result)) { return result.Movie; } @@ -93,24 +93,42 @@ public Movie GetMovie(string title) return null; } - public MappingResult Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null) + public RemoteMovie Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null) { - var result = GetMovie(parsedMovieInfo, imdbId, searchCriteria); - - if (result == null) - { - result = new MappingResult { MappingResultType = MappingResultType.Unknown }; - result.Movie = null; - } - - result.RemoteMovie.ParsedMovieInfo = parsedMovieInfo; - - return result; + return Map(parsedMovieInfo, imdbId, null, searchCriteria); } - private MappingResult GetMovie(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria) + public RemoteMovie Map(ParsedMovieInfo parsedMovieInfo, string imdbId, Movie movie, SearchCriteriaBase searchCriteria) { - MappingResult result = null; + var remoteMovie = new RemoteMovie + { + ParsedMovieInfo = parsedMovieInfo + }; + + if (movie == null) + { + var movieMatch = FindMovie(parsedMovieInfo, imdbId, searchCriteria); + + if (movieMatch != null) + { + movie = movieMatch.Movie; + remoteMovie.MovieMatchType = movieMatch.MatchType; + } + } + + if (movie != null) + { + remoteMovie.Movie = movie; + } + + remoteMovie.Languages = parsedMovieInfo.Languages; + + return remoteMovie; + } + + private FindMovieResult FindMovie(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria) + { + FindMovieResult result = null; if (!string.IsNullOrWhiteSpace(imdbId) && imdbId != "0") { @@ -140,30 +158,30 @@ private MappingResult GetMovie(ParsedMovieInfo parsedMovieInfo, string imdbId, S return result; } - private bool TryGetMovieByImDbId(ParsedMovieInfo parsedMovieInfo, string imdbId, out MappingResult result) + private bool TryGetMovieByImDbId(ParsedMovieInfo parsedMovieInfo, string imdbId, out FindMovieResult result) { var movie = _movieService.FindByImdbId(imdbId); // Should fix practically all problems, where indexer is shite at adding correct imdbids to movies. if (movie != null && parsedMovieInfo.Year > 1800 && (parsedMovieInfo.Year != movie.MovieMetadata.Value.Year && movie.MovieMetadata.Value.SecondaryYear != parsedMovieInfo.Year)) { - result = new MappingResult { Movie = movie, MappingResultType = MappingResultType.WrongYear }; + result = new FindMovieResult(movie, MovieMatchType.Id); return false; } if (movie != null) { - result = new MappingResult { Movie = movie }; + result = new FindMovieResult(movie, MovieMatchType.Id); } else { - result = new MappingResult { Movie = movie, MappingResultType = MappingResultType.TitleNotFound }; + result = new FindMovieResult(movie, MovieMatchType.Unknown); } return movie != null; } - private bool TryGetMovieByTitleAndOrYear(ParsedMovieInfo parsedMovieInfo, out MappingResult result) + private bool TryGetMovieByTitleAndOrYear(ParsedMovieInfo parsedMovieInfo, out FindMovieResult result) { var candidates = _movieService.FindByTitleCandidates(parsedMovieInfo.MovieTitles, out var otherTitles); @@ -173,7 +191,7 @@ private bool TryGetMovieByTitleAndOrYear(ParsedMovieInfo parsedMovieInfo, out Ma movieByTitleAndOrYear = _movieService.FindByTitle(parsedMovieInfo.MovieTitles, parsedMovieInfo.Year, otherTitles, candidates); if (movieByTitleAndOrYear != null) { - result = new MappingResult { Movie = movieByTitleAndOrYear }; + result = new FindMovieResult(movieByTitleAndOrYear, MovieMatchType.Title); return true; } @@ -183,27 +201,27 @@ private bool TryGetMovieByTitleAndOrYear(ParsedMovieInfo parsedMovieInfo, out Ma movieByTitleAndOrYear = _movieService.FindByTitle(parsedMovieInfo.MovieTitles, null, otherTitles, candidates); if (movieByTitleAndOrYear != null) { - result = new MappingResult { Movie = movieByTitleAndOrYear, MappingResultType = MappingResultType.WrongYear }; + result = new FindMovieResult(movieByTitleAndOrYear, MovieMatchType.Title); return false; } } - result = new MappingResult { Movie = movieByTitleAndOrYear, MappingResultType = MappingResultType.TitleNotFound }; + result = new FindMovieResult(movieByTitleAndOrYear, MovieMatchType.Unknown); return false; } movieByTitleAndOrYear = _movieService.FindByTitle(parsedMovieInfo.MovieTitles, null, otherTitles, candidates); if (movieByTitleAndOrYear != null) { - result = new MappingResult { Movie = movieByTitleAndOrYear }; + result = new FindMovieResult(movieByTitleAndOrYear, MovieMatchType.Title); return true; } - result = new MappingResult { Movie = movieByTitleAndOrYear, MappingResultType = MappingResultType.TitleNotFound }; + result = new FindMovieResult(movieByTitleAndOrYear, MovieMatchType.Unknown); return false; } - private bool TryGetMovieBySearchCriteria(ParsedMovieInfo parsedMovieInfo, SearchCriteriaBase searchCriteria, out MappingResult result) + private bool TryGetMovieBySearchCriteria(ParsedMovieInfo parsedMovieInfo, SearchCriteriaBase searchCriteria, out FindMovieResult result) { Movie possibleMovie = null; @@ -228,98 +246,17 @@ private bool TryGetMovieBySearchCriteria(ParsedMovieInfo parsedMovieInfo, Search { if (parsedMovieInfo.Year < 1800 || possibleMovie.MovieMetadata.Value.Year == parsedMovieInfo.Year || possibleMovie.MovieMetadata.Value.SecondaryYear == parsedMovieInfo.Year) { - result = new MappingResult { Movie = possibleMovie, MappingResultType = MappingResultType.Success }; + result = new FindMovieResult(possibleMovie, MovieMatchType.Title); return true; } - result = new MappingResult { Movie = possibleMovie, MappingResultType = MappingResultType.WrongYear }; + result = new FindMovieResult(possibleMovie, MovieMatchType.Title); return false; } - result = new MappingResult { Movie = searchCriteria.Movie, MappingResultType = MappingResultType.WrongTitle }; + result = new FindMovieResult(searchCriteria.Movie, MovieMatchType.Unknown); return false; } } - - public class MappingResult - { - public string Message - { - get - { - switch (MappingResultType) - { - case MappingResultType.Success: - return $"Successfully mapped release name {ReleaseName} to movie {Movie}"; - case MappingResultType.NotParsable: - return $"Failed to find movie title and/or year in release name {ReleaseName}"; - case MappingResultType.TitleNotFound: - return $"Could not find {RemoteMovie.ParsedMovieInfo.PrimaryMovieTitle}"; - case MappingResultType.WrongYear: - var movieYears = new HashSet { RemoteMovie.Movie.MovieMetadata.Value.Year, RemoteMovie.Movie.MovieMetadata.Value.SecondaryYear.GetValueOrDefault() }; - - return $"Failed to map movie, expected year {string.Join(", ", movieYears.Where(x => x > 0))}, but found {RemoteMovie.ParsedMovieInfo.Year}"; - case MappingResultType.WrongTitle: - var comma = RemoteMovie.Movie.MovieMetadata.Value.AlternativeTitles.Count > 0 ? ", " : ""; - return - $"Failed to map movie, found title(s) {string.Join(", ", RemoteMovie.ParsedMovieInfo.MovieTitles)}, expected one of: {RemoteMovie.Movie.MovieMetadata.Value.Title}{comma}{string.Join(", ", RemoteMovie.Movie.MovieMetadata.Value.AlternativeTitles)}"; - default: - return $"Failed to map movie for unknown reasons"; - } - } - } - - public RemoteMovie RemoteMovie; - public MappingResultType MappingResultType { get; set; } - public Movie Movie - { - get - { - return RemoteMovie.Movie; - } - set - { - ParsedMovieInfo parsedInfo = null; - if (RemoteMovie != null) - { - parsedInfo = RemoteMovie.ParsedMovieInfo; - } - - RemoteMovie = new RemoteMovie - { - Movie = value, - ParsedMovieInfo = parsedInfo - }; - } - } - - public string ReleaseName { get; set; } - - public override string ToString() - { - return string.Format(Message, RemoteMovie.Movie); - } - - public Rejection ToRejection() - { - switch (MappingResultType) - { - case MappingResultType.Success: - return null; - default: - return new Rejection(Message); - } - } - } - - public enum MappingResultType - { - Unknown = -1, - Success = 0, - WrongYear = 2, - WrongTitle = 3, - TitleNotFound = 4, - NotParsable = 5, - } } diff --git a/src/Radarr.Api.V3/Parse/ParseController.cs b/src/Radarr.Api.V3/Parse/ParseController.cs index bc9444c7e..cb983023d 100644 --- a/src/Radarr.Api.V3/Parse/ParseController.cs +++ b/src/Radarr.Api.V3/Parse/ParseController.cs @@ -45,14 +45,14 @@ public ParseResource Parse(string title) var remoteMovie = _parsingService.Map(parsedMovieInfo, ""); - _aggregationService.Augment(remoteMovie.RemoteMovie); + _aggregationService.Augment(remoteMovie); if (remoteMovie != null) { return new ParseResource { Title = title, - ParsedMovieInfo = remoteMovie.RemoteMovie.ParsedMovieInfo, + ParsedMovieInfo = remoteMovie.ParsedMovieInfo, Movie = remoteMovie.Movie.ToResource(_configService.AvailabilityDelay) }; }