Fixed: Compatibility with the new Download Station API

Fixes #2289
Fixes #2338
pull/2420/head
Qstick 3 years ago
parent 7548c17007
commit 0d7b6f8a4f

@ -288,6 +288,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems);
Mocker.GetMock<IDownloadStationTaskProxySelector>()
.Setup(s => s.GetProxy(It.IsAny<DownloadStationSettings>()))
.Returns(Mocker.GetMock<IDownloadStationTaskProxy>().Object);
}
protected void GivenSharedFolder()
@ -427,7 +431,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _defaultDestination, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]

@ -180,6 +180,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems);
Mocker.GetMock<IDownloadStationTaskProxySelector>()
.Setup(s => s.GetProxy(It.IsAny<DownloadStationSettings>()))
.Returns(Mocker.GetMock<IDownloadStationTaskProxy>().Object);
}
protected void GivenSharedFolder()
@ -304,7 +308,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _defaultDestination, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]

@ -6,6 +6,7 @@
Auth,
DownloadStationInfo,
DownloadStationTask,
DownloadStation2Task,
FileStationList,
DSMInfo,
}

@ -0,0 +1,31 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Download.Clients.DownloadStation
{
public class DownloadStation2Task
{
public string Username { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public long Size { get; set; }
/// <summary>
/// /// Possible values are: BT, NZB, http, ftp, eMule and https
/// </summary>
public string Type { get; set; }
public int Status { get; set; }
public DownloadStationTaskAdditional Additional { get; set; }
public override string ToString()
{
return this.Title;
}
}
}

@ -167,7 +167,14 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
if (apiInfo.NeedsAuthentication)
{
requestBuilder.AddFormParameter("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
if (_apiType == DiskStationApi.DownloadStation2Task)
{
requestBuilder.AddQueryParam("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
}
else
{
requestBuilder.AddFormParameter("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
}
}
requestBuilder.AddFormParameter("api", apiInfo.Name);
@ -237,7 +244,14 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
if (info == null)
{
throw new DownloadClientException("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
if (api == DiskStationApi.DownloadStation2Task)
{
_logger.Warn("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
}
else
{
throw new DownloadClientException("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
}
}
}

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
public interface IDownloadStationTaskProxy : IDiskStationProxy
{
bool IsApiSupported(DownloadStationSettings settings);
IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings);
void RemoveTask(string downloadId, DownloadStationSettings settings);
void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings);
void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings);
}
public interface IDownloadStationTaskProxySelector
{
IDownloadStationTaskProxy GetProxy(DownloadStationSettings settings);
}
public class DownloadStationTaskProxySelector : IDownloadStationTaskProxySelector
{
private readonly ICached<IDownloadStationTaskProxy> _proxyCache;
private readonly Logger _logger;
private readonly IDownloadStationTaskProxy _proxyV1;
private readonly IDownloadStationTaskProxy _proxyV2;
public DownloadStationTaskProxySelector(DownloadStationTaskProxyV1 proxyV1, DownloadStationTaskProxyV2 proxyV2, ICacheManager cacheManager, Logger logger)
{
_proxyCache = cacheManager.GetCache<IDownloadStationTaskProxy>(GetType(), "taskProxy");
_logger = logger;
_proxyV1 = proxyV1;
_proxyV2 = proxyV2;
}
public IDownloadStationTaskProxy GetProxy(DownloadStationSettings settings)
{
return GetProxyCache(settings);
}
private IDownloadStationTaskProxy GetProxyCache(DownloadStationSettings settings)
{
var propKey = $"{settings.Host}_{settings.Port}";
return _proxyCache.Get(propKey, () => FetchProxy(settings), TimeSpan.FromMinutes(10.0));
}
private IDownloadStationTaskProxy FetchProxy(DownloadStationSettings settings)
{
if (_proxyV2.IsApiSupported(settings))
{
_logger.Trace("Using DownloadStation Task API v2");
return _proxyV2;
}
if (_proxyV1.IsApiSupported(settings))
{
_logger.Trace("Using DownloadStation Task API v1");
return _proxyV1;
}
throw new DownloadClientException("Unable to determine DownloadStations Task API version");
}
}
}

@ -7,21 +7,18 @@ using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
public interface IDownloadStationTaskProxy : IDiskStationProxy
public class DownloadStationTaskProxyV1 : DiskStationProxyBase, IDownloadStationTaskProxy
{
IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings);
void RemoveTask(string downloadId, DownloadStationSettings settings);
void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings);
void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings);
}
public class DownloadStationTaskProxy : DiskStationProxyBase, IDownloadStationTaskProxy
{
public DownloadStationTaskProxy(IHttpClient httpClient, ICacheManager cacheManager, Logger logger)
public DownloadStationTaskProxyV1(IHttpClient httpClient, ICacheManager cacheManager, Logger logger)
: base(DiskStationApi.DownloadStationTask, "SYNO.DownloadStation.Task", httpClient, cacheManager, logger)
{
}
public bool IsApiSupported(DownloadStationSettings settings)
{
return GetApiInfo(settings) != null;
}
public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "create", 2, HttpMethod.POST);

