1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-16 11:37:58 +02:00

Fixed: DownloadStation api client for DSM 5.x.

This commit is contained in:
margaale 2017-03-07 16:43:58 -03:00 committed by Taloth
parent 29419d6575
commit 5033886b90
12 changed files with 322 additions and 318 deletions

View File

@ -275,7 +275,7 @@ public void Setup()
{ "default_destination", _defaultDestination }, { "default_destination", _defaultDestination },
}; };
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>())) .Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems); .Returns(_downloadStationConfigItems);
} }
@ -311,7 +311,7 @@ protected virtual void GivenTasks(List<DownloadStationTask> torrents)
torrents = new List<DownloadStationTask>(); torrents = new List<DownloadStationTask>();
} }
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>())) .Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>()))
.Returns(torrents); .Returns(torrents);
} }
@ -330,11 +330,11 @@ protected void GivenSuccessfulDownload()
.Setup(s => s.Get(It.IsAny<HttpRequest>())) .Setup(s => s.Get(It.IsAny<HttpRequest>()))
.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<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromUrl(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<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromData(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);
} }
@ -352,7 +352,7 @@ protected int GivenAllKindOfTasks()
{ {
var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding }; var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(d => d.GetTasks(_settings)) .Setup(d => d.GetTasks(_settings))
.Returns(tasks); .Returns(tasks);
@ -372,7 +372,7 @@ public void Download_with_TvDirectory_should_force_directory()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -389,7 +389,7 @@ public void Download_with_category_should_force_directory()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -405,7 +405,7 @@ public void Download_without_TvDirectory_and_Category_should_use_default()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -482,7 +482,7 @@ public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode)); Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
} }

View File

@ -177,7 +177,7 @@ public void Setup()
{ "default_destination", _defaultDestination }, { "default_destination", _defaultDestination },
}; };
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>())) .Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems); .Returns(_downloadStationConfigItems);
} }
@ -213,7 +213,7 @@ protected virtual void GivenTasks(List<DownloadStationTask> nzbs)
nzbs = new List<DownloadStationTask>(); nzbs = new List<DownloadStationTask>();
} }
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>())) .Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>()))
.Returns(nzbs); .Returns(nzbs);
} }
@ -233,7 +233,7 @@ protected void GivenSuccessfulDownload()
.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<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromData(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);
} }
@ -242,7 +242,7 @@ protected void GivenAllKindOfTasks()
{ {
var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding }; var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(d => d.GetTasks(_settings)) .Setup(d => d.GetTasks(_settings))
.Returns(tasks); .Returns(tasks);
} }
@ -260,7 +260,7 @@ public void Download_with_TvDirectory_should_force_directory()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -277,7 +277,7 @@ public void Download_with_category_should_force_directory()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once()); .Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -293,7 +293,7 @@ public void Download_without_TvDirectory_and_Category_should_use_default()
id.Should().NotBeNullOrEmpty(); id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationProxy>() 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>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
} }
@ -370,7 +370,7 @@ public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode)); Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationProxy>() Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never()); .Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
} }

View File

