From 192e79d2ff59f2b3dda88718209cb0dfaec4daab Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 12 Apr 2014 13:49:41 -0700 Subject: [PATCH] New: Automatic search for missing episodes if RSS Sync hasn't been run recently --- .../IndexerSearch/EpisodeSearchService.cs | 35 +++++++++++++++---- src/NzbDrone.Core/Indexers/RssSyncService.cs | 15 ++++++-- src/NzbDrone.Core/Jobs/Scheduler.cs | 2 +- .../Messaging/Commands/Command.cs | 1 + .../Messaging/Commands/CommandExecutor.cs | 7 ++++ .../Messaging/Commands/ICommandExecutor.cs | 3 ++ 6 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs index 0a33c001e..049677f78 100644 --- a/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs @@ -11,7 +11,12 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Core.IndexerSearch { - public class MissingEpisodeSearchService : IExecute, IExecute + public interface IEpisodeSearchService + { + void MissingEpisodesAiredAfter(DateTime dateTime); + } + + public class MissingEpisodeSearchService : IEpisodeSearchService, IExecute, IExecute { private readonly ISearchForNzb _nzbSearchService; private readonly IDownloadApprovedReports _downloadApprovedReports; @@ -32,6 +37,26 @@ namespace NzbDrone.Core.IndexerSearch _logger = logger; } + public void MissingEpisodesAiredAfter(DateTime dateTime) + { + var missing = _episodeService.EpisodesBetweenDates(dateTime, DateTime.UtcNow) + .Where(e => !e.HasFile && + !_queueService.GetQueue().Select(q => q.Episode.Id).Contains(e.Id)) + .ToList(); + + var downloadedCount = 0; + _logger.Info("Searching for {0} missing episodes since last RSS Sync", missing.Count); + + foreach (var episode in missing) + { + var decisions = _nzbSearchService.EpisodeSearch(episode); + var downloaded = _downloadApprovedReports.DownloadApproved(decisions); + downloadedCount += downloaded.Count; + } + + _logger.ProgressInfo("Completed search for {0} episodes. {1} reports downloaded.", missing.Count, downloadedCount); + } + public void Execute(EpisodeSearchCommand message) { foreach (var episodeId in message.EpisodeIds) @@ -57,9 +82,9 @@ namespace NzbDrone.Core.IndexerSearch FilterExpression = v => v.Monitored == true && v.Series.Monitored == true }).Records.ToList(); - var missing = episodes.Where(e => !_queueService.GetQueue().Select(q => q.Episode.Id).Contains(e.Id)); + var missing = episodes.Where(e => !_queueService.GetQueue().Select(q => q.Episode.Id).Contains(e.Id)).ToList(); - _logger.ProgressInfo("Performing missing search for {0} episodes", episodes.Count); + _logger.ProgressInfo("Performing missing search for {0} episodes", missing.Count); var downloadedCount = 0; //Limit requests to indexers at 100 per minute @@ -71,12 +96,10 @@ namespace NzbDrone.Core.IndexerSearch var decisions = _nzbSearchService.EpisodeSearch(episode); var downloaded = _downloadApprovedReports.DownloadApproved(decisions); downloadedCount += downloaded.Count; - - _logger.ProgressInfo("Episode search completed. {0} reports downloaded.", downloaded.Count); } } - _logger.ProgressInfo("Completed missing search for {0} episodes. {1} reports downloaded.", episodes.Count, downloadedCount); + _logger.ProgressInfo("Completed missing search for {0} episodes. {1} reports downloaded.", missing.Count, downloadedCount); } } } diff --git a/src/NzbDrone.Core/Indexers/RssSyncService.cs b/src/NzbDrone.Core/Indexers/RssSyncService.cs index 8958d8e76..07b26bfff 100644 --- a/src/NzbDrone.Core/Indexers/RssSyncService.cs +++ b/src/NzbDrone.Core/Indexers/RssSyncService.cs @@ -1,7 +1,9 @@ -using System.Linq; +using System; +using System.Linq; using NLog; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download; +using NzbDrone.Core.IndexerSearch; using NzbDrone.Core.Instrumentation.Extensions; using NzbDrone.Core.Messaging.Commands; @@ -17,16 +19,19 @@ namespace NzbDrone.Core.Indexers private readonly IFetchAndParseRss _rssFetcherAndParser; private readonly IMakeDownloadDecision _downloadDecisionMaker; private readonly IDownloadApprovedReports _downloadApprovedReports; + private readonly IEpisodeSearchService _episodeSearchService; private readonly Logger _logger; public RssSyncService(IFetchAndParseRss rssFetcherAndParser, IMakeDownloadDecision downloadDecisionMaker, IDownloadApprovedReports downloadApprovedReports, + IEpisodeSearchService episodeSearchService, Logger logger) { _rssFetcherAndParser = rssFetcherAndParser; _downloadDecisionMaker = downloadDecisionMaker; _downloadApprovedReports = downloadApprovedReports; + _episodeSearchService = episodeSearchService; _logger = logger; } @@ -45,6 +50,12 @@ namespace NzbDrone.Core.Indexers public void Execute(RssSyncCommand message) { Sync(); + + if (message.LastExecutionTime.HasValue && DateTime.UtcNow.Subtract(message.LastExecutionTime.Value).TotalHours > 3) + { + _logger.Info("RSS Sync hasn't run since: {0}. Searching for any missing episodes since then.", message.LastExecutionTime.Value); + _episodeSearchService.MissingEpisodesAiredAfter(message.LastExecutionTime.Value.AddDays(-1)); + } } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Jobs/Scheduler.cs b/src/NzbDrone.Core/Jobs/Scheduler.cs index 869b5b10a..42c1acef6 100644 --- a/src/NzbDrone.Core/Jobs/Scheduler.cs +++ b/src/NzbDrone.Core/Jobs/Scheduler.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Jobs try { - _commandExecutor.PublishCommand(task.TypeName); + _commandExecutor.PublishCommand(task.TypeName, task.LastExecution); } catch (Exception e) { diff --git a/src/NzbDrone.Core/Messaging/Commands/Command.cs b/src/NzbDrone.Core/Messaging/Commands/Command.cs index 516464381..9c8b64b30 100644 --- a/src/NzbDrone.Core/Messaging/Commands/Command.cs +++ b/src/NzbDrone.Core/Messaging/Commands/Command.cs @@ -35,6 +35,7 @@ namespace NzbDrone.Core.Messaging.Commands public string Message { get; private set; } public string Name { get; private set; } + public DateTime? LastExecutionTime { get; set; } protected Command() { diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs index 7ccdad4d7..52534d5a5 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs @@ -49,8 +49,15 @@ namespace NzbDrone.Core.Messaging.Commands } public void PublishCommand(string commandTypeName) + { + PublishCommand(commandTypeName, null); + } + + public void PublishCommand(string commandTypeName, DateTime? lastExecutionTime) { dynamic command = GetCommand(commandTypeName); + command.LastExecutionTime = lastExecutionTime; + PublishCommand(command); } diff --git a/src/NzbDrone.Core/Messaging/Commands/ICommandExecutor.cs b/src/NzbDrone.Core/Messaging/Commands/ICommandExecutor.cs index 45d300fcd..d456f6511 100644 --- a/src/NzbDrone.Core/Messaging/Commands/ICommandExecutor.cs +++ b/src/NzbDrone.Core/Messaging/Commands/ICommandExecutor.cs @@ -1,9 +1,12 @@ +using System; + namespace NzbDrone.Core.Messaging.Commands { public interface ICommandExecutor { void PublishCommand(TCommand command) where TCommand : Command; void PublishCommand(string commandTypeName); + void PublishCommand(string commandTypeName, DateTime? lastEecutionTime); Command PublishCommandAsync(TCommand command) where TCommand : Command; Command PublishCommandAsync(string commandTypeName); }