@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
public class DownloadStationTaskProxyV2 : DiskStationProxyBase, IDownloadStationTaskProxy
{
public DownloadStationTaskProxyV2(IHttpClient httpClient, ICacheManager cacheManager, Logger logger)
: base(DiskStationApi.DownloadStation2Task, "SYNO.DownloadStation2.Task", httpClient, cacheManager, logger)
{
}
public bool IsApiSupported(DownloadStationSettings settings)
{
return GetApiInfo(settings) != null;
}
public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "create", 2, HttpMethod.POST);
requestBuilder.AddFormParameter("type", "\"file\"");
requestBuilder.AddFormParameter("file", "[\"fileData\"]");
requestBuilder.AddFormParameter("create_list", "false");
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
requestBuilder.AddFormParameter("destination", $"\"{downloadDirectory}\"");
}
requestBuilder.AddFormUpload("fileData", filename, data);
ProcessRequest<object>(requestBuilder, $"add task from data {filename}", settings);
}
public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "create", 2);
requestBuilder.AddQueryParam("type", "url");
requestBuilder.AddQueryParam("url", url);
requestBuilder.AddQueryParam("create_list", "false");
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("destination", downloadDirectory);
}
ProcessRequest<object>(requestBuilder, $"add task from url {url}", settings);
}
public IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings)
{
try
{
var result = new List<DownloadStationTask>();
var requestBuilder = BuildRequest(settings, "list", 1);
requestBuilder.AddQueryParam("additional", "detail");
var response = ProcessRequest<DownloadStation2TaskInfoResponse>(requestBuilder, "get tasks with additional detail", settings);
if (response.Success && response.Data.Total > 0)
{
requestBuilder.AddQueryParam("additional", "transfer");
var responseTransfer = ProcessRequest<DownloadStation2TaskInfoResponse>(requestBuilder, "get tasks with additional transfer", settings);
if (responseTransfer.Success)
{
foreach (var task in response.Data.Task)
{
var taskTransfer = responseTransfer.Data.Task.Where(t => t.Id == task.Id).First();
var combinedTask = new DownloadStationTask
{
Username = task.Username,
Id = task.Id,
Title = task.Title,
Size = task.Size,
Status = (DownloadStationTaskStatus)task.Status,
Type = task.Type,
Additional = new DownloadStationTaskAdditional
{
Detail = task.Additional.Detail,
Transfer = taskTransfer.Additional.Transfer
}
};
result.Add(combinedTask);
}
}
}
return result;
}
catch (DownloadClientException e)
{
_logger.Error(e);
return new List<DownloadStationTask>();
}
}
public void RemoveTask(string downloadId, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "delete", 2);
requestBuilder.AddQueryParam("id", downloadId);
requestBuilder.AddQueryParam("force_complete", "false");
ProcessRequest<object>(requestBuilder, $"remove item {downloadId}", settings);
}
}
}

@ -85,7 +85,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Responses
return AuthMessages[Code];
}
if (api == DiskStationApi.DownloadStationTask && DownloadStationTaskMessages.ContainsKey(Code))
if ((api == DiskStationApi.DownloadStationTask || api == DiskStationApi.DownloadStation2Task) && DownloadStationTaskMessages.ContainsKey(Code))
{
return DownloadStationTaskMessages[Code];
}

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Responses
{
public class DownloadStation2TaskInfoResponse
{
public int Offset { get; set; }
public List<DownloadStation2Task> Task { get; set; }
public int Total { get; set; }
}
}

