diff --git a/src/NzbDrone.Common/Http/HttpUri.cs b/src/NzbDrone.Common/Http/HttpUri.cs index cbbecd718..ebba19e27 100644 --- a/src/NzbDrone.Common/Http/HttpUri.cs +++ b/src/NzbDrone.Common/Http/HttpUri.cs @@ -135,7 +135,7 @@ namespace NzbDrone.Common.Http return new HttpUri(Scheme, Host, Port, CombinePath(Path, path), Query, Fragment); } - private static string CombinePath(string basePath, string relativePath) + public static string CombinePath(string basePath, string relativePath) { if (relativePath.IsNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs index ab4b29783..c20548e57 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs @@ -286,7 +286,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { return new NzbDroneValidationFailure("TvCategory", "Category does not exist") { - InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings), DetailedDescription = "The Category your entered doesn't exist in NzbGet. Go to NzbGet to create it." }; } @@ -304,7 +304,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0") { - InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings), DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Sonarr from seeing completed downloads." }; } @@ -312,7 +312,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be less than 25000") { - InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings), DetailedDescription = "NzbGet setting KeepHistory is set too high." }; } diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs index 7338fdecd..89fc35049 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { public interface INzbgetProxy { + string GetBaseUrl(NzbgetSettings settings, string relativePath = null); string DownloadNzb(byte[] nzbData, string title, string category, int priority, bool addpaused, NzbgetSettings settings); NzbgetGlobalStatus GetGlobalStatus(NzbgetSettings settings); List GetQueue(NzbgetSettings settings); @@ -36,9 +37,17 @@ namespace NzbDrone.Core.Download.Clients.Nzbget _versionCache = cacheManager.GetCache(GetType(), "versions"); } + public string GetBaseUrl(NzbgetSettings settings, string relativePath = null) + { + var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase); + baseUrl = HttpUri.CombinePath(baseUrl, relativePath); + + return baseUrl; + } + private bool HasVersion(int minimumVersion, NzbgetSettings settings) { - var versionString = _versionCache.Find(settings.Host + ":" + settings.Port) ?? GetVersion(settings); + var versionString = _versionCache.Find(GetBaseUrl(settings)) ?? GetVersion(settings); var version = int.Parse(versionString.Split(new[] { '.', '-' })[0]); @@ -139,7 +148,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { var response = ProcessRequest(settings, "version"); - _versionCache.Set(settings.Host + ":" + settings.Port, response, TimeSpan.FromDays(1)); + _versionCache.Set(GetBaseUrl(settings), response, TimeSpan.FromDays(1)); return response; } @@ -170,7 +179,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget queueItem = queue.SingleOrDefault(h => h.Parameters.Any(p => p.Name == "drone" && id == (p.Value as string))); historyItem = history.SingleOrDefault(h => h.Parameters.Any(p => p.Name == "drone" && id == (p.Value as string))); } - + if (queueItem != null) { if (!EditQueue("GroupFinalDelete", 0, "", queueItem.NzbId, settings)) @@ -218,7 +227,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget private T ProcessRequest(NzbgetSettings settings, string method, params object[] parameters) { - var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, "jsonrpc"); + var baseUrl = GetBaseUrl(settings, "jsonrpc"); var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters); requestBuilder.LogResponseContent = true; diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs index 5bd604b36..1e82c49e2 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs @@ -1,4 +1,5 @@ using FluentValidation; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; @@ -11,6 +12,8 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { RuleFor(c => c.Host).ValidHost(); RuleFor(c => c.Port).InclusiveBetween(1, 65535); + RuleFor(c => c.UrlBase).ValidUrlBase().When(c => c.UrlBase.IsNotNullOrWhiteSpace()); + RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password)); RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username)); @@ -37,25 +40,28 @@ namespace NzbDrone.Core.Download.Clients.Nzbget [FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)] public int Port { get; set; } - [FieldDefinition(2, Label = "Username", Type = FieldType.Textbox)] + [FieldDefinition(2, Label = "Url Base", Type = FieldType.Textbox, Advanced = true, HelpText = "Adds a prefix to the nzbget url, e.g. http://[host]:[port]/[urlBase]/jsonrpc")] + public string UrlBase { get; set; } + + [FieldDefinition(3, Label = "Username", Type = FieldType.Textbox)] public string Username { get; set; } - [FieldDefinition(3, Label = "Password", Type = FieldType.Password)] + [FieldDefinition(4, Label = "Password", Type = FieldType.Password)] public string Password { get; set; } - [FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")] public string TvCategory { get; set; } - [FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] + [FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] public int RecentTvPriority { get; set; } - [FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] + [FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] public int OlderTvPriority { get; set; } - [FieldDefinition(7, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NzbGet version 16.0")] + [FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NzbGet version 16.0")] public bool AddPaused { get; set; } - [FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)] + [FieldDefinition(9, Label = "Use SSL", Type = FieldType.Checkbox)] public bool UseSsl { get; set; } public NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs index 1e4840df8..9d88a75e7 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs @@ -419,7 +419,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("", "Disable 'Check before download' option in Sabnbzd") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/switches/"), DetailedDescription = "Using Check before download affects Sonarr ability to track new downloads. Also Sabnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective." }; } @@ -438,7 +438,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("TvCategory", "Enable Job folders") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"), DetailedDescription = "Sonarr prefers each download to have a separate folder. With * appended to the Folder/Path Sabnzbd will not create these job folders. Go to Sabnzbd to fix it." }; } @@ -449,7 +449,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("TvCategory", "Category does not exist") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"), DetailedDescription = "The Category your entered doesn't exist in Sabnzbd. Go to Sabnzbd to create it." }; } @@ -458,7 +458,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("TvCategory", "Disable TV Sorting") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"), DetailedDescription = "You must disable Sabnzbd TV Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it." }; } @@ -466,7 +466,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("TvCategory", "Disable Movie Sorting") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"), DetailedDescription = "You must disable Sabnzbd Movie Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it." }; } @@ -474,7 +474,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { return new NzbDroneValidationFailure("TvCategory", "Disable Date Sorting") { - InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), + InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"), DetailedDescription = "You must disable Sabnzbd Date Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it." }; } diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs index 282f901d7..0f5234727 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { public interface ISabnzbdProxy { + string GetBaseUrl(SabnzbdSettings settings, string relativePath = null); SabnzbdAddResponse DownloadNzb(byte[] nzbData, string filename, string category, int priority, SabnzbdSettings settings); void RemoveFrom(string source, string id,bool deleteData, SabnzbdSettings settings); string GetVersion(SabnzbdSettings settings); @@ -32,6 +33,14 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd _logger = logger; } + public string GetBaseUrl(SabnzbdSettings settings, string relativePath = null) + { + var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase); + baseUrl = HttpUri.CombinePath(baseUrl, relativePath); + + return baseUrl; + } + public SabnzbdAddResponse DownloadNzb(byte[] nzbData, string filename, string category, int priority, SabnzbdSettings settings) { var request = BuildRequest("addfile", settings).Post(); @@ -140,10 +149,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd private HttpRequestBuilder BuildRequest(string mode, SabnzbdSettings settings) { - var baseUrl = string.Format(@"{0}://{1}:{2}/api", - settings.UseSsl ? "https" : "http", - settings.Host, - settings.Port); + var baseUrl = GetBaseUrl(settings, "api"); var requestBuilder = new HttpRequestBuilder(baseUrl) .Accept(HttpAccept.Json) diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs index a4f21b70a..9065c287d 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs @@ -49,25 +49,28 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd [FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)] public int Port { get; set; } - [FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox)] + [FieldDefinition(2, Label = "Url Base", Type = FieldType.Textbox, Advanced = true, HelpText = "Adds a prefix to the Sabnzbd url, e.g. http://[host]:[port]/[urlBase]/api")] + public string UrlBase { get; set; } + + [FieldDefinition(3, Label = "API Key", Type = FieldType.Textbox)] public string ApiKey { get; set; } - [FieldDefinition(3, Label = "Username", Type = FieldType.Textbox)] + [FieldDefinition(4, Label = "Username", Type = FieldType.Textbox)] public string Username { get; set; } - [FieldDefinition(4, Label = "Password", Type = FieldType.Password)] + [FieldDefinition(5, Label = "Password", Type = FieldType.Password)] public string Password { get; set; } - [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")] public string TvCategory { get; set; } - [FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] + [FieldDefinition(7, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] public int RecentTvPriority { get; set; } - [FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] + [FieldDefinition(8, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] public int OlderTvPriority { get; set; } - [FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)] + [FieldDefinition(9, Label = "Use SSL", Type = FieldType.Checkbox)] public bool UseSsl { get; set; } public NzbDroneValidationResult Validate()