1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-10-30 23:42:33 +01:00

New: Search for previously aired episodes that were just added to the database

This commit is contained in:
Mark McDowall 2014-11-26 23:08:17 -08:00
parent 709f96920d
commit 3f8366a190
12 changed files with 234 additions and 72 deletions

View File

@ -0,0 +1,42 @@
using System;
namespace NzbDrone.Common.Extensions
{
public static class DateTimeExtensions
{
public static bool InNextDays(this DateTime dateTime, int days)
{
return InNext(dateTime, new TimeSpan(days, 0, 0, 0));
}
public static bool InLastDays(this DateTime dateTime, int days)
{
return InLast(dateTime, new TimeSpan(days, 0, 0, 0));
}
public static bool InNext(this DateTime dateTime, TimeSpan timeSpan)
{
return dateTime >= DateTime.UtcNow && dateTime <= DateTime.UtcNow.Add(timeSpan);
}
public static bool InLast(this DateTime dateTime, TimeSpan timeSpan)
{
return dateTime >= DateTime.UtcNow.Add(-timeSpan) && dateTime <= DateTime.UtcNow;
}
public static bool Before(this DateTime dateTime, DateTime beforeDateTime)
{
return dateTime <= beforeDateTime;
}
public static bool After(this DateTime dateTime, DateTime afterDateTime)
{
return dateTime >= afterDateTime;
}
public static bool Between(this DateTime dateTime, DateTime afterDateTime, DateTime beforeDateTime)
{
return dateTime >= afterDateTime && dateTime <= beforeDateTime;
}
}
}

View File

@ -128,6 +128,7 @@
<Compile Include="Expansive\TreeNode.cs" /> <Compile Include="Expansive\TreeNode.cs" />
<Compile Include="Expansive\TreeNodeList.cs" /> <Compile Include="Expansive\TreeNodeList.cs" />
<Compile Include="Extensions\Base64Extentions.cs" /> <Compile Include="Extensions\Base64Extentions.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
<Compile Include="Extensions\Int64Extensions.cs" /> <Compile Include="Extensions\Int64Extensions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" /> <Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="Extensions\XmlExtentions.cs" /> <Compile Include="Extensions\XmlExtentions.cs" />

View File

@ -3,7 +3,6 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ICSharpCode.SharpZipLib.Zip;
namespace NzbDrone.Common namespace NzbDrone.Common
{ {

View File

@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Core.Test.IndexerSearchTests
{
[TestFixture]
public class EpisodeInfoRefreshedSearchFixture : CoreTest<EpisodeSearchService>
{
private Series _series;
private IList<Episode> _added;
private IList<Episode> _updated;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew()
.With(s => s.Added = DateTime.UtcNow.AddDays(-7))
.Build();
_added = new List<Episode>();
_updated = new List<Episode>();
}
private void GivenUpdated()
{
_updated.Add(Builder<Episode>.CreateNew().Build());
}
[Test]
public void should_not_search_if_no_episodes_were_upgraded()
{
_added.Add(new Episode());
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
VerifyNoSearch();
}
[Test]
public void should_not_search_if_series_was_added_within_the_last_day()
{
GivenUpdated();
_series.Added = DateTime.UtcNow;
_added.Add(new Episode());
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
VerifyNoSearch();
}
[Test]
public void should_not_search_if_no_episodes_were_added()
{
GivenUpdated();
_updated.Add(new Episode());
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
VerifyNoSearch();
}
[Test]
public void should_not_search_if_air_date_doesnt_have_a_value()
{
GivenUpdated();
_added.Add(new Episode());
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
VerifyNoSearch();
}
[Test]
public void should_not_search_if_episodes_air_in_the_future()
{
GivenUpdated();
_added.Add(new Episode { AirDateUtc = DateTime.UtcNow.AddDays(7) });
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
VerifyNoSearch();
}
[Test]
public void should_search_for_a_newly_added_episode()
{
GivenUpdated();
_added.Add(new Episode { AirDateUtc = DateTime.UtcNow });
Mocker.GetMock<IProcessDownloadDecisions>()
.Setup(s => s.ProcessDecisions(It.IsAny<List<DownloadDecision>>()))
.Returns(new ProcessedDecisions(new List<DownloadDecision>(), new List<DownloadDecision>()));
Subject.Handle(new EpisodeInfoRefreshedEvent(_series, _added, _updated));
Mocker.GetMock<ISearchForNzb>()
.Verify(v => v.EpisodeSearch(It.IsAny<Episode>()), Times.Once());
}
private void VerifyNoSearch()
{
Mocker.GetMock<ISearchForNzb>()
.Verify(v => v.EpisodeSearch(It.IsAny<Episode>()), Times.Never());
}
}
}

View File

@ -179,6 +179,7 @@
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedMetadataFilesFixture.cs" /> <Compile Include="Housekeeping\Housekeepers\CleanupOrphanedMetadataFilesFixture.cs" />
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" /> <Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" />
<Compile Include="Housekeeping\Housekeepers\FixFutureRunScheduledTasksFixture.cs" /> <Compile Include="Housekeeping\Housekeepers\FixFutureRunScheduledTasksFixture.cs" />
<Compile Include="IndexerSearchTests\EpisodeInfoRefreshedSearchFixture.cs" />
<Compile Include="IndexerSearchTests\SeriesSearchServiceFixture.cs" /> <Compile Include="IndexerSearchTests\SeriesSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\NzbSearchServiceFixture.cs" /> <Compile Include="IndexerSearchTests\NzbSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\SearchDefinitionFixture.cs" /> <Compile Include="IndexerSearchTests\SearchDefinitionFixture.cs" />

View File

@ -3,22 +3,27 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Queue; using NzbDrone.Core.Queue;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Core.IndexerSearch namespace NzbDrone.Core.IndexerSearch
{ {
public interface IEpisodeSearchService public interface IEpisodeSearchService
{ {
void MissingEpisodesAiredAfter(DateTime dateTime, IEnumerable<Int32> grabbed void MissingEpisodesAiredAfter(DateTime dateTime, IEnumerable<Int32> grabbed);
);
} }
public class MissingEpisodeSearchService : IEpisodeSearchService, IExecute<EpisodeSearchCommand>, IExecute<MissingEpisodeSearchCommand> public class EpisodeSearchService : IEpisodeSearchService,
IExecute<EpisodeSearchCommand>,
IExecute<MissingEpisodeSearchCommand>,
IHandle<EpisodeInfoRefreshedEvent>
{ {
private readonly ISearchForNzb _nzbSearchService; private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions; private readonly IProcessDownloadDecisions _processDownloadDecisions;
@ -26,7 +31,7 @@ namespace NzbDrone.Core.IndexerSearch
private readonly IQueueService _queueService; private readonly IQueueService _queueService;
private readonly Logger _logger; private readonly Logger _logger;
public MissingEpisodeSearchService(ISearchForNzb nzbSearchService, public EpisodeSearchService(ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions, IProcessDownloadDecisions processDownloadDecisions,
IEpisodeService episodeService, IEpisodeService episodeService,
IQueueService queueService, IQueueService queueService,
@ -105,5 +110,42 @@ namespace NzbDrone.Core.IndexerSearch
_logger.ProgressInfo("Completed missing search for {0} episodes. {1} reports downloaded.", missing.Count, downloadedCount); _logger.ProgressInfo("Completed missing search for {0} episodes. {1} reports downloaded.", missing.Count, downloadedCount);
} }
public void Handle(EpisodeInfoRefreshedEvent message)
{
if (message.Updated.Empty() || message.Series.Added.InLastDays(1))
{
_logger.Debug("Appears to be a new series, skipping search.");
return;
}
if (message.Added.Empty())
{
_logger.Debug("No new episodes, skipping search");
return;
}
if (message.Added.None(a => a.AirDateUtc.HasValue))
{
_logger.Debug("No new episodes have an air date");
return;
}
var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue && a.AirDateUtc.Value.Before(DateTime.UtcNow.AddDays(1))).ToList();
if (previouslyAired.Empty())
{
_logger.Debug("Newly added episodes all air in the future");
return;
}
foreach (var episode in previouslyAired)
{
var decisions = _nzbSearchService.EpisodeSearch(episode);
var processed = _processDownloadDecisions.ProcessDecisions(decisions);
_logger.ProgressInfo("Episode search completed. {0} reports downloaded.", processed.Grabbed.Count);
}
}
} }
} }