@ -21,7 +21,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
public class TorrentDownloadStation : TorrentClientBase<DownloadStationSettings>
{
protected readonly IDownloadStationInfoProxy _dsInfoProxy;
protected readonly IDownloadStationTaskProxy _dsTaskProxy;
protected readonly IDownloadStationTaskProxySelector _dsTaskProxySelector;
protected readonly ISharedFolderResolver _sharedFolderResolver;
protected readonly ISerialNumberProvider _serialNumberProvider;
protected readonly IFileStationProxy _fileStationProxy;
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
ISerialNumberProvider serialNumberProvider,
IFileStationProxy fileStationProxy,
IDownloadStationInfoProxy dsInfoProxy,
IDownloadStationTaskProxy dsTaskProxy,
IDownloadStationTaskProxySelector dsTaskProxySelector,
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;
_dsTaskProxySelector = dsTaskProxySelector;
_fileStationProxy = fileStationProxy;
_sharedFolderResolver = sharedFolderResolver;
_serialNumberProvider = serialNumberProvider;
@ -50,9 +50,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
public override ProviderMessage Message => new ProviderMessage("Lidarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning);
private IDownloadStationTaskProxy DsTaskProxy => _dsTaskProxySelector.GetProxy(Settings);
protected IEnumerable<DownloadStationTask> GetTasks()
{
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.BT.ToString().ToLower());
return DsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.BT.ToString().ToLower());
}
public override IEnumerable<DownloadClientItem> GetItems()
@ -139,7 +141,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
DeleteItemData(downloadId);
}
_dsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
DsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId);
}
@ -158,7 +160,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_dsTaskProxy.AddTaskFromUrl(magnetLink, GetDownloadDirectory(), Settings);
DsTaskProxy.AddTaskFromUrl(magnetLink, GetDownloadDirectory(), Settings);
var item = GetTasks().SingleOrDefault(t => t.Additional.Detail["uri"] == magnetLink);
@ -177,7 +179,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_dsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
DsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = GetTasks().Where(t => t.Additional.Detail["uri"] == Path.GetFileNameWithoutExtension(filename));
@ -398,7 +400,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected ValidationFailure ValidateVersion()
{
var info = _dsTaskProxy.GetApiInfo(Settings);
var info = DsTaskProxy.GetApiInfo(Settings);
_logger.Debug("Download Station api version information: Min {0} - Max {1}", info.MinVersion, info.MaxVersion);
@ -448,14 +450,15 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{
return Settings.TvDirectory.TrimStart('/');
}
else if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
{
var destDir = GetDefaultDir();
var destDir = GetDefaultDir();
if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
{
return $"{destDir.TrimEnd('/')}/{Settings.MusicCategory}";
}
return null;
return destDir.TrimEnd('/');
}
}
}

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings>
{
protected readonly IDownloadStationInfoProxy _dsInfoProxy;
protected readonly IDownloadStationTaskProxy _dsTaskProxy;
protected readonly IDownloadStationTaskProxySelector _dsTaskProxySelector;
protected readonly ISharedFolderResolver _sharedFolderResolver;
protected readonly ISerialNumberProvider _serialNumberProvider;
protected readonly IFileStationProxy _fileStationProxy;
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
ISerialNumberProvider serialNumberProvider,
IFileStationProxy fileStationProxy,
IDownloadStationInfoProxy dsInfoProxy,
IDownloadStationTaskProxy dsTaskProxy,
IDownloadStationTaskProxySelector dsTaskProxySelector,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;
_dsTaskProxySelector = dsTaskProxySelector;
_fileStationProxy = fileStationProxy;
_sharedFolderResolver = sharedFolderResolver;
_serialNumberProvider = serialNumberProvider;
@ -48,9 +48,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
public override ProviderMessage Message => new ProviderMessage("Lidarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning);
private IDownloadStationTaskProxy DsTaskProxy => _dsTaskProxySelector.GetProxy(Settings);
protected IEnumerable<DownloadStationTask> GetTasks()
{
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.NZB.ToString().ToLower());
return DsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.NZB.ToString().ToLower());
}
public override IEnumerable<DownloadClientItem> GetItems()
@ -163,7 +165,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
DeleteItemData(downloadId);
}
_dsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
DsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId);
}
@ -171,7 +173,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_dsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
DsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = GetTasks().Where(t => t.Additional.Detail["uri"] == filename);
@ -296,7 +298,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected ValidationFailure ValidateVersion()
{
var info = _dsTaskProxy.GetApiInfo(Settings);
var info = DsTaskProxy.GetApiInfo(Settings);
_logger.Debug("Download Station api version information: Min {0} - Max {1}", info.MinVersion, info.MaxVersion);
@ -424,14 +426,15 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{
return Settings.TvDirectory.TrimStart('/');
}
else if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
{
var destDir = GetDefaultDir();
var destDir = GetDefaultDir();
if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
{
return $"{destDir.TrimEnd('/')}/{Settings.MusicCategory}";
}
return null;
return destDir.TrimEnd('/');
}
}
}

Loading…
Cancel
Save