Merge branch 'blackhole-delay' into develop

pull/6/head
Taloth Saldono 9 years ago
commit 19b8fb6d8b

@ -10,12 +10,16 @@ namespace NzbDrone.Common.Crypto
public static int GetHashInt31(string target) public static int GetHashInt31(string target)
{ {
byte[] hash; var hash = GetHash(target);
return BitConverter.ToInt32(hash, 0) & 0x7fffffff;
}
public static byte[] GetHash(string target)
{
lock (Sha1) lock (Sha1)
{ {
hash = Sha1.ComputeHash(Encoding.Default.GetBytes(target)); return Sha1.ComputeHash(Encoding.Default.GetBytes(target));
} }
return BitConverter.ToInt32(hash, 0) & 0x7fffffff;
} }
} }
} }

@ -100,5 +100,10 @@ namespace NzbDrone.Common.Extensions
.Select(x => Convert.ToByte(input.Substring(x, 2), 16)) .Select(x => Convert.ToByte(input.Substring(x, 2), 16))
.ToArray(); .ToArray();
} }
public static string ToHexString(this byte[] input)
{
return string.Concat(Array.ConvertAll(input, x => x.ToString("X2")));
}
} }
} }

@ -0,0 +1,94 @@
using System;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Download;
using NzbDrone.Test.Common;
using System.Threading;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Download.Clients.Blackhole;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
{
[TestFixture]
public class ScanWatchFolderFixture : CoreTest<ScanWatchFolder>
{
protected readonly string _title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE";
protected string _completedDownloadFolder = @"c:\blackhole\completed".AsOsAgnostic();
protected void GivenCompletedItem()
{
var targetDir = Path.Combine(_completedDownloadFolder, _title);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetDirectories(_completedDownloadFolder))
.Returns(new[] { targetDir });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(targetDir, "somefile.mkv") });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>()))
.Returns(1000000);
}
protected void GivenChangedItem()
{
var currentSize = Mocker.GetMock<IDiskProvider>().Object.GetFileSize("abc");
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>()))
.Returns(currentSize + 1);
}
private void VerifySingleItem(DownloadItemStatus status)
{
var items = Subject.GetItems(_completedDownloadFolder, TimeSpan.FromMilliseconds(50)).ToList();
items.Count.Should().Be(1);
items.First().Status.Should().Be(status);
}
[Test]
public void GetItems_should_considered_locked_files_queued()
{
GivenCompletedItem();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.IsFileLocked(It.IsAny<string>()))
.Returns(true);
Thread.Sleep(60);
VerifySingleItem(DownloadItemStatus.Downloading);
}
[Test]
public void GetItems_should_considered_changing_files_queued()
{
GivenCompletedItem();
VerifySingleItem(DownloadItemStatus.Downloading);
// If we keep changing the file every 20ms we should stay Downloading.
for (int i = 0; i < 10; i++)
{
TestLogger.Info("Iteration {0}", i);
GivenChangedItem();
VerifySingleItem(DownloadItemStatus.Downloading);
Thread.Sleep(10);
}
// Until it remains unchanged for >=50ms.
Thread.Sleep(60);
VerifySingleItem(DownloadItemStatus.Completed);
}
}
}

