New: Drone now uses the Download Client API to determine if a download is ready for import. (User configuration is required to replace the drone factory with this feature)
This commit is contained in:
parent
dcb586b937
commit
2035fe8578
|
@ -9,9 +9,12 @@ namespace NzbDrone.Api.Config
|
|||
public String DownloadClientWorkingFolders { get; set; }
|
||||
public Int32 DownloadedEpisodesScanInterval { get; set; }
|
||||
|
||||
public Boolean EnableCompletedDownloadHandling { get; set; }
|
||||
public Boolean RemoveCompletedDownloads { get; set; }
|
||||
|
||||
public Boolean EnableFailedDownloadHandling { get; set; }
|
||||
public Boolean AutoRedownloadFailed { get; set; }
|
||||
public Boolean RemoveFailedDownloads { get; set; }
|
||||
public Boolean EnableFailedDownloadHandling { get; set; }
|
||||
public Int32 BlacklistGracePeriod { get; set; }
|
||||
public Int32 BlacklistRetryInterval { get; set; }
|
||||
public Int32 BlacklistRetryLimit { get; set; }
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Api.DownloadClient
|
||||
{
|
||||
public class DownloadClientResource : ProviderResource
|
||||
{
|
||||
public Boolean Enable { get; set; }
|
||||
public Int32 Protocol { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,28 +7,28 @@ namespace NzbDrone.Api.DownloadClient
|
|||
{
|
||||
public class DownloadClientSchemaModule : NzbDroneRestModule<DownloadClientResource>
|
||||
{
|
||||
private readonly IDownloadClientFactory _notificationFactory;
|
||||
private readonly IDownloadClientFactory _downloadClientFactory;
|
||||
|
||||
public DownloadClientSchemaModule(IDownloadClientFactory notificationFactory)
|
||||
public DownloadClientSchemaModule(IDownloadClientFactory downloadClientFactory)
|
||||
: base("downloadclient/schema")
|
||||
{
|
||||
_notificationFactory = notificationFactory;
|
||||
_downloadClientFactory = downloadClientFactory;
|
||||
GetResourceAll = GetSchema;
|
||||
}
|
||||
|
||||
private List<DownloadClientResource> GetSchema()
|
||||
{
|
||||
var notifications = _notificationFactory.Templates();
|
||||
var downloadClients = _downloadClientFactory.Templates();
|
||||
|
||||
var result = new List<DownloadClientResource>(notifications.Count);
|
||||
var result = new List<DownloadClientResource>(downloadClients.Count);
|
||||
|
||||
foreach (var notification in notifications)
|
||||
foreach (var downloadClient in downloadClients)
|
||||
{
|
||||
var notificationResource = new DownloadClientResource();
|
||||
notificationResource.InjectFrom(notification);
|
||||
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
|
||||
var downloadClientResource = new DownloadClientResource();
|
||||
downloadClientResource.InjectFrom(downloadClient);
|
||||
downloadClientResource.Fields = SchemaBuilder.ToSchema(downloadClient.Settings);
|
||||
|
||||
result.Add(notificationResource);
|
||||
result.Add(downloadClientResource);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
public class IndexerResource : ProviderResource
|
||||
{
|
||||
public Boolean Enable { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Api.Indexers
|
|||
|
||||
private List<IndexerResource> GetSchema()
|
||||
{
|
||||
var indexers = _indexerFactory.Templates().Where(c => c.Implementation =="Newznab");
|
||||
var indexers = _indexerFactory.Templates();
|
||||
|
||||
var result = new List<IndexerResource>(indexers.Count());
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
|
@ -30,5 +31,6 @@ namespace NzbDrone.Api.Indexers
|
|||
public String DownloadUrl { get; set; }
|
||||
public String InfoUrl { get; set; }
|
||||
public Boolean DownloadAllowed { get; set; }
|
||||
public DownloadProtocol DownloadProtocol { get; set; }
|
||||
}
|
||||
}
|
|
@ -30,10 +30,11 @@ namespace NzbDrone.Api
|
|||
DeleteResource = DeleteProvider;
|
||||
|
||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.Name).Must((v,c) => !_providerFactory.All().Any(p => p.Name == c && p.Id != v.Id)).WithMessage("Should be unique");
|
||||
SharedValidator.RuleFor(c => c.Implementation).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.ConfigContract).NotEmpty();
|
||||
|
||||
PostValidator.RuleFor(c => c.Fields).NotEmpty();
|
||||
PostValidator.RuleFor(c => c.Fields).NotNull();
|
||||
}
|
||||
|
||||
private TProviderResource GetProviderById(int id)
|
||||
|
|
|
@ -137,7 +137,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void move_read_only_file()
|
||||
public void should_be_able_to_move_read_only_file()
|
||||
{
|
||||
var source = GetTempFilePath();
|
||||
var destination = GetTempFilePath();
|
||||
|
@ -151,6 +151,23 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
Subject.MoveFile(source, destination);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_delete_directory_with_read_only_file()
|
||||
{
|
||||
var sourceDir = GetTempFilePath();
|
||||
var source = Path.Combine(sourceDir, "test.txt");
|
||||
|
||||
Directory.CreateDirectory(sourceDir);
|
||||
|
||||
Subject.WriteAllText(source, "SourceFile");
|
||||
|
||||
File.SetAttributes(source, FileAttributes.ReadOnly);
|
||||
|
||||
Subject.DeleteFolder(sourceDir, true);
|
||||
|
||||
Directory.Exists(sourceDir).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void empty_folder_should_return_folder_modified_date()
|
||||
{
|
||||
|
|
|
@ -5,32 +5,7 @@ using NzbDrone.Test.Common;
|
|||
|
||||
namespace NzbDrone.Common.Test.DiskProviderTests
|
||||
{
|
||||
public class IsParentFixture : TestBase
|
||||
public class IsParentPathFixture : TestBase
|
||||
{
|
||||
private string _parent = @"C:\Test".AsOsAgnostic();
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_not_a_child()
|
||||
{
|
||||
var path = @"C:\Another Folder".AsOsAgnostic();
|
||||
|
||||
DiskProviderBase.IsParent(_parent, path).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_folder_is_parent_of_another_folder()
|
||||
{
|
||||
var path = @"C:\Test\TV".AsOsAgnostic();
|
||||
|
||||
DiskProviderBase.IsParent(_parent, path).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_folder_is_parent_of_a_file()
|
||||
{
|
||||
var path = @"C:\Test\30.Rock.S01E01.Pilot.avi".AsOsAgnostic();
|
||||
|
||||
DiskProviderBase.IsParent(_parent, path).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,57 @@ namespace NzbDrone.Common.Test
|
|||
{
|
||||
first.AsOsAgnostic().PathEquals(second.AsOsAgnostic()).Should().BeFalse();
|
||||
}
|
||||
|
||||
private string _parent = @"C:\Test".AsOsAgnostic();
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_not_a_child()
|
||||
{
|
||||
var path = @"C:\Another Folder".AsOsAgnostic();
|
||||
|
||||
_parent.IsParentPath(path).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_folder_is_parent_of_another_folder()
|
||||
{
|
||||
var path = @"C:\Test\TV".AsOsAgnostic();
|
||||
|
||||
_parent.IsParentPath(path).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_folder_is_parent_of_a_file()
|
||||
{
|
||||
var path = @"C:\Test\30.Rock.S01E01.Pilot.avi".AsOsAgnostic();
|
||||
|
||||
_parent.IsParentPath(path).Should().BeTrue();
|
||||
}
|
||||
[TestCase(@"C:\Test\", @"C:\Test\mydir")]
|
||||
[TestCase(@"C:\Test\", @"C:\Test\mydir\")]
|
||||
[TestCase(@"C:\Test", @"C:\Test\30.Rock.S01E01.Pilot.avi")]
|
||||
public void path_should_be_parent(string parentPath, string childPath)
|
||||
{
|
||||
parentPath.AsOsAgnostic().IsParentPath(childPath.AsOsAgnostic()).Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test2\", @"C:\Test")]
|
||||
[TestCase(@"C:\Test\Test\", @"C:\Test\")]
|
||||
[TestCase(@"C:\Test\", @"C:\Test")]
|
||||
[TestCase(@"C:\Test\", @"C:\Test\")]
|
||||
public void path_should_not_be_parent(string parentPath, string childPath)
|
||||
{
|
||||
parentPath.AsOsAgnostic().IsParentPath(childPath.AsOsAgnostic()).Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase(@"C:\test\", @"C:\Test\mydir")]
|
||||
[TestCase(@"C:\test", @"C:\Test\mydir\")]
|
||||
public void path_should_be_parent_on_windows_only(string parentPath, string childPath)
|
||||
{
|
||||
var expectedResult = OsInfo.IsWindows;
|
||||
|
||||
parentPath.IsParentPath(childPath).Should().Be(expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void normalize_path_exception_empty()
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Common
|
||||
{
|
||||
public static class ConvertBase32
|
||||
{
|
||||
private static string ValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
public static byte[] FromBase32String(string str)
|
||||
{
|
||||
int numBytes = str.Length * 5 / 8;
|
||||
byte[] bytes = new Byte[numBytes];
|
||||
|
||||
// all UPPERCASE chars
|
||||
str = str.ToUpper();
|
||||
|
||||
int bitBuffer = 0;
|
||||
int bitBufferCount = 0;
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < str.Length;i++ )
|
||||
{
|
||||
bitBuffer = (bitBuffer << 5) | ValidChars.IndexOf(str[i]);
|
||||
bitBufferCount += 5;
|
||||
|
||||
if (bitBufferCount >= 8)
|
||||
{
|
||||
bitBufferCount -= 8;
|
||||
bytes[index++] = (byte)(bitBuffer >> bitBufferCount);
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,45 +25,17 @@ namespace NzbDrone.Common.Disk
|
|||
public abstract void SetPermissions(string path, string mask, string user, string group);
|
||||
public abstract long? GetTotalSize(string path);
|
||||
|
||||
public static string GetRelativePath(string parentPath, string childPath)
|
||||
|
||||
public DateTime FolderGetCreationTimeUtc(string path)
|
||||
{
|
||||
if (!IsParent(parentPath, childPath))
|
||||
{
|
||||
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
||||
}
|
||||
CheckFolderExists(path);
|
||||
|
||||
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
public static bool IsParent(string parentPath, string childPath)
|
||||
{
|
||||
parentPath = parentPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
childPath = childPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
||||
var parent = new DirectoryInfo(parentPath);
|
||||
var child = new DirectoryInfo(childPath);
|
||||
|
||||
while (child.Parent != null)
|
||||
{
|
||||
if (child.Parent.FullName == parent.FullName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
child = child.Parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
return new DirectoryInfo(path).CreationTimeUtc;
|
||||
}
|
||||
|
||||
public DateTime FolderGetLastWrite(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
if (!FolderExists(path))
|
||||
{
|
||||
throw new DirectoryNotFoundException("Directory doesn't exist. " + path);
|
||||
}
|
||||
CheckFolderExists(path);
|
||||
|
||||
var dirFiles = GetFiles(path, SearchOption.AllDirectories).ToList();
|
||||
|
||||
|
@ -76,21 +48,38 @@ namespace NzbDrone.Common.Disk
|
|||
.Max(c => c.LastWriteTimeUtc);
|
||||
}
|
||||
|
||||
public DateTime FileGetCreationTimeUtc(string path)
|
||||
{
|
||||
CheckFileExists(path);
|
||||
|
||||
return new FileInfo(path).CreationTimeUtc;
|
||||
}
|
||||
|
||||
public DateTime FileGetLastWrite(string path)
|
||||
{
|
||||
PathEnsureFileExists(path);
|
||||
CheckFileExists(path);
|
||||
|
||||
return new FileInfo(path).LastWriteTime;
|
||||
}
|
||||
|
||||
public DateTime FileGetLastWriteUtc(string path)
|
||||
{
|
||||
PathEnsureFileExists(path);
|
||||
CheckFileExists(path);
|
||||
|
||||
return new FileInfo(path).LastWriteTimeUtc;
|
||||
}
|
||||
|
||||
private void PathEnsureFileExists(string path)
|
||||
private void CheckFolderExists(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
if (!FolderExists(path))
|
||||
{
|
||||
throw new DirectoryNotFoundException("Directory doesn't exist. " + path);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckFileExists(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
|
@ -286,6 +275,9 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
var files = Directory.GetFiles(path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
Array.ForEach(files, RemoveReadOnly);
|
||||
|
||||
Directory.Delete(path, recursive);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ namespace NzbDrone.Common.Disk
|
|||
void InheritFolderPermissions(string filename);
|
||||
void SetPermissions(string path, string mask, string user, string group);
|
||||
long? GetTotalSize(string path);
|
||||
DateTime FolderGetCreationTimeUtc(string path);
|
||||
DateTime FolderGetLastWrite(string path);
|
||||
DateTime FileGetCreationTimeUtc(string path);
|
||||
DateTime FileGetLastWrite(string path);
|
||||
DateTime FileGetLastWriteUtc(string path);
|
||||
void EnsureFolder(string path);
|
||||
|
|
|
@ -24,11 +24,14 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||
if (!IsMono)
|
||||
{
|
||||
Os = Os.Windows;
|
||||
}
|
||||
|
||||
PathStringComparison = StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
else
|
||||
{
|
||||
Os = IsOsx ? Os.Osx : Os.Linux;
|
||||
|
||||
PathStringComparison = StringComparison.Ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +43,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||
public static bool IsWindows { get; private set; }
|
||||
public static Os Os { get; private set; }
|
||||
public static DayOfWeek FirstDayOfWeek { get; private set; }
|
||||
public static StringComparison PathStringComparison { get; private set; }
|
||||
|
||||
//Borrowed from: https://github.com/jpobst/Pinta/blob/master/Pinta.Core/Managers/SystemManager.cs
|
||||
//From Managed.Windows.Forms/XplatUI
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace NzbDrone.Common.Http
|
|||
public Stream DownloadStream(string url, NetworkCredential credential = null)
|
||||
{
|
||||
var request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
request.UserAgent = _userAgent;
|
||||
request.Timeout = 20 * 1000;
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ArchiveProvider.cs" />
|
||||
<Compile Include="ConvertBase32.cs" />
|
||||
<Compile Include="Cache\Cached.cs" />
|
||||
<Compile Include="Cache\CacheManager.cs" />
|
||||
<Compile Include="Cache\ICached.cs" />
|
||||
|
|
|
@ -39,14 +39,39 @@ namespace NzbDrone.Common
|
|||
|
||||
public static bool PathEquals(this string firstPath, string secondPath)
|
||||
{
|
||||
if (OsInfo.IsMono)
|
||||
if (firstPath.Equals(secondPath, OsInfo.PathStringComparison)) return true;
|
||||
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), OsInfo.PathStringComparison);
|
||||
}
|
||||
|
||||
public static string GetRelativePath(this string parentPath, string childPath)
|
||||
{
|
||||
if (!parentPath.IsParentPath(childPath))
|
||||
{
|
||||
if (firstPath.Equals(secondPath)) return true;
|
||||
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath());
|
||||
throw new NzbDrone.Common.Exceptions.NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
||||
}
|
||||
|
||||
if (firstPath.Equals(secondPath, StringComparison.OrdinalIgnoreCase)) return true;
|
||||
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), StringComparison.OrdinalIgnoreCase);
|
||||
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
public static bool IsParentPath(this string parentPath, string childPath)
|
||||
{
|
||||
parentPath = parentPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
childPath = childPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
||||
var parent = new DirectoryInfo(parentPath);
|
||||
var child = new DirectoryInfo(childPath);
|
||||
|
||||
while (child.Parent != null)
|
||||
{
|
||||
if (child.Parent.FullName.Equals(parent.FullName, OsInfo.PathStringComparison))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
child = child.Parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly Regex WindowsPathWithDriveRegex = new Regex(@"^[a-zA-Z]:\\", RegexOptions.Compiled);
|
||||
|
|
|
@ -67,7 +67,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Mocker.GetMock<IHistoryService>().Setup(c => c.GetBestQualityInHistory(It.IsAny<QualityProfile>(), 3)).Returns<QualityModel>(null);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClient()).Returns(Mocker.GetMock<IDownloadClient>().Object);
|
||||
.Setup(c => c.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { Mocker.GetMock<IDownloadClient>().Object });
|
||||
}
|
||||
|
||||
private void WithFirstReportUpgradable()
|
||||
|
@ -83,7 +84,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
private void GivenSabnzbdDownloadClient()
|
||||
{
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClient()).Returns(Mocker.Resolve<Sabnzbd>());
|
||||
.Setup(c => c.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { Mocker.Resolve<Sabnzbd>() });
|
||||
}
|
||||
|
||||
private void GivenMostRecentForEpisode(HistoryEventType eventType)
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Queue;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
|
@ -18,7 +19,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
private Series _series;
|
||||
private Episode _episode;
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
private Mock<IDownloadClient> _downloadClient;
|
||||
|
||||
private Series _otherSeries;
|
||||
private Episode _otherEpisode;
|
||||
|
@ -50,34 +50,30 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD)})
|
||||
.Build();
|
||||
|
||||
_downloadClient = Mocker.GetMock<IDownloadClient>();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClient())
|
||||
.Returns(_downloadClient.Object);
|
||||
}
|
||||
|
||||
private void GivenEmptyQueue()
|
||||
{
|
||||
_downloadClient.Setup(s => s.GetQueue())
|
||||
.Returns(new List<QueueItem>());
|
||||
Mocker.GetMock<IQueueService>()
|
||||
.Setup(s => s.GetQueue())
|
||||
.Returns(new List<Queue.Queue>());
|
||||
}
|
||||
|
||||
private void GivenQueue(IEnumerable<RemoteEpisode> remoteEpisodes)
|
||||
{
|
||||
var queue = new List<QueueItem>();
|
||||
var queue = new List<Queue.Queue>();
|
||||
|
||||
foreach (var remoteEpisode in remoteEpisodes)
|
||||
{
|
||||
queue.Add(new QueueItem
|
||||
{
|
||||
RemoteEpisode = remoteEpisode
|
||||
queue.Add(new Queue.Queue
|
||||
{
|
||||
RemoteEpisode = remoteEpisode
|
||||
});
|
||||
}
|
||||
|
||||
_downloadClient.Setup(s => s.GetQueue())
|
||||
.Returns(queue);
|
||||
Mocker.GetMock<IQueueService>()
|
||||
.Setup(s => s.GetQueue())
|
||||
.Returns(queue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class CompletedDownloadServiceFixture : CoreTest<DownloadTrackingService>
|
||||
{
|
||||
private List<DownloadClientItem> _completed;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_completed = Builder<DownloadClientItem>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(h => h.Status = DownloadItemStatus.Completed)
|
||||
.With(h => h.OutputPath = @"C:\DropFolder\MyDownload".AsOsAgnostic())
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClients())
|
||||
.Returns( new IDownloadClient[] { Mocker.GetMock<IDownloadClient>().Object });
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.SetupGet(c => c.Definition)
|
||||
.Returns(new Core.Download.DownloadClientDefinition { Id = 1, Name = "testClient" });
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.RemoveCompletedDownloads)
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Failed())
|
||||
.Returns(new List<History.History>());
|
||||
|
||||
Mocker.SetConstant<ICompletedDownloadService>(Mocker.Resolve<CompletedDownloadService>());
|
||||
}
|
||||
|
||||
private void GivenNoGrabbedHistory()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Grabbed())
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
private void GivenGrabbedHistory(List<History.History> history)
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Grabbed())
|
||||
.Returns(history);
|
||||
}
|
||||
|
||||
private void GivenNoImportedHistory()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Imported())
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
private void GivenImportedHistory(List<History.History> importedHistory)
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Imported())
|
||||
.Returns(importedHistory);
|
||||
}
|
||||
|
||||
private void GivenCompletedDownloadClientHistory(bool hasStorage = true)
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(_completed);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(hasStorage);
|
||||
}
|
||||
|
||||
private void GivenCompletedImport()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>() { new Core.MediaFiles.EpisodeImport.ImportDecision(null) });
|
||||
}
|
||||
|
||||
private void GivenFailedImport()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>());
|
||||
}
|
||||
|
||||
private void VerifyNoImports()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Verify(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()), Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyImports()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Verify(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_matching_history_is_not_found_but_category_specified()
|
||||
{
|
||||
_completed.First().Category = "tv";
|
||||
|
||||
GivenCompletedDownloadClientHistory();
|
||||
GivenNoGrabbedHistory();
|
||||
GivenNoImportedHistory();
|
||||
GivenCompletedImport();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_matching_history_is_not_found_and_no_category_specified()
|
||||
{
|
||||
_completed.First().Category = null;
|
||||
|
||||
GivenCompletedDownloadClientHistory();
|
||||
GivenNoGrabbedHistory();
|
||||
GivenNoImportedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_grabbed_history_contains_null_downloadclient_id()
|
||||
{
|
||||
_completed.First().Category = null;
|
||||
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", null);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoImportedHistory();
|
||||
GivenFailedImport();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_failed_history_contains_null_downloadclient_id()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
|
||||
var historyImported = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyImported.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyImported.First().Data.Add("downloadClientId", null);
|
||||
|
||||
GivenImportedHistory(historyImported);
|
||||
GivenCompletedImport();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_already_added_to_history_as_imported()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenImportedHistory(history);
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_not_already_in_imported_history()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
GivenCompletedImport();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_storage_directory_does_not_exist()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory(false);
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
VerifyNoImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_storage_directory_in_drone_factory()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory(true);
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(v => v.DownloadedEpisodesFolder)
|
||||
.Returns(@"C:\DropFolder".AsOsAgnostic());
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
VerifyNoImports();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_remove_if_config_disabled()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
GivenCompletedImport();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.RemoveCompletedDownloads)
|
||||
.Returns(false);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_remove_while_readonly()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
GivenCompletedImport();
|
||||
|
||||
_completed.First().IsReadOnly = true;
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_remove_if_imported_failed()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
GivenFailedImport();
|
||||
|
||||
_completed.First().IsReadOnly = true;
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_if_imported()
|
||||
{
|
||||
GivenCompletedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoImportedHistory();
|
||||
GivenCompletedImport();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _completed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using FluentAssertions;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.Download.Clients.UsenetBlackhole;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class UsenetBlackholeFixture : DownloadClientFixtureBase<UsenetBlackhole>
|
||||
{
|
||||
protected string _completedDownloadFolder;
|
||||
protected string _blackholeFolder;
|
||||
protected string _filePath;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_completedDownloadFolder = @"c:\blackhole\completed".AsOsAgnostic();
|
||||
_blackholeFolder = @"c:\blackhole\nzb".AsOsAgnostic();
|
||||
_filePath = (@"c:\blackhole\nzb\" + _title + ".nzb").AsOsAgnostic();
|
||||
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new UsenetBlackholeSettings
|
||||
{
|
||||
NzbFolder = _blackholeFolder,
|
||||
WatchFolder = _completedDownloadFolder
|
||||
};
|
||||
}
|
||||
|
||||
protected void WithSuccessfulDownload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void WithFailedDownload()
|
||||
{
|
||||
Mocker.GetMock<IHttpProvider>()
|
||||
.Setup(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Throws(new WebException());
|
||||
}
|
||||
|
||||
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(_completedDownloadFolder, "somefile.mkv") });
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(1000000);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void completed_download_should_have_required_properties()
|
||||
{
|
||||
GivenCompletedItem();
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyCompleted(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_download_file_if_it_doesnt_exist()
|
||||
{
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_downloadUrl, _filePath), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_replace_illegal_characters_in_title()
|
||||
{
|
||||
var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]";
|
||||
var expectedFilename = Path.Combine(_blackholeFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV]" + Path.GetExtension(_filePath));
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
remoteEpisode.Release.Title = illegalTitle;
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.Download.Clients.Blackhole;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class BlackholeProviderFixture : CoreTest<Blackhole>
|
||||
{
|
||||
private const string _nzbUrl = "http://www.nzbs.com/url";
|
||||
private const string _title = "some_nzb_title";
|
||||
private string _blackHoleFolder;
|
||||
private string _nzbPath;
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_blackHoleFolder = @"c:\nzb\blackhole\".AsOsAgnostic();
|
||||
_nzbPath = @"c:\nzb\blackhole\some_nzb_title.nzb".AsOsAgnostic();
|
||||
|
||||
_remoteEpisode = new RemoteEpisode();
|
||||
_remoteEpisode.Release = new ReleaseInfo();
|
||||
_remoteEpisode.Release.Title = _title;
|
||||
_remoteEpisode.Release.DownloadUrl = _nzbUrl;
|
||||
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new FolderSettings
|
||||
{
|
||||
Folder = _blackHoleFolder
|
||||
};
|
||||
}
|
||||
|
||||
private void WithExistingFile()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(_nzbPath)).Returns(true);
|
||||
}
|
||||
|
||||
private void WithFailedDownload()
|
||||
{
|
||||
Mocker.GetMock<IHttpProvider>().Setup(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>())).Throws(new WebException());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadNzb_should_download_file_if_it_doesnt_exist()
|
||||
{
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_nzbUrl, _nzbPath), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_illegal_characters_in_title()
|
||||
{
|
||||
var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]";
|
||||
var expectedFilename = Path.Combine(_blackHoleFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV].nzb");
|
||||
_remoteEpisode.Release.Title = illegalTitle;
|
||||
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using FluentAssertions;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
||||
{
|
||||
public abstract class DownloadClientFixtureBase<TSubject> : CoreTest<TSubject>
|
||||
where TSubject : class, IDownloadClient
|
||||
{
|
||||
protected readonly string _title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE";
|
||||
protected readonly string _downloadUrl = "http://somewhere.com/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.ext";
|
||||
|
||||
[SetUp]
|
||||
public void SetupBase()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), null))
|
||||
.Returns(CreateRemoteEpisode());
|
||||
}
|
||||
|
||||
protected virtual RemoteEpisode CreateRemoteEpisode()
|
||||
{
|
||||
var remoteEpisode = new RemoteEpisode();
|
||||
remoteEpisode.Release = new ReleaseInfo();
|
||||
remoteEpisode.Release.Title = _title;
|
||||
remoteEpisode.Release.DownloadUrl = _downloadUrl;
|
||||
remoteEpisode.Release.DownloadProtocol = Subject.Protocol;
|
||||
|
||||
remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo();
|
||||
remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
|
||||
|
||||
remoteEpisode.Episodes = new List<Episode>();
|
||||
|
||||
remoteEpisode.Series = new Series();
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
|
||||
protected void VerifyIdentifiable(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
downloadClientItem.DownloadClient.Should().Be(Subject.Definition.Name);
|
||||
downloadClientItem.DownloadClientId.Should().NotBeNullOrEmpty();
|
||||
|
||||
downloadClientItem.Title.Should().NotBeNullOrEmpty();
|
||||
|
||||
downloadClientItem.RemoteEpisode.Should().NotBeNull();
|
||||
|
||||
}
|
||||
|
||||
protected void VerifyQueued(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
VerifyIdentifiable(downloadClientItem);
|
||||
downloadClientItem.RemainingSize.Should().NotBe(0);
|
||||
//downloadClientItem.RemainingTime.Should().NotBe(TimeSpan.Zero);
|
||||
//downloadClientItem.OutputPath.Should().NotBeNullOrEmpty();
|
||||
downloadClientItem.Status.Should().Be(DownloadItemStatus.Queued);
|
||||
}
|
||||
|
||||
protected void VerifyPaused(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
VerifyIdentifiable(downloadClientItem);
|
||||
|
||||
downloadClientItem.RemainingSize.Should().NotBe(0);
|
||||
//downloadClientItem.RemainingTime.Should().NotBe(TimeSpan.Zero);
|
||||
//downloadClientItem.OutputPath.Should().NotBeNullOrEmpty();
|
||||
downloadClientItem.Status.Should().Be(DownloadItemStatus.Paused);
|
||||
}
|
||||
|
||||
protected void VerifyDownloading(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
VerifyIdentifiable(downloadClientItem);
|
||||
|
||||
downloadClientItem.RemainingSize.Should().NotBe(0);
|
||||
//downloadClientItem.RemainingTime.Should().NotBe(TimeSpan.Zero);
|
||||
//downloadClientItem.OutputPath.Should().NotBeNullOrEmpty();
|
||||
downloadClientItem.Status.Should().Be(DownloadItemStatus.Downloading);
|
||||
}
|
||||
|
||||
protected void VerifyCompleted(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
VerifyIdentifiable(downloadClientItem);
|
||||
|
||||
downloadClientItem.Title.Should().NotBeNullOrEmpty();
|
||||
downloadClientItem.RemainingSize.Should().Be(0);
|
||||
downloadClientItem.RemainingTime.Should().Be(TimeSpan.Zero);
|
||||
//downloadClientItem.OutputPath.Should().NotBeNullOrEmpty();
|
||||
downloadClientItem.Status.Should().Be(DownloadItemStatus.Completed);
|
||||
}
|
||||
|
||||
protected void VerifyFailed(DownloadClientItem downloadClientItem)
|
||||
{
|
||||
VerifyIdentifiable(downloadClientItem);
|
||||
|
||||
downloadClientItem.Status.Should().Be(DownloadItemStatus.Failed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
{
|
||||
public class DownloadNzbFixture : CoreTest<Nzbget>
|
||||
{
|
||||
private const string _url = "http://www.nzbdrone.com";
|
||||
private const string _title = "30.Rock.S01E01.Pilot.720p.hdtv";
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_remoteEpisode = new RemoteEpisode();
|
||||
_remoteEpisode.Release = new ReleaseInfo();
|
||||
_remoteEpisode.Release.Title = _title;
|
||||
_remoteEpisode.Release.DownloadUrl = _url;
|
||||
|
||||
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new NzbgetSettings
|
||||
{
|
||||
Host = "localhost",
|
||||
Port = 6789,
|
||||
Username = "nzbget",
|
||||
Password = "pass",
|
||||
TvCategory = "tv",
|
||||
RecentTvPriority = (int)NzbgetPriority.High
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_item_to_queue()
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<NzbgetSettings>()))
|
||||
.Returns("id");
|
||||
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<NzbgetSettings>()), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class NzbgetFixture : DownloadClientFixtureBase<Nzbget>
|
||||
{
|
||||
private NzbgetQueueItem _queued;
|
||||
private NzbgetHistoryItem _failed;
|
||||
private NzbgetHistoryItem _completed;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new NzbgetSettings
|
||||
{
|
||||
Host = "192.168.5.55",
|
||||
Port = 2222,
|
||||
Username = "admin",
|
||||
Password = "pass",
|
||||
TvCategory = "tv",
|
||||
RecentTvPriority = (int)NzbgetPriority.High
|
||||
};
|
||||
|
||||
_queued = new NzbgetQueueItem
|
||||
{
|
||||
FileSizeLo = 1000,
|
||||
RemainingSizeLo = 10,
|
||||
Category = "tv",
|
||||
NzbName = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }
|
||||
};
|
||||
|
||||
_failed = new NzbgetHistoryItem
|
||||
{
|
||||
FileSizeLo = 1000,
|
||||
Category = "tv",
|
||||
Name = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
DestDir = "somedirectory",
|
||||
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
|
||||
ParStatus = "Some Error"
|
||||
};
|
||||
|
||||
_completed = new NzbgetHistoryItem
|
||||
{
|
||||
FileSizeLo = 1000,
|
||||
Category = "tv",
|
||||
Name = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
DestDir = "somedirectory",
|
||||
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
|
||||
ParStatus = "SUCCESS",
|
||||
ScriptStatus = "NONE"
|
||||
};
|
||||
}
|
||||
|
||||
protected void WithFailedDownload()
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
|
||||
.Returns((String)null);
|
||||
}
|
||||
|
||||
protected void WithSuccessfulDownload()
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
|
||||
.Returns(Guid.NewGuid().ToString().Replace("-", ""));
|
||||
}
|
||||
|
||||
protected virtual void WithQueue(NzbgetQueueItem queue)
|
||||
{
|
||||
var list = new List<NzbgetQueueItem>();
|
||||
|
||||
if (queue != null)
|
||||
{
|
||||
list.Add(queue);
|
||||
}
|
||||
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(list);
|
||||
}
|
||||
|
||||
protected virtual void WithHistory(NzbgetHistoryItem history)
|
||||
{
|
||||
var list = new List<NzbgetHistoryItem>();
|
||||
|
||||
if (history != null)
|
||||
{
|
||||
list.Add(history);
|
||||
}
|
||||
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.GetHistory(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_return_no_items_when_queue_is_empty()
|
||||
{
|
||||
WithQueue(null);
|
||||
WithHistory(null);
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void queued_item_should_have_required_properties()
|
||||
{
|
||||
_queued.ActiveDownloads = 0;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyQueued(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void paused_item_should_have_required_properties()
|
||||
{
|
||||
_queued.PausedSizeLo = _queued.FileSizeLo;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyPaused(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void downloading_item_should_have_required_properties()
|
||||
{
|
||||
_queued.ActiveDownloads = 1;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyDownloading(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void completed_download_should_have_required_properties()
|
||||
{
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyCompleted(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void failed_item_should_have_required_properties()
|
||||
{
|
||||
WithQueue(null);
|
||||
WithHistory(_failed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyFailed(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_return_unique_id()
|
||||
{
|
||||
WithSuccessfulDownload();
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
|
||||
var id = Subject.Download(remoteEpisode);
|
||||
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_ignore_downloads_from_other_categories()
|
||||
{
|
||||
_completed.Category = "mycat";
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
{
|
||||
public class QueueFixture : CoreTest<Nzbget>
|
||||
{
|
||||
private List<NzbgetQueueItem> _queue;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_queue = Builder<NzbgetQueueItem>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(q => q.NzbName = "30.Rock.S01E01.Pilot.720p.hdtv.nzb")
|
||||
.With(q => q.Parameters = new List<NzbgetParameter>
|
||||
{
|
||||
new NzbgetParameter { Name = "drone", Value = "id" }
|
||||
})
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new NzbgetSettings
|
||||
{
|
||||
Host = "localhost",
|
||||
Port = 6789,
|
||||
Username = "nzbget",
|
||||
Password = "pass",
|
||||
TvCategory = "tv",
|
||||
RecentTvPriority = (int)NzbgetPriority.High
|
||||
};
|
||||
}
|
||||
|
||||
private void WithFullQueue()
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(_queue);
|
||||
}
|
||||
|
||||
private void WithEmptyQueue()
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(new List<NzbgetQueueItem>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_no_items_when_queue_is_empty()
|
||||
{
|
||||
WithEmptyQueue();
|
||||
|
||||
Subject.GetQueue()
|
||||
.Should()
|
||||
.BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_item_when_queue_has_item()
|
||||
{
|
||||
WithFullQueue();
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), 0, null))
|
||||
.Returns(new RemoteEpisode {Series = new Series()});
|
||||
|
||||
Subject.GetQueue()
|
||||
.Should()
|
||||
.HaveCount(_queue.Count);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
|||
[Test]
|
||||
public void should_download_file_if_it_doesnt_exist()
|
||||
{
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
Subject.Download(_remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_nzbUrl, _nzbPath), Times.Once());
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
|||
{
|
||||
WithFailedDownload();
|
||||
|
||||
Assert.Throws<WebException>(() => Subject.DownloadNzb(_remoteEpisode));
|
||||
Assert.Throws<WebException>(() => Subject.Download(_remoteEpisode));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -84,7 +84,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
|||
_remoteEpisode.Release.Title = "30 Rock - Season 1";
|
||||
_remoteEpisode.ParsedEpisodeInfo.FullSeason = true;
|
||||
|
||||
Assert.Throws<NotImplementedException>(() => Subject.DownloadNzb(_remoteEpisode));
|
||||
Assert.Throws<NotSupportedException>(() => Subject.Download(_remoteEpisode));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_item_is_removed()
|
||||
{
|
||||
Assert.Throws<NotSupportedException>(() => Subject.RemoveItem(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -94,7 +100,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
|
|||
var expectedFilename = Path.Combine(_pneumaticFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV].nzb");
|
||||
_remoteEpisode.Release.Title = illegalTitle;
|
||||
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
Subject.Download(_remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
|
||||
}
|
||||
|
|
|
@ -12,30 +12,20 @@ using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SabnzbdFixture : CoreTest<Sabnzbd>
|
||||
public class SabnzbdFixture : DownloadClientFixtureBase<Sabnzbd>
|
||||
{
|
||||
private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232";
|
||||
private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]";
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
private SabnzbdQueue _queued;
|
||||
private SabnzbdHistory _failed;
|
||||
private SabnzbdHistory _completed;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_remoteEpisode = new RemoteEpisode();
|
||||
_remoteEpisode.Release = new ReleaseInfo();
|
||||
_remoteEpisode.Release.Title = TITLE;
|
||||
_remoteEpisode.Release.DownloadUrl = URL;
|
||||
|
||||
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new SabnzbdSettings
|
||||
{
|
||||
|
@ -47,16 +37,219 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
TvCategory = "tv",
|
||||
RecentTvPriority = (int)SabnzbdPriority.High
|
||||
};
|
||||
_queued = new SabnzbdQueue
|
||||
{
|
||||
Paused = false,
|
||||
Items = new List<SabnzbdQueueItem>()
|
||||
{
|
||||
new SabnzbdQueueItem
|
||||
{
|
||||
Status = SabnzbdDownloadStatus.Downloading,
|
||||
Size = 1000,
|
||||
Sizeleft = 10,
|
||||
Timeleft = TimeSpan.FromSeconds(10),
|
||||
Category = "tv",
|
||||
Id = "sabnzbd_nzb12345",
|
||||
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_failed = new SabnzbdHistory
|
||||
{
|
||||
Items = new List<SabnzbdHistoryItem>()
|
||||
{
|
||||
new SabnzbdHistoryItem
|
||||
{
|
||||
Status = SabnzbdDownloadStatus.Failed,
|
||||
Size = 1000,
|
||||
Category = "tv",
|
||||
Id = "sabnzbd_nzb12345",
|
||||
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_completed = new SabnzbdHistory
|
||||
{
|
||||
Items = new List<SabnzbdHistoryItem>()
|
||||
{
|
||||
new SabnzbdHistoryItem
|
||||
{
|
||||
Status = SabnzbdDownloadStatus.Completed,
|
||||
Size = 1000,
|
||||
Category = "tv",
|
||||
Id = "sabnzbd_nzb12345",
|
||||
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
Storage = "somedirectory"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void WithFailedDownload()
|
||||
{
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<int>(), It.IsAny<SabnzbdSettings>()))
|
||||
.Returns((SabnzbdAddResponse)null);
|
||||
}
|
||||
|
||||
protected void WithSuccessfulDownload()
|
||||
{
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<int>(), It.IsAny<SabnzbdSettings>()))
|
||||
.Returns(new SabnzbdAddResponse()
|
||||
{
|
||||
Status = true,
|
||||
Ids = new List<string> { "sabznbd_nzo12345" }
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void WithQueue(SabnzbdQueue queue)
|
||||
{
|
||||
if (queue == null)
|
||||
{
|
||||
queue = new SabnzbdQueue() { Items = new List<SabnzbdQueueItem>() };
|
||||
}
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.GetQueue(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SabnzbdSettings>()))
|
||||
.Returns(queue);
|
||||
}
|
||||
|
||||
protected virtual void WithHistory(SabnzbdHistory history)
|
||||
{
|
||||
if (history == null)
|
||||
history = new SabnzbdHistory() { Items = new List<SabnzbdHistoryItem>() };
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.GetHistory(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<SabnzbdSettings>()))
|
||||
.Returns(history);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
|
||||
public void GetItems_should_return_no_items_when_queue_is_empty()
|
||||
{
|
||||
WithQueue(null);
|
||||
WithHistory(null);
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[TestCase(SabnzbdDownloadStatus.Grabbing)]
|
||||
[TestCase(SabnzbdDownloadStatus.Queued)]
|
||||
public void queued_item_should_have_required_properties(SabnzbdDownloadStatus status)
|
||||
{
|
||||
_queued.Items.First().Status = status;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyQueued(result);
|
||||
result.RemainingTime.Should().NotBe(TimeSpan.Zero);
|
||||
}
|
||||
|
||||
[TestCase(SabnzbdDownloadStatus.Paused)]
|
||||
public void paused_item_should_have_required_properties(SabnzbdDownloadStatus status)
|
||||
{
|
||||
_queued.Items.First().Status = status;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyPaused(result);
|
||||
}
|
||||
|
||||
[TestCase(SabnzbdDownloadStatus.Checking)]
|
||||
[TestCase(SabnzbdDownloadStatus.Downloading)]
|
||||
[TestCase(SabnzbdDownloadStatus.QuickCheck)]
|
||||
[TestCase(SabnzbdDownloadStatus.Verifying)]
|
||||
[TestCase(SabnzbdDownloadStatus.Repairing)]
|
||||
[TestCase(SabnzbdDownloadStatus.Fetching)]
|
||||
[TestCase(SabnzbdDownloadStatus.Extracting)]
|
||||
[TestCase(SabnzbdDownloadStatus.Moving)]
|
||||
[TestCase(SabnzbdDownloadStatus.Running)]
|
||||
public void downloading_item_should_have_required_properties(SabnzbdDownloadStatus status)
|
||||
{
|
||||
_queued.Items.First().Status = status;
|
||||
|
||||
WithQueue(_queued);
|
||||
WithHistory(null);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyDownloading(result);
|
||||
result.RemainingTime.Should().NotBe(TimeSpan.Zero);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void completed_download_should_have_required_properties()
|
||||
{
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyCompleted(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void failed_item_should_have_required_properties()
|
||||
{
|
||||
_completed.Items.First().Status = SabnzbdDownloadStatus.Failed;
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
VerifyFailed(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_return_unique_id()
|
||||
{
|
||||
WithSuccessfulDownload();
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
|
||||
var id = Subject.Download(remoteEpisode);
|
||||
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_ignore_downloads_from_other_categories()
|
||||
{
|
||||
_completed.Items.First().Category = "myowncat";
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
|
||||
{
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()))
|
||||
.Returns(new SabnzbdAddResponse());
|
||||
|
||||
Subject.DownloadNzb(_remoteEpisode);
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()), Times.Once());
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
|
@ -16,12 +17,19 @@ namespace NzbDrone.Core.Test.Download
|
|||
public class DownloadServiceFixture : CoreTest<DownloadService>
|
||||
{
|
||||
private RemoteEpisode _parseResult;
|
||||
|
||||
private List<IDownloadClient> _downloadClients;
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_downloadClients = new List<IDownloadClient>();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClient()).Returns(Mocker.GetMock<IDownloadClient>().Object);
|
||||
.Setup(v => v.GetDownloadClients())
|
||||
.Returns(_downloadClients);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(v => v.GetDownloadClient(It.IsAny<Indexers.DownloadProtocol>()))
|
||||
.Returns<Indexers.DownloadProtocol>(v => _downloadClients.FirstOrDefault(d => d.Protocol == v));
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.TheFirst(1).With(s => s.Id = 12)
|
||||
|
@ -29,31 +37,43 @@ namespace NzbDrone.Core.Test.Download
|
|||
.All().With(s => s.SeriesId = 5)
|
||||
.Build().ToList();
|
||||
|
||||
var releaseInfo = Builder<ReleaseInfo>.CreateNew()
|
||||
.With(v => v.DownloadProtocol = Indexers.DownloadProtocol.Usenet)
|
||||
.Build();
|
||||
|
||||
_parseResult = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(c => c.Series = Builder<Series>.CreateNew().Build())
|
||||
.With(c => c.Release = Builder<ReleaseInfo>.CreateNew().Build())
|
||||
.With(c => c.Release = releaseInfo)
|
||||
.With(c => c.Episodes = episodes)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private void WithSuccessfulAdd()
|
||||
private Mock<IDownloadClient> WithUsenetClient()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<RemoteEpisode>()));
|
||||
var mock = new Mock<IDownloadClient>(Moq.MockBehavior.Default);
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
||||
mock.SetupGet(v => v.Protocol).Returns(Indexers.DownloadProtocol.Usenet);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private void WithFailedAdd()
|
||||
private Mock<IDownloadClient> WithTorrentClient()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.DownloadNzb(It.IsAny<RemoteEpisode>()))
|
||||
.Throws(new WebException());
|
||||
var mock = new Mock<IDownloadClient>(Moq.MockBehavior.Default);
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
||||
mock.SetupGet(v => v.Protocol).Returns(Indexers.DownloadProtocol.Torrent);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_report_should_publish_on_grab_event()
|
||||
{
|
||||
WithSuccessfulAdd();
|
||||
|
||||
var mock = WithUsenetClient();
|
||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
VerifyEventPublished<EpisodeGrabbedEvent>();
|
||||
|
@ -62,18 +82,20 @@ namespace NzbDrone.Core.Test.Download
|
|||
[Test]
|
||||
public void Download_report_should_grab_using_client()
|
||||
{
|
||||
WithSuccessfulAdd();
|
||||
|
||||
var mock = WithUsenetClient();
|
||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Verify(s => s.DownloadNzb(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_report_should_not_publish_on_failed_grab_event()
|
||||
{
|
||||
WithFailedAdd();
|
||||
var mock = WithUsenetClient();
|
||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||
.Throws(new WebException());
|
||||
|
||||
Assert.Throws<WebException>(() => Subject.DownloadReport(_parseResult));
|
||||
|
||||
|
@ -83,15 +105,38 @@ namespace NzbDrone.Core.Test.Download
|
|||
[Test]
|
||||
public void should_not_attempt_download_if_client_isnt_configure()
|
||||
{
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClient()).Returns((IDownloadClient)null);
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.DownloadNzb(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_send_download_to_correct_usenet_client()
|
||||
{
|
||||
var mockTorrent = WithTorrentClient();
|
||||
var mockUsenet = WithUsenetClient();
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_send_download_to_correct_torrent_client()
|
||||
{
|
||||
var mockTorrent = WithTorrentClient();
|
||||
var mockUsenet = WithUsenetClient();
|
||||
|
||||
_parseResult.Release.DownloadProtocol = Indexers.DownloadProtocol.Torrent;
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,32 +13,43 @@ using NzbDrone.Core.Test.Framework;
|
|||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class FailedDownloadServiceFixture : CoreTest<FailedDownloadService>
|
||||
public class FailedDownloadServiceFixture : CoreTest<DownloadTrackingService>
|
||||
{
|
||||
private List<HistoryItem> _completed;
|
||||
private List<HistoryItem> _failed;
|
||||
private List<DownloadClientItem> _completed;
|
||||
private List<DownloadClientItem> _failed;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_completed = Builder<HistoryItem>.CreateListOfSize(5)
|
||||
_completed = Builder<DownloadClientItem>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(h => h.Status = HistoryStatus.Completed)
|
||||
.With(h => h.Status = DownloadItemStatus.Completed)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
_failed = Builder<HistoryItem>.CreateListOfSize(1)
|
||||
_failed = Builder<DownloadClientItem>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(h => h.Status = HistoryStatus.Failed)
|
||||
.With(h => h.Status = DownloadItemStatus.Failed)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClient()).Returns(Mocker.GetMock<IDownloadClient>().Object);
|
||||
.Setup(c => c.GetDownloadClients())
|
||||
.Returns( new IDownloadClient[] { Mocker.GetMock<IDownloadClient>().Object });
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.SetupGet(c => c.Definition)
|
||||
.Returns(new Core.Download.DownloadClientDefinition { Id = 1, Name = "testClient" });
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableFailedDownloadHandling)
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Imported())
|
||||
.Returns(new List<History.History>());
|
||||
|
||||
Mocker.SetConstant<IFailedDownloadService>(Mocker.Resolve<FailedDownloadService>());
|
||||
}
|
||||
|
||||
private void GivenNoGrabbedHistory()
|
||||
|
@ -72,7 +83,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
private void GivenFailedDownloadClientHistory()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetHistory(0, 20))
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(_failed);
|
||||
}
|
||||
|
||||
|
@ -102,10 +113,10 @@ namespace NzbDrone.Core.Test.Download
|
|||
public void should_not_process_if_no_download_client_history()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetHistory(0, 20))
|
||||
.Returns(new List<HistoryItem>());
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(new List<DownloadClientItem>());
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Verify(s => s.BetweenDates(It.IsAny<DateTime>(), It.IsAny<DateTime>(), HistoryEventType.Grabbed),
|
||||
|
@ -117,11 +128,14 @@ namespace NzbDrone.Core.Test.Download
|
|||
[Test]
|
||||
public void should_not_process_if_no_failed_items_in_download_client_history()
|
||||
{
|
||||
GivenNoGrabbedHistory();
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetHistory(0, 20))
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(_completed);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Verify(s => s.BetweenDates(It.IsAny<DateTime>(), It.IsAny<DateTime>(), HistoryEventType.Grabbed),
|
||||
|
@ -136,7 +150,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
GivenNoGrabbedHistory();
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
@ -156,7 +170,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
@ -171,7 +185,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
|
||||
|
@ -184,7 +198,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
|
||||
GivenFailedHistory(historyFailed);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
@ -202,9 +216,9 @@ namespace NzbDrone.Core.Test.Download
|
|||
GivenFailedHistory(history);
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
history.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
@ -222,9 +236,9 @@ namespace NzbDrone.Core.Test.Download
|
|||
GivenNoFailedHistory();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
history.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
@ -244,10 +258,10 @@ namespace NzbDrone.Core.Test.Download
|
|||
history.ForEach(h =>
|
||||
{
|
||||
h.Data.Add("downloadClient", "SabnzbdClient");
|
||||
h.Data.Add("downloadClientId", _failed.First().Id);
|
||||
h.Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
});
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads(2);
|
||||
}
|
||||
|
@ -259,7 +273,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
.SetupGet(s => s.EnableFailedDownloadHandling)
|
||||
.Returns(false);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
@ -276,7 +290,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
|
||||
_failed.First().Message = "Unpacking failed, write error or disk is full?";
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
@ -291,12 +305,12 @@ namespace NzbDrone.Core.Test.Download
|
|||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
@ -311,13 +325,13 @@ namespace NzbDrone.Core.Test.Download
|
|||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "48");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
@ -332,14 +346,14 @@ namespace NzbDrone.Core.Test.Download
|
|||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "48");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
GivenGracePeriod(6);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
@ -354,7 +368,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().Id);
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "1");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
|
@ -362,7 +376,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
GivenGracePeriod(6);
|
||||
GivenRetryLimit(1);
|
||||
|
||||
Subject.Execute(new CheckForFailedDownloadCommand());
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||
public void should_return_warning_when_download_client_has_not_been_configured()
|
||||
{
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClient())
|
||||
.Returns((IDownloadClient)null);
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[0]);
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
@ -26,12 +26,12 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||
{
|
||||
var downloadClient = Mocker.GetMock<IDownloadClient>();
|
||||
|
||||
downloadClient.Setup(s => s.GetQueue())
|
||||
downloadClient.Setup(s => s.GetItems())
|
||||
.Throws<Exception>();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClient())
|
||||
.Returns(downloadClient.Object);
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||
|
||||
Subject.Check().ShouldBeError();
|
||||
}
|
||||
|
@ -41,12 +41,12 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||
{
|
||||
var downloadClient = Mocker.GetMock<IDownloadClient>();
|
||||
|
||||
downloadClient.Setup(s => s.GetQueue())
|
||||
.Returns(new List<QueueItem>());
|
||||
downloadClient.Setup(s => s.GetItems())
|
||||
.Returns(new List<DownloadClientItem>());
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClient())
|
||||
.Returns(downloadClient.Object);
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
|
|
|
@ -25,17 +25,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||
.Setup(s => s.FolderExists(DRONE_FACTORY_FOLDER))
|
||||
.Returns(exists);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_warning_when_drone_factory_folder_is_not_configured()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.DownloadedEpisodesFolder)
|
||||
.Returns("");
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_error_when_drone_factory_folder_does_not_exist()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using FizzWare.NBuilder;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.HealthCheck.Checks;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
{
|
||||
[TestFixture]
|
||||
public class ImportMechanismCheckFixture : CoreTest<ImportMechanismCheck>
|
||||
{
|
||||
private const string DRONE_FACTORY_FOLDER = @"C:\Test\Unsorted";
|
||||
|
||||
private IList<TrackedDownload> _completed;
|
||||
|
||||
private void GivenCompletedDownloadHandling(bool? enabled = null)
|
||||
{
|
||||
if (enabled.HasValue)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.IsDefined("EnableCompletedDownloadHandling"))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||
.Returns(enabled.Value);
|
||||
}
|
||||
|
||||
_completed = Builder<TrackedDownload>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(v => v.State == TrackedDownloadState.Downloading)
|
||||
.With(v => v.DownloadItem = new DownloadClientItem())
|
||||
.With(v => v.DownloadItem.Status = DownloadItemStatus.Completed)
|
||||
.With(v => v.DownloadItem.OutputPath = @"C:\Test\DropFolder\myfile.mkv".AsOsAgnostic())
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IDownloadTrackingService>()
|
||||
.Setup(v => v.GetCompletedDownloads())
|
||||
.Returns(_completed.ToList());
|
||||
}
|
||||
|
||||
private void GivenDroneFactoryFolder(bool exists = false)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.DownloadedEpisodesFolder)
|
||||
.Returns(DRONE_FACTORY_FOLDER.AsOsAgnostic());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FolderExists(DRONE_FACTORY_FOLDER.AsOsAgnostic()))
|
||||
.Returns(exists);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_warning_when_completed_download_handling_not_configured()
|
||||
{
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_warning_when_both_completeddownloadhandling_and_dronefactory_are_not_configured()
|
||||
{
|
||||
GivenCompletedDownloadHandling(false);
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_warning_when_downloadclient_drops_in_dronefactory_folder()
|
||||
{
|
||||
GivenCompletedDownloadHandling(true);
|
||||
GivenDroneFactoryFolder(true);
|
||||
|
||||
_completed.First().DownloadItem.OutputPath = (DRONE_FACTORY_FOLDER + @"\myfile.mkv").AsOsAgnostic();
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_ok_when_no_issues_found()
|
||||
{
|
||||
GivenCompletedDownloadHandling(true);
|
||||
GivenDroneFactoryFolder(true);
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,37 +29,6 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_create_default_indexer_on_startup()
|
||||
{
|
||||
IList<IndexerDefinition> storedIndexers = null;
|
||||
|
||||
Mocker.GetMock<IIndexerRepository>()
|
||||
.Setup(c => c.InsertMany(It.IsAny<IList<IndexerDefinition>>()))
|
||||
.Callback<IList<IndexerDefinition>>(indexers => storedIndexers = indexers);
|
||||
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
storedIndexers.Should().NotBeEmpty();
|
||||
storedIndexers.Select(c => c.Name).Should().OnlyHaveUniqueItems();
|
||||
storedIndexers.Select(c => c.Enable).Should().NotBeEmpty();
|
||||
storedIndexers.Select(c => c.Implementation).Should().NotContainNulls();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void getting_list_of_indexers()
|
||||
{
|
||||
Mocker.SetConstant<IIndexerRepository>(Mocker.Resolve<IndexerRepository>());
|
||||
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
var indexers = Subject.All().ToList();
|
||||
indexers.Should().NotBeEmpty();
|
||||
indexers.Should().NotContain(c => c.Settings == null);
|
||||
indexers.Should().NotContain(c => c.Name == null);
|
||||
indexers.Select(c => c.Name).Should().OnlyHaveUniqueItems();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_missing_indexers_on_startup()
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.Eztv;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
using NzbDrone.Core.Indexers.Wombles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -37,39 +36,6 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
|
|||
|
||||
ValidateResult(result, skipSize: true, skipInfo: true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void extv_rss()
|
||||
{
|
||||
var indexer = new Eztv();
|
||||
indexer.Definition = new IndexerDefinition
|
||||
{
|
||||
Name = "Eztv",
|
||||
Settings = NullConfig.Instance
|
||||
};
|
||||
|
||||
var result = Subject.FetchRss(indexer);
|
||||
|
||||
ValidateTorrentResult(result, skipSize: false, skipInfo: true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void nzbsorg_rss()
|
||||
{
|
||||
var indexer = new Newznab();
|
||||
|
||||
indexer.Definition = new IndexerDefinition();
|
||||
indexer.Definition.Name = "nzbs.org";
|
||||
indexer.Definition.Settings = new NewznabSettings
|
||||
{
|
||||
ApiKey = "64d61d3cfd4b75e51d01cbc7c6a78275",
|
||||
Url = "http://nzbs.org"
|
||||
};
|
||||
|
||||
var result = Subject.FetchRss(indexer);
|
||||
|
||||
ValidateResult(result);
|
||||
}
|
||||
|
||||
private void ValidateResult(IList<ReleaseInfo> reports, bool skipSize = false, bool skipInfo = false)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
indexer.Setup(s => s.GetSeasonSearchUrls(It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()))
|
||||
.Returns(new List<string> { "http://www.nzbdrone.com" });
|
||||
|
||||
indexer.SetupGet(s => s.SupportsPaging).Returns(paging);
|
||||
indexer.SetupGet(s => s.SupportedPageSize).Returns(paging ? 100 : 0);
|
||||
|
||||
var definition = new IndexerDefinition();
|
||||
definition.Name = "Test";
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Returns("c:\\drop\\".AsOsAgnostic());
|
||||
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true))
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
|
||||
.Returns(new List<ImportDecision>());
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
[Test]
|
||||
public void should_skip_if_file_is_in_use_by_another_process()
|
||||
{
|
||||
GivenValidSeries();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.IsFileLocked(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
|
@ -122,7 +124,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
public void should_not_delete_folder_if_no_files_were_imported()
|
||||
{
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false))
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false, null))
|
||||
.Returns(new List<ImportDecision>());
|
||||
|
||||
Subject.Execute(new DownloadedEpisodesScanCommand());
|
||||
|
@ -132,7 +134,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_folder_if_files_were_imported_and_video_files_remain()
|
||||
public void should_not_delete_folder_if_files_were_imported_and_video_files_remain()
|
||||
{
|
||||
GivenValidSeries();
|
||||
|
||||
|
@ -146,7 +148,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true))
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
|
||||
.Returns(imported);
|
||||
|
||||
Subject.Execute(new DownloadedEpisodesScanCommand());
|
||||
|
@ -172,7 +174,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true))
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<ISampleService>()
|
||||
|
@ -211,13 +213,13 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
private void VerifyNoImport()
|
||||
{
|
||||
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true),
|
||||
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyImport()
|
||||
{
|
||||
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true),
|
||||
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null),
|
||||
Times.Once());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
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.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
[TestFixture]
|
||||
public class NotInUseSpecificationFixture : CoreTest<NotInUseSpecification>
|
||||
{
|
||||
private LocalEpisode _localEpisode;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_localEpisode = new LocalEpisode
|
||||
{
|
||||
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi".AsOsAgnostic(),
|
||||
Size = 100,
|
||||
Series = Builder<Series>.CreateNew().Build()
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenChildOfSeries()
|
||||
{
|
||||
_localEpisode.ExistingFile = true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_file_is_under_series_folder()
|
||||
{
|
||||
GivenChildOfSeries();
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_check_for_file_in_use_if_child_of_series_folder()
|
||||
{
|
||||
GivenChildOfSeries();
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.IsFileLocked(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_file_is_in_use()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_file_is_not_in_use()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
||||
.Returns(false);
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,20 +57,20 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
}
|
||||
|
||||
Mocker.GetMock<IUpgradeMediaFiles>()
|
||||
.Setup(s => s.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), It.IsAny<LocalEpisode>()))
|
||||
.Setup(s => s.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), It.IsAny<LocalEpisode>(), false))
|
||||
.Returns(new EpisodeFileMoveResult());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_list_if_there_are_no_approved_decisions()
|
||||
{
|
||||
Subject.Import(_rejectedDecisions).Should().BeEmpty();
|
||||
Subject.Import(_rejectedDecisions, false).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_import_each_approved()
|
||||
{
|
||||
Subject.Import(_approvedDecisions).Should().HaveCount(5);
|
||||
Subject.Import(_approvedDecisions, false).Should().HaveCount(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
all.AddRange(_rejectedDecisions);
|
||||
all.AddRange(_approvedDecisions);
|
||||
|
||||
Subject.Import(all).Should().HaveCount(5);
|
||||
Subject.Import(all, false).Should().HaveCount(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
all.AddRange(_approvedDecisions);
|
||||
all.Add(new ImportDecision(_approvedDecisions.First().LocalEpisode));
|
||||
|
||||
Subject.Import(all).Should().HaveCount(5);
|
||||
Subject.Import(all, false).Should().HaveCount(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -99,7 +99,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
Subject.Import(new List<ImportDecision> {_approvedDecisions.First()}, true);
|
||||
|
||||
Mocker.GetMock<IUpgradeMediaFiles>()
|
||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode),
|
||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, false),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
|
@ -115,10 +115,10 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
[Test]
|
||||
public void should_not_move_existing_files()
|
||||
{
|
||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() });
|
||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, false);
|
||||
|
||||
Mocker.GetMock<IUpgradeMediaFiles>()
|
||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode),
|
||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, false),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
all.Add(fileDecision);
|
||||
all.Add(sampleDecision);
|
||||
|
||||
var results = Subject.Import(all);
|
||||
var results = Subject.Import(all, false);
|
||||
|
||||
results.Should().HaveCount(1);
|
||||
results.Should().ContainSingle(d => d.LocalEpisode.Size == fileDecision.LocalEpisode.Size);
|
||||
|
|
|
@ -115,18 +115,20 @@
|
|||
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
|
||||
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
||||
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\NzbgetTests\DownloadNzbFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\NzbgetTests\QueueFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\DownloadClientFixtureBase.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\PneumaticProviderFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\SabnzbdTests\SabnzbdFixture.cs" />
|
||||
<Compile Include="Download\DownloadServiceFixture.cs" />
|
||||
<Compile Include="Download\CompletedDownloadServiceFixture.cs" />
|
||||
<Compile Include="Download\FailedDownloadServiceFixture.cs" />
|
||||
<Compile Include="Framework\CoreTest.cs" />
|
||||
<Compile Include="Framework\DbTest.cs" />
|
||||
<Compile Include="Framework\NBuilderExtensions.cs" />
|
||||
<Compile Include="HealthCheck\Checks\RootFolderCheckFixture.cs" />
|
||||
<Compile Include="HealthCheck\Checks\DownloadClientCheckFixture.cs" />
|
||||
<Compile Include="HealthCheck\Checks\ImportMechanismCheckFixture.cs" />
|
||||
<Compile Include="HealthCheck\Checks\UpdateCheckFixture.cs" />
|
||||
<Compile Include="HealthCheck\Checks\IndexerCheckFixture.cs" />
|
||||
<Compile Include="HealthCheck\Checks\DroneFactoryCheckFixture.cs" />
|
||||
|
@ -156,7 +158,6 @@
|
|||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMakerFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotInUseSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\SampleServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecificationFixture.cs" />
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration />
|
|
@ -72,6 +72,11 @@ namespace NzbDrone.Core.Configuration
|
|||
_eventAggregator.PublishEvent(new ConfigSavedEvent());
|
||||
}
|
||||
|
||||
public Boolean IsDefined(String key)
|
||||
{
|
||||
return _repository.Get(key.ToLower()) != null;
|
||||
}
|
||||
|
||||
public String DownloadedEpisodesFolder
|
||||
{
|
||||
get { return GetValue(ConfigKey.DownloadedEpisodesFolder.ToString()); }
|
||||
|
@ -117,6 +122,27 @@ namespace NzbDrone.Core.Configuration
|
|||
set { SetValue("AutoDownloadPropers", value); }
|
||||
}
|
||||
|
||||
public Boolean EnableCompletedDownloadHandling
|
||||
{
|
||||
get { return GetValueBoolean("EnableCompletedDownloadHandling", false); }
|
||||
|
||||
set { SetValue("EnableCompletedDownloadHandling", value); }
|
||||
}
|
||||
|
||||
public Boolean RemoveCompletedDownloads
|
||||
{
|
||||
get { return GetValueBoolean("RemoveCompletedDownloads", false); }
|
||||
|
||||
set { SetValue("RemoveCompletedDownloads", value); }
|
||||
}
|
||||
|
||||
public Boolean EnableFailedDownloadHandling
|
||||
{
|
||||
get { return GetValueBoolean("EnableFailedDownloadHandling", true); }
|
||||
|
||||
set { SetValue("EnableFailedDownloadHandling", value); }
|
||||
}
|
||||
|
||||
public Boolean AutoRedownloadFailed
|
||||
{
|
||||
get { return GetValueBoolean("AutoRedownloadFailed", true); }
|
||||
|
@ -152,13 +178,6 @@ namespace NzbDrone.Core.Configuration
|
|||
set { SetValue("BlacklistRetryLimit", value); }
|
||||
}
|
||||
|
||||
public Boolean EnableFailedDownloadHandling
|
||||
{
|
||||
get { return GetValueBoolean("EnableFailedDownloadHandling", true); }
|
||||
|
||||
set { SetValue("EnableFailedDownloadHandling", value); }
|
||||
}
|
||||
|
||||
public Boolean CreateEmptySeriesFolders
|
||||
{
|
||||
get { return GetValueBoolean("CreateEmptySeriesFolders", false); }
|
||||
|
|
|
@ -11,15 +11,20 @@ namespace NzbDrone.Core.Configuration
|
|||
Dictionary<String, Object> AllWithDefaults();
|
||||
void SaveConfigDictionary(Dictionary<string, object> configValues);
|
||||
|
||||
Boolean IsDefined(String key);
|
||||
|
||||
//Download Client
|
||||
String DownloadedEpisodesFolder { get; set; }
|
||||
String DownloadClientWorkingFolders { get; set; }
|
||||
Int32 DownloadedEpisodesScanInterval { get; set; }
|
||||
|
||||
//Failed Download Handling (Download client)
|
||||
//Completed/Failed Download Handling (Download client)
|
||||
Boolean EnableCompletedDownloadHandling { get; set; }
|
||||
Boolean RemoveCompletedDownloads { get; set; }
|
||||
|
||||
Boolean EnableFailedDownloadHandling { get; set; }
|
||||
Boolean AutoRedownloadFailed { get; set; }
|
||||
Boolean RemoveFailedDownloads { get; set; }
|
||||
Boolean EnableFailedDownloadHandling { get; set; }
|
||||
Int32 BlacklistGracePeriod { get; set; }
|
||||
Int32 BlacklistRetryInterval { get; set; }
|
||||
Int32 BlacklistRetryLimit { get; set; }
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace NzbDrone.Core.Datastore
|
|||
Mapper.Entity<Config>().RegisterModel("Config");
|
||||
Mapper.Entity<RootFolder>().RegisterModel("RootFolders").Ignore(r => r.FreeSpace);
|
||||
|
||||
Mapper.Entity<IndexerDefinition>().RegisterModel("Indexers");
|
||||
Mapper.Entity<IndexerDefinition>().RegisterModel("Indexers")
|
||||
.Ignore(s => s.Protocol);
|
||||
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
||||
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
|
||||
Mapper.Entity<MetadataDefinition>().RegisterModel("Metadata");
|
||||
|
|
|
@ -5,17 +5,18 @@ using NzbDrone.Core.Download;
|
|||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Queue;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class NotInQueueSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IQueueService _queueService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public NotInQueueSpecification(IProvideDownloadClient downloadClientProvider, Logger logger)
|
||||
public NotInQueueSpecification(IQueueService queueService, Logger logger)
|
||||
{
|
||||
_downloadClientProvider = downloadClientProvider;
|
||||
_queueService = queueService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -29,15 +30,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
public bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
{
|
||||
_logger.Warn("Download client isn't configured yet.");
|
||||
return true;
|
||||
}
|
||||
|
||||
var queue = downloadClient.GetQueue().Select(q => q.RemoteEpisode);
|
||||
var queue = _queueService.GetQueue().Select(q => q.RemoteEpisode);
|
||||
|
||||
if (IsInQueue(subject, queue))
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.Sabnzbd;
|
||||
|
@ -41,9 +42,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
return true;
|
||||
}
|
||||
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
var downloadClients = _downloadClientProvider.GetDownloadClients();
|
||||
|
||||
if (downloadClient != null && downloadClient.GetType() == typeof (Sabnzbd))
|
||||
foreach (var downloadClient in downloadClients.OfType<Sabnzbd>())
|
||||
{
|
||||
_logger.Debug("Performing history status check on report");
|
||||
foreach (var episode in subject.Episodes)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class CheckForFailedDownloadCommand : Command
|
||||
public class CheckForFinishedDownloadCommand : Command
|
||||
{
|
||||
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||
{
|
||||
public class Blackhole : DownloadClientBase<FolderSettings>, IExecute<TestBlackholeCommand>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IHttpProvider _httpProvider;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public Blackhole(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_httpProvider = httpProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title;
|
||||
|
||||
title = FileNameBuilder.CleanFilename(title);
|
||||
|
||||
var filename = Path.Combine(Settings.Folder, title + ".nzb");
|
||||
|
||||
|
||||
_logger.Debug("Downloading NZB from: {0} to: {1}", url, filename);
|
||||
_httpProvider.DownloadFile(url, filename);
|
||||
_logger.Debug("NZB Download succeeded, saved to: {0}", filename);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<QueueItem> GetQueue()
|
||||
{
|
||||
return new QueueItem[0];
|
||||
}
|
||||
|
||||
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
|
||||
{
|
||||
return new HistoryItem[0];
|
||||
}
|
||||
|
||||
public override void RemoveFromQueue(string id)
|
||||
{
|
||||
}
|
||||
|
||||
public override void RemoveFromHistory(string id)
|
||||
{
|
||||
}
|
||||
|
||||
public override void RetryDownload(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Test()
|
||||
{
|
||||
PerformTest(Settings.Folder);
|
||||
}
|
||||
|
||||
private void PerformTest(string folder)
|
||||
{
|
||||
var testPath = Path.Combine(folder, "drone_test.txt");
|
||||
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
|
||||
_diskProvider.DeleteFile(testPath);
|
||||
}
|
||||
|
||||
public void Execute(TestBlackholeCommand message)
|
||||
{
|
||||
PerformTest(message.Folder);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,15 +5,18 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
{
|
||||
public class NzbgetQueueItem
|
||||
{
|
||||
private string _nzbName;
|
||||
public Int32 NzbId { get; set; }
|
||||
public Int32 FirstId { get; set; }
|
||||
public Int32 LastId { get; set; }
|
||||
public string NzbName { get; set; }
|
||||
public String Category { get; set; }
|
||||
public Int32 FileSizeMb { get; set; }
|
||||
public Int32 RemainingSizeMb { get; set; }
|
||||
public Int32 PausedSizeMb { get; set; }
|
||||
public UInt32 FileSizeLo { get; set; }
|
||||
public UInt32 FileSizeHi { get; set; }
|
||||
public UInt32 RemainingSizeLo { get; set; }
|
||||
public UInt32 RemainingSizeHi { get; set; }
|
||||
public UInt32 PausedSizeLo { get; set; }
|
||||
public UInt32 PausedSizeHi { get; set; }
|
||||
public Int32 ActiveDownloads { get; set; }
|
||||
public List<NzbgetParameter> Parameters { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -14,22 +15,27 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
public class Nzbget : DownloadClientBase<NzbgetSettings>, IExecute<TestNzbgetCommand>
|
||||
{
|
||||
private readonly INzbgetProxy _proxy;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IHttpProvider _httpProvider;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public Nzbget(INzbgetProxy proxy,
|
||||
IParsingService parsingService,
|
||||
IHttpProvider httpProvider,
|
||||
Logger logger)
|
||||
: base(parsingService, logger)
|
||||
{
|
||||
_proxy = proxy;
|
||||
_parsingService = parsingService;
|
||||
_httpProvider = httpProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Download(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title + ".nzb";
|
||||
|
@ -48,7 +54,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<QueueItem> GetQueue()
|
||||
private IEnumerable<DownloadClientItem> GetQueue()
|
||||
{
|
||||
List<NzbgetQueueItem> queue;
|
||||
|
||||
|
@ -59,36 +65,42 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
catch (DownloadClientException ex)
|
||||
{
|
||||
_logger.ErrorException(ex.Message, ex);
|
||||
return Enumerable.Empty<QueueItem>();
|
||||
return Enumerable.Empty<DownloadClientItem>();
|
||||
}
|
||||
|
||||
var queueItems = new List<QueueItem>();
|
||||
var queueItems = new List<DownloadClientItem>();
|
||||
|
||||
foreach (var item in queue)
|
||||
{
|
||||
var droneParameter = item.Parameters.SingleOrDefault(p => p.Name == "drone");
|
||||
|
||||
var queueItem = new QueueItem();
|
||||
queueItem.Id = droneParameter == null ? item.NzbId.ToString() : droneParameter.Value.ToString();
|
||||
var queueItem = new DownloadClientItem();
|
||||
queueItem.DownloadClientId = droneParameter == null ? item.NzbId.ToString() : droneParameter.Value.ToString();
|
||||
queueItem.Title = item.NzbName;
|
||||
queueItem.Size = item.FileSizeMb;
|
||||
queueItem.Sizeleft = item.RemainingSizeMb;
|
||||
queueItem.Status = item.FileSizeMb == item.PausedSizeMb ? "paused" : "queued";
|
||||
queueItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo);
|
||||
queueItem.RemainingSize = MakeInt64(item.RemainingSizeHi, item.RemainingSizeLo);
|
||||
queueItem.Category = item.Category;
|
||||
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title);
|
||||
if (parsedEpisodeInfo == null) continue;
|
||||
if (queueItem.TotalSize == MakeInt64(item.PausedSizeHi, item.PausedSizeLo))
|
||||
{
|
||||
queueItem.Status = DownloadItemStatus.Paused;
|
||||
}
|
||||
else if (item.ActiveDownloads == 0 && queueItem.RemainingSize != 0)
|
||||
{
|
||||
queueItem.Status = DownloadItemStatus.Queued;
|
||||
}
|
||||
else
|
||||
{
|
||||
queueItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
|
||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
||||
if (remoteEpisode.Series == null) continue;
|
||||
|
||||
queueItem.RemoteEpisode = remoteEpisode;
|
||||
queueItems.Add(queueItem);
|
||||
}
|
||||
|
||||
return queueItems;
|
||||
}
|
||||
|
||||
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
|
||||
private IEnumerable<DownloadClientItem> GetHistory()
|
||||
{
|
||||
List<NzbgetHistoryItem> history;
|
||||
|
||||
|
@ -99,10 +111,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
catch (DownloadClientException ex)
|
||||
{
|
||||
_logger.ErrorException(ex.Message, ex);
|
||||
return Enumerable.Empty<HistoryItem>();
|
||||
return Enumerable.Empty<DownloadClientItem>();
|
||||
}
|
||||
|
||||
var historyItems = new List<HistoryItem>();
|
||||
var historyItems = new List<DownloadClientItem>();
|
||||
var successStatues = new[] {"SUCCESS", "NONE"};
|
||||
|
||||
foreach (var item in history)
|
||||
|
@ -110,15 +122,15 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
var droneParameter = item.Parameters.SingleOrDefault(p => p.Name == "drone");
|
||||
var status = successStatues.Contains(item.ParStatus) &&
|
||||
successStatues.Contains(item.ScriptStatus)
|
||||
? HistoryStatus.Completed
|
||||
: HistoryStatus.Failed;
|
||||
? DownloadItemStatus.Completed
|
||||
: DownloadItemStatus.Failed;
|
||||
|
||||
var historyItem = new HistoryItem();
|
||||
historyItem.Id = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString();
|
||||
var historyItem = new DownloadClientItem();
|
||||
historyItem.DownloadClient = Definition.Name;
|
||||
historyItem.DownloadClientId = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString();
|
||||
historyItem.Title = item.Name;
|
||||
historyItem.Size = item.FileSizeMb.ToString(); //Why is this a string?
|
||||
historyItem.DownloadTime = 0;
|
||||
historyItem.Storage = item.DestDir;
|
||||
historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo);
|
||||
historyItem.OutputPath = item.DestDir;
|
||||
historyItem.Category = item.Category;
|
||||
historyItem.Message = String.Format("PAR Status: {0} - Script Status: {1}", item.ParStatus, item.ScriptStatus);
|
||||
historyItem.Status = status;
|
||||
|
@ -129,12 +141,20 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
return historyItems;
|
||||
}
|
||||
|
||||
public override void RemoveFromQueue(string id)
|
||||
public override IEnumerable<DownloadClientItem> GetItems()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
foreach (var downloadClientItem in GetQueue().Concat(GetHistory()))
|
||||
{
|
||||
if (downloadClientItem.Category != Settings.TvCategory) continue;
|
||||
|
||||
downloadClientItem.RemoteEpisode = GetRemoteEpisode(downloadClientItem.Title);
|
||||
if (downloadClientItem.RemoteEpisode == null) continue;
|
||||
|
||||
yield return downloadClientItem;
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveFromHistory(string id)
|
||||
public override void RemoveItem(string id)
|
||||
{
|
||||
_proxy.RemoveFromHistory(id, Settings);
|
||||
}
|
||||
|
@ -161,5 +181,17 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
|
||||
_proxy.GetVersion(settings);
|
||||
}
|
||||
|
||||
// Javascript doesn't support 64 bit integers natively so json officially doesn't either.
|
||||
// NzbGet api thus sends it in two 32 bit chunks. Here we join the two chunks back together.
|
||||
// Simplified decimal example: "42" splits into "4" and "2". To join them I shift (<<) the "4" 1 digit to the left = "40". combine it with "2". which becomes "42" again.
|
||||
private Int64 MakeInt64(UInt32 high, UInt32 low)
|
||||
{
|
||||
Int64 result = high;
|
||||
|
||||
result = (result << 32) | (Int64)low;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,11 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
{
|
||||
public class NzbgetHistoryItem
|
||||
{
|
||||
private string _nzbName;
|
||||
public Int32 Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Category { get; set; }
|
||||
public Int32 FileSizeMb { get; set; }
|
||||
public UInt32 FileSizeLo { get; set; }
|
||||
public UInt32 FileSizeHi { get; set; }
|
||||
public String ParStatus { get; set; }
|
||||
public String ScriptStatus { get; set; }
|
||||
public String DestDir { get; set; }
|
||||
|
|
|
@ -13,9 +13,14 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public String Host { get; set; }
|
||||
public Int32 Port { get; set; }
|
||||
public String Username { get; set; }
|
||||
public String Password { get; set; }
|
||||
public String TvCategory { get; set; }
|
||||
public Int32 RecentTvPriority { get; set; }
|
||||
public Int32 OlderTvPriority { get; set; }
|
||||
public Boolean UseSsl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@ using NzbDrone.Common.Disk;
|
|||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.Instrumentation;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||
|
@ -21,22 +23,34 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
|
|||
|
||||
private static readonly Logger logger = NzbDroneLogger.GetLogger();
|
||||
|
||||
public Pneumatic(IConfigService configService, IHttpProvider httpProvider,
|
||||
IDiskProvider diskProvider)
|
||||
public Pneumatic(IConfigService configService,
|
||||
IHttpProvider httpProvider,
|
||||
IDiskProvider diskProvider,
|
||||
IParsingService parsingService,
|
||||
Logger logger)
|
||||
: base(parsingService, logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_httpProvider = httpProvider;
|
||||
_diskProvider = diskProvider;
|
||||
}
|
||||
|
||||
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Download(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title;
|
||||
|
||||
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
|
||||
{
|
||||
throw new NotImplementedException("Full season releases are not supported with Pneumatic.");
|
||||
throw new NotSupportedException("Full season releases are not supported with Pneumatic.");
|
||||
}
|
||||
|
||||
title = FileNameBuilder.CleanFilename(title);
|
||||
|
@ -63,27 +77,19 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
|
|||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<QueueItem> GetQueue()
|
||||
public override IEnumerable<DownloadClientItem> GetItems()
|
||||
{
|
||||
return new QueueItem[0];
|
||||
return new DownloadClientItem[0];
|
||||
}
|
||||
|
||||
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
|
||||
{
|
||||
return new HistoryItem[0];
|
||||
}
|
||||
|
||||
public override void RemoveFromQueue(string id)
|
||||
{
|
||||
}
|
||||
|
||||
public override void RemoveFromHistory(string id)
|
||||
|
||||
public override void RemoveItem(string id)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void RetryDownload(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Test()
|
||||
|
|
|
@ -6,7 +6,7 @@ using NzbDrone.Core.Annotations;
|
|||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients
|
||||
namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||
{
|
||||
public class FolderSettingsValidator : AbstractValidator<FolderSettings>
|
||||
{
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -15,25 +15,27 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
public class Sabnzbd : DownloadClientBase<SabnzbdSettings>, IExecute<TestSabnzbdCommand>
|
||||
{
|
||||
private readonly IHttpProvider _httpProvider;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly ISabnzbdProxy _proxy;
|
||||
private readonly ICached<IEnumerable<QueueItem>> _queueCache;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public Sabnzbd(IHttpProvider httpProvider,
|
||||
ICacheManager cacheManager,
|
||||
IParsingService parsingService,
|
||||
ISabnzbdProxy proxy,
|
||||
Logger logger)
|
||||
: base(parsingService, logger)
|
||||
{
|
||||
_httpProvider = httpProvider;
|
||||
_parsingService = parsingService;
|
||||
_proxy = proxy;
|
||||
_queueCache = cacheManager.GetCache<IEnumerable<QueueItem>>(GetType(), "queue");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string DownloadNzb(RemoteEpisode remoteEpisode)
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Download(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title;
|
||||
|
@ -54,76 +56,104 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<QueueItem> GetQueue()
|
||||
private IEnumerable<DownloadClientItem> GetQueue()
|
||||
{
|
||||
return _queueCache.Get("queue", () =>
|
||||
SabnzbdQueue sabQueue;
|
||||
|
||||
try
|
||||
{
|
||||
SabnzbdQueue sabQueue;
|
||||
sabQueue = _proxy.GetQueue(0, 0, Settings);
|
||||
}
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
_logger.ErrorException(ex.Message, ex);
|
||||
return Enumerable.Empty<DownloadClientItem>();
|
||||
}
|
||||
|
||||
try
|
||||
var queueItems = new List<DownloadClientItem>();
|
||||
|
||||
foreach (var sabQueueItem in sabQueue.Items)
|
||||
{
|
||||
var queueItem = new DownloadClientItem();
|
||||
queueItem.DownloadClient = Definition.Name;
|
||||
queueItem.DownloadClientId = sabQueueItem.Id;
|
||||
queueItem.Category = sabQueueItem.Category;
|
||||
queueItem.Title = sabQueueItem.Title;
|
||||
queueItem.TotalSize = (long)(sabQueueItem.Size * 1024 * 1024);
|
||||
queueItem.RemainingSize = (long)(sabQueueItem.Sizeleft * 1024 * 1024);
|
||||
queueItem.RemainingTime = sabQueueItem.Timeleft;
|
||||
|
||||
if (sabQueue.Paused || sabQueueItem.Status == SabnzbdDownloadStatus.Paused)
|
||||
{
|
||||
sabQueue = _proxy.GetQueue(0, 0, Settings);
|
||||
queueItem.Status = DownloadItemStatus.Paused;
|
||||
}
|
||||
catch (DownloadClientException ex)
|
||||
else if (sabQueueItem.Status == SabnzbdDownloadStatus.Queued || sabQueueItem.Status == SabnzbdDownloadStatus.Grabbing)
|
||||
{
|
||||
_logger.ErrorException(ex.Message, ex);
|
||||
return Enumerable.Empty<QueueItem>();
|
||||
queueItem.Status = DownloadItemStatus.Queued;
|
||||
}
|
||||
else
|
||||
{
|
||||
queueItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
|
||||
var queueItems = new List<QueueItem>();
|
||||
|
||||
foreach (var sabQueueItem in sabQueue.Items)
|
||||
if (queueItem.Title.StartsWith("ENCRYPTED /"))
|
||||
{
|
||||
var queueItem = new QueueItem();
|
||||
queueItem.Id = sabQueueItem.Id;
|
||||
queueItem.Title = sabQueueItem.Title;
|
||||
queueItem.Size = sabQueueItem.Size;
|
||||
queueItem.Sizeleft = sabQueueItem.Sizeleft;
|
||||
queueItem.Timeleft = sabQueueItem.Timeleft;
|
||||
queueItem.Status = sabQueueItem.Status;
|
||||
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title.Replace("ENCRYPTED / ", ""));
|
||||
if (parsedEpisodeInfo == null) continue;
|
||||
|
||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
||||
if (remoteEpisode.Series == null) continue;
|
||||
|
||||
queueItem.RemoteEpisode = remoteEpisode;
|
||||
|
||||
queueItems.Add(queueItem);
|
||||
queueItem.Title = queueItem.Title.Substring(11);
|
||||
queueItem.IsEncrypted = true;
|
||||
}
|
||||
|
||||
return queueItems;
|
||||
}, TimeSpan.FromSeconds(10));
|
||||
queueItems.Add(queueItem);
|
||||
}
|
||||
|
||||
return queueItems;
|
||||
}
|
||||
|
||||
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
|
||||
private IEnumerable<DownloadClientItem> GetHistory()
|
||||
{
|
||||
SabnzbdHistory sabHistory;
|
||||
|
||||
try
|
||||
{
|
||||
sabHistory = _proxy.GetHistory(start, limit, Settings);
|
||||
sabHistory = _proxy.GetHistory(0, 0, Settings);
|
||||
}
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
_logger.ErrorException(ex.Message, ex);
|
||||
return Enumerable.Empty<HistoryItem>();
|
||||
return Enumerable.Empty<DownloadClientItem>();
|
||||
}
|
||||
|
||||
var historyItems = new List<HistoryItem>();
|
||||
var historyItems = new List<DownloadClientItem>();
|
||||
|
||||
foreach (var sabHistoryItem in sabHistory.Items)
|
||||
{
|
||||
var historyItem = new HistoryItem();
|
||||
historyItem.Id = sabHistoryItem.Id;
|
||||
historyItem.Title = sabHistoryItem.Title;
|
||||
historyItem.Size = sabHistoryItem.Size;
|
||||
historyItem.DownloadTime = sabHistoryItem.DownloadTime;
|
||||
historyItem.Storage = sabHistoryItem.Storage;
|
||||
historyItem.Category = sabHistoryItem.Category;
|
||||
historyItem.Message = sabHistoryItem.FailMessage;
|
||||
historyItem.Status = sabHistoryItem.Status == "Failed" ? HistoryStatus.Failed : HistoryStatus.Completed;
|
||||
var historyItem = new DownloadClientItem
|
||||
{
|
||||
DownloadClient = Definition.Name,
|
||||
DownloadClientId = sabHistoryItem.Id,
|
||||
Category = sabHistoryItem.Category,
|
||||
Title = sabHistoryItem.Title,
|
||||
|
||||
TotalSize = sabHistoryItem.Size,
|
||||
RemainingSize = 0,
|
||||
DownloadTime = TimeSpan.FromSeconds(sabHistoryItem.DownloadTime),
|
||||
RemainingTime = TimeSpan.Zero,
|
||||
|
||||
OutputPath = sabHistoryItem.Storage,
|
||||
Message = sabHistoryItem.FailMessage
|
||||
};
|
||||
|
||||
if (sabHistoryItem.Status == SabnzbdDownloadStatus.Failed)
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Failed;
|
||||
}
|
||||
else if (sabHistoryItem.Status == SabnzbdDownloadStatus.Completed)
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Completed;
|
||||
}
|
||||
else // Verifying/Moving etc
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
|
||||
historyItems.Add(historyItem);
|
||||
}
|
||||
|
@ -131,14 +161,29 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
return historyItems;
|
||||
}
|
||||
|
||||
public override void RemoveFromQueue(string id)
|
||||
public override IEnumerable<DownloadClientItem> GetItems()
|
||||
{
|
||||
_proxy.RemoveFrom("queue", id, Settings);
|
||||
foreach (var downloadClientItem in GetQueue().Concat(GetHistory()))
|
||||
{
|
||||
if (downloadClientItem.Category != Settings.TvCategory) continue;
|
||||
|
||||
downloadClientItem.RemoteEpisode = GetRemoteEpisode(downloadClientItem.Title);
|
||||
if (downloadClientItem.RemoteEpisode == null) continue;
|
||||
|
||||
yield return downloadClientItem;
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveFromHistory(string id)
|
||||
public override void RemoveItem(string id)
|
||||
{
|
||||
_proxy.RemoveFrom("history", id, Settings);
|
||||
if (GetQueue().Any(v => v.DownloadClientId == id))
|
||||
{
|
||||
_proxy.RemoveFrom("queue", id, Settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
_proxy.RemoveFrom("history", id, Settings);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RetryDownload(string id)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||
{
|
||||
public enum SabnzbdDownloadStatus
|
||||
{
|
||||
Grabbing,
|
||||
Queued,
|
||||
Paused,
|
||||
Checking,
|
||||
Downloading,
|
||||
QuickCheck,
|
||||
Verifying,
|
||||
Repairing,
|
||||
Fetching, // Fetching additional blocks
|
||||
Extracting,
|
||||
Moving,
|
||||
Running, // Running PP Script
|
||||
Completed,
|
||||
Failed
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||
{
|
||||
|
@ -7,7 +8,8 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
[JsonProperty(PropertyName = "fail_message")]
|
||||
public string FailMessage { get; set; }
|
||||
|
||||
public string Size { get; set; }
|
||||
[JsonProperty(PropertyName = "bytes")]
|
||||
public Int64 Size { get; set; }
|
||||
public string Category { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "nzb_name")]
|
||||
|
@ -17,7 +19,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
public int DownloadTime { get; set; }
|
||||
|
||||
public string Storage { get; set; }
|
||||
public string Status { get; set; }
|
||||
public SabnzbdDownloadStatus Status { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "nzo_id")]
|
||||
public string Id { get; set; }
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
|
||||
result.Error = response.Content.Replace("error: ", "");
|
||||
}
|
||||
|
||||
|
||||
if (result.Failed)
|
||||
throw new DownloadClientException("Error response received from SABnzbd: {0}", result.Error);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
{
|
||||
public class SabnzbdQueueItem
|
||||
{
|
||||
public string Status { get; set; }
|
||||
public SabnzbdDownloadStatus Status { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
[JsonConverter(typeof(SabnzbdQueueTimeConverter))]
|
||||
|
@ -15,8 +15,6 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
[JsonProperty(PropertyName = "mb")]
|
||||
public decimal Size { get; set; }
|
||||
|
||||
private string _title;
|
||||
|
||||
[JsonProperty(PropertyName = "filename")]
|
||||
public string Title { get; set; }
|
||||
|
||||
|
|
|
@ -13,11 +13,15 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public String Host { get; set; }
|
||||
public Int32 Port { get; set; }
|
||||
public String ApiKey { get; set; }
|
||||
public String Username { get; set; }
|
||||
public String Password { get; set; }
|
||||
public String TvCategory { get; set; }
|
||||
public Int32 RecentTvPriority { get; set; }
|
||||
public Int32 OlderTvPriority { get; set; }
|
||||
public Boolean UseSsl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||
namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
||||
{
|
||||
public class TestBlackholeCommand : Command
|
||||
public class TestUsenetBlackholeCommand : Command
|
||||
{
|
||||
public override bool SendUpdatesToClient
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
|
|||
}
|
||||
}
|
||||
|
||||
public String Folder { get; set; }
|
||||
public String NzbFolder { get; set; }
|
||||
public String WatchFolder { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
||||
{
|
||||
public class UsenetBlackhole : DownloadClientBase<UsenetBlackholeSettings>, IExecute<TestUsenetBlackholeCommand>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
private readonly IHttpProvider _httpProvider;
|
||||
|
||||
public UsenetBlackhole(IDiskProvider diskProvider,
|
||||
IDiskScanService diskScanService,
|
||||
IParsingService parsingService,
|
||||
IHttpProvider httpProvider,
|
||||
Logger logger)
|
||||
: base(parsingService, logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_diskScanService = diskScanService;
|
||||
_httpProvider = httpProvider;
|
||||
}
|
||||
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Download(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title;
|
||||
|
||||
title = FileNameBuilder.CleanFilename(title);
|
||||
|
||||
var filename = Path.Combine(Settings.NzbFolder, title + ".nzb");
|
||||
|
||||
_logger.Debug("Downloading NZB from: {0} to: {1}", url, filename);
|
||||
_httpProvider.DownloadFile(url, filename);
|
||||
_logger.Debug("NZB Download succeeded, saved to: {0}", filename);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<DownloadClientItem> GetItems()
|
||||
{
|
||||
foreach (var folder in _diskProvider.GetDirectories(Settings.WatchFolder))
|
||||
{
|
||||
var title = FileNameBuilder.CleanFilename(Path.GetFileName(folder));
|
||||
|
||||
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
|
||||
|
||||
var historyItem = new DownloadClientItem
|
||||
{
|
||||
DownloadClient = Definition.Name,
|
||||
DownloadClientId = Definition.Name + "_" + Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTimeUtc(folder).Ticks,
|
||||
Title = title,
|
||||
|
||||
TotalSize = files.Select(_diskProvider.GetFileSize).Sum(),
|
||||
|
||||
OutputPath = folder
|
||||
};
|
||||
|
||||
if (files.Any(_diskProvider.IsFileLocked))
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
else
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Completed;
|
||||
}
|
||||
|
||||
historyItem.RemoteEpisode = GetRemoteEpisode(historyItem.Title);
|
||||
if (historyItem.RemoteEpisode == null) continue;
|
||||
|
||||
yield return historyItem;
|
||||
}
|
||||
|
||||
foreach (var videoFile in _diskScanService.GetVideoFiles(Settings.WatchFolder, false))
|
||||
{
|
||||
var title = FileNameBuilder.CleanFilename(Path.GetFileName(videoFile));
|
||||
|
||||
var historyItem = new DownloadClientItem
|
||||
{
|
||||
DownloadClient = Definition.Name,
|
||||
DownloadClientId = Definition.Name + "_" + Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWriteUtc(videoFile).Ticks,
|
||||
Title = title,
|
||||
|
||||
TotalSize = _diskProvider.GetFileSize(videoFile),
|
||||
|
||||
OutputPath = videoFile
|
||||
};
|
||||
|
||||
if (_diskProvider.IsFileLocked(videoFile))
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
else
|
||||
{
|
||||
historyItem.Status = DownloadItemStatus.Completed;
|
||||
}
|
||||
|
||||
historyItem.RemoteEpisode = GetRemoteEpisode(historyItem.Title);
|
||||
if (historyItem.RemoteEpisode == null) continue;
|
||||
|
||||
yield return historyItem;
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveItem(string id)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void RetryDownload(string id)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Test()
|
||||
{
|
||||
PerformTest(Settings.NzbFolder);
|
||||
PerformTest(Settings.WatchFolder);
|
||||
}
|
||||
|
||||
private void PerformTest(string folder)
|
||||
{
|
||||
var testPath = Path.Combine(folder, "drone_test.txt");
|
||||
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
|
||||
_diskProvider.DeleteFile(testPath);
|
||||
}
|
||||
|
||||
public void Execute(TestUsenetBlackholeCommand message)
|
||||
{
|
||||
PerformTest(Settings.NzbFolder);
|
||||
PerformTest(Settings.WatchFolder);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
||||
{
|
||||
public class UsenetBlackholeSettingsValidator : AbstractValidator<UsenetBlackholeSettings>
|
||||
{
|
||||
public UsenetBlackholeSettingsValidator()
|
||||
{
|
||||
//Todo: Validate that the path actually exists
|
||||
RuleFor(c => c.NzbFolder).IsValidPath();
|
||||
}
|
||||
}
|
||||
|
||||
public class UsenetBlackholeSettings : IProviderConfig
|
||||
{
|
||||
private static readonly UsenetBlackholeSettingsValidator Validator = new UsenetBlackholeSettingsValidator();
|
||||
|
||||
[FieldDefinition(0, Label = "Nzb Folder", Type = FieldType.Path)]
|
||||
public String NzbFolder { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path)]
|
||||
public String WatchFolder { get; set; }
|
||||
|
||||
public ValidationResult Validate()
|
||||
{
|
||||
return Validator.Validate(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using System.IO;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public interface ICompletedDownloadService
|
||||
{
|
||||
void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> importedHistory);
|
||||
}
|
||||
|
||||
public class CompletedDownloadService : ICompletedDownloadService
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
IDiskProvider diskProvider,
|
||||
IDownloadedEpisodesImportService downloadedEpisodesImportService,
|
||||
Logger logger)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_diskProvider = diskProvider;
|
||||
_downloadedEpisodesImportService = downloadedEpisodesImportService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> importedHistory)
|
||||
{
|
||||
if (!_configService.EnableCompletedDownloadHandling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackedDownload.DownloadItem.Status == DownloadItemStatus.Completed && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||
{
|
||||
var grabbedItems = GetHistoryItems(grabbedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (!grabbedItems.Any() && trackedDownload.DownloadItem.Category.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Trace("Ignoring download that wasn't grabbed by drone: " + trackedDownload.DownloadItem.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
var importedItems = GetHistoryItems(importedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (importedItems.Any())
|
||||
{
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
|
||||
_logger.Debug("Already added to history as imported: " + trackedDownload.DownloadItem.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
string downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
|
||||
string downloadItemOutputPath = trackedDownload.DownloadItem.OutputPath;
|
||||
if (downloadItemOutputPath.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Trace("Storage path not specified: " + trackedDownload.DownloadItem.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!downloadedEpisodesFolder.IsNullOrWhiteSpace() && (downloadedEpisodesFolder.PathEquals(downloadItemOutputPath) || downloadedEpisodesFolder.IsParentPath(downloadItemOutputPath)))
|
||||
{
|
||||
_logger.Trace("Storage path inside drone factory, ignoring download: " + trackedDownload.DownloadItem.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
var decisions = _downloadedEpisodesImportService.ProcessFolder(new DirectoryInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
|
||||
|
||||
if (decisions.Any())
|
||||
{
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
}
|
||||
}
|
||||
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
var decisions = _downloadedEpisodesImportService.ProcessFile(new FileInfo(trackedDownload.DownloadItem.OutputPath), trackedDownload.DownloadItem);
|
||||
|
||||
if (decisions.Any())
|
||||
{
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Storage path does not exist: " + trackedDownload.DownloadItem.Title);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_configService.RemoveCompletedDownloads && trackedDownload.State == TrackedDownloadState.Imported && !trackedDownload.DownloadItem.IsReadOnly)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Removing completed download from history: {0}", trackedDownload.DownloadItem.Title);
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
_logger.Info("Removing completed download directory: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath, true);
|
||||
}
|
||||
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
|
||||
{
|
||||
_logger.Info("Removing completed download file: {0}", trackedDownload.DownloadItem.OutputPath);
|
||||
_diskProvider.DeleteFile(trackedDownload.DownloadItem.OutputPath);
|
||||
}
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Removed;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_logger.Debug("Removing item not supported by your download client");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,20 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public abstract class DownloadClientBase<TSettings> : IDownloadClient where TSettings : IProviderConfig, new()
|
||||
public abstract class DownloadClientBase<TSettings> : IDownloadClient
|
||||
where TSettings : IProviderConfig, new()
|
||||
{
|
||||
private readonly IParsingService _parsingService;
|
||||
protected readonly Logger _logger;
|
||||
|
||||
public Type ConfigContract
|
||||
{
|
||||
get
|
||||
|
@ -33,17 +41,39 @@ namespace NzbDrone.Core.Download
|
|||
}
|
||||
}
|
||||
|
||||
protected DownloadClientBase(IParsingService parsingService, Logger logger)
|
||||
{
|
||||
_parsingService = parsingService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetType().Name;
|
||||
}
|
||||
|
||||
public abstract string DownloadNzb(RemoteEpisode remoteEpisode);
|
||||
public abstract IEnumerable<QueueItem> GetQueue();
|
||||
public abstract IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10);
|
||||
public abstract void RemoveFromQueue(string id);
|
||||
public abstract void RemoveFromHistory(string id);
|
||||
|
||||
|
||||
public abstract DownloadProtocol Protocol
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract string Download(RemoteEpisode remoteEpisode);
|
||||
public abstract IEnumerable<DownloadClientItem> GetItems();
|
||||
public abstract void RemoveItem(string id);
|
||||
public abstract void RetryDownload(string id);
|
||||
public abstract void Test();
|
||||
|
||||
protected RemoteEpisode GetRemoteEpisode(String title)
|
||||
{
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(title);
|
||||
if (parsedEpisodeInfo == null) return null;
|
||||
|
||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
|
||||
if (remoteEpisode.Series == null) return null;
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
public interface IDownloadClientFactory : IProviderFactory<IDownloadClient, DownloadClientDefinition>
|
||||
{
|
||||
List<IDownloadClient> Enabled();
|
||||
|
||||
}
|
||||
|
||||
public class DownloadClientFactory : ProviderFactory<IDownloadClient, DownloadClientDefinition>, IDownloadClientFactory
|
||||
|
@ -22,9 +22,18 @@ namespace NzbDrone.Core.Download
|
|||
_providerRepository = providerRepository;
|
||||
}
|
||||
|
||||
public List<IDownloadClient> Enabled()
|
||||
protected override List<DownloadClientDefinition> Active()
|
||||
{
|
||||
return GetAvailableProviders().Where(n => ((DownloadClientDefinition)n.Definition).Enable).ToList();
|
||||
return base.Active().Where(c => c.Enable).ToList();
|
||||
}
|
||||
|
||||
protected override DownloadClientDefinition GetTemplate(IDownloadClient provider)
|
||||
{
|
||||
var definition = base.GetTemplate(provider);
|
||||
|
||||
definition.Protocol = provider.Protocol;
|
||||
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class DownloadClientItem
|
||||
{
|
||||
public string DownloadClient { get; set; }
|
||||
public string DownloadClientId { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public long TotalSize { get; set; }
|
||||
public long RemainingSize { get; set; }
|
||||
public TimeSpan DownloadTime { get; set; }
|
||||
public TimeSpan RemainingTime { get; set; }
|
||||
|
||||
public string OutputPath { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public DownloadItemStatus Status { get; set; }
|
||||
public bool IsEncrypted { get; set; }
|
||||
public bool IsReadOnly { get; set; }
|
||||
public RemoteEpisode RemoteEpisode { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public interface IProvideDownloadClient
|
||||
{
|
||||
IDownloadClient GetDownloadClient();
|
||||
IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol);
|
||||
IEnumerable<IDownloadClient> GetDownloadClients();
|
||||
}
|
||||
|
||||
public class DownloadClientProvider : IProvideDownloadClient
|
||||
|
@ -16,9 +20,14 @@ namespace NzbDrone.Core.Download
|
|||
_downloadClientFactory = downloadClientFactory;
|
||||
}
|
||||
|
||||
public IDownloadClient GetDownloadClient()
|
||||
public IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol)
|
||||
{
|
||||
return _downloadClientFactory.Enabled().FirstOrDefault();
|
||||
return _downloadClientFactory.GetAvailableProviders().FirstOrDefault(v => v.Protocol == downloadProtocol);
|
||||
}
|
||||
|
||||
public IEnumerable<IDownloadClient> GetDownloadClients()
|
||||
{
|
||||
return _downloadClientFactory.GetAvailableProviders();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public enum DownloadItemStatus
|
||||
{
|
||||
Queued = 0,
|
||||
Paused = 1,
|
||||
Downloading = 2,
|
||||
Completed = 3,
|
||||
Failed = 4
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ namespace NzbDrone.Core.Download
|
|||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
||||
public DownloadService(IProvideDownloadClient downloadClientProvider,
|
||||
IEventAggregator eventAggregator, Logger logger)
|
||||
{
|
||||
|
@ -34,15 +33,15 @@ namespace NzbDrone.Core.Download
|
|||
Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems();
|
||||
|
||||
var downloadTitle = remoteEpisode.Release.Title;
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteEpisode.Release.DownloadProtocol);
|
||||
|
||||
if (downloadClient == null)
|
||||
{
|
||||
_logger.Warn("Download client isn't configured yet.");
|
||||
_logger.Warn("{0} Download client isn't configured yet.", remoteEpisode.Release.DownloadProtocol);
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadClientId = downloadClient.DownloadNzb(remoteEpisode);
|
||||
var downloadClientId = downloadClient.Download(remoteEpisode);
|
||||
var episodeGrabbedEvent = new EpisodeGrabbedEvent(remoteEpisode);
|
||||
episodeGrabbedEvent.DownloadClient = downloadClient.GetType().Name;
|
||||
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Queue;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public interface IDownloadTrackingService
|
||||
{
|
||||
List<TrackedDownload> GetTrackedDownloads();
|
||||
List<TrackedDownload> GetCompletedDownloads();
|
||||
List<TrackedDownload> GetQueuedDownloads();
|
||||
}
|
||||
|
||||
public class DownloadTrackingService : IDownloadTrackingService, IExecute<CheckForFinishedDownloadCommand>, IHandle<ApplicationStartedEvent>
|
||||
{
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IFailedDownloadService _failedDownloadService;
|
||||
private readonly ICompletedDownloadService _completedDownloadService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private readonly ICached<TrackedDownload> _trackedDownloads;
|
||||
private readonly ICached<List<TrackedDownload>> _queuedDownloads;
|
||||
|
||||
public static string DOWNLOAD_CLIENT = "downloadClient";
|
||||
public static string DOWNLOAD_CLIENT_ID = "downloadClientId";
|
||||
|
||||
public DownloadTrackingService(IProvideDownloadClient downloadClientProvider,
|
||||
IHistoryService historyService,
|
||||
IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
ICacheManager cacheManager,
|
||||
IFailedDownloadService failedDownloadService,
|
||||
ICompletedDownloadService completedDownloadService,
|
||||
Logger logger)
|
||||
{
|
||||
_downloadClientProvider = downloadClientProvider;
|
||||
_historyService = historyService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_failedDownloadService = failedDownloadService;
|
||||
_completedDownloadService = completedDownloadService;
|
||||
_logger = logger;
|
||||
|
||||
_trackedDownloads = cacheManager.GetCache<TrackedDownload>(GetType());
|
||||
_queuedDownloads = cacheManager.GetCache<List<TrackedDownload>>(GetType(), "queued");
|
||||
}
|
||||
|
||||
public List<TrackedDownload> GetTrackedDownloads()
|
||||
{
|
||||
return _trackedDownloads.Values.ToList();
|
||||
}
|
||||
|
||||
public List<TrackedDownload> GetCompletedDownloads()
|
||||
{
|
||||
return _trackedDownloads.Values.Where(v => v.State == TrackedDownloadState.Downloading && v.DownloadItem.Status == DownloadItemStatus.Completed).ToList();
|
||||
}
|
||||
|
||||
public List<TrackedDownload> GetQueuedDownloads()
|
||||
{
|
||||
return _queuedDownloads.Get("queued", () =>
|
||||
{
|
||||
UpdateTrackedDownloads();
|
||||
|
||||
var enabledFailedDownloadHandling = _configService.EnableFailedDownloadHandling;
|
||||
var enabledCompletedDownloadHandling = _configService.EnableCompletedDownloadHandling;
|
||||
|
||||
return _trackedDownloads.Values
|
||||
.Where(v => v.State == TrackedDownloadState.Downloading)
|
||||
.Where(v =>
|
||||
v.DownloadItem.Status == DownloadItemStatus.Queued ||
|
||||
v.DownloadItem.Status == DownloadItemStatus.Paused ||
|
||||
v.DownloadItem.Status == DownloadItemStatus.Downloading ||
|
||||
v.DownloadItem.Status == DownloadItemStatus.Failed && enabledFailedDownloadHandling ||
|
||||
v.DownloadItem.Status == DownloadItemStatus.Completed && enabledCompletedDownloadHandling)
|
||||
.ToList();
|
||||
|
||||
}, TimeSpan.FromSeconds(5.0));
|
||||
}
|
||||
|
||||
private TrackedDownload GetTrackedDownload(IDownloadClient downloadClient, DownloadClientItem queueItem)
|
||||
{
|
||||
var id = String.Format("{0}-{1}", downloadClient.Definition.Id, queueItem.DownloadClientId);
|
||||
var trackedDownload = _trackedDownloads.Get(id, () => new TrackedDownload
|
||||
{
|
||||
TrackingId = id,
|
||||
DownloadClient = downloadClient.Definition.Id,
|
||||
StartedTracking = DateTime.UtcNow,
|
||||
State = TrackedDownloadState.Unknown
|
||||
});
|
||||
|
||||
trackedDownload.DownloadItem = queueItem;
|
||||
|
||||
return trackedDownload;
|
||||
}
|
||||
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
private Boolean UpdateTrackedDownloads()
|
||||
{
|
||||
var downloadClients = _downloadClientProvider.GetDownloadClients();
|
||||
|
||||
var oldTrackedDownloads = new HashSet<TrackedDownload>(_trackedDownloads.Values);
|
||||
var newTrackedDownloads = new HashSet<TrackedDownload>();
|
||||
|
||||
var stateChanged = false;
|
||||
|
||||
foreach (var downloadClient in downloadClients)
|
||||
{
|
||||
var downloadClientHistory = downloadClient.GetItems().Select(v => GetTrackedDownload(downloadClient, v)).ToList();
|
||||
foreach (var trackedDownload in downloadClientHistory)
|
||||
{
|
||||
if (!oldTrackedDownloads.Contains(trackedDownload))
|
||||
{
|
||||
_logger.Trace("Started tracking download from history: {0}", trackedDownload.TrackingId);
|
||||
stateChanged = true;
|
||||
}
|
||||
|
||||
newTrackedDownloads.Add(trackedDownload);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in oldTrackedDownloads.Except(newTrackedDownloads))
|
||||
{
|
||||
if (item.State != TrackedDownloadState.Removed)
|
||||
{
|
||||
item.State = TrackedDownloadState.Removed;
|
||||
stateChanged = true;
|
||||
|
||||
_logger.Debug("Item removed from download client by user: {0}", item.TrackingId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in newTrackedDownloads.Union(oldTrackedDownloads).Where(v => v.State == TrackedDownloadState.Removed))
|
||||
{
|
||||
_trackedDownloads.Remove(item.TrackingId);
|
||||
|
||||
_logger.Trace("Stopped tracking download: {0}", item.TrackingId);
|
||||
}
|
||||
|
||||
_queuedDownloads.Clear();
|
||||
|
||||
return stateChanged;
|
||||
}
|
||||
|
||||
private void ProcessTrackedDownloads()
|
||||
{
|
||||
var grabbedHistory = _historyService.Grabbed();
|
||||
var failedHistory = _historyService.Failed();
|
||||
var importedHistory = _historyService.Imported();
|
||||
|
||||
var stateChanged = UpdateTrackedDownloads();
|
||||
|
||||
var downloadClients = _downloadClientProvider.GetDownloadClients();
|
||||
var trackedDownloads = _trackedDownloads.Values.ToArray();
|
||||
|
||||
foreach (var trackedDownload in trackedDownloads)
|
||||
{
|
||||
var downloadClient = downloadClients.Single(v => v.Definition.Id == trackedDownload.DownloadClient);
|
||||
|
||||
var state = trackedDownload.State;
|
||||
|
||||
if (trackedDownload.State == TrackedDownloadState.Unknown)
|
||||
{
|
||||
trackedDownload.State = TrackedDownloadState.Downloading;
|
||||
}
|
||||
|
||||
_failedDownloadService.CheckForFailedItem(downloadClient, trackedDownload, grabbedHistory, failedHistory);
|
||||
_completedDownloadService.CheckForCompletedItem(downloadClient, trackedDownload, grabbedHistory, importedHistory);
|
||||
|
||||
if (state != trackedDownload.State)
|
||||
{
|
||||
stateChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (stateChanged)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new UpdateQueueEvent());
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(CheckForFinishedDownloadCommand message)
|
||||
{
|
||||
ProcessTrackedDownloads();
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
ProcessTrackedDownloads();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Download.Events
|
||||
{
|
||||
public class DownloadFailedEvent : IEvent
|
||||
{
|
||||
public Int32 SeriesId { get; set; }
|
||||
public List<Int32> EpisodeIds { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public String SourceTitle { get; set; }
|
||||
public String DownloadClient { get; set; }
|
||||
public String DownloadClientId { get; set; }
|
||||
public String Message { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.Events
|
||||
{
|
||||
public class EpisodeGrabbedEvent : IEvent
|
||||
{
|
||||
public RemoteEpisode Episode { get; private set; }
|
||||
public String DownloadClient { get; set; }
|
||||
public String DownloadClientId { get; set; }
|
||||
|
||||
public EpisodeGrabbedEvent(RemoteEpisode episode)
|
||||
{
|
||||
Episode = episode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class FailedDownload
|
||||
{
|
||||
public HistoryItem DownloadClientHistoryItem { get; set; }
|
||||
public DateTime LastRetry { get; set; }
|
||||
public Int32 RetryCount { get; set; }
|
||||
}
|
||||
}
|
|
@ -14,35 +14,25 @@ namespace NzbDrone.Core.Download
|
|||
public interface IFailedDownloadService
|
||||
{
|
||||
void MarkAsFailed(int historyId);
|
||||
void CheckForFailedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> failedHistory);
|
||||
}
|
||||
|
||||
public class FailedDownloadService : IFailedDownloadService, IExecute<CheckForFailedDownloadCommand>
|
||||
public class FailedDownloadService : IFailedDownloadService
|
||||
{
|
||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private readonly ICached<FailedDownload> _failedDownloads;
|
||||
|
||||
private static string DOWNLOAD_CLIENT = "downloadClient";
|
||||
private static string DOWNLOAD_CLIENT_ID = "downloadClientId";
|
||||
|
||||
public FailedDownloadService(IProvideDownloadClient downloadClientProvider,
|
||||
IHistoryService historyService,
|
||||
public FailedDownloadService(IHistoryService historyService,
|
||||
IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
ICacheManager cacheManager,
|
||||
Logger logger)
|
||||
{
|
||||
_downloadClientProvider = downloadClientProvider;
|
||||
_historyService = historyService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
|
||||
_failedDownloads = cacheManager.GetCache<FailedDownload>(GetType());
|
||||
}
|
||||
|
||||
public void MarkAsFailed(int historyId)
|
||||
|
@ -51,149 +41,92 @@ namespace NzbDrone.Core.Download
|
|||
PublishDownloadFailedEvent(new List<History.History> { item }, "Manually marked as failed");
|
||||
}
|
||||
|
||||
private void CheckQueue(List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
public void CheckForFailedItem(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
{
|
||||
var downloadClient = GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
if (!_configService.EnableFailedDownloadHandling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadClientQueue = downloadClient.GetQueue().ToList();
|
||||
var failedItems = downloadClientQueue.Where(q => q.Title.StartsWith("ENCRYPTED / ")).ToList();
|
||||
|
||||
if (!failedItems.Any())
|
||||
if (trackedDownload.DownloadItem.IsEncrypted && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||
{
|
||||
_logger.Debug("Yay! No encrypted downloads");
|
||||
return;
|
||||
}
|
||||
var grabbedItems = GetHistoryItems(grabbedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
foreach (var failedItem in failedItems)
|
||||
{
|
||||
var failedLocal = failedItem;
|
||||
var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id);
|
||||
|
||||
if (!historyItems.Any())
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Debug("Unable to find matching history item");
|
||||
continue;
|
||||
_logger.Debug("Download was not grabbed by drone, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (failedHistory.Any(h => failedLocal.Id.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID))))
|
||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||
|
||||
var failedItems = GetHistoryItems(failedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Already added to history as failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishDownloadFailedEvent(historyItems, "Encrypted download detected");
|
||||
|
||||
if (_configService.RemoveFailedDownloads)
|
||||
else
|
||||
{
|
||||
_logger.Info("Removing encrypted download from queue: {0}", failedItem.Title.Replace("ENCRYPTED / ", ""));
|
||||
downloadClient.RemoveFromQueue(failedItem.Id);
|
||||
PublishDownloadFailedEvent(grabbedItems, "Encrypted download detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckHistory(List<History.History> grabbedHistory, List<History.History> failedHistory)
|
||||
{
|
||||
var downloadClient = GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
if (trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var grabbedItems = GetHistoryItems(grabbedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
var downloadClientHistory = downloadClient.GetHistory(0, 20).ToList();
|
||||
var failedItems = downloadClientHistory.Where(h => h.Status == HistoryStatus.Failed).ToList();
|
||||
|
||||
if (!failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Yay! No failed downloads");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var failedItem in failedItems)
|
||||
{
|
||||
var failedLocal = failedItem;
|
||||
var historyItems = GetHistoryItems(grabbedHistory, failedLocal.Id);
|
||||
|
||||
if (!historyItems.Any())
|
||||
if (!grabbedItems.Any())
|
||||
{
|
||||
_logger.Debug("Unable to find matching history item");
|
||||
continue;
|
||||
_logger.Debug("Download was not grabbed by drone, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Make this more configurable (ignore failure reasons) to support changes and other failures that should be ignored
|
||||
if (failedLocal.Message.Equals("Unpacking failed, write error or disk is full?",
|
||||
if (trackedDownload.DownloadItem.Message.Equals("Unpacking failed, write error or disk is full?",
|
||||
StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Failed due to lack of disk space, do not blacklist");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FailedDownloadForRecentRelease(failedItem, historyItems))
|
||||
if (FailedDownloadForRecentRelease(downloadClient, trackedDownload, grabbedItems))
|
||||
{
|
||||
_logger.Debug("Recent release Failed, do not blacklist");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (failedHistory.Any(h => failedLocal.Id.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID))))
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||
|
||||
var failedItems = GetHistoryItems(failedHistory, trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
if (failedItems.Any())
|
||||
{
|
||||
_logger.Debug("Already added to history as failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishDownloadFailedEvent(historyItems, failedItem.Message);
|
||||
|
||||
if (_configService.RemoveFailedDownloads)
|
||||
else
|
||||
{
|
||||
_logger.Info("Removing failed download from history: {0}", failedItem.Title);
|
||||
downloadClient.RemoveFromHistory(failedItem.Id);
|
||||
PublishDownloadFailedEvent(grabbedItems, trackedDownload.DownloadItem.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (_configService.RemoveFailedDownloads && trackedDownload.State == TrackedDownloadState.DownloadFailed)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Removing failed download from client: {0}", trackedDownload.DownloadItem.Title);
|
||||
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Removed;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
_logger.Debug("Removing item not supported by your download client");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void PublishDownloadFailedEvent(List<History.History> historyItems, string message)
|
||||
{
|
||||
var historyItem = historyItems.First();
|
||||
|
||||
var downloadFailedEvent = new DownloadFailedEvent
|
||||
{
|
||||
SeriesId = historyItem.SeriesId,
|
||||
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(),
|
||||
Quality = historyItem.Quality,
|
||||
SourceTitle = historyItem.SourceTitle,
|
||||
DownloadClient = historyItem.Data.GetValueOrDefault(DOWNLOAD_CLIENT),
|
||||
DownloadClientId = historyItem.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID),
|
||||
Message = message
|
||||
};
|
||||
|
||||
downloadFailedEvent.Data = downloadFailedEvent.Data.Merge(historyItem.Data);
|
||||
|
||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||
}
|
||||
|
||||
private IDownloadClient GetDownloadClient()
|
||||
{
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
|
||||
if (downloadClient == null)
|
||||
{
|
||||
_logger.Debug("No download client is configured");
|
||||
}
|
||||
|
||||
return downloadClient;
|
||||
}
|
||||
|
||||
private bool FailedDownloadForRecentRelease(HistoryItem failedDownloadHistoryItem, List<History.History> matchingHistoryItems)
|
||||
private bool FailedDownloadForRecentRelease(IDownloadClient downloadClient, TrackedDownload trackedDownload, List<History.History> matchingHistoryItems)
|
||||
{
|
||||
double ageHours;
|
||||
|
||||
|
@ -209,31 +142,23 @@ namespace NzbDrone.Core.Download
|
|||
return false;
|
||||
}
|
||||
|
||||
var tracked = _failedDownloads.Get(failedDownloadHistoryItem.Id, () => new FailedDownload
|
||||
{
|
||||
DownloadClientHistoryItem = failedDownloadHistoryItem,
|
||||
LastRetry = DateTime.UtcNow
|
||||
}
|
||||
);
|
||||
|
||||
if (tracked.RetryCount >= _configService.BlacklistRetryLimit)
|
||||
if (trackedDownload.RetryCount >= _configService.BlacklistRetryLimit)
|
||||
{
|
||||
_logger.Debug("Retry limit reached");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tracked.LastRetry.AddMinutes(_configService.BlacklistRetryInterval) < DateTime.UtcNow)
|
||||
if (trackedDownload.RetryCount == 0 || trackedDownload.LastRetry.AddMinutes(_configService.BlacklistRetryInterval) < DateTime.UtcNow)
|
||||
{
|
||||
_logger.Debug("Retrying failed release");
|
||||
tracked.LastRetry = DateTime.UtcNow;
|
||||
tracked.RetryCount++;
|
||||
trackedDownload.LastRetry = DateTime.UtcNow;
|
||||
trackedDownload.RetryCount++;
|
||||
|
||||
try
|
||||
{
|
||||
GetDownloadClient().RetryDownload(failedDownloadHistoryItem.Id);
|
||||
downloadClient.RetryDownload(trackedDownload.DownloadItem.DownloadClientId);
|
||||
}
|
||||
|
||||
catch (NotImplementedException ex)
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
_logger.Debug("Retrying failed downloads is not supported by your download client");
|
||||
return false;
|
||||
|
@ -243,19 +168,30 @@ namespace NzbDrone.Core.Download
|
|||
return true;
|
||||
}
|
||||
|
||||
public void Execute(CheckForFailedDownloadCommand message)
|
||||
private List<History.History> GetHistoryItems(List<History.History> grabbedHistory, string downloadClientId)
|
||||
{
|
||||
if (!_configService.EnableFailedDownloadHandling)
|
||||
return grabbedHistory.Where(h => downloadClientId.Equals(h.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT_ID)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void PublishDownloadFailedEvent(List<History.History> historyItems, string message)
|
||||
{
|
||||
var historyItem = historyItems.First();
|
||||
|
||||
var downloadFailedEvent = new DownloadFailedEvent
|
||||
{
|
||||
_logger.Debug("Failed Download Handling is not enabled");
|
||||
return;
|
||||
}
|
||||
SeriesId = historyItem.SeriesId,
|
||||
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(),
|
||||
Quality = historyItem.Quality,
|
||||
SourceTitle = historyItem.SourceTitle,
|
||||
DownloadClient = historyItem.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT),
|
||||
DownloadClientId = historyItem.Data.GetValueOrDefault(DownloadTrackingService.DOWNLOAD_CLIENT_ID),
|
||||
Message = message
|
||||
};
|
||||
|
||||
var grabbedHistory = _historyService.Grabbed();
|
||||
var failedHistory = _historyService.Failed();
|
||||
downloadFailedEvent.Data = downloadFailedEvent.Data.Merge(historyItem.Data);
|
||||
|
||||
CheckQueue(grabbedHistory, failedHistory);
|
||||
CheckHistory(grabbedHistory, failedHistory);
|
||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class HistoryItem
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String Size { get; set; }
|
||||
public String Category { get; set; }
|
||||
public Int32 DownloadTime { get; set; }
|
||||
public String Storage { get; set; }
|
||||
public String Message { get; set; }
|
||||
public HistoryStatus Status { get; set; }
|
||||
}
|
||||
|
||||
public enum HistoryStatus
|
||||
{
|
||||
Completed = 0,
|
||||
Failed = 1
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
|
@ -6,11 +7,11 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
public interface IDownloadClient : IProvider
|
||||
{
|
||||
string DownloadNzb(RemoteEpisode remoteEpisode);
|
||||
IEnumerable<QueueItem> GetQueue();
|
||||
IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0);
|
||||
void RemoveFromQueue(string id);
|
||||
void RemoveFromHistory(string id);
|
||||
DownloadProtocol Protocol { get; }
|
||||
|
||||
string Download(RemoteEpisode remoteEpisode);
|
||||
IEnumerable<DownloadClientItem> GetItems();
|
||||
void RemoveItem(string id);
|
||||
void RetryDownload(string id);
|
||||
void Test();
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class QueueItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public decimal Size { get; set; }
|
||||
public string Title { get; set; }
|
||||
public decimal Sizeleft { get; set; }
|
||||
public TimeSpan Timeleft { get; set; }
|
||||
public String Status { get; set; }
|
||||
public RemoteEpisode RemoteEpisode { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class TrackedDownload
|
||||
{
|
||||
public String TrackingId { get; set; }
|
||||
public Int32 DownloadClient { get; set; }
|
||||
public DownloadClientItem DownloadItem { get; set; }
|
||||
public TrackedDownloadState State { get; set; }
|
||||
public DateTime StartedTracking { get; set; }
|
||||
public DateTime LastRetry { get; set; }
|
||||
public Int32 RetryCount { get; set; }
|
||||
}
|
||||
|
||||
public enum TrackedDownloadState
|
||||
{
|
||||
Unknown,
|
||||
Downloading,
|
||||
Imported,
|
||||
DownloadFailed,
|
||||
Removed
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.HealthCheck.Checks
|
||||
|
@ -14,16 +15,19 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||
|
||||
public override HealthCheck Check()
|
||||
{
|
||||
var downloadClient = _downloadClientProvider.GetDownloadClient();
|
||||
var downloadClients = _downloadClientProvider.GetDownloadClients();
|
||||
|
||||
if (downloadClient == null)
|
||||
if (downloadClients.Count() == 0)
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, "No download client is available");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
downloadClient.GetQueue();
|
||||
foreach (var downloadClient in downloadClients)
|
||||
{
|
||||
downloadClient.GetItems();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||
|
||||
if (droneFactoryFolder.IsNullOrWhiteSpace())
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Drone factory folder is not configured");
|
||||
return new HealthCheck(GetType());
|
||||
}
|
||||
|
||||
if (!_diskProvider.FolderExists(droneFactoryFolder))
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.HealthCheck.Checks
|
||||
{
|
||||
public class ImportMechanismCheck : HealthCheckBase
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IDownloadTrackingService _downloadTrackingService;
|
||||
|
||||
public ImportMechanismCheck(IConfigService configService, IDownloadTrackingService downloadTrackingService)
|
||||
{
|
||||
_configService = configService;
|
||||
_downloadTrackingService = downloadTrackingService;
|
||||
}
|
||||
|
||||
public override HealthCheck Check()
|
||||
{
|
||||
if (!_configService.IsDefined("EnableCompletedDownloadHandling"))
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Completed Download Handling is disabled");
|
||||
}
|
||||
|
||||
var droneFactoryFolder = _configService.DownloadedEpisodesFolder;
|
||||
|
||||
if (!_configService.EnableCompletedDownloadHandling && droneFactoryFolder.IsNullOrWhiteSpace())
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Enable Completed Download Handling or configure Drone factory");
|
||||
}
|
||||
|
||||
if (_configService.EnableCompletedDownloadHandling && !droneFactoryFolder.IsNullOrWhiteSpace() && _downloadTrackingService.GetCompletedDownloads().Any(v => droneFactoryFolder.PathEquals(v.DownloadItem.OutputPath) || droneFactoryFolder.IsParentPath(v.DownloadItem.OutputPath)))
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Download Client has history items in Drone Factory conflicting with Completed Download Handling");
|
||||
}
|
||||
|
||||
return new HealthCheck(GetType());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ namespace NzbDrone.Core.History
|
|||
List<History> BetweenDates(DateTime startDate, DateTime endDate, HistoryEventType eventType);
|
||||
List<History> Failed();
|
||||
List<History> Grabbed();
|
||||
List<History> Imported();
|
||||
History MostRecentForEpisode(int episodeId);
|
||||
List<History> FindBySourceTitle(string sourceTitle);
|
||||
}
|
||||
|
@ -62,6 +63,11 @@ namespace NzbDrone.Core.History
|
|||
return Query.Where(h => h.EventType == HistoryEventType.Grabbed);
|
||||
}
|
||||
|
||||
public List<History> Imported()
|
||||
{
|
||||
return Query.Where(h => h.EventType == HistoryEventType.DownloadFolderImported);
|
||||
}
|
||||
|
||||
public History MostRecentForEpisode(int episodeId)
|
||||
{
|
||||
return Query.Where(h => h.EpisodeId == episodeId)
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace NzbDrone.Core.History
|
|||
List<History> BetweenDates(DateTime startDate, DateTime endDate, HistoryEventType eventType);
|
||||
List<History> Failed();
|
||||
List<History> Grabbed();
|
||||
List<History> Imported();
|
||||
History MostRecentForEpisode(int episodeId);
|
||||
History Get(int id);
|
||||
List<History> FindBySourceTitle(string sourceTitle);
|
||||
|
@ -62,6 +63,11 @@ namespace NzbDrone.Core.History
|
|||
return _historyRepository.Grabbed();
|
||||
}
|
||||
|
||||
public List<History> Imported()
|
||||
{
|
||||
return _historyRepository.Imported();
|
||||
}
|
||||
|
||||
public History MostRecentForEpisode(int episodeId)
|
||||
{
|
||||
return _historyRepository.MostRecentForEpisode(episodeId);
|
||||
|
@ -149,6 +155,8 @@ namespace NzbDrone.Core.History
|
|||
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
|
||||
history.Data.Add("DroppedPath", message.EpisodeInfo.Path);
|
||||
history.Data.Add("ImportedPath", message.ImportedEpisode.Path);
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
history.Data.Add("DownloadClientId", message.DownloadClientId);
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
public enum DownloadProtocol
|
||||
{
|
||||
Usenet = 1,
|
||||
Torrent = 2
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
public enum DownloadProtocols
|
||||
{
|
||||
Nzb = 0,
|
||||
Torrent =1
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Eztv
|
||||
{
|
||||
public class Eztv : IndexerBase<NullConfig>
|
||||
{
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Torrent;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsPaging
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override IParseFeed Parser
|
||||
{
|
||||
get
|
||||
{
|
||||
return new BasicTorrentRssParser();
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> RecentFeed
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "http://www.ezrss.it/feed/";
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
yield return string.Format("http://www.ezrss.it/search/index.php?show_name={0}&season={1}&episode={2}&mode=rss", seriesTitle, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset)
|
||||
{
|
||||
yield return string.Format("http://www.ezrss.it/search/index.php?show_name={0}&season={1}&mode=rss", seriesTitle, seasonNumber);
|
||||
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date)
|
||||
{
|
||||
//EZTV doesn't support searching based on actual episode airdate. they only support release date.
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetSearchUrls(string query, int offset)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace NzbDrone.Core.Indexers
|
|||
{
|
||||
IParseFeed Parser { get; }
|
||||
DownloadProtocol Protocol { get; }
|
||||
Int32 SupportedPageSize { get; }
|
||||
Boolean SupportsPaging { get; }
|
||||
Boolean SupportsSearching { get; }
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
public abstract DownloadProtocol Protocol { get; }
|
||||
|
||||
public abstract bool SupportsPaging { get; }
|
||||
public virtual bool SupportsSearching { get { return true; } }
|
||||
public virtual Boolean SupportsFeed { get { return true; } }
|
||||
public virtual Int32 SupportedPageSize { get { return 0; } }
|
||||
public bool SupportsPaging { get { return SupportedPageSize > 0; } }
|
||||
public virtual Boolean SupportsSearching { get { return true; } }
|
||||
|
||||
protected TSettings Settings
|
||||
{
|
||||
|
@ -58,10 +60,4 @@ namespace NzbDrone.Core.Indexers
|
|||
return Definition.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DownloadProtocol
|
||||
{
|
||||
Usenet = 1,
|
||||
Torrent = 2
|
||||
}
|
||||
}
|
|
@ -5,5 +5,7 @@ namespace NzbDrone.Core.Indexers
|
|||
public class IndexerDefinition : ProviderDefinition
|
||||
{
|
||||
public bool Enable { get; set; }
|
||||
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
}
|
||||
}
|
|
@ -31,17 +31,7 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
protected override void InitializeProviders()
|
||||
{
|
||||
var definitions = _providers.Where(c => c.Protocol == DownloadProtocol.Usenet)
|
||||
.SelectMany(indexer => indexer.DefaultDefinitions);
|
||||
|
||||
var currentProviders = All();
|
||||
|
||||
var newProviders = definitions.Where(def => currentProviders.All(c => c.Implementation != def.Implementation)).ToList();
|
||||
|
||||
if (newProviders.Any())
|
||||
{
|
||||
_providerRepository.InsertMany(newProviders.Cast<IndexerDefinition>().ToList());
|
||||
}
|
||||
}
|
||||
|
||||
protected override List<IndexerDefinition> Active()
|
||||
|
@ -59,5 +49,14 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
return base.Create(definition);
|
||||
}
|
||||
|
||||
protected override IndexerDefinition GetTemplate(IIndexer provider)
|
||||
{
|
||||
var definition = base.GetTemplate(provider);
|
||||
|
||||
definition.Protocol = provider.Protocol;
|
||||
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,11 +63,9 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
_logger.Info("{0} offset {1}. Found {2}", indexer, searchCriteria, result.Count);
|
||||
|
||||
if (result.Count > 90 &&
|
||||
offset < 900 &&
|
||||
indexer.SupportsPaging)
|
||||
if (indexer.SupportsPaging && result.Count >= indexer.SupportedPageSize && offset < 900)
|
||||
{
|
||||
result.AddRange(Fetch(indexer, searchCriteria, offset + 100));
|
||||
result.AddRange(Fetch(indexer, searchCriteria, offset + indexer.SupportedPageSize));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -152,7 +150,11 @@ namespace NzbDrone.Core.Indexers
|
|||
}
|
||||
}
|
||||
|
||||
result.ForEach(c => c.Indexer = indexer.Definition.Name);
|
||||
result.ForEach(c =>
|
||||
{
|
||||
c.Indexer = indexer.Definition.Name;
|
||||
c.DownloadProtocol = indexer.Protocol;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ namespace NzbDrone.Core.Indexers.Newznab
|
|||
{
|
||||
public class Newznab : IndexerBase<NewznabSettings>
|
||||
{
|
||||
public override DownloadProtocol Protocol { get { return DownloadProtocol.Usenet; } }
|
||||
public override Int32 SupportedPageSize { get { return 100; } }
|
||||
|
||||
public override IParseFeed Parser
|
||||
{
|
||||
get
|
||||
|
@ -72,14 +75,6 @@ namespace NzbDrone.Core.Indexers.Newznab
|
|||
return settings;
|
||||
}
|
||||
|
||||
public override bool SupportsPaging
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> RecentFeed
|
||||
{
|
||||
get
|
||||
|
@ -140,14 +135,6 @@ namespace NzbDrone.Core.Indexers.Newznab
|
|||
return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2}&offset={3}", url, NewsnabifyTitle(seriesTitle), seasonNumber, offset));
|
||||
}
|
||||
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
private static string NewsnabifyTitle(string title)
|
||||
{
|
||||
return title.Replace("+", "%20");
|
||||
|
|
|
@ -5,13 +5,7 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
|||
{
|
||||
public class Omgwtfnzbs : IndexerBase<OmgwtfnzbsSettings>
|
||||
{
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
public override DownloadProtocol Protocol { get { return DownloadProtocol.Usenet; } }
|
||||
|
||||
public override IParseFeed Parser
|
||||
{
|
||||
|
@ -25,7 +19,6 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
|||
{
|
||||
get
|
||||
{
|
||||
|
||||
yield return String.Format("http://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user={0}&api={1}&eng=1",
|
||||
Settings.Username, Settings.ApiKey);
|
||||
}
|
||||
|
@ -71,13 +64,5 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
|||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
public override bool SupportsPaging
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace NzbDrone.Core.Indexers
|
|||
try
|
||||
{
|
||||
var reportInfo = ParseFeedItem(item.StripNameSpace(), url);
|
||||
|
||||
if (reportInfo != null)
|
||||
{
|
||||
reportInfo.DownloadUrl = GetNzbUrl(item);
|
||||
|
@ -69,7 +70,7 @@ namespace NzbDrone.Core.Indexers
|
|||
var reportInfo = CreateNewReleaseInfo();
|
||||
|
||||
reportInfo.Title = title;
|
||||
reportInfo.PublishDate = item.PublishDate();
|
||||
reportInfo.PublishDate = GetPublishDate(item);
|
||||
reportInfo.DownloadUrl = GetNzbUrl(item);
|
||||
reportInfo.InfoUrl = GetNzbInfoUrl(item);
|
||||
|
||||
|
@ -92,6 +93,11 @@ namespace NzbDrone.Core.Indexers
|
|||
return item.Title();
|
||||
}
|
||||
|
||||
protected virtual DateTime GetPublishDate(XElement item)
|
||||
{
|
||||
return item.PublishDate();
|
||||
}
|
||||
|
||||
protected virtual string GetNzbUrl(XElement item)
|
||||
{
|
||||
return item.Links().First();
|
||||
|
|
|
@ -6,29 +6,8 @@ namespace NzbDrone.Core.Indexers.Wombles
|
|||
{
|
||||
public class Wombles : IndexerBase<NullConfig>
|
||||
{
|
||||
public override DownloadProtocol Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return DownloadProtocol.Usenet;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsPaging
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsSearching
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override DownloadProtocol Protocol { get { return DownloadProtocol.Usenet; } }
|
||||
public override bool SupportsSearching { get { return false; } }
|
||||
|
||||
public override IParseFeed Parser
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace NzbDrone.Core.Indexers
|
|||
{
|
||||
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
|
||||
|
||||
private static readonly Regex RemoveTimeZoneRegex = new Regex(@"\s[A-Z]{2,4}$", RegexOptions.Compiled);
|
||||
public static readonly Regex RemoveTimeZoneRegex = new Regex(@"\s[A-Z]{2,4}$", RegexOptions.Compiled);
|
||||
|
||||
public static string Title(this XElement item)
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Indexers
|
|||
return long.Parse(item.TryGetValue("length"));
|
||||
}
|
||||
|
||||
private static string TryGetValue(this XElement item, string elementName, string defaultValue = "")
|
||||
public static string TryGetValue(this XElement item, string elementName, string defaultValue = "")
|
||||
{
|
||||
var element = item.Element(elementName);
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Jobs
|
|||
var defaultTasks = new[]
|
||||
{
|
||||
new ScheduledTask{ Interval = 1, TypeName = typeof(TrackedCommandCleanupCommand).FullName},
|
||||
new ScheduledTask{ Interval = 1, TypeName = typeof(CheckForFailedDownloadCommand).FullName},
|
||||
new ScheduledTask{ Interval = 1, TypeName = typeof(CheckForFinishedDownloadCommand).FullName},
|
||||
new ScheduledTask{ Interval = 1*60, TypeName = typeof(ApplicationUpdateCommand).FullName},
|
||||
new ScheduledTask{ Interval = 1*60, TypeName = typeof(TrimLogCommand).FullName},
|
||||
new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
decisionsStopwatch.Stop();
|
||||
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
||||
|
||||
_importApprovedEpisodes.Import(decisions);
|
||||
_importApprovedEpisodes.Import(decisions, false);
|
||||
|
||||
_logger.Info("Completed scanning disk for {0}", series.Title);
|
||||
_eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
||||
|
|
|
@ -14,10 +14,17 @@ using NzbDrone.Core.Messaging.Commands;
|
|||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public class DownloadedEpisodesImportService : IExecute<DownloadedEpisodesScanCommand>
|
||||
public interface IDownloadedEpisodesImportService
|
||||
{
|
||||
List<ImportDecision> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem);
|
||||
List<ImportDecision> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem);
|
||||
}
|
||||
|
||||
public class DownloadedEpisodesImportService : IDownloadedEpisodesImportService, IExecute<DownloadedEpisodesScanCommand>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
|
@ -50,9 +57,53 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ImportDecision> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
|
||||
var series = _parsingService.GetSeries(cleanedUpName);
|
||||
var quality = QualityParser.ParseQuality(cleanedUpName);
|
||||
_logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
_logger.Debug("Unknown Series {0}", cleanedUpName);
|
||||
return new List<ImportDecision>();
|
||||
}
|
||||
|
||||
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
|
||||
|
||||
var importedDecisions = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
|
||||
|
||||
if (!downloadClientItem.IsReadOnly && importedDecisions.Any() && ShouldDeleteFolder(directoryInfo))
|
||||
{
|
||||
_logger.Debug("Deleting folder after importing valid files");
|
||||
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
|
||||
}
|
||||
|
||||
return importedDecisions;
|
||||
}
|
||||
|
||||
public List<ImportDecision> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name));
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
_logger.Debug("Unknown Series for file: {0}", fileInfo.Name);
|
||||
return new List<ImportDecision>();
|
||||
}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, true, null);
|
||||
|
||||
var importedDecisions = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
|
||||
|
||||
return importedDecisions;
|
||||
}
|
||||
|
||||
private void ProcessDownloadedEpisodesFolder()
|
||||
{
|
||||
//TODO: We should also process the download client's category folder
|
||||
var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
|
||||
|
||||
if (String.IsNullOrEmpty(downloadedEpisodesFolder))
|
||||
|
@ -100,6 +151,15 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
|
||||
|
||||
foreach (var videoFile in videoFiles)
|
||||
{
|
||||
if (_diskProvider.IsFileLocked(videoFile))
|
||||
{
|
||||
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
|
||||
return new List<ImportDecision>();
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessFiles(series, quality, videoFiles);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue