Episode auto-ignore is now done in realtime rather than using a job.

pull/2/head
kay.one 13 years ago
parent 24d51093d6
commit 4da2e1cb72

@ -37,9 +37,6 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(p => p.Scan(series))
.Returns(new List<EpisodeFile>());
Mocker.GetMock<AutoIgnoreJob>()
.Setup(s => s.Start(It.IsAny<ProgressNotification>(), 0, 0));
//Act
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId, 0);
@ -71,9 +68,6 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>());
Mocker.GetMock<AutoIgnoreJob>()
.Setup(s => s.Start(It.IsAny<ProgressNotification>(), 0, 0));
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0);
@ -102,9 +96,6 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.Scan(series[1]))
.Throws(new InvalidOperationException("Bad Job"));
Mocker.GetMock<AutoIgnoreJob>()
.Setup(s => s.Start(It.IsAny<ProgressNotification>(), 0, 0));
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0);
@ -134,8 +125,6 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>());
Mocker.GetMock<AutoIgnoreJob>()
.Setup(s => s.Start(It.IsAny<ProgressNotification>(), 0, 0));
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0);

@ -102,6 +102,7 @@
<Compile Include="JobTests\BacklogSearchJobTest.cs" />
<Compile Include="JobTests\BannerDownloadJobTest.cs" />
<Compile Include="JobTests\RecentBacklogSearchJobTest.cs" />
<Compile Include="ProviderTests\MediaFileProviderTests\CleanUpDatabaseFixture.cs" />
<Compile Include="ProviderTests\ReferenceDataProviderTest.cs" />
<Compile Include="ProviderTests\NotificationProviderTests\NotificationProviderFixture.cs" />
<Compile Include="ProviderTests\SearchProviderTests\ProcessDailySearchResultsFixture.cs" />
@ -151,7 +152,7 @@
<Compile Include="ProviderTests\RootDirProviderTest.cs" />
<Compile Include="ProviderTests\IndexerProviderTest.cs" />
<Compile Include="ProviderTests\HistoryProviderTest.cs" />
<Compile Include="ProviderTests\MediaFileProviderTests.cs" />
<Compile Include="ProviderTests\MediaFileProviderTest.cs" />
<Compile Include="ProviderTests\ConfigProviderTest.cs" />
<Compile Include="ProviderTests\EpisodeProviderTest.cs" />
<Compile Include="Framework\TestDbHelper.cs" />