@ -8,7 +8,7 @@ using NUnit.Framework;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.TorrentBlackhole; using NzbDrone.Core.Download.Clients.Blackhole;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -30,6 +30,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
_blackholeFolder = @"c:\blackhole\torrent".AsOsAgnostic(); _blackholeFolder = @"c:\blackhole\torrent".AsOsAgnostic();
_filePath = (@"c:\blackhole\torrent\" + _title + ".torrent").AsOsAgnostic(); _filePath = (@"c:\blackhole\torrent\" + _title + ".torrent").AsOsAgnostic();
Mocker.SetConstant<IScanWatchFolder>(Mocker.Resolve<ScanWatchFolder>());
Subject.Definition = new DownloadClientDefinition(); Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new TorrentBlackholeSettings Subject.Definition.Settings = new TorrentBlackholeSettings
{ {
@ -56,13 +58,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
protected void GivenCompletedItem() protected void GivenCompletedItem()
{ {
var targetDir = Path.Combine(_completedDownloadFolder, _title); var targetDir = Path.Combine(_completedDownloadFolder, _title);
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetDirectories(_completedDownloadFolder)) .Setup(c => c.GetDirectories(_completedDownloadFolder))
.Returns(new[] { targetDir }); .Returns(new[] { targetDir });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(_completedDownloadFolder, "somefile.mkv") }); .Returns(new[] { Path.Combine(targetDir, "somefile.mkv") });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>())) .Setup(c => c.GetFileSize(It.IsAny<string>()))
@ -87,6 +90,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void completed_download_should_have_required_properties() public void completed_download_should_have_required_properties()
{ {
Subject.ScanGracePeriod = TimeSpan.Zero;
GivenCompletedItem(); GivenCompletedItem();
var result = Subject.GetItems().Single(); var result = Subject.GetItems().Single();
@ -94,6 +99,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
VerifyCompleted(result); VerifyCompleted(result);
} }
[Test]
public void partial_download_should_have_required_properties()
{
GivenCompletedItem();
var result = Subject.GetItems().Single();
VerifyPostprocessing(result);
}
[Test] [Test]
public void should_return_category() public void should_return_category()
{ {
@ -142,21 +157,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteEpisode)); Assert.Throws<ReleaseDownloadException>(() => Subject.Download(remoteEpisode));
} }
[Test]
public void GetItems_should_considered_locked_files_queued()
{
GivenCompletedItem();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.IsFileLocked(It.IsAny<string>()))
.Returns(true);
var items = Subject.GetItems().ToList();
items.Count.Should().Be(1);
items.First().Status.Should().Be(DownloadItemStatus.Downloading);
}
[Test] [Test]
public void RemoveItem_should_delete_file() public void RemoveItem_should_delete_file()
{ {

@ -9,7 +9,7 @@ using NUnit.Framework;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.UsenetBlackhole; using NzbDrone.Core.Download.Clients.Blackhole;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
@ -29,6 +29,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
_blackholeFolder = @"c:\blackhole\nzb".AsOsAgnostic(); _blackholeFolder = @"c:\blackhole\nzb".AsOsAgnostic();
_filePath = (@"c:\blackhole\nzb\" + _title + ".nzb").AsOsAgnostic(); _filePath = (@"c:\blackhole\nzb\" + _title + ".nzb").AsOsAgnostic();
Mocker.SetConstant<IScanWatchFolder>(Mocker.Resolve<ScanWatchFolder>());
Subject.Definition = new DownloadClientDefinition(); Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new UsenetBlackholeSettings Subject.Definition.Settings = new UsenetBlackholeSettings
{ {
@ -58,7 +60,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories))
.Returns(new[] { Path.Combine(_completedDownloadFolder, "somefile.mkv") }); .Returns(new[] { Path.Combine(targetDir, "somefile.mkv") });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileSize(It.IsAny<string>())) .Setup(c => c.GetFileSize(It.IsAny<string>()))
@ -68,6 +70,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
[Test] [Test]
public void completed_download_should_have_required_properties() public void completed_download_should_have_required_properties()
{ {
Subject.ScanGracePeriod = TimeSpan.Zero;
GivenCompletedItem(); GivenCompletedItem();
var result = Subject.GetItems().Single(); var result = Subject.GetItems().Single();
@ -75,6 +79,17 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
VerifyCompleted(result); VerifyCompleted(result);
} }
[Test]
public void partial_download_should_have_required_properties()
{
GivenCompletedItem();
var result = Subject.GetItems().Single();
VerifyPostprocessing(result);
}
[Test] [Test]
public void should_return_category() public void should_return_category()
{ {
@ -114,20 +129,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never()); Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
} }
[Test]
public void GetItems_should_considered_locked_files_downloading()
{
GivenCompletedItem();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.IsFileLocked(It.IsAny<string>()))
.Returns(true);
var result = Subject.GetItems().Single();
result.Status.Should().Be(DownloadItemStatus.Downloading);
}
[Test] [Test]
public void RemoveItem_should_delete_file() public void RemoveItem_should_delete_file()
{ {

@ -96,6 +96,15 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
downloadClientItem.Status.Should().Be(DownloadItemStatus.Downloading); downloadClientItem.Status.Should().Be(DownloadItemStatus.Downloading);
} }
protected void VerifyPostprocessing(DownloadClientItem downloadClientItem)
{
VerifyIdentifiable(downloadClientItem);
//downloadClientItem.RemainingTime.Should().NotBe(TimeSpan.Zero);
//downloadClientItem.OutputPath.Should().NotBeNullOrEmpty();
downloadClientItem.Status.Should().Be(DownloadItemStatus.Downloading);
}
protected void VerifyCompleted(DownloadClientItem downloadClientItem) protected void VerifyCompleted(DownloadClientItem downloadClientItem)
{ {
VerifyIdentifiable(downloadClientItem); VerifyIdentifiable(downloadClientItem);

@ -23,8 +23,6 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.SetConstant<IHttpClient>(Mocker.GetMock<IHttpClient>().Object);
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
Mocker.SetConstant<ITorrentRssSettingsDetector>(Mocker.Resolve<TorrentRssSettingsDetector>()); Mocker.SetConstant<ITorrentRssSettingsDetector>(Mocker.Resolve<TorrentRssSettingsDetector>());
Mocker.SetConstant<ITorrentRssParserFactory>(Mocker.Resolve<TorrentRssParserFactory>()); Mocker.SetConstant<ITorrentRssParserFactory>(Mocker.Resolve<TorrentRssParserFactory>());

@ -158,6 +158,7 @@
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />
<Compile Include="Download\CompletedDownloadServiceFixture.cs" /> <Compile Include="Download\CompletedDownloadServiceFixture.cs" />
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" /> <Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
<Compile Include="Download\DownloadClientTests\Blackhole\ScanWatchFolderFixture.cs" />
<Compile Include="Download\DownloadClientTests\Blackhole\TorrentBlackholeFixture.cs" /> <Compile Include="Download\DownloadClientTests\Blackhole\TorrentBlackholeFixture.cs" />
<Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" /> <Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" />
<Compile Include="Download\DownloadClientTests\DelugeTests\DelugeFixture.cs" /> <Compile Include="Download\DownloadClientTests\DelugeTests\DelugeFixture.cs" />

@ -0,0 +1,196 @@
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Crypto;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Organizer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public interface IScanWatchFolder
{
IEnumerable<WatchFolderItem> GetItems(string watchFolder, TimeSpan waitPeriod);
}
public class ScanWatchFolder : IScanWatchFolder
{
private readonly Logger _logger;
private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService;
private readonly ICached<Dictionary<string, WatchFolderItem>> _watchFolderItemCache;
public ScanWatchFolder(ICacheManager cacheManager, IDiskScanService diskScanService, IDiskProvider diskProvider, Logger logger)
{
_logger = logger;
_diskProvider = diskProvider;
_diskScanService = diskScanService;
_watchFolderItemCache = cacheManager.GetCache<Dictionary<string, WatchFolderItem>>(GetType());
}
public IEnumerable<WatchFolderItem> GetItems(string watchFolder, TimeSpan waitPeriod)
{
var newWatchItems = new Dictionary<string, WatchFolderItem>();
var lastWatchItems = _watchFolderItemCache.Get(watchFolder, () => newWatchItems);
foreach (var newWatchItem in GetDownloadItems(watchFolder, lastWatchItems, waitPeriod))
{
newWatchItems[newWatchItem.DownloadId] = newWatchItem;
}
_watchFolderItemCache.Set(watchFolder, newWatchItems, TimeSpan.FromMinutes(5));
return newWatchItems.Values;
}
private IEnumerable<WatchFolderItem> GetDownloadItems(string watchFolder, Dictionary<string, WatchFolderItem> lastWatchItems, TimeSpan waitPeriod)
{
foreach (var folder in _diskProvider.GetDirectories(watchFolder))
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder));
var newWatchItem = new WatchFolderItem
{
DownloadId = Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks,
Title = title,
OutputPath = new OsPath(folder),
Status = DownloadItemStatus.Completed,
RemainingTime = TimeSpan.Zero
};
var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId);
if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
{
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
newWatchItem.TotalSize = files.Select(_diskProvider.GetFileSize).Sum();
newWatchItem.Hash = GetHash(folder, files);
if (files.Any(_diskProvider.IsFileLocked))
{
newWatchItem.Status = DownloadItemStatus.Downloading;
newWatchItem.RemainingTime = null;
}
UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod);
}
yield return newWatchItem;
}
foreach (var videoFile in _diskScanService.GetVideoFiles(watchFolder, false))
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));
var newWatchItem = new WatchFolderItem
{
DownloadId = Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks,
Title = title,
OutputPath = new OsPath(videoFile),
Status = DownloadItemStatus.Completed,
RemainingTime = TimeSpan.Zero
};
var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId);
if (PreCheckWatchItemExpiry(oldWatchItem, newWatchItem))
{
newWatchItem.TotalSize = _diskProvider.GetFileSize(videoFile);
newWatchItem.Hash = GetHash(videoFile);
if (_diskProvider.IsFileLocked(videoFile))
{
newWatchItem.Status = DownloadItemStatus.Downloading;
}
UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod);
}
yield return newWatchItem;
}
}
private static bool PreCheckWatchItemExpiry(WatchFolderItem newWatchItem, WatchFolderItem oldWatchItem)
{
if (oldWatchItem == null || oldWatchItem.LastChanged.AddHours(1) > DateTime.UtcNow)
{
return true;
}
newWatchItem.TotalSize = oldWatchItem.TotalSize;
newWatchItem.Hash = oldWatchItem.Hash;
return false;
}
private static void UpdateWatchItemExpiry(WatchFolderItem newWatchItem, WatchFolderItem oldWatchItem, TimeSpan waitPeriod)
{
if (oldWatchItem != null && newWatchItem.Hash == oldWatchItem.Hash)
{
newWatchItem.LastChanged = oldWatchItem.LastChanged;
}
else
{
newWatchItem.LastChanged = DateTime.UtcNow;
}
var remainingTime = waitPeriod - (DateTime.UtcNow - newWatchItem.LastChanged);
if (remainingTime > TimeSpan.Zero)
{
newWatchItem.RemainingTime = remainingTime;
newWatchItem.Status = DownloadItemStatus.Downloading;
}
}
private string GetHash(string folder, string[] files)
{
var data = new StringBuilder();
data.Append(folder);
try
{
data.Append(_diskProvider.FolderGetLastWrite(folder).ToBinary());
}
catch (Exception ex)
{
_logger.TraceException(string.Format("Ignored hashing error during scan for {0}", folder), ex);
}
foreach (var file in files.OrderBy(v => v))
{
data.Append(GetHash(file));
}
return HashConverter.GetHash(data.ToString()).ToHexString();
}
private string GetHash(string file)
{
var data = new StringBuilder();
data.Append(file);
try
{
data.Append(_diskProvider.FileGetLastWrite(file).ToBinary());
data.Append(_diskProvider.GetFileSize(file));
}
catch (Exception ex)
{
_logger.TraceException(string.Format("Ignored hashing error during scan for {0}", file), ex);
}
return HashConverter.GetHash(data.ToString()).ToHexString();
}
}
}

