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

New: Added support for nzb downloads in Synology Download Station.

This commit is contained in:
margaale 2017-02-13 17:18:35 -03:00 committed by Taloth Saldono
parent c6fa883662
commit c56c83e169
11 changed files with 894 additions and 94 deletions

View File

@ -20,16 +20,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{ {
protected DownloadStationSettings _settings; protected DownloadStationSettings _settings;
protected DownloadStationTorrent _queued; protected DownloadStationTask _queued;
protected DownloadStationTorrent _downloading; protected DownloadStationTask _downloading;
protected DownloadStationTorrent _failed; protected DownloadStationTask _failed;
protected DownloadStationTorrent _completed; protected DownloadStationTask _completed;
protected DownloadStationTorrent _seeding; protected DownloadStationTask _seeding;
protected DownloadStationTorrent _magnet; protected DownloadStationTask _magnet;
protected DownloadStationTorrent _singleFile; protected DownloadStationTask _singleFile;
protected DownloadStationTorrent _multipleFiles; protected DownloadStationTask _multipleFiles;
protected DownloadStationTorrent _singleFileCompleted; protected DownloadStationTask _singleFileCompleted;
protected DownloadStationTorrent _multipleFilesCompleted; protected DownloadStationTask _multipleFilesCompleted;
protected string _serialNumber = "SERIALNUMBER"; protected string _serialNumber = "SERIALNUMBER";
protected string _category = "sonarr"; protected string _category = "sonarr";
@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Subject.Definition = new DownloadClientDefinition(); Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = _settings; Subject.Definition.Settings = _settings;
_queued = new DownloadStationTorrent() _queued = new DownloadStationTask()
{ {
Id = "id1", Id = "id1",
Size = 1000, Size = 1000,
@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_completed = new DownloadStationTorrent() _completed = new DownloadStationTask()
{ {
Id = "id2", Id = "id2",
Size = 1000, Size = 1000,
@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -101,7 +101,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_seeding = new DownloadStationTorrent() _seeding = new DownloadStationTask()
{ {
Id = "id2", Id = "id2",
Size = 1000, Size = 1000,
@ -109,7 +109,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -124,7 +124,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_downloading = new DownloadStationTorrent() _downloading = new DownloadStationTask()
{ {
Id = "id3", Id = "id3",
Size = 1000, Size = 1000,
@ -132,7 +132,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -147,7 +147,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_failed = new DownloadStationTorrent() _failed = new DownloadStationTask()
{ {
Id = "id4", Id = "id4",
Size = 1000, Size = 1000,
@ -155,7 +155,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -170,7 +170,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_singleFile = new DownloadStationTorrent() _singleFile = new DownloadStationTask()
{ {
Id = "id5", Id = "id5",
Size = 1000, Size = 1000,
@ -178,7 +178,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "a.mkv", Title = "a.mkv",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -193,7 +193,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_multipleFiles = new DownloadStationTorrent() _multipleFiles = new DownloadStationTask()
{ {
Id = "id6", Id = "id6",
Size = 1000, Size = 1000,
@ -201,7 +201,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -216,7 +216,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_singleFileCompleted = new DownloadStationTorrent() _singleFileCompleted = new DownloadStationTask()
{ {
Id = "id6", Id = "id6",
Size = 1000, Size = 1000,
@ -224,7 +224,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "a.mkv", Title = "a.mkv",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -239,7 +239,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
}; };
_multipleFilesCompleted = new DownloadStationTorrent() _multipleFilesCompleted = new DownloadStationTask()
{ {
Id = "id6", Id = "id6",
Size = 1000, Size = 1000,
@ -247,7 +247,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Type = DownloadStationTaskType.BT, Type = DownloadStationTaskType.BT,
Username = "admin", Username = "admin",
Title = "title", Title = "title",
Additional = new DownloadStationTorrentAdditional Additional = new DownloadStationTaskAdditional
{ {
Detail = new Dictionary<string, string> Detail = new Dictionary<string, string>
{ {
@ -304,21 +304,21 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
_settings.TvDirectory = _tvDirectory; _settings.TvDirectory = _tvDirectory;
} }
protected virtual void GivenTorrents(List<DownloadStationTorrent> torrents) protected virtual void GivenTorrents(List<DownloadStationTask> torrents)
{ {
if (torrents == null) if (torrents == null)
{ {
torrents = new List<DownloadStationTorrent>(); torrents = new List<DownloadStationTask>();
} }
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Setup(s => s.GetTorrents(It.IsAny<DownloadStationSettings>())) .Setup(s => s.GetTasks(DownloadStationTaskType.BT, It.IsAny<DownloadStationSettings>()))
.Returns(torrents); .Returns(torrents);
} }
protected void PrepareClientToReturnQueuedItem() protected void PrepareClientToReturnQueuedItem()
{ {
GivenTorrents(new List<DownloadStationTorrent> GivenTorrents(new List<DownloadStationTask>
{ {
_queued _queued
}); });
@ -331,11 +331,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000])); .Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>())) .Setup(s => s.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem); .Callback(PrepareClientToReturnQueuedItem);
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Setup(s => s.AddTorrentFromData(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>())) .Setup(s => s.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem); .Callback(PrepareClientToReturnQueuedItem);
} }
@ -350,10 +350,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
protected int GivenAllKindOfTasks() protected int GivenAllKindOfTasks()
{ {
var tasks = new List<DownloadStationTorrent>() { _queued, _completed, _failed, _downloading, _seeding }; var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Setup(d => d.GetTorrents(_settings)) .Setup(d => d.GetTasks(DownloadStationTaskType.BT, _settings))
.Returns(tasks); .Returns(tasks);
return tasks.Count; return tasks.Count;
@ -373,7 +373,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTorrentFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
[Test] [Test]
@ -390,7 +390,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTorrentFromUrl(It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
} }
[Test] [Test]
@ -406,7 +406,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTorrentFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
[Test] [Test]
@ -416,7 +416,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent> { _completed }); GivenTorrents(new List<DownloadStationTask> { _completed });
Subject.GetItems().Should().BeEmpty(); Subject.GetItems().Should().BeEmpty();
} }
@ -450,7 +450,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void Download_should_throw_and_not_add_torrent_if_cannot_get_serial_number() public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
{ {
var remoteEpisode = CreateRemoteEpisode(); var remoteEpisode = CreateRemoteEpisode();
@ -461,16 +461,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode)); Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTorrentFromUrl(It.IsAny<string>(), null, _settings), Times.Never()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
} }
[Test] [Test]
public void GetItems_should_set_outputPath_to_base_folder_when_single_file_non_finished_torrent() public void GetItems_should_set_outputPath_to_base_folder_when_single_file_non_finished_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent>() { _singleFile }); GivenTorrents(new List<DownloadStationTask>() { _singleFile });
var items = Subject.GetItems(); var items = Subject.GetItems();
@ -479,12 +479,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_non_finished_torrent() public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_non_finished_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent>() { _multipleFiles }); GivenTorrents(new List<DownloadStationTask>() { _multipleFiles });
var items = Subject.GetItems(); var items = Subject.GetItems();
@ -493,12 +493,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void GetItems_should_set_outputPath_to_base_folder_when_single_file_finished_torrent() public void GetItems_should_set_outputPath_to_base_folder_when_single_file_finished_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent>() { _singleFileCompleted }); GivenTorrents(new List<DownloadStationTask>() { _singleFileCompleted });
var items = Subject.GetItems(); var items = Subject.GetItems();
@ -507,12 +507,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_finished_torrent() public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_finished_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent>() { _multipleFilesCompleted }); GivenTorrents(new List<DownloadStationTask>() { _multipleFilesCompleted });
var items = Subject.GetItems(); var items = Subject.GetItems();
@ -521,12 +521,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void GetItems_should_not_map_outputpath_for_queued_or_downloading_torrents() public void GetItems_should_not_map_outputpath_for_queued_or_downloading_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent> GivenTorrents(new List<DownloadStationTask>
{ {
_queued, _downloading _queued, _downloading
}); });
@ -538,12 +538,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
} }
[Test] [Test]
public void GetItems_should_map_outputpath_for_completed_or_failed_torrents() public void GetItems_should_map_outputpath_for_completed_or_failed_tasks()
{ {
GivenSerialNumber(); GivenSerialNumber();
GivenSharedFolder(); GivenSharedFolder();
GivenTorrents(new List<DownloadStationTorrent> GivenTorrents(new List<DownloadStationTask>
{ {
_completed, _failed, _seeding _completed, _failed, _seeding
}); });
@ -565,7 +565,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
_queued.Status = apiStatus; _queued.Status = apiStatus;
GivenTorrents(new List<DownloadStationTorrent>() { _queued }); GivenTorrents(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems(); var items = Subject.GetItems();
@ -589,7 +589,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
_queued.Status = apiStatus; _queued.Status = apiStatus;
GivenTorrents(new List<DownloadStationTorrent>() { _queued }); GivenTorrents(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems(); var items = Subject.GetItems();
items.Should().HaveCount(1); items.Should().HaveCount(1);

View File

@ -0,0 +1,442 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.DownloadStation;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Test.Common;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{
[TestFixture]
public class UsenetDownloadStationFixture : DownloadClientFixtureBase<UsenetDownloadStation>
{
protected DownloadStationSettings _settings;
protected DownloadStationTask _queued;
protected DownloadStationTask _downloading;
protected DownloadStationTask _failed;
protected DownloadStationTask _completed;
protected DownloadStationTask _seeding;
protected string _serialNumber = "SERIALNUMBER";
protected string _category = "sonarr";
protected string _tvDirectory = @"video/Series";
protected string _defaultDestination = "somepath";
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
protected RemoteEpisode _remoteEpisode;
protected Dictionary<string, object> _downloadStationConfigItems;
[SetUp]
public void Setup()
{
_remoteEpisode = CreateRemoteEpisode();
_settings = new DownloadStationSettings()
{
Host = "127.0.0.1",
Port = 5000,
Username = "admin",
Password = "pass"
};
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = _settings;
_queued = new DownloadStationTask()
{
Id = "id1",
Size = 1000,
Status = DownloadStationTaskStatus.Waiting,
Type = DownloadStationTaskType.NZB,
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "0"},
{ "speed_download", "0" }
}
}
};
_completed = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Finished,
Type = DownloadStationTaskType.NZB,
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
},
}
};
_seeding = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Seeding,
Type = DownloadStationTaskType.NZB,
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_downloading = new DownloadStationTask()
{
Id = "id3",
Size = 1000,
Status = DownloadStationTaskStatus.Downloading,
Type = DownloadStationTaskType.NZB,
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "100"},
{ "speed_download", "50" }
}
}
};
_failed = new DownloadStationTask()
{
Id = "id4",
Size = 1000,
Status = DownloadStationTaskStatus.Error,
Type = DownloadStationTaskType.NZB,
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "10"},
{ "speed_download", "0" }
}
}
};
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0]));
_downloadStationConfigItems = new Dictionary<string, object>
{
{ "default_destination", _defaultDestination },
};
Mocker.GetMock<IDownloadStationProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems);
}
protected void GivenSharedFolder()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Returns<OsPath, DownloadStationSettings, string>((path, setttings, serial) => _physicalPath);
}
protected void GivenSerialNumber()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(It.IsAny<DownloadStationSettings>()))
.Returns(_serialNumber);
}
protected void GivenTvCategory()
{
_settings.TvCategory = _category;
}
protected void GivenTvDirectory()
{
_settings.TvDirectory = _tvDirectory;
}
protected virtual void GivenNZBs(List<DownloadStationTask> nzbs)
{
if (nzbs == null)
{
nzbs = new List<DownloadStationTask>();
}
Mocker.GetMock<IDownloadStationProxy>()
.Setup(s => s.GetTasks(DownloadStationTaskType.NZB, It.IsAny<DownloadStationSettings>()))
.Returns(nzbs);
}
protected void PrepareClientToReturnQueuedItem()
{
GivenNZBs(new List<DownloadStationTask>
{
_queued
});
}
protected void GivenSuccessfulDownload()
{/*
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
*/
Mocker.GetMock<IDownloadStationProxy>()
.Setup(s => s.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem);
}
protected void GivenAllKindOfTasks()
{
var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationProxy>()
.Setup(d => d.GetTasks(DownloadStationTaskType.NZB, _settings))
.Returns(tasks);
}
[Test]
public void Download_with_TvDirectory_should_force_directory()
{
GivenSerialNumber();
GivenTvDirectory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_with_category_should_force_directory()
{
GivenSerialNumber();
GivenTvCategory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_without_TvDirectory_and_Category_should_use_default()
{
GivenSerialNumber();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void GetItems_should_return_empty_list_if_no_tasks_available()
{
_settings.TvDirectory = @"/shared/folder/sub";
GivenSerialNumber();
GivenSharedFolder();
GivenNZBs(new List<DownloadStationTask>());
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_ignore_downloads_in_wrong_folder()
{
_settings.TvDirectory = @"/shared/folder/sub";
GivenSerialNumber();
GivenSharedFolder();
GivenNZBs(new List<DownloadStationTask> { _completed });
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_throw_if_shared_folder_resolve_fails()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSerialNumber();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void GetItems_should_throw_if_serial_number_unavailable()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSharedFolder();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void Download_should_throw_and_not_add_tasks_if_cannot_get_serial_number()
{
var remoteEpisode = CreateRemoteEpisode();
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
}
[Test]
public void GetItems_should_not_map_outputpath_for_queued_or_downloading_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenNZBs(new List<DownloadStationTask>
{
_queued, _downloading
});
var items = Subject.GetItems();
items.Should().HaveCount(2);
items.Should().OnlyContain(v => v.OutputPath.IsEmpty);
}
[Test]
public void GetItems_should_map_outputpath_for_completed_or_failed_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenNZBs(new List<DownloadStationTask>
{
_completed, _failed, _seeding
});
var items = Subject.GetItems();
items.Should().HaveCount(3);
items.Should().OnlyContain(v => !v.OutputPath.IsEmpty);
}
[TestCase(DownloadStationTaskStatus.Downloading, DownloadItemStatus.Downloading, true)]
[TestCase(DownloadStationTaskStatus.Finished, DownloadItemStatus.Completed, false)]
[TestCase(DownloadStationTaskStatus.Waiting, DownloadItemStatus.Queued, true)]
public void GetItems_should_return_readonly_expected(DownloadStationTaskStatus apiStatus, DownloadItemStatus expectedItemStatus, bool readOnlyExpected)
{
GivenSerialNumber();
GivenSharedFolder();
_queued.Status = apiStatus;
GivenNZBs(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().IsReadOnly.Should().Be(readOnlyExpected);
}
[TestCase(DownloadStationTaskStatus.Downloading, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Error, DownloadItemStatus.Failed)]
[TestCase(DownloadStationTaskStatus.Extracting, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Finished, DownloadItemStatus.Completed)]
[TestCase(DownloadStationTaskStatus.Finishing, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.HashChecking, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Paused, DownloadItemStatus.Paused)]
[TestCase(DownloadStationTaskStatus.Waiting, DownloadItemStatus.Queued)]
public void GetItems_should_return_item_as_downloadItemStatus(DownloadStationTaskStatus apiStatus, DownloadItemStatus expectedItemStatus)
{
GivenSerialNumber();
GivenSharedFolder();
_queued.Status = apiStatus;
GivenNZBs(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().Status.Should().Be(expectedItemStatus);
}
}
}

View File

@ -176,6 +176,7 @@
<Compile Include="Download\DownloadClientTests\DownloadStationTests\TorrentDownloadStationFixture.cs" /> <Compile Include="Download\DownloadClientTests\DownloadStationTests\TorrentDownloadStationFixture.cs" />
<Compile Include="Download\DownloadClientTests\DownloadStationTests\SerialNumberProviderFixture.cs" /> <Compile Include="Download\DownloadClientTests\DownloadStationTests\SerialNumberProviderFixture.cs" />
<Compile Include="Download\DownloadClientTests\DownloadStationTests\SharedFolderResolverFixture.cs" /> <Compile Include="Download\DownloadClientTests\DownloadStationTests\SharedFolderResolverFixture.cs" />
<Compile Include="Download\DownloadClientTests\DownloadStationTests\UsenetDownloadStationFixture.cs" />
<Compile Include="Download\DownloadClientTests\HadoukenTests\HadoukenFixture.cs" /> <Compile Include="Download\DownloadClientTests\HadoukenTests\HadoukenFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" /> <Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbVortexTests\NzbVortexFixture.cs" /> <Compile Include="Download\DownloadClientTests\NzbVortexTests\NzbVortexFixture.cs" />

View File

@ -5,7 +5,7 @@ using Newtonsoft.Json.Converters;
namespace NzbDrone.Core.Download.Clients.DownloadStation namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class DownloadStationTorrent public class DownloadStationTask
{ {
public string Username { get; set; } public string Username { get; set; }
@ -24,7 +24,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(StringEnumConverter))]
public DownloadStationTaskStatus Status { get; set; } public DownloadStationTaskStatus Status { get; set; }
public DownloadStationTorrentAdditional Additional { get; set; } public DownloadStationTaskAdditional Additional { get; set; }
public override string ToString() public override string ToString()
{ {

View File

@ -3,13 +3,13 @@ using System.Collections.Generic;
namespace NzbDrone.Core.Download.Clients.DownloadStation namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class DownloadStationTorrentAdditional public class DownloadStationTaskAdditional
{ {
public Dictionary<string, string> Detail { get; set; } public Dictionary<string, string> Detail { get; set; }
public Dictionary<string, string> Transfer { get; set; } public Dictionary<string, string> Transfer { get; set; }
[JsonProperty("File")] [JsonProperty("File")]
public List<DownloadStationTorrentFile> Files { get; set; } public List<DownloadStationTaskFile> Files { get; set; }
} }
} }

View File

@ -4,11 +4,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using static NzbDrone.Core.Download.Clients.DownloadStation.DownloadStationTorrent; using static NzbDrone.Core.Download.Clients.DownloadStation.DownloadStationTask;
namespace NzbDrone.Core.Download.Clients.DownloadStation namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class DownloadStationTorrentFile public class DownloadStationTaskFile
{ {
public string FileName { get; set; } public string FileName { get; set; }

View File

@ -10,11 +10,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{ {
public interface IDownloadStationProxy public interface IDownloadStationProxy
{ {
IEnumerable<DownloadStationTorrent> GetTorrents(DownloadStationSettings settings); IEnumerable<DownloadStationTask> GetTasks(DownloadStationTaskType type, DownloadStationSettings settings);
Dictionary<string, object> GetConfig(DownloadStationSettings settings); Dictionary<string, object> GetConfig(DownloadStationSettings settings);
void RemoveTorrent(string downloadId, DownloadStationSettings settings); void RemoveTask(string downloadId, DownloadStationSettings settings);
void AddTorrentFromUrl(string url, string downloadDirectory, DownloadStationSettings settings); void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings);
void AddTorrentFromData(byte[] torrentData, string filename, string downloadDirectory, DownloadStationSettings settings); void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings);
IEnumerable<int> GetApiVersion(DownloadStationSettings settings); IEnumerable<int> GetApiVersion(DownloadStationSettings settings);
} }
@ -25,7 +25,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{ {
} }
public void AddTorrentFromData(byte[] torrentData, string filename, string downloadDirectory, DownloadStationSettings settings) public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var arguments = new Dictionary<string, object>
{ {
@ -39,19 +39,19 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
arguments.Add("destination", downloadDirectory); arguments.Add("destination", downloadDirectory);
} }
arguments.Add("file", new Dictionary<string, object>() { { "name", filename }, { "data", torrentData } }); arguments.Add("file", new Dictionary<string, object>() { { "name", filename }, { "data", data } });
var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add torrent from data {filename}", HttpMethod.POST); var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add task from data {filename}", HttpMethod.POST);
} }
public void AddTorrentFromUrl(string torrentUrl, string downloadDirectory, DownloadStationSettings settings) public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var arguments = new Dictionary<string, object>
{ {
{ "api", "SYNO.DownloadStation.Task" }, { "api", "SYNO.DownloadStation.Task" },
{ "version", "3" }, { "version", "3" },
{ "method", "create" }, { "method", "create" },
{ "uri", torrentUrl } { "uri", url }
}; };
if (downloadDirectory.IsNotNullOrWhiteSpace()) if (downloadDirectory.IsNotNullOrWhiteSpace())
@ -59,10 +59,10 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
arguments.Add("destination", downloadDirectory); arguments.Add("destination", downloadDirectory);
} }
var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add torrent from url {torrentUrl}", HttpMethod.GET); var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add task from url {url}");
} }
public IEnumerable<DownloadStationTorrent> GetTorrents(DownloadStationSettings settings) public IEnumerable<DownloadStationTask> GetTasks(DownloadStationTaskType type, DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var arguments = new Dictionary<string, object>
{ {
@ -74,14 +74,14 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
try try
{ {
var response = ProcessRequest<DownloadStationTaskInfoResponse>(DiskStationApi.DownloadStationTask, arguments, settings, "get torrents"); var response = ProcessRequest<DownloadStationTaskInfoResponse>(DiskStationApi.DownloadStationTask, arguments, settings, "get tasks");
return response.Data.Tasks.Where(t => t.Type == DownloadStationTaskType.BT); return response.Data.Tasks.Where(t => t.Type == type);
} }
catch (DownloadClientException e) catch (DownloadClientException e)
{ {
_logger.Error(e); _logger.Error(e);
return new List<DownloadStationTorrent>(); return new List<DownloadStationTask>();
} }
} }
@ -99,7 +99,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
return response.Data; return response.Data;
} }
public void RemoveTorrent(string downloadId, DownloadStationSettings settings) public void RemoveTask(string downloadId, DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var arguments = new Dictionary<string, object>
{ {

View File

@ -5,7 +5,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Responses
public class DownloadStationTaskInfoResponse public class DownloadStationTaskInfoResponse
{ {
public int Offset { get; set; } public int Offset { get; set; }
public List<DownloadStationTorrent> Tasks {get;set;} public List<DownloadStationTask> Tasks {get;set;}
public int Total { get; set; } public int Total { get; set; }
} }
} }

View File

@ -45,7 +45,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
public override IEnumerable<DownloadClientItem> GetItems() public override IEnumerable<DownloadClientItem> GetItems()
{ {
var torrents = _proxy.GetTorrents(Settings); var torrents = _proxy.GetTasks(DownloadStationTaskType.BT, Settings);
var serialNumber = _serialNumberProvider.GetSerialNumber(Settings); var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
var items = new List<DownloadClientItem>(); var items = new List<DownloadClientItem>();
@ -122,11 +122,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
DeleteItemData(downloadId); DeleteItemData(downloadId);
} }
_proxy.RemoveTorrent(ParseDownloadId(downloadId), Settings); _proxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId); _logger.Debug("{0} removed correctly", downloadId);
} }
protected OsPath GetOutputPath(OsPath outputPath, DownloadStationTorrent torrent, string serialNumber) protected OsPath GetOutputPath(OsPath outputPath, DownloadStationTask torrent, string serialNumber)
{ {
var fullPath = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber); var fullPath = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
@ -141,9 +141,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings); var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTorrentFromUrl(magnetLink, GetDownloadDirectory(), Settings); _proxy.AddTaskFromUrl(magnetLink, GetDownloadDirectory(), Settings);
var item = _proxy.GetTorrents(Settings).SingleOrDefault(t => t.Additional.Detail["uri"] == magnetLink); var item = _proxy.GetTasks(DownloadStationTaskType.BT, Settings).SingleOrDefault(t => t.Additional.Detail["uri"] == magnetLink);
if (item != null) if (item != null)
{ {
@ -160,9 +160,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings); var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTorrentFromData(fileContent, filename, GetDownloadDirectory(), Settings); _proxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = _proxy.GetTorrents(Settings).Where(t => t.Additional.Detail["uri"] == Path.GetFileNameWithoutExtension(filename)); var items = _proxy.GetTasks(DownloadStationTaskType.BT, Settings).Where(t => t.Additional.Detail["uri"] == Path.GetFileNameWithoutExtension(filename));
var item = items.SingleOrDefault(); var item = items.SingleOrDefault();
@ -232,12 +232,12 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
return null; return null;
} }
protected bool IsFinished(DownloadStationTorrent torrent) protected bool IsFinished(DownloadStationTask torrent)
{ {
return torrent.Status == DownloadStationTaskStatus.Finished; return torrent.Status == DownloadStationTaskStatus.Finished;
} }
protected string GetMessage(DownloadStationTorrent torrent) protected string GetMessage(DownloadStationTask torrent)
{ {
if (torrent.StatusExtra != null) if (torrent.StatusExtra != null)
{ {
@ -255,7 +255,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
return null; return null;
} }
protected DownloadItemStatus GetStatus(DownloadStationTorrent torrent) protected DownloadItemStatus GetStatus(DownloadStationTask torrent)
{ {
switch (torrent.Status) switch (torrent.Status)
{ {
@ -273,7 +273,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
return DownloadItemStatus.Downloading; return DownloadItemStatus.Downloading;
} }
protected long GetRemainingSize(DownloadStationTorrent torrent) protected long GetRemainingSize(DownloadStationTask torrent)
{ {
var downloadedString = torrent.Additional.Transfer["size_downloaded"]; var downloadedString = torrent.Additional.Transfer["size_downloaded"];
long downloadedSize; long downloadedSize;
@ -287,7 +287,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
return torrent.Size - Math.Max(0, downloadedSize); return torrent.Size - Math.Max(0, downloadedSize);
} }
protected TimeSpan? GetRemainingTime(DownloadStationTorrent torrent) protected TimeSpan? GetRemainingTime(DownloadStationTask torrent)
{ {
var speedString = torrent.Additional.Transfer["speed_download"]; var speedString = torrent.Additional.Transfer["speed_download"];
long downloadSpeed; long downloadSpeed;
@ -312,7 +312,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
try try
{ {
_proxy.GetTorrents(Settings); _proxy.GetTasks(DownloadStationTaskType.BT, Settings);
return null; return null;
} }
catch (Exception ex) catch (Exception ex)

View File

@ -0,0 +1,356 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Download.Clients.DownloadStation
{
public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings>
{
protected readonly IDownloadStationProxy _proxy;
protected readonly ISharedFolderResolver _sharedFolderResolver;
protected readonly ISerialNumberProvider _serialNumberProvider;
public UsenetDownloadStation(IDownloadStationProxy proxy,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger,
ISharedFolderResolver sharedFolderResolver,
ISerialNumberProvider serialNumberProvider)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
_sharedFolderResolver = sharedFolderResolver;
_serialNumberProvider = serialNumberProvider;
}
public override string Name => "Download Station";
public override IEnumerable<DownloadClientItem> GetItems()
{
var nzbTasks = _proxy.GetTasks(DownloadStationTaskType.NZB, Settings);
var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
var items = new List<DownloadClientItem>();
long totalRemainingSize = 0;
long globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
.Select(GetDownloadSpeed)
.Sum();
foreach (var nzb in nzbTasks)
{
var outputPath = new OsPath($"/{nzb.Additional.Detail["destination"]}");
var taskRemainingSize = GetRemainingSize(nzb);
if (nzb.Status != DownloadStationTaskStatus.Paused)
{
totalRemainingSize += taskRemainingSize;
}
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
{
if (!new OsPath($"/{Settings.TvDirectory}").Contains(outputPath))
{
continue;
}
}
else if (Settings.TvCategory.IsNotNullOrWhiteSpace())
{
var directories = outputPath.FullPath.Split('\\', '/');
if (!directories.Contains(Settings.TvCategory))
{
continue;
}
}
var item = new DownloadClientItem()
{
Category = Settings.TvCategory,
DownloadClient = Definition.Name,
DownloadId = CreateDownloadId(nzb.Id, serialNumber),
Title = nzb.Title,
TotalSize = nzb.Size,
RemainingSize = taskRemainingSize,
Status = GetStatus(nzb),
Message = GetMessage(nzb),
IsReadOnly = !IsFinished(nzb)
};
if (item.Status != DownloadItemStatus.Paused)
{
item.RemainingTime = GetRemainingTime(totalRemainingSize, globalSpeed);
}
if (item.Status == DownloadItemStatus.Completed || item.Status == DownloadItemStatus.Failed)
{
item.OutputPath = GetOutputPath(outputPath, nzb, serialNumber);
}
items.Add(item);
}
return items;
}
protected OsPath GetOutputPath(OsPath outputPath, DownloadStationTask task, string serialNumber)
{
var fullPath = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
var remotePath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, fullPath);
var finalPath = remotePath + task.Title;
return finalPath;
}
public override DownloadClientStatus GetStatus()
{
try
{
var path = GetDownloadDirectory();
return new DownloadClientStatus
{
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(path)) }
};
}
catch (DownloadClientException e)
{
_logger.Debug(e, "Failed to get config from Download Station");
throw e;
}
}
public override void RemoveItem(string downloadId, bool deleteData)
{
if (deleteData)
{
DeleteItemData(downloadId);
}
_proxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId);
}
protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent)
{
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = _proxy.GetTasks(DownloadStationTaskType.NZB, Settings).Where(t => t.Additional.Detail["uri"] == filename);
var item = items.SingleOrDefault();
if (item != null)
{
_logger.Debug("{0} added correctly", remoteEpisode);
return CreateDownloadId(item.Id, hashedSerialNumber);
}
_logger.Debug("No such task {0} in Download Station", filename);
throw new DownloadClientException("Failed to add NZB task to Download Station");
}
protected override void Test(List<ValidationFailure> failures)
{
failures.AddIfNotNull(TestConnection());
if (failures.Any()) return;
failures.AddIfNotNull(TestGetNZB());
}
protected ValidationFailure TestConnection()
{
try
{
return ValidateVersion();
}
catch (DownloadClientAuthenticationException ex)
{
_logger.Error(ex, ex.Message);
return new NzbDroneValidationFailure("Username", "Authentication failure")
{
DetailedDescription = $"Please verify your username and password. Also verify if the host running Sonarr isn't blocked from accessing {Name} by WhiteList limitations in the {Name} configuration."
};
}
catch (WebException ex)
{
_logger.Error(ex);
if (ex.Status == WebExceptionStatus.ConnectFailure)
{
return new NzbDroneValidationFailure("Host", "Unable to connect")
{
DetailedDescription = "Please verify the hostname and port."
};
}
return new NzbDroneValidationFailure(string.Empty, "Unknown exception: " + ex.Message);
}
catch (Exception ex)
{
_logger.Error(ex);
return new NzbDroneValidationFailure(string.Empty, "Unknown exception: " + ex.Message);
}
}
protected ValidationFailure ValidateVersion()
{
var versionRange = _proxy.GetApiVersion(Settings);
_logger.Debug("Download Station api version information: Min {0} - Max {1}", versionRange.Min(), versionRange.Max());
if (!versionRange.Contains(2))
{
return new ValidationFailure(string.Empty, $"Download Station API version not supported, should be at least 2. It supports from {versionRange.Min()} to {versionRange.Max()}");
}
return null;
}
protected bool IsFinished(DownloadStationTask task)
{
return task.Status == DownloadStationTaskStatus.Finished;
}
protected string GetMessage(DownloadStationTask task)
{
if (task.StatusExtra != null)
{
if (task.Status == DownloadStationTaskStatus.Extracting)
{
return $"Extracting: {int.Parse(task.StatusExtra["unzip_progress"])}%";
}
if (task.Status == DownloadStationTaskStatus.Error)
{
return task.StatusExtra["error_detail"];
}
}
return null;
}
protected DownloadItemStatus GetStatus(DownloadStationTask task)
{
switch (task.Status)
{
case DownloadStationTaskStatus.Waiting:
return task.Size == 0 || GetRemainingSize(task) > 0 ? DownloadItemStatus.Queued : DownloadItemStatus.Completed;
case DownloadStationTaskStatus.Paused:
return DownloadItemStatus.Paused;
case DownloadStationTaskStatus.Finished:
case DownloadStationTaskStatus.Seeding:
return DownloadItemStatus.Completed;
case DownloadStationTaskStatus.Error:
return DownloadItemStatus.Failed;
}
return DownloadItemStatus.Downloading;
}
protected long GetRemainingSize(DownloadStationTask task)
{
var downloadedString = task.Additional.Transfer["size_downloaded"];
long downloadedSize;
if (downloadedString.IsNullOrWhiteSpace() || !long.TryParse(downloadedString, out downloadedSize))
{
_logger.Debug("Task {0} has invalid size_downloaded: {1}", task.Title, downloadedString);
downloadedSize = 0;
}
return task.Size - Math.Max(0, downloadedSize);
}
protected long GetDownloadSpeed(DownloadStationTask task)
{
var speedString = task.Additional.Transfer["speed_download"];
long downloadSpeed;
if (speedString.IsNullOrWhiteSpace() || !long.TryParse(speedString, out downloadSpeed))
{
_logger.Debug("Task {0} has invalid speed_download: {1}", task.Title, speedString);
downloadSpeed = 0;
}
return Math.Max(downloadSpeed, 0);
}
protected TimeSpan? GetRemainingTime(long remainingSize, long downloadSpeed)
{
if (downloadSpeed > 0)
{
return TimeSpan.FromSeconds(remainingSize / downloadSpeed);
}
else
{
return null;
}
}
protected ValidationFailure TestGetNZB()
{
try
{
_proxy.GetTasks(DownloadStationTaskType.NZB, Settings);
return null;
}
catch (Exception ex)
{
return new NzbDroneValidationFailure(string.Empty, "Failed to get the list of NZBs: " + ex.Message);
}
}
protected string ParseDownloadId(string id)
{
return id.Split(':')[1];
}
protected string CreateDownloadId(string id, string hashedSerialNumber)
{
return $"{hashedSerialNumber}:{id}";
}
protected string GetDefaultDir()
{
var config = _proxy.GetConfig(Settings);
var path = config["default_destination"] as string;
return path;
}
protected string GetDownloadDirectory()
{
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
{
return Settings.TvDirectory.TrimStart('/');
}
else if (Settings.TvCategory.IsNotNullOrWhiteSpace())
{
var destDir = GetDefaultDir();
return $"{destDir.TrimEnd('/')}/{Settings.TvCategory}";
}
return null;
}
}
}