@ -1,13 +1,19 @@
namespace NzbDrone.Core.Download.Clients.DownloadStation namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class DiskStationApiInfo public class DiskStationApiInfo
{ {
private string _path; private string _path;
public int MaxVersion { get; set; } public int MaxVersion { get; set; }
public int MinVersion { get; set; } public int MinVersion { get; set; }
public DiskStationApi Type { get; set; }
public string Name { get; set; }
public bool NeedsAuthentication { get; set; }
public string Path public string Path
{ {
get { return _path; } get { return _path; }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Download.Clients.DownloadStation.Responses; using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
@ -13,20 +14,19 @@ public interface IDSMInfoProxy
public class DSMInfoProxy : DiskStationProxyBase, IDSMInfoProxy public class DSMInfoProxy : DiskStationProxyBase, IDSMInfoProxy
{ {
public DSMInfoProxy(IHttpClient httpClient, Logger logger) : public DSMInfoProxy(IHttpClient httpClient, ICacheManager cacheManager, Logger logger) :
base(httpClient, logger) base(DiskStationApi.DSMInfo, "SYNO.DSM.Info", httpClient, cacheManager, logger)
{ {
} }
public string GetSerialNumber(DownloadStationSettings settings) public string GetSerialNumber(DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object>() { var info = GetApiInfo(settings);
{ "api", "SYNO.DSM.Info" },
{ "version", "2" }, var requestBuilder = BuildRequest(settings, "getinfo", info.MinVersion);
{ "method", "getinfo" }
}; var response = ProcessRequest<DSMInfoResponse>(requestBuilder, "get serial number", settings);
var response = ProcessRequest<DSMInfoResponse>(DiskStationApi.DSMInfo, arguments, settings, "get serial number");
return response.Data.SerialNumber; return response.Data.SerialNumber;
} }
} }

View File

@ -1,63 +1,77 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using NLog; using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Download.Clients.DownloadStation.Responses; using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{ {
public abstract class DiskStationProxyBase public interface IDiskStationProxy
{ {
private static readonly Dictionary<DiskStationApi, string> Resources; DiskStationApiInfo GetApiInfo(DownloadStationSettings settings);
}
public abstract class DiskStationProxyBase : IDiskStationProxy
{
protected readonly Logger _logger;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
protected readonly Logger _logger; private readonly ICached<DiskStationApiInfo> _infoCache;
private bool _authenticated; private readonly ICached<string> _sessionCache;
private readonly DiskStationApi _apiType;
private readonly string _apiName;
private static readonly DiskStationApiInfo _apiInfo;
static DiskStationProxyBase() static DiskStationProxyBase()
{ {
Resources = new Dictionary<DiskStationApi, string> _apiInfo = new DiskStationApiInfo()
{ {
{ DiskStationApi.Info, "query.cgi" } Type = DiskStationApi.Info,
Name = "SYNO.API.Info",
Path = "query.cgi",
MaxVersion = 1,
MinVersion = 1,
NeedsAuthentication = false
}; };
} }
public DiskStationProxyBase(IHttpClient httpClient, Logger logger) public DiskStationProxyBase(DiskStationApi apiType,
string apiName,
IHttpClient httpClient,
ICacheManager cacheManager,
Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_logger = logger; _logger = logger;
_infoCache = cacheManager.GetCache<DiskStationApiInfo>(typeof(DiskStationProxyBase), "apiInfo");
_sessionCache = cacheManager.GetCache<string>(typeof(DiskStationProxyBase), "sessions");
_apiType = apiType;
_apiName = apiName;
} }
private string GenerateSessionCacheKey(DownloadStationSettings settings)
protected DiskStationResponse<object> ProcessRequest(DiskStationApi api,
Dictionary<string, object> arguments,
DownloadStationSettings settings,
string operation,
HttpMethod method = HttpMethod.GET)
{ {
return ProcessRequest<object>(api, arguments, settings, operation, method); return $"{settings.Username}@{settings.Host}:{settings.Port}";
} }
protected DiskStationResponse<T> ProcessRequest<T>(DiskStationApi api, protected DiskStationResponse<T> ProcessRequest<T>(HttpRequestBuilder requestBuilder,
Dictionary<string, object> arguments, string operation,
DownloadStationSettings settings, DownloadStationSettings settings) where T : new()
string operation,
HttpMethod method = HttpMethod.GET,
int retries = 0) where T : new()
{ {
if (retries == 5) return ProcessRequest<T>(requestBuilder, operation, _apiType, settings);
{ }
throw new DownloadClientException("Try to process request to {0} with {1} more than 5 times", api, arguments.ToJson().ToString());
}
if (!_authenticated && api != DiskStationApi.Info && api != DiskStationApi.DSMInfo) private DiskStationResponse<T> ProcessRequest<T>(HttpRequestBuilder requestBuilder,
{ string operation,
AuthenticateClient(settings); DiskStationApi api,
} DownloadStationSettings settings) where T : new()
{
var request = BuildRequest(settings, api, arguments, method); var request = requestBuilder.Build();
var response = _httpClient.Execute(request); var response = _httpClient.Execute(request);
_logger.Debug("Trying to {0}", operation); _logger.Debug("Trying to {0}", operation);
@ -77,16 +91,14 @@ protected DiskStationResponse<T> ProcessRequest<T>(DiskStationApi api,
if (responseContent.Error.SessionError) if (responseContent.Error.SessionError)
{ {
_authenticated = false; _sessionCache.Remove(GenerateSessionCacheKey(settings));
if (responseContent.Error.Code == 105) if (responseContent.Error.Code == 105)
{ {
throw new DownloadClientAuthenticationException(msg); throw new DownloadClientAuthenticationException(msg);
} }
return ProcessRequest<T>(api, arguments, settings, operation, method, ++retries);
} }
throw new DownloadClientException(msg); throw new DownloadClientException(msg);
} }
} }
@ -96,124 +108,126 @@ protected DiskStationResponse<T> ProcessRequest<T>(DiskStationApi api,
} }
} }
private void AuthenticateClient(DownloadStationSettings settings) private string AuthenticateClient(DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var authInfo = GetApiInfo(DiskStationApi.Auth, settings);
{
{ "api", "SYNO.API.Auth" },
{ "version", "1" },
{ "method", "login" },
{ "account", settings.Username },
{ "passwd", settings.Password },
{ "format", "cookie" },
{ "session", "DownloadStation" },
};
var authLoginRequest = BuildRequest(settings, DiskStationApi.Auth, arguments, HttpMethod.GET); var requestBuilder = BuildRequest(settings, authInfo, "login", 2);
authLoginRequest.StoreResponseCookie = true; requestBuilder.AddQueryParam("account", settings.Username);
requestBuilder.AddQueryParam("passwd", settings.Password);
requestBuilder.AddQueryParam("format", "sid");
requestBuilder.AddQueryParam("session", Guid.NewGuid().ToString());
var response = _httpClient.Execute(authLoginRequest); var authResponse = ProcessRequest<DiskStationAuthResponse>(requestBuilder, "login", DiskStationApi.Auth, settings);
var downloadStationResponse = Json.Deserialize<DiskStationResponse<DiskStationAuthResponse>>(response.Content); return authResponse.Data.SId;
var authResponse = Json.Deserialize<DiskStationResponse<DiskStationAuthResponse>>(response.Content);
_authenticated = authResponse.Success;
if (!_authenticated)
{
throw new DownloadClientAuthenticationException(downloadStationResponse.Error.GetMessage(DiskStationApi.Auth));
}
} }
private HttpRequest BuildRequest(DownloadStationSettings settings, DiskStationApi api, Dictionary<string, object> arguments, HttpMethod method) protected HttpRequestBuilder BuildRequest(DownloadStationSettings settings, string methodName, int apiVersion, HttpMethod httpVerb = HttpMethod.GET)
{ {
if (!Resources.ContainsKey(api)) var info = GetApiInfo(_apiType, settings);
{
GetApiVersion(settings, api);
}
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port).Resource($"webapi/{Resources[api]}"); return BuildRequest(settings, info, methodName, apiVersion, httpVerb);
requestBuilder.Method = method; }
private HttpRequestBuilder BuildRequest(DownloadStationSettings settings, DiskStationApiInfo apiInfo, string methodName, int apiVersion, HttpMethod httpVerb = HttpMethod.GET)
{
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port).Resource($"webapi/{apiInfo.Path}");
requestBuilder.Method = httpVerb;
requestBuilder.LogResponseContent = true; requestBuilder.LogResponseContent = true;
requestBuilder.SuppressHttpError = true; requestBuilder.SuppressHttpError = true;
requestBuilder.AllowAutoRedirect = false; requestBuilder.AllowAutoRedirect = false;
requestBuilder.Headers.ContentType = "application/json";
if (requestBuilder.Method == HttpMethod.POST) if (apiVersion < apiInfo.MinVersion || apiVersion > apiInfo.MaxVersion)
{ {
if (api == DiskStationApi.DownloadStationTask && arguments.ContainsKey("file")) throw new ArgumentOutOfRangeException(nameof(apiVersion));
{ }
requestBuilder.Headers.ContentType = "multipart/form-data";
foreach (var arg in arguments) if (httpVerb == HttpMethod.POST)
{ {
if (arg.Key == "file") if (apiInfo.NeedsAuthentication)
{
Dictionary<string, object> file = (Dictionary<string, object>)arg.Value;
requestBuilder.AddFormUpload(arg.Key, file["name"].ToString(), (byte[])file["data"]);
}
else
{
requestBuilder.AddFormParameter(arg.Key, arg.Value);
}
}
}
else
{ {
requestBuilder.Headers.ContentType = "application/json"; requestBuilder.AddFormParameter("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
} }
requestBuilder.AddFormParameter("api", apiInfo.Name);
requestBuilder.AddFormParameter("version", apiVersion);
requestBuilder.AddFormParameter("method", methodName);
} }
else else
{ {
foreach (var arg in arguments) if (apiInfo.NeedsAuthentication)
{ {
requestBuilder.AddQueryParam(arg.Key, arg.Value); requestBuilder.AddQueryParam("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
}
requestBuilder.AddQueryParam("api", apiInfo.Name);
requestBuilder.AddQueryParam("version", apiVersion);
requestBuilder.AddQueryParam("method", methodName);
}
return requestBuilder;
}
private string GenerateInfoCacheKey(DownloadStationSettings settings, DiskStationApi api)
{
return $"{settings.Host}:{settings.Port}->{api}";
}
private void UpdateApiInfo(DownloadStationSettings settings)
{
var apis = new Dictionary<string, DiskStationApi>()
{
{ "SYNO.API.Auth", DiskStationApi.Auth },
{ _apiName, _apiType }
};
var requestBuilder = BuildRequest(settings, _apiInfo, "query", _apiInfo.MinVersion);
requestBuilder.AddQueryParam("query", string.Join(",", apis.Keys));
var infoResponse = ProcessRequest<DiskStationApiInfoResponse>(requestBuilder, "get api info", _apiInfo.Type, settings);
foreach (var data in infoResponse.Data)
{
if (apis.ContainsKey(data.Key))
{
data.Value.Name = data.Key;
data.Value.Type = apis[data.Key];
data.Value.NeedsAuthentication = apis[data.Key] != DiskStationApi.Auth;
_infoCache.Set(GenerateInfoCacheKey(settings, apis[data.Key]), data.Value, TimeSpan.FromHours(1));
}
}
}
private DiskStationApiInfo GetApiInfo(DiskStationApi api, DownloadStationSettings settings)
{
if (api == DiskStationApi.Info)
{
return _apiInfo;
}
var key = GenerateInfoCacheKey(settings, api);
var info = _infoCache.Find(key);
if (info == null)
{
UpdateApiInfo(settings);
info = _infoCache.Find(key);
if (info == null)
{
throw new DownloadClientException("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
} }
} }
return requestBuilder.Build(); return info;
} }
protected IEnumerable<int> GetApiVersion(DownloadStationSettings settings, DiskStationApi api) public DiskStationApiInfo GetApiInfo(DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> return GetApiInfo(_apiType, settings);
{
{ "api", "SYNO.API.Info" },
{ "version", "1" },
{ "method", "query" },
{ "query", "SYNO.API.Auth, SYNO.DownloadStation.Info, SYNO.DownloadStation.Task, SYNO.FileStation.List, SYNO.DSM.Info" },
};
var infoResponse = ProcessRequest<DiskStationApiInfoResponse>(DiskStationApi.Info, arguments, settings, "Get api version");
//TODO: Refactor this into more elegant code
var infoResponeDSAuth = infoResponse.Data["SYNO.API.Auth"];
var infoResponeDSInfo = infoResponse.Data["SYNO.DownloadStation.Info"];
var infoResponeDSTask = infoResponse.Data["SYNO.DownloadStation.Task"];
var infoResponseFSList = infoResponse.Data["SYNO.FileStation.List"];
var infoResponseDSMInfo = infoResponse.Data["SYNO.DSM.Info"];
Resources[DiskStationApi.Auth] = infoResponeDSAuth.Path;
Resources[DiskStationApi.DownloadStationInfo] = infoResponeDSInfo.Path;
Resources[DiskStationApi.DownloadStationTask] = infoResponeDSTask.Path;
Resources[DiskStationApi.FileStationList] = infoResponseFSList.Path;
Resources[DiskStationApi.DSMInfo] = infoResponseDSMInfo.Path;
switch (api)
{
case DiskStationApi.Auth:
return Enumerable.Range(infoResponeDSAuth.MinVersion, infoResponeDSAuth.MaxVersion - infoResponeDSAuth.MinVersion + 1);
case DiskStationApi.DownloadStationInfo:
return Enumerable.Range(infoResponeDSInfo.MinVersion, infoResponeDSInfo.MaxVersion - infoResponeDSInfo.MinVersion + 1);
case DiskStationApi.DownloadStationTask:
return Enumerable.Range(infoResponeDSTask.MinVersion, infoResponeDSTask.MaxVersion - infoResponeDSTask.MinVersion + 1);
case DiskStationApi.FileStationList:
return Enumerable.Range(infoResponseFSList.MinVersion, infoResponseFSList.MaxVersion - infoResponseFSList.MinVersion + 1);
case DiskStationApi.DSMInfo:
return Enumerable.Range(infoResponseDSMInfo.MinVersion, infoResponseDSMInfo.MaxVersion - infoResponseDSMInfo.MinVersion + 1);
default:
throw new DownloadClientException("Api not implemented");
}
} }
} }
} }