@ -15,13 +15,15 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Download.Clients.TorrentBlackhole namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
public class TorrentBlackhole : TorrentClientBase<TorrentBlackholeSettings> public class TorrentBlackhole : TorrentClientBase<TorrentBlackholeSettings>
{ {
private readonly IDiskScanService _diskScanService; private readonly IScanWatchFolder _scanWatchFolder;
public TorrentBlackhole(IDiskScanService diskScanService, public TimeSpan ScanGracePeriod { get; set; }
public TorrentBlackhole(IScanWatchFolder scanWatchFolder,
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
@ -30,7 +32,9 @@ namespace NzbDrone.Core.Download.Clients.TorrentBlackhole
Logger logger) Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
{ {
_diskScanService = diskScanService; _scanWatchFolder = scanWatchFolder;
ScanGracePeriod = TimeSpan.FromSeconds(30);
} }
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink) protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
@ -72,71 +76,28 @@ namespace NzbDrone.Core.Download.Clients.TorrentBlackhole
} }
} }
public override IEnumerable<DownloadClientItem> GetItems() public override IEnumerable<DownloadClientItem> GetItems()
{ {
foreach (var folder in _diskProvider.GetDirectories(Settings.WatchFolder)) foreach (var item in _scanWatchFolder.GetItems(Settings.WatchFolder, ScanGracePeriod))
{ {
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder)); yield return new DownloadClientItem
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
var historyItem = new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClient = Definition.Name,
DownloadId = Definition.Name + "_" + Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks, DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "sonarr", Category = "sonarr",
Title = title, Title = item.Title,
TotalSize = files.Select(_diskProvider.GetFileSize).Sum(), TotalSize = item.TotalSize,
RemainingTime = item.RemainingTime,
OutputPath = new OsPath(folder) OutputPath = item.OutputPath,
};
if (files.Any(_diskProvider.IsFileLocked)) Status = item.Status,
{
historyItem.Status = DownloadItemStatus.Downloading;
}
else
{
historyItem.Status = DownloadItemStatus.Completed;
historyItem.RemainingTime = TimeSpan.Zero;
}
historyItem.IsReadOnly = Settings.ReadOnly;
yield return historyItem;
}
foreach (var videoFile in _diskScanService.GetVideoFiles(Settings.WatchFolder, false)) IsReadOnly = Settings.ReadOnly
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));
var historyItem = new DownloadClientItem
{
DownloadClient = Definition.Name,
DownloadId = Definition.Name + "_" + Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks,
Category = "sonarr",
Title = title,
TotalSize = _diskProvider.GetFileSize(videoFile),
OutputPath = new OsPath(videoFile)
}; };
if (_diskProvider.IsFileLocked(videoFile))
{
historyItem.Status = DownloadItemStatus.Downloading;
}
else
{
historyItem.Status = DownloadItemStatus.Completed;
historyItem.RemainingTime = TimeSpan.Zero;
}
historyItem.IsReadOnly = Settings.ReadOnly;
yield return historyItem;
} }
} }

