diff --git a/src/NzbDrone.Core/IndexerSearch/EpisodeSearchGroup.cs b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchGroup.cs new file mode 100644 index 000000000..cb0e8c53b --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchGroup.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.IndexerSearch +{ + public class EpisodeSearchGroup + { + public int SeriesId { get; set; } + public int SeasonNumber { get; set; } + public List Episodes { get; set; } + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs index 73a54186a..13883ed0b 100644 --- a/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation.Extensions; @@ -40,48 +39,65 @@ namespace NzbDrone.Core.IndexerSearch _logger = logger; } - private void SearchForEpisodes(List episodes, bool monitoredOnly, bool userInvokedSearch) + private void SearchForBulkEpisodes(List episodes, bool monitoredOnly, bool userInvokedSearch) { _logger.ProgressInfo("Performing search for {0} episodes", episodes.Count); var downloadedCount = 0; + var groups = new List(); foreach (var series in episodes.GroupBy(e => e.SeriesId)) { foreach (var season in series.Select(e => e).GroupBy(e => e.SeasonNumber)) { - List decisions; - - if (season.Count() > 1) + groups.Add(new EpisodeSearchGroup { - try - { - decisions = _releaseSearchService.SeasonSearch(series.Key, season.Key, season.ToList(), monitoredOnly, userInvokedSearch, false); - } - catch (Exception ex) - { - _logger.Error(ex, "Unable to search for episodes in season {0} of [{1}]", season.Key, series.Key); - continue; - } - } - else - { - try - { - decisions = _releaseSearchService.EpisodeSearch(season.First(), userInvokedSearch, false); - } - catch (Exception ex) - { - _logger.Error(ex, "Unable to search for episode: [{0}]", season.First()); - continue; - } - } - - var processed = _processDownloadDecisions.ProcessDecisions(decisions); - - downloadedCount += processed.Grabbed.Count; + SeriesId = series.Key, + SeasonNumber = season.Key, + Episodes = season.ToList() + }); } } + foreach (var group in groups.OrderBy(g => g.Episodes.Min(e => e.LastSearchTime ?? DateTime.MinValue))) + { + List decisions; + + var seriesId = group.SeriesId; + var seasonNumber = group.SeasonNumber; + var groupEpisodes = group.Episodes; + + if (groupEpisodes.Count > 1) + { + try + { + decisions = _releaseSearchService.SeasonSearch(seriesId, seasonNumber, groupEpisodes, monitoredOnly, userInvokedSearch, false); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to search for episodes in season {0} of [{1}]", seasonNumber, seriesId); + continue; + } + } + else + { + var episode = groupEpisodes.First(); + + try + { + decisions = _releaseSearchService.EpisodeSearch(episode, userInvokedSearch, false); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to search for episode: [{0}]", episode); + continue; + } + } + + var processed = _processDownloadDecisions.ProcessDecisions(decisions); + + downloadedCount += processed.Grabbed.Count; + } + _logger.ProgressInfo("Completed search for {0} episodes. {1} reports downloaded.", episodes.Count, downloadedCount); } @@ -120,7 +136,7 @@ namespace NzbDrone.Core.IndexerSearch var pagingSpec = new PagingSpec { Page = 1, - PageSize = 100000, + PageSize = 1000000, SortDirection = SortDirection.Ascending, SortKey = "Id" }; @@ -140,7 +156,7 @@ namespace NzbDrone.Core.IndexerSearch var queue = _queueService.GetQueue().Where(q => q.Episode != null).Select(q => q.Episode.Id); var missing = episodes.Where(e => !queue.Contains(e.Id)).ToList(); - SearchForEpisodes(missing, monitored, message.Trigger == CommandTrigger.Manual); + SearchForBulkEpisodes(missing, monitored, message.Trigger == CommandTrigger.Manual); } public void Execute(CutoffUnmetEpisodeSearchCommand message) @@ -174,7 +190,7 @@ namespace NzbDrone.Core.IndexerSearch var queue = _queueService.GetQueue().Where(q => q.Episode != null).Select(q => q.Episode.Id); var cutoffUnmet = episodes.Where(e => !queue.Contains(e.Id)).ToList(); - SearchForEpisodes(cutoffUnmet, monitored, message.Trigger == CommandTrigger.Manual); + SearchForBulkEpisodes(cutoffUnmet, monitored, message.Trigger == CommandTrigger.Manual); } } } diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index b511c6141..7ed143f15 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -540,7 +540,7 @@ namespace NzbDrone.Core.IndexerSearch _logger.Debug("Setting last search time to: {0}", lastSearchTime); criteriaBase.Episodes.ForEach(e => e.LastSearchTime = lastSearchTime); - _episodeService.UpdateEpisodes(criteriaBase.Episodes); + _episodeService.UpdateLastSearchTime(criteriaBase.Episodes); } return _makeDownloadDecision.GetSearchDecision(reports, criteriaBase).ToList(); diff --git a/src/NzbDrone.Core/Tv/EpisodeService.cs b/src/NzbDrone.Core/Tv/EpisodeService.cs index 255fa6255..241037799 100644 --- a/src/NzbDrone.Core/Tv/EpisodeService.cs +++ b/src/NzbDrone.Core/Tv/EpisodeService.cs @@ -31,6 +31,7 @@ namespace NzbDrone.Core.Tv void SetEpisodeMonitored(int episodeId, bool monitored); void SetMonitored(IEnumerable ids, bool monitored); void UpdateEpisodes(List episodes); + void UpdateLastSearchTime(List episodes); List EpisodesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored); void InsertMany(List episodes); void UpdateMany(List episodes); @@ -187,6 +188,11 @@ namespace NzbDrone.Core.Tv _episodeRepository.UpdateMany(episodes); } + public void UpdateLastSearchTime(List episodes) + { + _episodeRepository.SetFields(episodes, e => e.LastSearchTime); + } + public List EpisodesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored) { var episodes = _episodeRepository.EpisodesBetweenDates(start.ToUniversalTime(), end.ToUniversalTime(), includeUnmonitored);