View File

@ -0,0 +1,29 @@
using NLog;
using NzbDrone.Common.Http;
using System.Collections.Generic;
using NzbDrone.Common.Cache;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
public interface IDownloadStationInfoProxy : IDiskStationProxy
{
Dictionary<string, object> GetConfig(DownloadStationSettings settings);
}
public class DownloadStationInfoProxy : DiskStationProxyBase, IDownloadStationInfoProxy
{
public DownloadStationInfoProxy(IHttpClient httpClient, ICacheManager cacheManager, Logger logger) :
base(DiskStationApi.DownloadStationInfo, "SYNO.DownloadStation.Info", httpClient, cacheManager, logger)
{
}
public Dictionary<string, object> GetConfig(DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "getConfig", 1);
var response = ProcessRequest<Dictionary<string, object>>(requestBuilder, "get config", settings);
return response.Data;
}
}
}

View File

@ -1,121 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{
public interface IDownloadStationProxy
{
IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings);
Dictionary<string, object> GetConfig(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);
IEnumerable<int> GetApiVersion(DownloadStationSettings settings);
}
public class DownloadStationProxy : DiskStationProxyBase, IDownloadStationProxy
{
public DownloadStationProxy(IHttpClient httpClient, Logger logger)
: base(httpClient, logger)
{
}
public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings)
{
var arguments = new Dictionary<string, object>
{
{ "api", "SYNO.DownloadStation.Task" },
{ "version", "2" },
{ "method", "create" }
};
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
arguments.Add("destination", downloadDirectory);
}
arguments.Add("file", new Dictionary<string, object>() { { "name", filename }, { "data", data } });
var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add task from data {filename}", HttpMethod.POST);
}
public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
{
var arguments = new Dictionary<string, object>
{
{ "api", "SYNO.DownloadStation.Task" },
{ "version", "3" },
{ "method", "create" },
{ "uri", url }
};
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
arguments.Add("destination", downloadDirectory);
}
var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add task from url {url}");
}
public IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings)
{
var arguments = new Dictionary<string, object>
{
{ "api", "SYNO.DownloadStation.Task" },
{ "version", "1" },
{ "method", "list" },
{ "additional", "detail,transfer" }
};
try
{
var response = ProcessRequest<DownloadStationTaskInfoResponse>(DiskStationApi.DownloadStationTask, arguments, settings, "get tasks");
return response.Data.Tasks;
}
catch (DownloadClientException e)
{
_logger.Error(e);
return new List<DownloadStationTask>();
}
}
public Dictionary<string, object> GetConfig(DownloadStationSettings settings)
{
var arguments = new Dictionary<string, object>
{
{ "api", "SYNO.DownloadStation.Info" },
{ "version", "1" },
{ "method", "getconfig" }
};
var response = ProcessRequest<Dictionary<string, object>>(DiskStationApi.DownloadStationInfo, arguments, settings, "get config");
return response.Data;
}
public void RemoveTask(string downloadId, DownloadStationSettings settings)
{
var arguments = new Dictionary<string, object>
{
{ "api", "SYNO.DownloadStation.Task" },
{ "version", "1" },
{ "method", "delete" },
{ "id", downloadId },
{ "force_complete", false }
};
var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"remove item {downloadId}");
}
public IEnumerable<int> GetApiVersion(DownloadStationSettings settings)
{
return base.GetApiVersion(settings, DiskStationApi.DownloadStationInfo);
}
}
}