View File

@ -356,13 +356,13 @@
<Compile Include="Download\Clients\DownloadStation\TorrentDownloadStation.cs" /> <Compile Include="Download\Clients\DownloadStation\TorrentDownloadStation.cs" />
<Compile Include="Download\Clients\DownloadStation\Proxies\DownloadStationProxy.cs" /> <Compile Include="Download\Clients\DownloadStation\Proxies\DownloadStationProxy.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationSettings.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationSettings.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationTorrent.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationTask.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationTorrentAdditional.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationTaskAdditional.cs" />
<Compile Include="Download\Clients\DownloadStation\Proxies\DSMInfoProxy.cs" /> <Compile Include="Download\Clients\DownloadStation\Proxies\DSMInfoProxy.cs" />
<Compile Include="Download\Clients\DownloadStation\Proxies\FileStationProxy.cs" /> <Compile Include="Download\Clients\DownloadStation\Proxies\FileStationProxy.cs" />
<Compile Include="Download\Clients\DownloadStation\Proxies\DiskStationProxyBase.cs" /> <Compile Include="Download\Clients\DownloadStation\Proxies\DiskStationProxyBase.cs" />
<Compile Include="Download\Clients\DownloadStation\Responses\DiskStationAuthResponse.cs" /> <Compile Include="Download\Clients\DownloadStation\Responses\DiskStationAuthResponse.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationTorrentFile.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationTaskFile.cs" />
<Compile Include="Download\Clients\DownloadStation\Responses\DSMInfoResponse.cs" /> <Compile Include="Download\Clients\DownloadStation\Responses\DSMInfoResponse.cs" />
<Compile Include="Download\Clients\DownloadStation\Responses\FileStationListFileInfoResponse.cs" /> <Compile Include="Download\Clients\DownloadStation\Responses\FileStationListFileInfoResponse.cs" />
<Compile Include="Download\Clients\DownloadStation\Responses\FileStationListResponse.cs" /> <Compile Include="Download\Clients\DownloadStation\Responses\FileStationListResponse.cs" />
@ -375,6 +375,7 @@
<Compile Include="Download\Clients\DownloadStation\SharedFolderMapping.cs" /> <Compile Include="Download\Clients\DownloadStation\SharedFolderMapping.cs" />
<Compile Include="Download\Clients\DownloadStation\SharedFolderResolver.cs" /> <Compile Include="Download\Clients\DownloadStation\SharedFolderResolver.cs" />
<Compile Include="Download\Clients\DownloadStation\DiskStationApi.cs" /> <Compile Include="Download\Clients\DownloadStation\DiskStationApi.cs" />
<Compile Include="Download\Clients\DownloadStation\UsenetDownloadStation.cs" />
<Compile Include="Download\Clients\Hadouken\Hadouken.cs" /> <Compile Include="Download\Clients\Hadouken\Hadouken.cs" />
<Compile Include="Download\Clients\Hadouken\HadoukenProxy.cs" /> <Compile Include="Download\Clients\Hadouken\HadoukenProxy.cs" />
<Compile Include="Download\Clients\Hadouken\HadoukenSettings.cs" /> <Compile Include="Download\Clients\Hadouken\HadoukenSettings.cs" />