View File

@ -796,9 +796,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Tv\EpisodeService.cs" /> <Compile Include="Tv\EpisodeService.cs" />
<Compile Include="Tv\Events\EpisodeInfoAddedEvent.cs" /> <Compile Include="Tv\Events\EpisodeInfoRefreshedEvent.cs" />
<Compile Include="Tv\Events\EpisodeInfoDeletedEvent.cs" />
<Compile Include="Tv\Events\EpisodeInfoUpdatedEvent.cs" />
<Compile Include="Tv\Events\SeriesAddedEvent.cs" /> <Compile Include="Tv\Events\SeriesAddedEvent.cs" />
<Compile Include="Tv\Events\SeriesDeletedEvent.cs" /> <Compile Include="Tv\Events\SeriesDeletedEvent.cs" />
<Compile Include="Tv\Events\SeriesEditedEvent.cs" /> <Compile Include="Tv\Events\SeriesEditedEvent.cs" />

View File

@ -1,18 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Tv.Events
{
public class EpisodeInfoAddedEvent : IEvent
{
public Series Series { get; private set; }
public ReadOnlyCollection<Episode> Episodes { get; private set; }
public EpisodeInfoAddedEvent(IList<Episode> episodes, Series series)
{
Series = series;
Episodes = new ReadOnlyCollection<Episode>(episodes);
}
}
}

View File

@ -1,16 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Tv.Events
{
public class EpisodeInfoDeletedEvent : IEvent
{
public ReadOnlyCollection<Episode> Episodes { get; private set; }
public EpisodeInfoDeletedEvent(IList<Episode> episodes)
{
Episodes = new ReadOnlyCollection<Episode>(episodes);
}
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Tv.Events
{
public class EpisodeInfoRefreshedEvent : IEvent
{
public Series Series { get; set; }
public ReadOnlyCollection<Episode> Added { get; private set; }
public ReadOnlyCollection<Episode> Updated { get; private set; }
public EpisodeInfoRefreshedEvent(Series series, IList<Episode> added, IList<Episode> updated)
{
Series = series;
Added = new ReadOnlyCollection<Episode>(added);
Updated = new ReadOnlyCollection<Episode>(updated);
}
}
}

View File

@ -1,16 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Tv.Events
{
public class EpisodeInfoUpdatedEvent : IEvent
{
public ReadOnlyCollection<Episode> Episodes { get; private set; }
public EpisodeInfoUpdatedEvent(IList<Episode> episodes)
{
Episodes = new ReadOnlyCollection<Episode>(episodes);
}
}
}

View File

@ -96,20 +96,7 @@ namespace NzbDrone.Core.Tv
_episodeService.UpdateMany(updateList); _episodeService.UpdateMany(updateList);
_episodeService.InsertMany(newList); _episodeService.InsertMany(newList);
if (newList.Any()) _eventAggregator.PublishEvent(new EpisodeInfoRefreshedEvent(series, newList, updateList));
{
_eventAggregator.PublishEvent(new EpisodeInfoAddedEvent(newList, series));
}
if (updateList.Any())
{
_eventAggregator.PublishEvent(new EpisodeInfoUpdatedEvent(updateList));
}
if (existingEpisodes.Any())
{
_eventAggregator.PublishEvent(new EpisodeInfoDeletedEvent(updateList));
}
if (failCount != 0) if (failCount != 0)
{ {