diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs index f23a2b762..c72c165e5 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Net; using FizzWare.NBuilder; @@ -46,30 +47,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests .ToList(); } - private void WithFailResponse() - { - Mocker.GetMock() - .Setup(s => s.DownloadString(It.IsAny())).Returns("{ \"status\": false, \"error\": \"API Key Required\" }"); - } - - [Test] - public void add_url_should_format_request_properly() - { - Mocker.GetMock(MockBehavior.Strict) - .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=addurl&name=http://www.nzbclub.com/nzb_download.aspx?mid=1950232&priority=0&pp=3&cat=tv&nzbname=My+Series+Name+-+5x2-5x3+-+My+title+%5bBluray720p%5d+%5bProper%5d&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) - .Returns("{ \"status\": true }"); - - - Subject.DownloadNzb(_remoteEpisode); - } - - [Test] - public void add_by_url_should_detect_and_handle_sab_errors() - { - WithFailResponse(); - Assert.Throws(() => Subject.DownloadNzb(_remoteEpisode)); - } - [Test] public void should_be_able_to_get_categories_when_config_is_passed_in() { @@ -195,15 +172,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests result.Should().Be("0.6.9"); } - [Test] - public void should_throw_when_WebException_is_thrown() - { - Mocker.GetMock() - .Setup(s => s.DownloadString(It.IsAny())).Throws(new WebException()); - - Assert.Throws(() => Subject.DownloadNzb(_remoteEpisode)); - } - [Test] public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true() { @@ -211,16 +179,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests .SetupGet(s => s.SabRecentTvPriority) .Returns(SabPriorityType.High); - - Mocker.GetMock() - .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=addurl&name=http://www.nzbclub.com/nzb_download.aspx?mid=1950232&priority=1&pp=3&cat=tv&nzbname=My+Series+Name+-+5x2-5x3+-+My+title+%5bBluray720p%5d+%5bProper%5d&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) - .Returns("{ \"status\": true }"); - - Subject.DownloadNzb(_remoteEpisode); - Mocker.GetMock() - .Verify(v => v.DownloadString("http://192.168.5.55:2222/api?mode=addurl&name=http://www.nzbclub.com/nzb_download.aspx?mid=1950232&priority=1&pp=3&cat=tv&nzbname=My+Series+Name+-+5x2-5x3+-+My+title+%5bBluray720p%5d+%5bProper%5d&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"), Times.Once()); + Mocker.GetMock() + .Verify(v => v.DownloadNzb(It.IsAny(), It.IsAny(), It.IsAny(), (int)SabPriorityType.High), Times.Once()); } } } diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs new file mode 100644 index 000000000..ed26110c6 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabCommunicationProxy.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Configuration; +using RestSharp; + +namespace NzbDrone.Core.Download.Clients.Sabnzbd +{ + public interface ISabCommunicationProxy + { + string DownloadNzb(Stream nzb, string name, string category, int priority); + string ProcessRequest(IRestRequest restRequest, string action); + } + + public class SabCommunicationProxy : ISabCommunicationProxy + { + private readonly IConfigService _configService; + + public SabCommunicationProxy(IConfigService configService) + { + _configService = configService; + } + + public string DownloadNzb(Stream nzb, string title, string category, int priority) + { + var request = new RestRequest(Method.POST); + var action = String.Format("mode=addfile&cat={0}&priority={1}", category, priority); + + request.AddFile("name", ReadFully(nzb), title, "application/x-nzb"); + + return ProcessRequest(request, action); + } + + public string ProcessRequest(IRestRequest restRequest, string action) + { + var client = BuildClient(action); + var response = client.Execute(restRequest); + + CheckForError(response); + + return response.Content; + } + + private IRestClient BuildClient(string action) + { + var protocol = _configService.SabUseSsl ? "https" : "http"; + + var url = string.Format(@"{0}://{1}:{2}/api?{3}&apikey={4}&ma_username={5}&ma_password={6}&output=json", + protocol, + _configService.SabHost, + _configService.SabPort, + action, + _configService.SabApiKey, + _configService.SabUsername, + _configService.SabPassword); + + return new RestClient(url); + } + + private void CheckForError(IRestResponse response) + { + if (response.ResponseStatus != ResponseStatus.Completed) + { + throw new ApplicationException("Unable to connect to SABnzbd, please check your settings"); + } + + var result = Json.Deserialize(response.Content); + + if (result.Status != null && result.Status.Equals("false", StringComparison.InvariantCultureIgnoreCase)) + throw new ApplicationException(result.Error); + } + + //TODO: Find a better home for this + private byte[] ReadFully(Stream input) + { + byte[] buffer = new byte[16 * 1024]; + using (MemoryStream ms = new MemoryStream()) + { + int read; + while ((read = input.Read(buffer, 0, buffer.Length)) > 0) + { + ms.Write(buffer, 0, read); + } + return ms.ToArray(); + } + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs index 4e1fabcfc..c7ae37e34 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs @@ -55,6 +55,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; private readonly IParsingService _parsingService; + private readonly ISabCommunicationProxy _sabCommunicationProxy; private readonly ICached> _queueCache; private readonly Logger _logger; @@ -62,11 +63,13 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd IHttpProvider httpProvider, ICacheManger cacheManger, IParsingService parsingService, + ISabCommunicationProxy sabCommunicationProxy, Logger logger) { _configService = configService; _httpProvider = httpProvider; _parsingService = parsingService; + _sabCommunicationProxy = sabCommunicationProxy; _queueCache = cacheManger.GetCache>(GetType(), "queue"); _logger = logger; } @@ -75,24 +78,16 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { var url = remoteEpisode.Release.DownloadUrl; var title = remoteEpisode.Release.Title; + var category = _configService.SabTvCategory; + var priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.SabRecentTvPriority : (int)_configService.SabOlderTvPriority; - string cat = _configService.SabTvCategory; - int priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.SabRecentTvPriority : (int)_configService.SabOlderTvPriority; - - string name = url.Replace("&", "%26"); - string nzbName = HttpUtility.UrlEncode(title); - - string action = string.Format("mode=addurl&name={0}&priority={1}&pp=3&cat={2}&nzbname={3}&output=json", - name, priority, cat, nzbName); - - string request = GetSabRequest(action); - _logger.Info("Adding report [{0}] to the queue.", title); - - var response = _httpProvider.DownloadString(request); - - _logger.Debug("Queue Response: [{0}]", response); + using (var nzb = _httpProvider.DownloadStream(url)) + { + _logger.Info("Adding report [{0}] to the queue.", title); + var response = _sabCommunicationProxy.DownloadNzb(nzb, title, category, priority); - CheckForError(response); + _logger.Debug("Queue Response: [{0}]", response); + } } public bool IsConfigured diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index e3527efb7..b7f1607c4 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -225,6 +225,7 @@ + @@ -627,7 +628,6 @@ -