@ -147,13 +147,10 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(s => s.Path = @"C:\Test\TV\SeriesName\")
.Build();
Mocker.GetMock<MediaFileProvider>()
.Setup(c => c.DeleteOrphaned())
.Returns(0);
Mocker.GetMock<MediaFileProvider>()
.Setup(c => c.RepairLinks())
.Returns(0);
.Setup(c => c.CleanUpDatabase());
Mocker.GetMock<DiskProvider>()
.Setup(c => c.FolderExists(series.Path))

@ -1590,39 +1590,5 @@ namespace NzbDrone.Core.Test.ProviderTests
result.Where(e => e.Ignored).Should().HaveCount(episodeCount - 1);
result.Single(e => e.SeasonNumber == 1).Ignored.Should().BeFalse();
}
[Test]
public void SetPreviouslyDownloadedToIgnored_should_set_only_episodes_with_no_episode_file_and_postdownload_status_noError_to_ignored()
{
WithRealDb();
var postDownloadStatus = PostDownloadStatusType.NoError;
var fakeEpisodes = Builder<Episode>.CreateListOfSize(10)
.All()
.With(c => c.Ignored = false)
.TheFirst(2)
.With(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.With(c => c.EpisodeFileId = 0)
.TheNext(3)
.With(c => c.PostDownloadStatus = PostDownloadStatusType.Unknown)
.With(c => c.EpisodeFileId = 0)
.TheNext(4)
.With(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.TheNext(1)
.With(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.With(c => c.Ignored = true)
.Build();
Db.InsertMany(fakeEpisodes);
//Act
Mocker.Resolve<EpisodeProvider>().SetPreviouslyDownloadedToIgnored();
//Assert
var result = Db.Fetch<Episode>();
result.Should().HaveCount(10);
result.Where(e => e.Ignored).Count().Should().Be(3);
}
}
}

@ -1,5 +1,6 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
@ -7,6 +8,7 @@ using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
@ -17,7 +19,7 @@ namespace NzbDrone.Core.Test.ProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class MediaFileProviderTests : CoreTest
public class MediaFileProviderTest : CoreTest
{
[Test]
public void get_series_files()
@ -28,7 +30,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var secondSeriesFiles = Builder<EpisodeFile>.CreateListOfSize(10)
.All().With(s => s.SeriesId = 20).Build();
var database = TestDbHelper.GetEmptyDatabase(true);
@ -59,7 +61,7 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(s => s.SeasonNumber = 2)
.Build();
var database = TestDbHelper.GetEmptyDatabase(true);
@ -83,15 +85,13 @@ namespace NzbDrone.Core.Test.ProviderTests
.Returns(new List<Episode>());
Mocker.GetMock<MediaFileProvider>()
.Setup(e => e.RepairLinks()).Returns(0);
.Setup(e => e.CleanUpDatabase());
Mocker.GetMock<MediaFileProvider>()
.Setup(e => e.DeleteOrphaned()).Returns(0);
Mocker.GetMock<DiskProvider>()
.Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12).Build();
@ -114,49 +114,6 @@ namespace NzbDrone.Core.Test.ProviderTests
Assert.AreEqual(expectedName, result);
}
[Test]
public void CleanEpisodesWithNonExistantFiles()
{
//Setup
var episodes = Builder<Episode>.CreateListOfSize(10).Build();
var database = TestDbHelper.GetEmptyDatabase(true);
Mocker.SetConstant(database);
database.InsertMany(episodes);
//Act
var removedLinks = Mocker.Resolve<MediaFileProvider>().RepairLinks();
var result = database.Fetch<Episode>();
//Assert
result.Should().HaveSameCount(episodes);
result.Should().OnlyContain(e => e.EpisodeFileId == 0);
removedLinks.Should().Be(10);
}
[Test]
public void DeleteOrphanedEpisodeFiles()
{
//Setup
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10).Build();
var episodes = Builder<Episode>.CreateListOfSize(5).Build();
var database = TestDbHelper.GetEmptyDatabase(true);
Mocker.SetConstant(database);
database.InsertMany(episodes);
database.InsertMany(episodeFiles);
//Act
Mocker.Resolve<MediaFileProvider>().DeleteOrphaned();
var result = database.Fetch<EpisodeFile>();
//Assert
result.Should().HaveCount(5);
result.Should().OnlyContain(e => e.EpisodeFileId > 0);
}
[Test]
[TestCase("30 Rock - S01E05 - Episode Title", 1, true, "Season %0s", @"C:\Test\30 Rock\Season 01\30 Rock - S01E05 - Episode Title.mkv")]
[TestCase("30 Rock - S01E05 - Episode Title", 1, true, "Season %s", @"C:\Test\30 Rock\Season 1\30 Rock - S01E05 - Episode Title.mkv")]
@ -172,7 +129,7 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(s => s.SeasonFolder = useSeasonFolder)
.Build();
Mocker.GetMock<ConfigProvider>().Setup(e => e.SortingSeasonFolderFormat).Returns(seasonFolderFormat);
//Act
@ -188,7 +145,7 @@ namespace NzbDrone.Core.Test.ProviderTests
//Setup
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10).Build();
var database = TestDbHelper.GetEmptyDatabase(true);
Mocker.SetConstant(database);
database.InsertMany(episodeFiles);

