diff --git a/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs b/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs index e03161702..e7ab0126d 100644 --- a/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs @@ -92,6 +92,10 @@ namespace NzbDrone.Common.Http { data = new XElement("base64", Convert.ToBase64String(bytes)); } + else if (value is Dictionary d) + { + data = new XElement("struct", d.Select(p => new XElement("member", new XElement("name", p.Key), new XElement("value", p.Value)))); + } else { throw new InvalidOperationException($"Unhandled argument type {value.GetType().Name}"); diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs index f141ef7ce..52f5a1bde 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using System.Xml.XPath; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Download.Extensions; @@ -97,8 +98,14 @@ namespace NzbDrone.Core.Download.Clients.Aria2 public string AddMagnet(Aria2Settings settings, string magnet) { - var response = ExecuteRequest(settings, "aria2.addUri", GetToken(settings), new List { magnet }); + var options = new Dictionary(); + if (settings.Directory.IsNotNullOrWhiteSpace()) + { + options.Add("dir", settings.Directory); + } + + var response = ExecuteRequest(settings, "aria2.addUri", GetToken(settings), new List { magnet }, options); var gid = response.GetStringResponse(); return gid; @@ -106,8 +113,16 @@ namespace NzbDrone.Core.Download.Clients.Aria2 public string AddTorrent(Aria2Settings settings, byte[] torrent) { - var response = ExecuteRequest(settings, "aria2.addTorrent", GetToken(settings), torrent); + // Aria2's second parameter is an array of URIs and needs to be sent if options are provided, this satisfies that requirement. + var emptyListOfUris = new List(); + var options = new Dictionary(); + if (settings.Directory.IsNotNullOrWhiteSpace()) + { + options.Add("dir", settings.Directory); + } + + var response = ExecuteRequest(settings, "aria2.addTorrent", GetToken(settings), torrent, emptyListOfUris, options); var gid = response.GetStringResponse(); return gid; diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs index 29449f739..82e4d93ab 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs @@ -40,6 +40,10 @@ namespace NzbDrone.Core.Download.Clients.Aria2 [FieldDefinition(4, Label = "Secret token", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string SecretToken { get; set; } + + [FieldDefinition(5, Label = "Directory", Type = FieldType.Textbox, HelpText = "DownloadClientAriaSettingsDirectoryHelpText")] + public string Directory { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 9cfa1f5e4..8608ab06b 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -315,6 +315,7 @@ "DoneEditingGroups": "Done Editing Groups", "Download": "Download", "DownloadClient": "Download Client", + "DownloadClientAriaSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Aria2 location", "DownloadClientCheckDownloadingToRoot": "Download client {downloadClientName} places downloads in the root folder {path}. You should not download to a root folder.", "DownloadClientCheckNoneAvailableMessage": "No download client is available", "DownloadClientCheckUnableToCommunicateMessage": "Unable to communicate with {downloadClientName}. {errorMessage}",