@ -6,7 +6,7 @@ using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths; using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Core.Download.Clients.TorrentBlackhole namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
public class TorrentBlackholeSettingsValidator : AbstractValidator<TorrentBlackholeSettings> public class TorrentBlackholeSettingsValidator : AbstractValidator<TorrentBlackholeSettings>
{ {

@ -13,13 +13,15 @@ using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
namespace NzbDrone.Core.Download.Clients.UsenetBlackhole namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
public class UsenetBlackhole : UsenetClientBase<UsenetBlackholeSettings> public class UsenetBlackhole : UsenetClientBase<UsenetBlackholeSettings>
{ {
private readonly IDiskScanService _diskScanService; private readonly IScanWatchFolder _scanWatchFolder;
public UsenetBlackhole(IDiskScanService diskScanService, public TimeSpan ScanGracePeriod { get; set; }
public UsenetBlackhole(IScanWatchFolder scanWatchFolder,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
@ -27,7 +29,9 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, logger)
{ {
_diskScanService = diskScanService; _scanWatchFolder = scanWatchFolder;
ScanGracePeriod = TimeSpan.FromSeconds(30);
} }
protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent) protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent)
@ -58,65 +62,22 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
public override IEnumerable<DownloadClientItem> GetItems() public override IEnumerable<DownloadClientItem> GetItems()
{ {
foreach (var folder in _diskProvider.GetDirectories(Settings.WatchFolder)) foreach (var item in _scanWatchFolder.GetItems(Settings.WatchFolder, ScanGracePeriod))
{ {
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder)); yield return new DownloadClientItem
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
var historyItem = new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClient = Definition.Name,
DownloadId = Definition.Name + "_" + Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks, DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "sonarr", Category = "sonarr",
Title = title, Title = item.Title,
TotalSize = files.Select(_diskProvider.GetFileSize).Sum(),
OutputPath = new OsPath(folder)
};
if (files.Any(_diskProvider.IsFileLocked))
{
historyItem.Status = DownloadItemStatus.Downloading;
}
else
{
historyItem.Status = DownloadItemStatus.Completed;
historyItem.RemainingTime = TimeSpan.Zero;
}
yield return historyItem; TotalSize = item.TotalSize,
} RemainingTime = item.RemainingTime,
foreach (var videoFile in _diskScanService.GetVideoFiles(Settings.WatchFolder, false))
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));
var historyItem = new DownloadClientItem OutputPath = item.OutputPath,
{
DownloadClient = Definition.Name,
DownloadId = Definition.Name + "_" + Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks,
Category = "sonarr",
Title = title,
TotalSize = _diskProvider.GetFileSize(videoFile), Status = item.Status
OutputPath = new OsPath(videoFile)
}; };
if (_diskProvider.IsFileLocked(videoFile))
{
historyItem.Status = DownloadItemStatus.Downloading;
}
else
{
historyItem.Status = DownloadItemStatus.Completed;
historyItem.RemainingTime = TimeSpan.Zero;
}
yield return historyItem;
} }
} }