@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ProviderTests.MediaFileProviderTests
{
[TestFixture]
public class CleanUpDatabaseFixture : CoreTest
{
[SetUp]
public void Setup()
{
WithRealDb();
}
private void WithAutoIgnore(bool autoIgnore)
{
Mocker.GetMock<ConfigProvider>()
.SetupGet(c => c.AutoIgnorePreviouslyDownloadedEpisodes).Returns(autoIgnore);
}
[Test]
public void CleanUpDatabse_should_detach_none_existing_file_from_episodes_with_auto_ignore()
{
WithAutoIgnore(true);
var episodes = Builder<Episode>.CreateListOfSize(3)
.All().With(c => c.GrabDate = DateTime.Now)
.And(c => c.Ignored = false)
.And(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.Build();
Db.InsertMany(episodes);
//Act
Mocker.Resolve<MediaFileProvider>().CleanUpDatabase();
var result = Db.Fetch<Episode>();
//Assert
result.Should().HaveSameCount(episodes);
result.Should().OnlyContain(e => e.EpisodeFileId == 0);
result.Should().OnlyContain(e => e.PostDownloadStatus == PostDownloadStatusType.Unknown);
result.Should().OnlyContain(e => e.Ignored);
result.Should().OnlyContain(e => e.GrabDate == null);
}
[Test]
public void CleanUpDatabse_should_detach_none_existing_file_from_episodes_with_no_auto_ignore()
{
WithAutoIgnore(false);
var episodes = Builder<Episode>.CreateListOfSize(3)
.All().With(c => c.GrabDate = DateTime.Now)
.And(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.TheFirst(2).With(c => c.Ignored = true)
.TheLast(1).With(c => c.Ignored = false)
.Build();
Db.InsertMany(episodes);
//Act
Mocker.Resolve<MediaFileProvider>().CleanUpDatabase();
var result = Db.Fetch<Episode>();
//Assert
result.Should().HaveSameCount(episodes);
result.Should().OnlyContain(e => e.EpisodeFileId == 0);
result.Should().OnlyContain(e => e.PostDownloadStatus == PostDownloadStatusType.Unknown);
result.Should().OnlyContain(e => e.GrabDate == null);
result.Should().Contain(c => c.Ignored == true);
result.Should().Contain(c => c.Ignored == false);
}
[Test]
public void CleanUpDatabse_should_not_change_episodes_with_no_file_id()
{
//Setup
var episodes = Builder<Episode>.CreateListOfSize(3)
.All().With(c => c.GrabDate = DateTime.Now)
.And(c => c.Ignored = false)
.And(c => c.PostDownloadStatus = PostDownloadStatusType.NoError)
.And(c => c.EpisodeFileId = 0)
.Build();
Db.InsertMany(episodes);
//Act
Mocker.Resolve<MediaFileProvider>().CleanUpDatabase();
var result = Db.Fetch<Episode>();
//Assert
result.Should().HaveSameCount(episodes);
result.Should().OnlyContain(e => e.EpisodeFileId == 0);
result.Should().NotContain(e => e.PostDownloadStatus == PostDownloadStatusType.Unknown);
result.Should().NotContain(e => e.Ignored);
result.Should().NotContain(e => e.GrabDate == null);
}
[Test]
public void DeleteOrphanedEpisodeFiles()
{
//Setup
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10).Build();
var episodes = Builder<Episode>.CreateListOfSize(5).Build();
Db.InsertMany(episodes);
Db.InsertMany(episodeFiles);
//Act
Mocker.Resolve<MediaFileProvider>().CleanUpDatabase();
var result = Db.Fetch<EpisodeFile>();
//Assert
result.Should().HaveCount(5);
result.Should().OnlyContain(e => e.EpisodeFileId > 0);
}
}
}

@ -96,7 +96,6 @@ namespace NzbDrone.Core
Kernel.Bind<IJob>().To<AppUpdateJob>().InSingletonScope();
Kernel.Bind<IJob>().To<TrimLogsJob>().InSingletonScope();
Kernel.Bind<IJob>().To<RecentBacklogSearchJob>().InSingletonScope();
Kernel.Bind<IJob>().To<AutoIgnoreJob>().InSingletonScope();
Kernel.Get<JobProvider>().Initialize();
Kernel.Get<WebTimer>().StartTimer(30);

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs
{
public class AutoIgnoreJob : IJob
{
private readonly ConfigProvider _configProvider;
private readonly EpisodeProvider _episodeProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject]
public AutoIgnoreJob(ConfigProvider configProvider, EpisodeProvider episodeProvider)
{
_configProvider = configProvider;
_episodeProvider = episodeProvider;
}
public AutoIgnoreJob()
{
}
public string Name
{
get { return "Auto Ignore Episodes"; }
}
public TimeSpan DefaultInterval
{
get { return TimeSpan.FromTicks(0); }
}
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
{
if (_configProvider.AutoIgnorePreviouslyDownloadedEpisodes)
{
Logger.Info("Ignoring Previously Downloaded Episodes");
_episodeProvider.SetPreviouslyDownloadedToIgnored();
}
}
}
}

@ -15,16 +15,13 @@ namespace NzbDrone.Core.Jobs
{
private readonly SeriesProvider _seriesProvider;
private readonly DiskScanProvider _diskScanProvider;
private readonly AutoIgnoreJob _autoIgnoreJob;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject]
public DiskScanJob(SeriesProvider seriesProvider, DiskScanProvider diskScanProvider,
AutoIgnoreJob autoIgnoreJob)
public DiskScanJob(SeriesProvider seriesProvider, DiskScanProvider diskScanProvider)
{
_seriesProvider = seriesProvider;
_diskScanProvider = diskScanProvider;
_autoIgnoreJob = autoIgnoreJob;
}
public DiskScanJob()
@ -66,9 +63,6 @@ namespace NzbDrone.Core.Jobs
Logger.ErrorException("An error has occurred while scanning " + series.Title, e);
}
}
//Start the Auto Ignore Job
_autoIgnoreJob.Start(notification, 0 , 0);
}
}
}