View File

@ -0,0 +1,79 @@
using System.Collections.Generic;
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 interface IDownloadStationTaskProxy : IDiskStationProxy
{
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)
: base(DiskStationApi.DownloadStationTask, "SYNO.DownloadStation.Task", httpClient, cacheManager, logger)
{
}
public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "create", 2, HttpMethod.POST);
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
requestBuilder.AddFormParameter("destination", downloadDirectory);
}
requestBuilder.AddFormUpload("file", filename, data);
var response = ProcessRequest<object>(requestBuilder, $"add task from data {filename}", settings);
}
public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "create", 3);
requestBuilder.AddQueryParam("uri", url);
if (downloadDirectory.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("destination", downloadDirectory);
}
var response = ProcessRequest<object>(requestBuilder, $"add task from url {url}", settings);
}
public IEnumerable<DownloadStationTask> GetTasks(DownloadStationSettings settings)
{
try
{
var requestBuilder = BuildRequest(settings, "list", 1);
requestBuilder.AddQueryParam("additional", "detail,transfer");
var response = ProcessRequest<DownloadStationTaskInfoResponse>(requestBuilder, "get tasks", settings);
return response.Data.Tasks;
}
catch (DownloadClientException e)
{
_logger.Error(e);
return new List<DownloadStationTask>();
}
}
public void RemoveTask(string downloadId, DownloadStationSettings settings)
{
var requestBuilder = BuildRequest(settings, "delete", 1);
requestBuilder.AddQueryParam("id", downloadId);
requestBuilder.AddQueryParam("force_complete", false);
var response = ProcessRequest<object>(requestBuilder, $"remove item {downloadId}", settings);
}
}
}