@ -5,7 +5,7 @@ using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths; using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Core.Download.Clients.UsenetBlackhole namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
public class UsenetBlackholeSettingsValidator : AbstractValidator<UsenetBlackholeSettings> public class UsenetBlackholeSettingsValidator : AbstractValidator<UsenetBlackholeSettings>
{ {

@ -0,0 +1,22 @@
using NzbDrone.Common.Disk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public class WatchFolderItem
{
public string DownloadId { get; set; }
public string Title { get; set; }
public long TotalSize { get; set; }
public TimeSpan? RemainingTime { get; set; }
public OsPath OutputPath { get; set; }
public DownloadItemStatus Status { get; set; }
public DateTime LastChanged { get; set; }
public string Hash { get; set; }
}
}

@ -332,6 +332,8 @@
<Compile Include="DiskSpace\DiskSpace.cs" /> <Compile Include="DiskSpace\DiskSpace.cs" />
<Compile Include="DiskSpace\DiskSpaceService.cs" /> <Compile Include="DiskSpace\DiskSpaceService.cs" />
<Compile Include="Download\CheckForFinishedDownloadCommand.cs" /> <Compile Include="Download\CheckForFinishedDownloadCommand.cs" />
<Compile Include="Download\Clients\Blackhole\ScanWatchFolder.cs" />
<Compile Include="Download\Clients\Blackhole\WatchFolderItem.cs" />
<Compile Include="Download\Clients\Deluge\Deluge.cs" /> <Compile Include="Download\Clients\Deluge\Deluge.cs" />
<Compile Include="Download\Clients\Deluge\DelugeError.cs" /> <Compile Include="Download\Clients\Deluge\DelugeError.cs" />
<Compile Include="Download\Clients\Deluge\DelugeException.cs" /> <Compile Include="Download\Clients\Deluge\DelugeException.cs" />
@ -411,8 +413,8 @@
<Compile Include="Download\Clients\Sabnzbd\SabnzbdQueue.cs" /> <Compile Include="Download\Clients\Sabnzbd\SabnzbdQueue.cs" />
<Compile Include="Download\Clients\Sabnzbd\SabnzbdQueueItem.cs" /> <Compile Include="Download\Clients\Sabnzbd\SabnzbdQueueItem.cs" />
<Compile Include="Download\Clients\Sabnzbd\SabnzbdSettings.cs" /> <Compile Include="Download\Clients\Sabnzbd\SabnzbdSettings.cs" />
<Compile Include="Download\Clients\TorrentBlackhole\TorrentBlackhole.cs" /> <Compile Include="Download\Clients\Blackhole\TorrentBlackhole.cs" />
<Compile Include="Download\Clients\TorrentBlackhole\TorrentBlackholeSettings.cs" /> <Compile Include="Download\Clients\Blackhole\TorrentBlackholeSettings.cs" />
<Compile Include="Download\Clients\TorrentSeedConfiguration.cs" /> <Compile Include="Download\Clients\TorrentSeedConfiguration.cs" />
<Compile Include="Download\Clients\rTorrent\RTorrent.cs" /> <Compile Include="Download\Clients\rTorrent\RTorrent.cs" />
<Compile Include="Download\Clients\rTorrent\RTorrentPriority.cs" /> <Compile Include="Download\Clients\rTorrent\RTorrentPriority.cs" />
@ -427,8 +429,8 @@
<Compile Include="Download\Clients\Transmission\TransmissionTorrent.cs" /> <Compile Include="Download\Clients\Transmission\TransmissionTorrent.cs" />
<Compile Include="Download\Clients\Transmission\TransmissionTorrentStatus.cs" /> <Compile Include="Download\Clients\Transmission\TransmissionTorrentStatus.cs" />
<Compile Include="Download\Clients\Transmission\TransmissionPriority.cs" /> <Compile Include="Download\Clients\Transmission\TransmissionPriority.cs" />
<Compile Include="Download\Clients\UsenetBlackhole\UsenetBlackhole.cs" /> <Compile Include="Download\Clients\Blackhole\UsenetBlackhole.cs" />
<Compile Include="Download\Clients\UsenetBlackhole\UsenetBlackholeSettings.cs" /> <Compile Include="Download\Clients\Blackhole\UsenetBlackholeSettings.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentPriority.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentPriority.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrent.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrent.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentProxy.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentProxy.cs" />

@ -80,6 +80,8 @@ namespace NzbDrone.Test.Common.AutoMoq
{ {
if (_registeredMocks.ContainsKey(type) == false) if (_registeredMocks.ContainsKey(type) == false)
_registeredMocks.Add(type, mock); _registeredMocks.Add(type, mock);
if (mock != null)
_container.RegisterInstance(type, mock.Object);
} }
public virtual void SetConstant<T>(T instance) public virtual void SetConstant<T>(T instance)

Loading…
Cancel
Save