diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index edec79135..05876a0fe 100644
--- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -231,6 +231,7 @@
+
diff --git a/src/NzbDrone.Core.Test/TvTests/ShouldRefreshSeriesFixture.cs b/src/NzbDrone.Core.Test/TvTests/ShouldRefreshSeriesFixture.cs
new file mode 100644
index 000000000..14d5f6d68
--- /dev/null
+++ b/src/NzbDrone.Core.Test/TvTests/ShouldRefreshSeriesFixture.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FizzWare.NBuilder;
+using FluentAssertions;
+using NUnit.Framework;
+using NzbDrone.Core.Tv;
+using NzbDrone.Test.Common;
+
+namespace NzbDrone.Core.Test.TvTests
+{
+ [TestFixture]
+ public class ShouldRefreshSeriesFixture : TestBase
+ {
+ private Series _series;
+
+ [SetUp]
+ public void Setup()
+ {
+ _series = Builder.CreateNew()
+ .Build();
+ }
+
+ private void GivenSeriesIsEnded()
+ {
+ _series.Status = SeriesStatusType.Ended;
+ }
+
+ private void GivenSeriesLastRefreshedRecently()
+ {
+ _series.LastInfoSync = DateTime.UtcNow.AddDays(-1);
+ }
+
+ [Test]
+ public void should_return_true_if_series_is_continuing()
+ {
+ _series.Status = SeriesStatusType.Continuing;
+
+ Subject.ShouldRefresh(_series).Should().BeTrue();
+ }
+
+ [Test]
+ public void should_return_true_if_series_last_refreshed_more_than_30_days_ago()
+ {
+ GivenSeriesIsEnded();
+ _series.LastInfoSync = DateTime.UtcNow.AddDays(-100);
+
+ Subject.ShouldRefresh(_series).Should().BeTrue();
+ }
+
+ [Test]
+ public void should_should_return_true_if_episode_aired_in_last_30_days()
+ {
+ Mocker.GetMock()
+ .Setup(s => s.GetEpisodeBySeries(_series.Id))
+ .Returns(Builder.CreateListOfSize(2)
+ .TheFirst(1)
+ .With(e => e.AirDateUtc = DateTime.Today.AddDays(-7))
+ .TheLast(1)
+ .With(e => e.AirDateUtc = DateTime.Today.AddDays(-100))
+ .Build()
+ .ToList());
+
+ Subject.ShouldRefresh(_series).Should().BeTrue();
+ }
+
+ [Test]
+ public void should_should_return_false_when_recently_refreshed_ended_show_has_not_aired_for_30_days()
+ {
+ Mocker.GetMock()
+ .Setup(s => s.GetEpisodeBySeries(_series.Id))
+ .Returns(Builder.CreateListOfSize(2)
+ .All()
+ .With(e => e.AirDateUtc = DateTime.Today.AddDays(-100))
+ .Build()
+ .ToList());
+
+ Subject.ShouldRefresh(_series).Should().BeTrue();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/MediaFiles/Commands/RescanSeriesCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/RescanSeriesCommand.cs
index 81ee0951f..4ff2450b0 100644
--- a/src/NzbDrone.Core/MediaFiles/Commands/RescanSeriesCommand.cs
+++ b/src/NzbDrone.Core/MediaFiles/Commands/RescanSeriesCommand.cs
@@ -13,5 +13,14 @@ public override bool SendUpdatesToClient
return true;
}
}
+
+ public RescanSeriesCommand()
+ {
+ }
+
+ public RescanSeriesCommand(int seriesId)
+ {
+ SeriesId = seriesId;
+ }
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj
index 3bf7c995c..ca9b25f0d 100644
--- a/src/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/src/NzbDrone.Core/NzbDrone.Core.csproj
@@ -670,6 +670,7 @@
+
diff --git a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs
index b9c9a56cf..b7b455048 100644
--- a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs
+++ b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs
@@ -5,6 +5,7 @@
using NLog;
using NzbDrone.Core.DataAugmentation.DailySeries;
using NzbDrone.Core.Instrumentation.Extensions;
+using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MetadataSource;
@@ -21,15 +22,26 @@ public class RefreshSeriesService : IExecute, IHandleAsync
private readonly IRefreshEpisodeService _refreshEpisodeService;
private readonly IEventAggregator _eventAggregator;
private readonly IDailySeriesService _dailySeriesService;
+ private readonly ICommandExecutor _commandExecutor;
+ private readonly ICheckIfSeriesShouldBeRefreshed _checkIfSeriesShouldBeRefreshed;
private readonly Logger _logger;
- public RefreshSeriesService(IProvideSeriesInfo seriesInfo, ISeriesService seriesService, IRefreshEpisodeService refreshEpisodeService, IEventAggregator eventAggregator, IDailySeriesService dailySeriesService, Logger logger)
+ public RefreshSeriesService(IProvideSeriesInfo seriesInfo,
+ ISeriesService seriesService,
+ IRefreshEpisodeService refreshEpisodeService,
+ IEventAggregator eventAggregator,
+ IDailySeriesService dailySeriesService,
+ ICommandExecutor commandExecutor,
+ ICheckIfSeriesShouldBeRefreshed checkIfSeriesShouldBeRefreshed,
+ Logger logger)
{
_seriesInfo = seriesInfo;
_seriesService = seriesService;
_refreshEpisodeService = refreshEpisodeService;
_eventAggregator = eventAggregator;
_dailySeriesService = dailySeriesService;
+ _commandExecutor = commandExecutor;
+ _checkIfSeriesShouldBeRefreshed = checkIfSeriesShouldBeRefreshed;
_logger = logger;
}
@@ -116,13 +128,29 @@ public void Execute(RefreshSeriesCommand message)
foreach (var series in allSeries)
{
- try
+ if (_checkIfSeriesShouldBeRefreshed.ShouldRefresh(series))
{
- RefreshSeriesInfo(series);
+ try
+ {
+ RefreshSeriesInfo(series);
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Couldn't refresh info for {0}".Inject(series), e);
+ }
}
- catch (Exception e)
+
+ else
{
- _logger.ErrorException("Couldn't refresh info for {0}".Inject(series), e);
+ try
+ {
+ _logger.Info("Skipping refresh of series: {0}", series.Title);
+ _commandExecutor.PublishCommand(new RescanSeriesCommand(series.Id));
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Couldn't rescan series {0}".Inject(series), e);
+ }
}
}
}
diff --git a/src/NzbDrone.Core/Tv/ShouldRefreshSeries.cs b/src/NzbDrone.Core/Tv/ShouldRefreshSeries.cs
new file mode 100644
index 000000000..a052935b4
--- /dev/null
+++ b/src/NzbDrone.Core/Tv/ShouldRefreshSeries.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Linq;
+using NLog;
+
+namespace NzbDrone.Core.Tv
+{
+ public interface ICheckIfSeriesShouldBeRefreshed
+ {
+ bool ShouldRefresh(Series series);
+ }
+
+ public class ShouldRefreshSeries : ICheckIfSeriesShouldBeRefreshed
+ {
+ private readonly IEpisodeService _episodeService;
+ private readonly Logger _logger;
+
+ public ShouldRefreshSeries(IEpisodeService episodeService, Logger logger)
+ {
+ _episodeService = episodeService;
+ _logger = logger;
+ }
+
+ public bool ShouldRefresh(Series series)
+ {
+ if (series.Status == SeriesStatusType.Continuing)
+ {
+ _logger.Trace("Series {0} is continuing, should refresh.", series.Title);
+ return true;
+ }
+
+ if (series.LastInfoSync < DateTime.UtcNow.AddDays(-30))
+ {
+ _logger.Trace("Series {0} last updated more than 30 days ago, should refresh.", series.Title);
+ return true;
+ }
+
+ var lastEpisode = _episodeService.GetEpisodeBySeries(series.Id).OrderByDescending(e => e.AirDateUtc).FirstOrDefault();
+
+ if (lastEpisode != null && lastEpisode.AirDateUtc > DateTime.UtcNow.AddDays(-30))
+ {
+ _logger.Trace("Last episode in {0} aired less than 30 days ago, should refresh.", series.Title);
+ return true;
+ }
+
+ _logger.Trace("Series {0} should not be refreshed.", series.Title);
+ return false;
+ }
+ }
+}