View File

@ -2,31 +2,27 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Download.Clients.DownloadStation.Responses; using NzbDrone.Core.Download.Clients.DownloadStation.Responses;
namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies
{ {
public interface IFileStationProxy public interface IFileStationProxy : IDiskStationProxy
{ {
SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadStationSettings settings); SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadStationSettings settings);
IEnumerable<int> GetApiVersion(DownloadStationSettings settings);
FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings); FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings);
} }
public class FileStationProxy : DiskStationProxyBase, IFileStationProxy public class FileStationProxy : DiskStationProxyBase, IFileStationProxy
{ {
public FileStationProxy(IHttpClient httpClient, Logger logger) public FileStationProxy(IHttpClient httpClient, ICacheManager cacheManager, Logger logger)
: base(httpClient, logger) : base(DiskStationApi.FileStationList, "SYNO.FileStation.List", httpClient, cacheManager, logger)
{ {
} }
public IEnumerable<int> GetApiVersion(DownloadStationSettings settings)
{
return base.GetApiVersion(settings, DiskStationApi.FileStationList);
}
public SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadStationSettings settings) public SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadStationSettings settings)
{ {
var info = GetInfoFileOrDirectory(sharedFolder, settings); var info = GetInfoFileOrDirectory(sharedFolder, settings);
@ -38,16 +34,11 @@ public SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadS
public FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings) public FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings)
{ {
var arguments = new Dictionary<string, object> var requestBuilder = BuildRequest(settings, "getinfo", 2);
{ requestBuilder.AddQueryParam("path", new[] { path }.ToJson());
{ "api", "SYNO.FileStation.List" }, requestBuilder.AddQueryParam("additional", "[\"real_path\"]");
{ "version", "2" },
{ "method", "getinfo" },
{ "path", new [] { path }.ToJson() },
{ "additional", $"[\"real_path\"]" }
};
var response = ProcessRequest<FileStationListResponse>(DiskStationApi.FileStationList, arguments, settings, $"get info of {path}"); var response = ProcessRequest<FileStationListResponse>(requestBuilder, $"get info of {path}", settings);
return response.Data.Files.First(); return response.Data.Files.First();
} }