@ -225,7 +225,6 @@
<Compile Include="Instrumentation\DatabaseTarget.cs" />
<Compile Include="Instrumentation\NlogWriter.cs" />
<Compile Include="Datastore\PetaPoco\PetaPoco.cs" />
<Compile Include="Jobs\AutoIgnoreJob.cs" />
<Compile Include="Model\AtomicParsleyTitleType.cs" />
<Compile Include="Model\ConnectionInfoModel.cs" />
<Compile Include="Model\PostDownloadStatusType.cs" />

@ -56,8 +56,7 @@ namespace NzbDrone.Core.Providers
/// <param name="path">Path to scan</param>
public virtual List<EpisodeFile> Scan(Series series, string path)
{
_mediaFileProvider.DeleteOrphaned();
_mediaFileProvider.RepairLinks();
_mediaFileProvider.CleanUpDatabase();
if (!_diskProvider.FolderExists(path))
{
@ -231,8 +230,11 @@ namespace NzbDrone.Core.Providers
//Set the EpisodeFileId for each episode attached to this file to 0
foreach(var episode in _episodeProvider.GetEpisodesByFileId(episodeFile.EpisodeFileId))
{
Logger.Trace("Setting EpisodeFileId for Episode: [{0}] to 0");
Logger.Trace("Setting EpisodeFileId for Episode: [{0}] to 0", episode.EpisodeId);
episode.EpisodeFileId = 0;
episode.Ignored = true;
episode.GrabDate = null;
episode.PostDownloadStatus = PostDownloadStatusType.Unknown;
_episodeProvider.UpdateEpisode(episode);
}

@ -463,13 +463,5 @@ namespace NzbDrone.Core.Providers
Logger.Trace("Updating PostDownloadStatus for all episodeIds in {0}", episodeIdString);
_database.Execute(episodeIdQuery);
}
/// <summary>
/// Sets Ignored to true if the episode successfully downloaded (PostDownloadStatus = 5), but EpisodeFileId = 0
/// </summary>
public virtual void SetPreviouslyDownloadedToIgnored()
{
_database.Execute("UPDATE Episodes SET Ignored = 1, PostDownloadStatus = 0 WHERE PostDownloadStatus = 5 AND EpisodeFileId = 0");
}
}
}

@ -99,41 +99,42 @@ namespace NzbDrone.Core.Providers
return new FileInfo(path);
}
public virtual int RepairLinks()
public virtual void CleanUpDatabase()
{
Logger.Trace("Verifying Episode>Episode file relationships.");
var updated = _database.Execute(@"UPDATE Episodes SET EpisodeFileId = 0
WHERE EpisodeFileId IN
(SELECT Episodes.EpisodeFileId FROM Episodes
LEFT OUTER JOIN EpisodeFiles
ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId
WHERE Episodes.EpisodeFileId > 0 AND EpisodeFiles.EpisodeFileId IS null)");
Logger.Trace("Verifying Episode > Episode file relationships.");
string updateString = "UPDATE Episodes SET EpisodeFileId = 0, GrabDate = NULL, PostDownloadStatus = 0";
if (_configProvider.AutoIgnorePreviouslyDownloadedEpisodes)
{
updateString += ", Ignored = 1";
}
var updated = _database.Execute(updateString +
@"WHERE EpisodeFileId IN
(SELECT Episodes.EpisodeFileId FROM Episodes
LEFT OUTER JOIN EpisodeFiles
ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId
WHERE Episodes.EpisodeFileId > 0 AND EpisodeFiles.EpisodeFileId IS NULL)");
if (updated > 0)
{
Logger.Debug("Removed {0} invalid links to episode files.", updated);
}
return updated;
}
public virtual int DeleteOrphaned()
{
Logger.Trace("Deleting orphan files.");
var updated = _database.Execute(@"DELETE FROM EpisodeFiles
updated = _database.Execute(@"DELETE FROM EpisodeFiles
WHERE EpisodeFileId IN
(SELECT EpisodeFiles.EpisodeFileId FROM EpisodeFiles
LEFT OUTER JOIN Episodes
ON EpisodeFiles.EpisodeFileId = Episodes.EpisodeFileId
WHERE Episodes.EpisodeFileId IS null)");
WHERE Episodes.EpisodeFileId IS NULL)");
if (updated > 0)
{
Logger.Debug("Removed {0} orphan file(s) from database.S", updated);
}
return updated;
}
public virtual string GetNewFilename(IList<Episode> episodes, string seriesTitle, QualityTypes quality)

Loading…
Cancel
Save