From 4f6380a73cd14c7e68367f1b5e2e3d27f1d8fdc1 Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Tue, 3 Jan 2017 11:59:03 +0100 Subject: [PATCH] Automatically downloading the best movie release works now. --- .../Migration/054_rename_profiles.cs | 5 +- .../Download/CompletedDownloadService.cs | 21 ++- .../Download/Pending/PendingRelease.cs | 2 + .../Download/Pending/PendingReleaseService.cs | 2 +- .../Download/ProcessDownloadDecisions.cs | 131 +++++++++++++----- .../IndexerSearch/MoviesSearchCommand.cs | 11 ++ .../IndexerSearch/MoviesSearchService.cs | 46 ++++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 2 + src/NzbDrone.Core/Parser/ParsingService.cs | 23 ++- src/UI/Commands/CommandController.js | 2 +- src/UI/Movies/Details/MoviesDetailsLayout.js | 5 +- 11 files changed, 204 insertions(+), 46 deletions(-) create mode 100644 src/NzbDrone.Core/IndexerSearch/MoviesSearchCommand.cs create mode 100644 src/NzbDrone.Core/IndexerSearch/MoviesSearchService.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs b/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs index e665c14a4..5535a1bd9 100644 --- a/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs +++ b/src/NzbDrone.Core/Datastore/Migration/054_rename_profiles.cs @@ -21,11 +21,12 @@ protected override void MainDbUpgrade() //Add HeldReleases Create.TableForModel("PendingReleases") - .WithColumn("SeriesId").AsInt32() + .WithColumn("SeriesId").AsInt32().WithDefaultValue(0) .WithColumn("Title").AsString() .WithColumn("Added").AsDateTime() .WithColumn("ParsedEpisodeInfo").AsString() - .WithColumn("Release").AsString(); + .WithColumn("Release").AsString() + .WithColumn("MovieId").AsInt32().WithDefaultValue(0); } } } diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index c4fbe11a2..024a41c8b 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -28,6 +28,7 @@ public class CompletedDownloadService : ICompletedDownloadService private readonly IHistoryService _historyService; private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IParsingService _parsingService; + private readonly IMovieService _movieService; private readonly Logger _logger; private readonly ISeriesService _seriesService; @@ -37,6 +38,7 @@ public CompletedDownloadService(IConfigService configService, IDownloadedEpisodesImportService downloadedEpisodesImportService, IParsingService parsingService, ISeriesService seriesService, + IMovieService movieService, Logger logger) { _configService = configService; @@ -44,6 +46,7 @@ public CompletedDownloadService(IConfigService configService, _historyService = historyService; _downloadedEpisodesImportService = downloadedEpisodesImportService; _parsingService = parsingService; + _movieService = movieService; _logger = logger; _seriesService = seriesService; } @@ -88,19 +91,31 @@ public void Process(TrackedDownload trackedDownload, bool ignoreWarnings = false return; } + var series = _parsingService.GetSeries(trackedDownload.DownloadItem.Title); if (series == null) { if (historyItem != null) { - series = _seriesService.GetSeries(historyItem.SeriesId); + //series = _seriesService.GetSeries(historyItem.SeriesId); } if (series == null) { - trackedDownload.Warn("Series title mismatch, automatic import is not possible."); - return; + var movie = _parsingService.GetMovie(trackedDownload.DownloadItem.Title); + + if (movie == null) + { + movie = _movieService.GetMovie(historyItem.MovieId); + + if (movie == null) + { + trackedDownload.Warn("Movie title mismatch, automatic import is not possible."); + } + } + //trackedDownload.Warn("Series title mismatch, automatic import is not possible."); + //return; } } } diff --git a/src/NzbDrone.Core/Download/Pending/PendingRelease.cs b/src/NzbDrone.Core/Download/Pending/PendingRelease.cs index a713fe48c..504db7e36 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingRelease.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingRelease.cs @@ -7,6 +7,7 @@ namespace NzbDrone.Core.Download.Pending public class PendingRelease : ModelBase { public int SeriesId { get; set; } + public int MovieId { get; set; } public string Title { get; set; } public DateTime Added { get; set; } public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } @@ -14,5 +15,6 @@ public class PendingRelease : ModelBase //Not persisted public RemoteEpisode RemoteEpisode { get; set; } + public RemoteMovie RemoteMovie { get; set; } } } diff --git a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs index d5fbff7d8..5a53e2d18 100644 --- a/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs +++ b/src/NzbDrone.Core/Download/Pending/PendingReleaseService.cs @@ -344,7 +344,7 @@ public void Handle(EpisodeGrabbedEvent message) public void Handle(MovieGrabbedEvent message) { - + //RemoveGrabbed(message.Movie); } public void Handle(RssSyncCompleteEvent message) diff --git a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs index 05719587d..adadebdee 100644 --- a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs +++ b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs @@ -32,53 +32,112 @@ public ProcessDownloadDecisions(IDownloadService downloadService, public ProcessedDecisions ProcessDecisions(List decisions) { - var qualifiedReports = GetQualifiedReports(decisions); - var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(qualifiedReports); + //var qualifiedReports = GetQualifiedReports(decisions); + var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions); var grabbed = new List(); var pending = new List(); foreach (var report in prioritizedDecisions) { - var remoteEpisode = report.RemoteEpisode; - var episodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList(); - - //Skip if already grabbed - if (grabbed.SelectMany(r => r.RemoteEpisode.Episodes) - .Select(e => e.Id) - .ToList() - .Intersect(episodeIds) - .Any()) + if (report.IsForMovie) { - continue; + var remoteMovie = report.RemoteMovie; + + if (report.TemporarilyRejected) + { + _pendingReleaseService.Add(report); + pending.Add(report); + continue; + } + + if (remoteMovie == null || remoteMovie.Movie == null) + { + continue; + } + + List movieIds = new List { remoteMovie.Movie.Id }; + + + //Skip if already grabbed + if (grabbed.Select(r => r.RemoteMovie.Movie) + .Select(e => e.Id) + .ToList() + .Intersect(movieIds) + .Any()) + { + continue; + } + + if (pending.Select(r => r.RemoteMovie.Movie) + .Select(e => e.Id) + .ToList() + .Intersect(movieIds) + .Any()) + { + continue; + } + + try + { + _downloadService.DownloadReport(remoteMovie); + grabbed.Add(report); + } + catch (Exception e) + { + //TODO: support for store & forward + //We'll need to differentiate between a download client error and an indexer error + _logger.Warn(e, "Couldn't add report to download queue. " + remoteMovie); + } } + else + { + var remoteEpisode = report.RemoteEpisode; - if (report.TemporarilyRejected) - { - _pendingReleaseService.Add(report); - pending.Add(report); - continue; - } + if (remoteEpisode == null || remoteEpisode.Episodes == null) + { + continue; + } - if (pending.SelectMany(r => r.RemoteEpisode.Episodes) - .Select(e => e.Id) - .ToList() - .Intersect(episodeIds) - .Any()) - { - continue; - } + var episodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList(); - try - { - _downloadService.DownloadReport(remoteEpisode); - grabbed.Add(report); - } - catch (Exception e) - { - //TODO: support for store & forward - //We'll need to differentiate between a download client error and an indexer error - _logger.Warn(e, "Couldn't add report to download queue. " + remoteEpisode); + //Skip if already grabbed + if (grabbed.SelectMany(r => r.RemoteEpisode.Episodes) + .Select(e => e.Id) + .ToList() + .Intersect(episodeIds) + .Any()) + { + continue; + } + + if (report.TemporarilyRejected) + { + _pendingReleaseService.Add(report); + pending.Add(report); + continue; + } + + if (pending.SelectMany(r => r.RemoteEpisode.Episodes) + .Select(e => e.Id) + .ToList() + .Intersect(episodeIds) + .Any()) + { + continue; + } + + try + { + _downloadService.DownloadReport(remoteEpisode); + grabbed.Add(report); + } + catch (Exception e) + { + //TODO: support for store & forward + //We'll need to differentiate between a download client error and an indexer error + _logger.Warn(e, "Couldn't add report to download queue. " + remoteEpisode); + } } } diff --git a/src/NzbDrone.Core/IndexerSearch/MoviesSearchCommand.cs b/src/NzbDrone.Core/IndexerSearch/MoviesSearchCommand.cs new file mode 100644 index 000000000..da0b9a8c1 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/MoviesSearchCommand.cs @@ -0,0 +1,11 @@ +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.IndexerSearch +{ + public class MoviesSearchCommand : Command + { + public int MovieId { get; set; } + + public override bool SendUpdatesToClient => true; + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/IndexerSearch/MoviesSearchService.cs b/src/NzbDrone.Core/IndexerSearch/MoviesSearchService.cs new file mode 100644 index 000000000..656423178 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/MoviesSearchService.cs @@ -0,0 +1,46 @@ +using System.Linq; +using NLog; +using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Download; +using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.IndexerSearch +{ + public class MovieSearchService : IExecute + { + private readonly IMovieService _seriesService; + private readonly ISearchForNzb _nzbSearchService; + private readonly IProcessDownloadDecisions _processDownloadDecisions; + private readonly Logger _logger; + + public MovieSearchService(IMovieService seriesService, + ISearchForNzb nzbSearchService, + IProcessDownloadDecisions processDownloadDecisions, + Logger logger) + { + _seriesService = seriesService; + _nzbSearchService = nzbSearchService; + _processDownloadDecisions = processDownloadDecisions; + _logger = logger; + } + + public void Execute(MoviesSearchCommand message) + { + var series = _seriesService.GetMovie(message.MovieId); + + var downloadedCount = 0; + + if (!series.Monitored) + { + _logger.Debug("Movie {0} is not monitored, skipping search", series.Title); + } + + var decisions = _nzbSearchService.MovieSearch(message.MovieId, false);//_nzbSearchService.SeasonSearch(message.MovieId, season.SeasonNumber, false, message.Trigger == CommandTrigger.Manual); + downloadedCount += _processDownloadDecisions.ProcessDecisions(decisions).Grabbed.Count; + + + _logger.ProgressInfo("Movie search completed. {0} reports downloaded.", downloadedCount); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 4bc218fe3..9dd64feb2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -564,6 +564,8 @@ + + diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 937c9cf94..cc9ca8447 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -16,6 +16,7 @@ public interface IParsingService LocalEpisode GetLocalEpisode(string filename, Series series); LocalEpisode GetLocalEpisode(string filename, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource); Series GetSeries(string title); + Movie GetMovie(string title); RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null); RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable episodeIds); RemoteMovie Map(ParsedEpisodeInfo parsedEpisodeInfo, string imdbId, SearchCriteriaBase searchCriteria = null); @@ -104,7 +105,7 @@ public Series GetSeries(string title) if (parsedEpisodeInfo == null) { - return _seriesService.FindByTitle(title); //Here we have a problem since it is not possible for movies to find a scene mapping, so these releases are always rejected :( + return _seriesService.FindByTitle(title); } var series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle); @@ -118,6 +119,26 @@ public Series GetSeries(string title) return series; } + public Movie GetMovie(string title) + { + var parsedEpisodeInfo = Parser.ParseTitle(title); + + if (parsedEpisodeInfo == null) + { + return _movieService.FindByTitle(title); + } + + var series = _movieService.FindByTitle(parsedEpisodeInfo.SeriesTitle); + + if (series == null) + { + series = _movieService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, + parsedEpisodeInfo.SeriesTitleInfo.Year); + } + + return series; + } + public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null) { var remoteEpisode = new RemoteEpisode diff --git a/src/UI/Commands/CommandController.js b/src/UI/Commands/CommandController.js index 2232d45ae..929870107 100644 --- a/src/UI/Commands/CommandController.js +++ b/src/UI/Commands/CommandController.js @@ -86,7 +86,7 @@ var singleton = function() { } } }); - + console.warn(options) options.element.startSpin(); } }; diff --git a/src/UI/Movies/Details/MoviesDetailsLayout.js b/src/UI/Movies/Details/MoviesDetailsLayout.js index 6dd34e360..4396c22de 100644 --- a/src/UI/Movies/Details/MoviesDetailsLayout.js +++ b/src/UI/Movies/Details/MoviesDetailsLayout.js @@ -32,7 +32,7 @@ module.exports = Marionette.Layout.extend({ edit : '.x-edit', refresh : '.x-refresh', rename : '.x-rename', - search : '.x-search', + searchAuto : '.x-search', poster : '.x-movie-poster', manualSearch : '.x-manual-search', history : '.x-movie-history', @@ -86,8 +86,9 @@ module.exports = Marionette.Layout.extend({ name : 'refreshMovie' } }); + CommandController.bindToCommand({ - element : this.ui.search, + element : this.ui.searchAuto, command : { name : 'moviesSearch' }