View File

@ -5,7 +5,6 @@
using System.Net; using System.Net;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@ -20,7 +19,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class TorrentDownloadStation : TorrentClientBase<DownloadStationSettings> public class TorrentDownloadStation : TorrentClientBase<DownloadStationSettings>
{ {
protected readonly IDownloadStationProxy _proxy; protected readonly IDownloadStationInfoProxy _dsInfoProxy;
protected readonly IDownloadStationTaskProxy _dsTaskProxy;
protected readonly ISharedFolderResolver _sharedFolderResolver; protected readonly ISharedFolderResolver _sharedFolderResolver;
protected readonly ISerialNumberProvider _serialNumberProvider; protected readonly ISerialNumberProvider _serialNumberProvider;
protected readonly IFileStationProxy _fileStationProxy; protected readonly IFileStationProxy _fileStationProxy;
@ -28,7 +28,8 @@ public class TorrentDownloadStation : TorrentClientBase<DownloadStationSettings>
public TorrentDownloadStation(ISharedFolderResolver sharedFolderResolver, public TorrentDownloadStation(ISharedFolderResolver sharedFolderResolver,
ISerialNumberProvider serialNumberProvider, ISerialNumberProvider serialNumberProvider,
IFileStationProxy fileStationProxy, IFileStationProxy fileStationProxy,
IDownloadStationProxy proxy, IDownloadStationInfoProxy dsInfoProxy,
IDownloadStationTaskProxy dsTaskProxy,
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
@ -37,7 +38,8 @@ public TorrentDownloadStation(ISharedFolderResolver sharedFolderResolver,
Logger logger) Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
{ {
_proxy = proxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;
_fileStationProxy = fileStationProxy; _fileStationProxy = fileStationProxy;
_sharedFolderResolver = sharedFolderResolver; _sharedFolderResolver = sharedFolderResolver;
_serialNumberProvider = serialNumberProvider; _serialNumberProvider = serialNumberProvider;
@ -47,7 +49,7 @@ public TorrentDownloadStation(ISharedFolderResolver sharedFolderResolver,
protected IEnumerable<DownloadStationTask> GetTasks() protected IEnumerable<DownloadStationTask> GetTasks()
{ {
return _proxy.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() public override IEnumerable<DownloadClientItem> GetItems()
@ -129,7 +131,7 @@ public override void RemoveItem(string downloadId, bool deleteData)
DeleteItemData(downloadId); DeleteItemData(downloadId);
} }
_proxy.RemoveTask(ParseDownloadId(downloadId), Settings); _dsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId); _logger.Debug("{0} removed correctly", downloadId);
} }
@ -148,7 +150,7 @@ protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string
{ {
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings); var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTaskFromUrl(magnetLink, GetDownloadDirectory(), Settings); _dsTaskProxy.AddTaskFromUrl(magnetLink, GetDownloadDirectory(), Settings);
var item = GetTasks().SingleOrDefault(t => t.Additional.Detail["uri"] == magnetLink); var item = GetTasks().SingleOrDefault(t => t.Additional.Detail["uri"] == magnetLink);
@ -167,7 +169,7 @@ protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string
{ {
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings); var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings); _dsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = GetTasks().Where(t => t.Additional.Detail["uri"] == Path.GetFileNameWithoutExtension(filename)); var items = GetTasks().Where(t => t.Additional.Detail["uri"] == Path.GetFileNameWithoutExtension(filename));
@ -358,13 +360,13 @@ protected ValidationFailure TestConnection()
protected ValidationFailure ValidateVersion() protected ValidationFailure ValidateVersion()
{ {
var versionRange = _proxy.GetApiVersion(Settings); var info = _dsTaskProxy.GetApiInfo(Settings);
_logger.Debug("Download Station api version information: Min {0} - Max {1}", versionRange.Min(), versionRange.Max()); _logger.Debug("Download Station api version information: Min {0} - Max {1}", info.MinVersion, info.MaxVersion);
if (!versionRange.Contains(2)) if (info.MinVersion > 2 || info.MaxVersion < 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 new ValidationFailure(string.Empty, $"Download Station API version not supported, should be at least 2. It supports from {info.MinVersion} to {info.MaxVersion}");
} }
return null; return null;
@ -395,7 +397,7 @@ protected string CreateDownloadId(string id, string hashedSerialNumber)
protected string GetDefaultDir() protected string GetDefaultDir()
{ {
var config = _proxy.GetConfig(Settings); var config = _dsInfoProxy.GetConfig(Settings);
var path = config["default_destination"] as string; var path = config["default_destination"] as string;

View File

@ -17,7 +17,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
{ {
public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings> public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings>
{ {
protected readonly IDownloadStationProxy _proxy; protected readonly IDownloadStationInfoProxy _dsInfoProxy;
protected readonly IDownloadStationTaskProxy _dsTaskProxy;
protected readonly ISharedFolderResolver _sharedFolderResolver; protected readonly ISharedFolderResolver _sharedFolderResolver;
protected readonly ISerialNumberProvider _serialNumberProvider; protected readonly ISerialNumberProvider _serialNumberProvider;
protected readonly IFileStationProxy _fileStationProxy; protected readonly IFileStationProxy _fileStationProxy;
@ -25,7 +26,8 @@ public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings>
public UsenetDownloadStation(ISharedFolderResolver sharedFolderResolver, public UsenetDownloadStation(ISharedFolderResolver sharedFolderResolver,
ISerialNumberProvider serialNumberProvider, ISerialNumberProvider serialNumberProvider,
IFileStationProxy fileStationProxy, IFileStationProxy fileStationProxy,
IDownloadStationProxy proxy, IDownloadStationInfoProxy dsInfoProxy,
IDownloadStationTaskProxy dsTaskProxy,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
@ -34,7 +36,8 @@ Logger logger
) )
: base(httpClient, configService, diskProvider, remotePathMappingService, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, logger)
{ {
_proxy = proxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;
_fileStationProxy = fileStationProxy; _fileStationProxy = fileStationProxy;
_sharedFolderResolver = sharedFolderResolver; _sharedFolderResolver = sharedFolderResolver;
_serialNumberProvider = serialNumberProvider; _serialNumberProvider = serialNumberProvider;
@ -44,7 +47,7 @@ Logger logger
protected IEnumerable<DownloadStationTask> GetTasks() protected IEnumerable<DownloadStationTask> GetTasks()
{ {
return _proxy.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() public override IEnumerable<DownloadClientItem> GetItems()
@ -153,7 +156,7 @@ public override void RemoveItem(string downloadId, bool deleteData)
DeleteItemData(downloadId); DeleteItemData(downloadId);
} }
_proxy.RemoveTask(ParseDownloadId(downloadId), Settings); _dsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
_logger.Debug("{0} removed correctly", downloadId); _logger.Debug("{0} removed correctly", downloadId);
} }
@ -161,7 +164,7 @@ protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string fil
{ {
var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings); var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
_proxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings); _dsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
var items = GetTasks().Where(t => t.Additional.Detail["uri"] == filename); var items = GetTasks().Where(t => t.Additional.Detail["uri"] == filename);
@ -276,13 +279,13 @@ protected ValidationFailure TestConnection()
protected ValidationFailure ValidateVersion() protected ValidationFailure ValidateVersion()
{ {
var versionRange = _proxy.GetApiVersion(Settings); var info = _dsTaskProxy.GetApiInfo(Settings);
_logger.Debug("Download Station api version information: Min {0} - Max {1}", versionRange.Min(), versionRange.Max()); _logger.Debug("Download Station api version information: Min {0} - Max {1}", info.MinVersion, info.MaxVersion);
if (!versionRange.Contains(2)) if (info.MinVersion > 2 || info.MaxVersion < 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 new ValidationFailure(string.Empty, $"Download Station API version not supported, should be at least 2. It supports from {info.MinVersion} to {info.MaxVersion}");
} }
return null; return null;
@ -394,7 +397,7 @@ protected string CreateDownloadId(string id, string hashedSerialNumber)
protected string GetDefaultDir() protected string GetDefaultDir()
{ {
var config = _proxy.GetConfig(Settings); var config = _dsInfoProxy.GetConfig(Settings);
var path = config["default_destination"] as string; var path = config["default_destination"] as string;

View File

@ -355,8 +355,9 @@
<Compile Include="Download\Clients\Deluge\DelugeUpdateUIResult.cs" /> <Compile Include="Download\Clients\Deluge\DelugeUpdateUIResult.cs" />
<Compile Include="Download\Clients\DownloadClientAuthenticationException.cs" /> <Compile Include="Download\Clients\DownloadClientAuthenticationException.cs" />
<Compile Include="Download\Clients\DownloadClientException.cs" /> <Compile Include="Download\Clients\DownloadClientException.cs" />
<Compile Include="Download\Clients\DownloadStation\Proxies\DownloadStationInfoProxy.cs" />
<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\DownloadStationTaskProxy.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationSettings.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationSettings.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationTask.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationTask.cs" />
<Compile Include="Download\Clients\DownloadStation\DownloadStationTaskAdditional.cs" /> <Compile Include="Download\Clients\DownloadStation\DownloadStationTaskAdditional.cs" />