From 7771899e29a5b91886776c810f705907fec791fb Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Thu, 22 Aug 2013 08:34:51 -0700 Subject: [PATCH] NotUnpacking check added to episode import Checks last write time when in working folder, should help with moving while unpacking --- NzbDrone.Common/DiskProvider.cs | 1 - .../NotUnpackingSpecificationFixture.cs | 77 +++++++++++++++++++ NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 1 + NzbDrone.Core/Configuration/ConfigService.cs | 6 ++ NzbDrone.Core/Configuration/IConfigService.cs | 1 + .../NotUnpackingSpecification.cs | 48 ++++++++++++ NzbDrone.Core/NzbDrone.Core.csproj | 1 + 7 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 NzbDrone.Core.Test/MediaFileTests/EpisodeImportTests/NotUnpackingSpecificationFixture.cs create mode 100644 NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs diff --git a/NzbDrone.Common/DiskProvider.cs b/NzbDrone.Common/DiskProvider.cs index 9ffdb8a77..062cd79d7 100644 --- a/NzbDrone.Common/DiskProvider.cs +++ b/NzbDrone.Common/DiskProvider.cs @@ -93,7 +93,6 @@ public DateTime GetLastFileWrite(string path) { Ensure.That(() => path).IsValidPath(); - if (!FileExists(path)) throw new FileNotFoundException("File doesn't exist: " + path); diff --git a/NzbDrone.Core.Test/MediaFileTests/EpisodeImportTests/NotUnpackingSpecificationFixture.cs b/NzbDrone.Core.Test/MediaFileTests/EpisodeImportTests/NotUnpackingSpecificationFixture.cs new file mode 100644 index 000000000..102f7a4f1 --- /dev/null +++ b/NzbDrone.Core.Test/MediaFileTests/EpisodeImportTests/NotUnpackingSpecificationFixture.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using Marr.Data; +using Moq; +using Newtonsoft.Json.Serialization; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.MediaFileTests.EpisodeImportTests +{ + [TestFixture] + public class NotUnpackingSpecificationFixture : CoreTest + { + private LocalEpisode _localEpisode; + + [SetUp] + public void Setup() + { + Mocker.GetMock() + .SetupGet(s => s.DownloadClientWorkingFolders) + .Returns("_UNPACK_|_FAILED_"); + + _localEpisode = new LocalEpisode + { + Path = @"C:\Test\Unsorted TV\30.rock\30.rock.s01e01.avi".AsOsAgnostic(), + Size = 100, + Series = Builder.CreateNew().Build() + }; + } + + private void GivenInWorkingFolder() + { + _localEpisode.Path = @"C:\Test\Unsorted TV\_UNPACK_30.rock\30.rock.s01e01.avi".AsOsAgnostic(); + } + + private void GivenLastWriteTimeUtc(DateTime time) + { + Mocker.GetMock() + .Setup(s => s.GetLastFileWrite(It.IsAny())) + .Returns(time); + } + + [Test] + public void should_return_true_if_not_in_working_folder() + { + Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue(); + } + + [Test] + public void should_return_true_when_in_old_working_folder() + { + GivenInWorkingFolder(); + GivenLastWriteTimeUtc(DateTime.UtcNow.AddHours(-1)); + + Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue(); + } + + [Test] + public void should_return_false_if_in_working_folder_and_last_write_time_was_recent() + { + GivenInWorkingFolder(); + GivenLastWriteTimeUtc(DateTime.UtcNow); + + Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse(); + } + } +} diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index a65e1eb59..8ed2f855d 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -129,6 +129,7 @@ + diff --git a/NzbDrone.Core/Configuration/ConfigService.cs b/NzbDrone.Core/Configuration/ConfigService.cs index a98e06cb5..0d9189fc6 100644 --- a/NzbDrone.Core/Configuration/ConfigService.cs +++ b/NzbDrone.Core/Configuration/ConfigService.cs @@ -258,6 +258,12 @@ public Boolean AutoDownloadPropers set { SetValue("AutoDownloadPropers", value); } } + public string DownloadClientWorkingFolders + { + get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); } + set { SetValue("DownloadClientWorkingFolders", value); } + } + private string GetValue(string key) { return GetValue(key, String.Empty); diff --git a/NzbDrone.Core/Configuration/IConfigService.cs b/NzbDrone.Core/Configuration/IConfigService.cs index 0b5779a37..07e70d25b 100644 --- a/NzbDrone.Core/Configuration/IConfigService.cs +++ b/NzbDrone.Core/Configuration/IConfigService.cs @@ -38,6 +38,7 @@ public interface IConfigService string ReleaseRestrictions { get; set; } Int32 RssSyncInterval { get; set; } Boolean AutoDownloadPropers { get; set; } + String DownloadClientWorkingFolders { get; set; } void SaveValues(Dictionary configValues); } } diff --git a/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs b/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs new file mode 100644 index 000000000..0f1e66d3a --- /dev/null +++ b/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using NLog; +using NzbDrone.Common; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications +{ + public class NotUnpackingSpecification : IImportDecisionEngineSpecification + { + private readonly IDiskProvider _diskProvider; + private readonly IConfigService _configService; + private readonly Logger _logger; + + public NotUnpackingSpecification(IDiskProvider diskProvider, IConfigService configService, Logger logger) + { + _diskProvider = diskProvider; + _configService = configService; + _logger = logger; + } + + public string RejectionReason { get { return "File is still being unpacked"; } } + + public bool IsSatisfiedBy(LocalEpisode localEpisode) + { + if (_diskProvider.IsParent(localEpisode.Series.Path, localEpisode.Path)) + { + _logger.Trace("{0} is in series folder, unpacking check", localEpisode.Path); + return true; + } + + foreach (var workingFolder in _configService.DownloadClientWorkingFolders.Split('|')) + { + if (Directory.GetParent(localEpisode.Path).Name.StartsWith(workingFolder)) + { + if (_diskProvider.GetLastFileWrite(localEpisode.Path) > DateTime.UtcNow.AddMinutes(-5)) + { + _logger.Trace("{0} appears to be unpacking still", localEpisode.Path); + return false; + } + } + } + + return true; + } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index bc4e017d5..57b9acb0a 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -225,6 +225,7 @@ +