diff --git a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs index 592b56dc3..2f58f7c90 100644 --- a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs @@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Core.MetadataSource.SkyHook; using NzbDrone.Core.Tv; using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.TvTests { @@ -77,12 +78,14 @@ namespace NzbDrone.Core.Test.TvTests { Mocker.GetMock().Setup(c => c.GetEpisodeBySeries(It.IsAny())) .Returns(new List()); - + Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes()); _insertedEpisodes.Should().HaveSameCount(GetEpisodes()); _updatedEpisodes.Should().BeEmpty(); _deletedEpisodes.Should().BeEmpty(); + + ExceptionVerification.ExpectedWarns(1); } [Test] @@ -146,6 +149,63 @@ namespace NzbDrone.Core.Test.TvTests _updatedEpisodes.Should().OnlyContain(e => e.Monitored == true); } + [Test] + public void should_not_set_monitored_status_for_old_episodes_to_false_if_recent_enough() + { + var series = GetSeries(); + series.Seasons = new List(); + series.Seasons.Add(new Season { SeasonNumber = 1, Monitored = true }); + + var episodes = GetEpisodes().OrderBy(v => v.SeasonNumber).ThenBy(v => v.EpisodeNumber).Take(5).ToList(); + + episodes[1].AirDateUtc = DateTime.UtcNow.AddDays(-15); + episodes[2].AirDateUtc = DateTime.UtcNow.AddDays(-10); + episodes[3].AirDateUtc = DateTime.UtcNow.AddDays(1); + + var existingEpisodes = episodes.Skip(4).ToList(); + + Mocker.GetMock().Setup(c => c.GetEpisodeBySeries(It.IsAny())) + .Returns(existingEpisodes); + + Subject.RefreshEpisodeInfo(series, episodes); + + _insertedEpisodes = _insertedEpisodes.OrderBy(v => v.EpisodeNumber).ToList(); + + _insertedEpisodes.Should().HaveCount(4); + _insertedEpisodes[0].Monitored.Should().Be(true); + _insertedEpisodes[1].Monitored.Should().Be(true); + _insertedEpisodes[2].Monitored.Should().Be(true); + _insertedEpisodes[3].Monitored.Should().Be(true); + } + + [Test] + public void should_set_monitored_status_for_old_episodes_to_false_if_no_episodes_existed() + { + var series = GetSeries(); + series.Seasons = new List(); + + var episodes = GetEpisodes().OrderBy(v => v.SeasonNumber).ThenBy(v => v.EpisodeNumber).Take(4).ToList(); + + episodes[1].AirDateUtc = DateTime.UtcNow.AddDays(-15); + episodes[2].AirDateUtc = DateTime.UtcNow.AddDays(-10); + episodes[3].AirDateUtc = DateTime.UtcNow.AddDays(1); + + Mocker.GetMock().Setup(c => c.GetEpisodeBySeries(It.IsAny())) + .Returns(new List()); + + Subject.RefreshEpisodeInfo(series, episodes); + + _insertedEpisodes = _insertedEpisodes.OrderBy(v => v.EpisodeNumber).ToList(); + + _insertedEpisodes.Should().HaveSameCount(episodes); + _insertedEpisodes[0].Monitored.Should().Be(false); + _insertedEpisodes[1].Monitored.Should().Be(false); + _insertedEpisodes[2].Monitored.Should().Be(false); + _insertedEpisodes[3].Monitored.Should().Be(true); + + ExceptionVerification.ExpectedWarns(1); + } + [Test] public void should_remove_duplicate_remote_episodes_before_processing() { diff --git a/src/NzbDrone.Core/Tv/EpisodeAddedService.cs b/src/NzbDrone.Core/Tv/EpisodeAddedService.cs index 54e3d2991..049a18963 100644 --- a/src/NzbDrone.Core/Tv/EpisodeAddedService.cs +++ b/src/NzbDrone.Core/Tv/EpisodeAddedService.cs @@ -73,7 +73,9 @@ namespace NzbDrone.Core.Tv return; } - var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue && a.AirDateUtc.Value.Before(DateTime.UtcNow.AddDays(1)) && a.Monitored).ToList(); + var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue + && a.AirDateUtc.Value.Between(DateTime.UtcNow.AddDays(-14), DateTime.UtcNow.AddDays(1)) + && a.Monitored).ToList(); if (previouslyAired.Empty()) { diff --git a/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs b/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs index b81292219..cb5cfb5c0 100644 --- a/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs +++ b/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs @@ -34,6 +34,7 @@ namespace NzbDrone.Core.Tv var existingEpisodes = _episodeService.GetEpisodeBySeries(series.Id); var seasons = series.Seasons; + var hasExisting = existingEpisodes.Any(); var updateList = new List(); var newList = new List(); @@ -82,6 +83,8 @@ namespace NzbDrone.Core.Tv } } + UnmonitorReaddedEpisodes(series, newList, hasExisting); + var allEpisodes = new List(); allEpisodes.AddRange(newList); allEpisodes.AddRange(updateList); @@ -117,6 +120,41 @@ namespace NzbDrone.Core.Tv return season == null || season.Monitored; } + + private void UnmonitorReaddedEpisodes(Series series, List episodes, bool hasExisting) + { + if (series.AddOptions != null) + { + return; + } + + var threshold = DateTime.UtcNow.AddDays(-14); + + var oldEpisodes = episodes.Where(e => e.AirDateUtc.HasValue && e.AirDateUtc.Value.Before(threshold)).ToList(); + + if (oldEpisodes.Any()) + { + if (hasExisting) + { + _logger.Warn("Show {0} ({1}) had {2} old episodes appear, please check monitored status.", series.TvdbId, series.Title, oldEpisodes.Count); + } + else + { + threshold = DateTime.UtcNow.AddDays(-1); + + foreach (var episode in episodes) + { + if (episode.AirDateUtc.HasValue && episode.AirDateUtc.Value.Before(threshold)) + { + episode.Monitored = false; + } + } + + _logger.Warn("Show {0} ({1}) had {2} old episodes appear, unmonitored aired episodes to prevent unexpected downloads.", series.TvdbId, series.Title, oldEpisodes.Count); + } + } + } + private void AdjustMultiEpisodeAirTime(Series series, IEnumerable allEpisodes) { if (series.Network == "Netflix")