From bf2c811a09b6c502fef05cc5b87646946ddd84b4 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Wed, 23 Jan 2013 22:36:37 -0800 Subject: [PATCH] Nzbget support added to core #ND-145 In Progress --- NzbDrone.Core.Test/Files/JsonError.txt | 8 +- NzbDrone.Core.Test/Files/Nzbget/JsonError.txt | 8 + NzbDrone.Core.Test/Files/Nzbget/Queue.txt | 33 ++++ .../Files/Nzbget/Queue_empty.txt | 4 + NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 11 ++ .../NzbgetProviderTests/DownloadNzbFixture.cs | 65 +++++++ .../NzbgetProviderTests/QueueFixture.cs | 83 +++++++++ .../SearchTests/GetSearchTitleFixture.cs | 24 ++- NzbDrone.Core/Model/DownloadClientType.cs | 3 +- NzbDrone.Core/Model/Nzbget/EnqueueResponse.cs | 13 ++ NzbDrone.Core/Model/Nzbget/ErrorModel.cs | 19 ++ NzbDrone.Core/Model/Nzbget/JsonError.cs | 13 ++ NzbDrone.Core/Model/Nzbget/JsonRequest.cs | 17 ++ NzbDrone.Core/Model/Nzbget/PriorityType.cs | 11 ++ NzbDrone.Core/Model/Nzbget/Queue.cs | 16 ++ NzbDrone.Core/Model/Nzbget/QueueItem.cs | 32 ++++ NzbDrone.Core/Model/Nzbget/VersionModel.cs | 13 ++ NzbDrone.Core/NzbDrone.Core.csproj | 9 + .../Providers/Core/ConfigProvider.cs | 57 ++++++ .../DownloadClients/NzbgetProvider.cs | 174 ++++++++++++++++++ .../Providers/SceneMappingProvider.cs | 4 +- NzbDrone.Core/Providers/Search/SearchBase.cs | 12 +- 22 files changed, 618 insertions(+), 11 deletions(-) create mode 100644 NzbDrone.Core.Test/Files/Nzbget/JsonError.txt create mode 100644 NzbDrone.Core.Test/Files/Nzbget/Queue.txt create mode 100644 NzbDrone.Core.Test/Files/Nzbget/Queue_empty.txt create mode 100644 NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs create mode 100644 NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs create mode 100644 NzbDrone.Core/Model/Nzbget/EnqueueResponse.cs create mode 100644 NzbDrone.Core/Model/Nzbget/ErrorModel.cs create mode 100644 NzbDrone.Core/Model/Nzbget/JsonError.cs create mode 100644 NzbDrone.Core/Model/Nzbget/JsonRequest.cs create mode 100644 NzbDrone.Core/Model/Nzbget/PriorityType.cs create mode 100644 NzbDrone.Core/Model/Nzbget/Queue.cs create mode 100644 NzbDrone.Core/Model/Nzbget/QueueItem.cs create mode 100644 NzbDrone.Core/Model/Nzbget/VersionModel.cs create mode 100644 NzbDrone.Core/Providers/DownloadClients/NzbgetProvider.cs diff --git a/NzbDrone.Core.Test/Files/JsonError.txt b/NzbDrone.Core.Test/Files/JsonError.txt index aa32a0bdd..3c937f046 100644 --- a/NzbDrone.Core.Test/Files/JsonError.txt +++ b/NzbDrone.Core.Test/Files/JsonError.txt @@ -1,4 +1,8 @@ { - "status": false, - "error": "API Key Incorrect" + "version": "1.1", + "error": { + "name": "JSONRPCError", + "code": 1, + "message": "Invalid procedure" + } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/Files/Nzbget/JsonError.txt b/NzbDrone.Core.Test/Files/Nzbget/JsonError.txt new file mode 100644 index 000000000..3c937f046 --- /dev/null +++ b/NzbDrone.Core.Test/Files/Nzbget/JsonError.txt @@ -0,0 +1,8 @@ +{ + "version": "1.1", + "error": { + "name": "JSONRPCError", + "code": 1, + "message": "Invalid procedure" + } +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/Files/Nzbget/Queue.txt b/NzbDrone.Core.Test/Files/Nzbget/Queue.txt new file mode 100644 index 000000000..ff3b1f354 --- /dev/null +++ b/NzbDrone.Core.Test/Files/Nzbget/Queue.txt @@ -0,0 +1,33 @@ +{ + "version": "1.1", + "result": [ + { + "FirstID": 1, + "LastID": 26, + "FileSizeLo": 350152055, + "FileSizeHi": 0, + "FileSizeMB": 333, + "RemainingSizeLo": 350152055, + "RemainingSizeHi": 0, + "RemainingSizeMB": 333, + "PausedSizeLo": 33317835, + "PausedSizeHi": 0, + "PausedSizeMB": 31, + "FileCount": 26, + "RemainingFileCount": 26, + "RemainingParCount": 7, + "MinPostTime": 1358913959, + "MaxPostTime": 1358913965, + "NZBID": 1, + "NZBName": "White.Collar.S04E11.HDTV.x264-2HD", + "NZBNicename": "White.Collar.S04E11.HDTV.x264-2HD", + "NZBFilename": "C:\\Test\\Blackhole\\White.Collar.S04E11.HDTV.x264-2HD.nzb", + "DestDir": "C:\\test\\NzbGet\\\\dst\\TV\\White.Collar.S04E11.HDTV.x264-2HD", + "Category": "TV", + "MinPriority": 0, + "MaxPriority": 0, + "ActiveDownloads": 4, + "Parameters": [] + } + ] +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/Files/Nzbget/Queue_empty.txt b/NzbDrone.Core.Test/Files/Nzbget/Queue_empty.txt new file mode 100644 index 000000000..4cd0e17ab --- /dev/null +++ b/NzbDrone.Core.Test/Files/Nzbget/Queue_empty.txt @@ -0,0 +1,4 @@ +{ + "version": "1.1", + "result": [] +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 3323c5cfb..bcbcad378 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -142,6 +142,8 @@ + + @@ -277,6 +279,15 @@ Always + + Always + + + Always + + + Always + Always diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs new file mode 100644 index 000000000..1c2fd7401 --- /dev/null +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.Model.Nzbget; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Providers.DownloadClients; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.NzbgetProviderTests +{ + public class DownloadNzbFixture : TestBase + { + [SetUp] + public void Setup() + { + var fakeConfig = Mocker.GetMock(); + fakeConfig.SetupGet(c => c.NzbgetHost).Returns("192.168.5.55"); + fakeConfig.SetupGet(c => c.NzbgetPort).Returns(6789); + fakeConfig.SetupGet(c => c.NzbgetUsername).Returns("nzbget"); + fakeConfig.SetupGet(c => c.NzbgetPassword).Returns("pass"); + fakeConfig.SetupGet(c => c.NzbgetTvCategory).Returns("TV"); + fakeConfig.SetupGet(c => c.NzbgetBacklogTvPriority).Returns(PriorityType.Normal); + fakeConfig.SetupGet(c => c.NzbgetRecentTvPriority).Returns(PriorityType.High); + } + + + private void WithFailResponse() + { + Mocker.GetMock() + .Setup(s => s.PostCommand("http://192.168.5.55:6789/jsonrpc", "nzbget", "pass", It.IsAny())) + .Returns(File.ReadAllText(@".\Files\Nzbget\JsonError.txt")); + } + + [Test] + public void should_add_item_to_queue() + { + const string url = "http://www.nzbdrone.com"; + const string title = "30 Rock - S01E01 - Pilot [HDTV-720p]"; + + Mocker.GetMock() + .Setup(s => s.PostCommand("http://192.168.5.55:6789/jsonrpc", "nzbget", "pass", + It.Is(c => c.Equals("{\"method\":\"appendurl\",\"params\":[\"30 Rock - S01E01 - Pilot [HDTV-720p]\",\"TV\",0,false,\"http://www.nzbdrone.com\"]}")))) + .Returns("{\"version\": \"1.1\",\"result\": true}"); + + Mocker.Resolve() + .DownloadNzb(url, title, false) + .Should() + .BeTrue(); + } + + [Test] + public void should_throw_when_error_is_returned() + { + WithFailResponse(); + + Assert.Throws(() => Mocker.Resolve().DownloadNzb("http://www.nzbdrone.com", "30 Rock - S01E01 - Pilot [HDTV-720p]", false)); + } + } +} diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs new file mode 100644 index 000000000..20afc7cb2 --- /dev/null +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.Model.Nzbget; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Providers.DownloadClients; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.NzbgetProviderTests +{ + public class QueueFixture : TestBase + { + [SetUp] + public void Setup() + { + var fakeConfig = Mocker.GetMock(); + fakeConfig.SetupGet(c => c.NzbgetHost).Returns("192.168.5.55"); + fakeConfig.SetupGet(c => c.NzbgetPort).Returns(6789); + fakeConfig.SetupGet(c => c.NzbgetUsername).Returns("nzbget"); + fakeConfig.SetupGet(c => c.NzbgetPassword).Returns("pass"); + fakeConfig.SetupGet(c => c.NzbgetTvCategory).Returns("TV"); + fakeConfig.SetupGet(c => c.NzbgetBacklogTvPriority).Returns(PriorityType.Normal); + fakeConfig.SetupGet(c => c.NzbgetRecentTvPriority).Returns(PriorityType.High); + } + + private void WithFullQueue() + { + Mocker.GetMock() + .Setup(s => s.PostCommand("http://192.168.5.55:6789/jsonrpc", "nzbget", "pass", It.IsAny())) + .Returns(File.ReadAllText(@".\Files\Nzbget\Queue.txt")); + } + + private void WithEmptyQueue() + { + Mocker.GetMock() + .Setup(s => s.PostCommand("http://192.168.5.55:6789/jsonrpc", "nzbget", "pass", It.IsAny())) + .Returns(File.ReadAllText(@".\Files\Nzbget\Queue_empty.txt")); + } + + private void WithFailResponse() + { + Mocker.GetMock() + .Setup(s => s.PostCommand("http://192.168.5.55:6789/jsonrpc", "nzbget", "pass", It.IsAny())) + .Returns(File.ReadAllText(@".\Files\Nzbget\JsonError.txt")); + } + + [Test] + public void should_return_no_items_when_queue_is_empty() + { + WithEmptyQueue(); + + Mocker.Resolve() + .GetQueue() + .Should() + .BeEmpty(); + } + + [Test] + public void should_return_item_when_queue_has_item() + { + WithFullQueue(); + + Mocker.Resolve() + .GetQueue() + .Should() + .HaveCount(1); + } + + [Test] + public void should_throw_when_error_is_returned() + { + WithFailResponse(); + + Assert.Throws(() => Mocker.Resolve().GetQueue()); + } + } +} diff --git a/NzbDrone.Core.Test/ProviderTests/SearchTests/GetSearchTitleFixture.cs b/NzbDrone.Core.Test/ProviderTests/SearchTests/GetSearchTitleFixture.cs index 82f6d78a8..02ad81710 100644 --- a/NzbDrone.Core.Test/ProviderTests/SearchTests/GetSearchTitleFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/SearchTests/GetSearchTitleFixture.cs @@ -28,7 +28,7 @@ public void Setup() private void WithSceneMapping() { Mocker.GetMock() - .Setup(s => s.GetSceneName(_series.SeriesId)) + .Setup(s => s.GetSceneName(_series.SeriesId, -1)) .Returns("Hawaii Five 0 2010"); } @@ -48,6 +48,26 @@ public void should_return_scene_mapping_when_one_exists() .Should().Be("Hawaii Five 0 2010"); } + [Test] + public void should_return_season_scene_name_when_one_exists() + { + Mocker.GetMock() + .Setup(s => s.GetSceneName(_series.SeriesId, 5)) + .Returns("Hawaii Five 0 2010 - Season 5"); + + Mocker.Resolve().GetSearchTitle(_series, 5) + .Should().Be("Hawaii Five 0 2010 - Season 5"); + } + + [Test] + public void should_return_series_scene_name_when_one_for_season_does_not_exist() + { + WithSceneMapping(); + + Mocker.Resolve().GetSearchTitle(_series, 5) + .Should().Be("Hawaii Five 0 2010"); + } + [Test] public void should_replace_ampersand_with_and() { @@ -65,7 +85,7 @@ public void should_replace_some_special_characters(string input, string expected _series.Title = input; Mocker.GetMock() - .Setup(s => s.GetSceneName(_series.SeriesId)) + .Setup(s => s.GetSceneName(_series.SeriesId, -1)) .Returns(""); Mocker.Resolve().GetSearchTitle(_series, 5) diff --git a/NzbDrone.Core/Model/DownloadClientType.cs b/NzbDrone.Core/Model/DownloadClientType.cs index 53072f9e6..31fb01c0d 100644 --- a/NzbDrone.Core/Model/DownloadClientType.cs +++ b/NzbDrone.Core/Model/DownloadClientType.cs @@ -4,6 +4,7 @@ public enum DownloadClientType { Sabnzbd = 0, Blackhole = 1, - Pneumatic = 2 + Pneumatic = 2, + Nzbget = 3 } } \ No newline at end of file diff --git a/NzbDrone.Core/Model/Nzbget/EnqueueResponse.cs b/NzbDrone.Core/Model/Nzbget/EnqueueResponse.cs new file mode 100644 index 000000000..c4aa4b4d6 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/EnqueueResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class EnqueueResponse + { + public String Version { get; set; } + public Boolean Result { get; set; } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/ErrorModel.cs b/NzbDrone.Core/Model/Nzbget/ErrorModel.cs new file mode 100644 index 000000000..592b8abab --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/ErrorModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class ErrorModel + { + public String Name { get; set; } + public Int32 Code { get; set; } + public String Message { get; set; } + + public override string ToString() + { + return String.Format("Name: {0}, Code: {1}, Message: {2}", Name, Code, Message); + } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/JsonError.cs b/NzbDrone.Core/Model/Nzbget/JsonError.cs new file mode 100644 index 000000000..7389efece --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/JsonError.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class JsonError + { + public String Version { get; set; } + public ErrorModel Error { get; set; } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/JsonRequest.cs b/NzbDrone.Core/Model/Nzbget/JsonRequest.cs new file mode 100644 index 000000000..3d3f812b1 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/JsonRequest.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class JsonRequest + { + [JsonProperty(PropertyName = "method")] + public String Method { get; set; } + + [JsonProperty(PropertyName = "params")] + public object[] Params { get; set; } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/PriorityType.cs b/NzbDrone.Core/Model/Nzbget/PriorityType.cs new file mode 100644 index 000000000..43be8b196 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/PriorityType.cs @@ -0,0 +1,11 @@ +namespace NzbDrone.Core.Model.Nzbget +{ + public enum PriorityType + { + VeryLow = -100, + Low = -50, + Normal = 0, + High = 50, + VeryHigh = 100 + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Model/Nzbget/Queue.cs b/NzbDrone.Core/Model/Nzbget/Queue.cs new file mode 100644 index 000000000..831608f60 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/Queue.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class Queue + { + public String Version { get; set; } + + [JsonProperty(PropertyName = "result")] + public List QueueItems { get; set; } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/QueueItem.cs b/NzbDrone.Core/Model/Nzbget/QueueItem.cs new file mode 100644 index 000000000..82257a213 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/QueueItem.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class QueueItem + { + private string _title; + + public Int32 NzbId { get; set; } + + [JsonProperty(PropertyName = "NzbName")] + public string Title + { + get { return _title; } + set + { + _title = value; + ParseResult = Parser.ParseTitle(value.Replace("DUPLICATE / ", String.Empty)); + } + } + + public String Category { get; set; } + public Int32 FileSizeMb { get; set; } + public Int32 RemainingSizeMb { get; set; } + + public EpisodeParseResult ParseResult { private set; get; } + } +} diff --git a/NzbDrone.Core/Model/Nzbget/VersionModel.cs b/NzbDrone.Core/Model/Nzbget/VersionModel.cs new file mode 100644 index 000000000..fdbbec462 --- /dev/null +++ b/NzbDrone.Core/Model/Nzbget/VersionModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model.Nzbget +{ + public class VersionModel + { + public String Version { get; set; } + public String Result { get; set; } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 44f7b2664..ea837fe2e 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -281,6 +281,14 @@ + + + + + + + + @@ -318,6 +326,7 @@ + diff --git a/NzbDrone.Core/Providers/Core/ConfigProvider.cs b/NzbDrone.Core/Providers/Core/ConfigProvider.cs index 2ed3a2833..a917eb20d 100644 --- a/NzbDrone.Core/Providers/Core/ConfigProvider.cs +++ b/NzbDrone.Core/Providers/Core/ConfigProvider.cs @@ -3,6 +3,7 @@ using System.Linq; using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Model.Nzbget; using NzbDrone.Core.Model.Sabnzbd; using NzbDrone.Core.Repository; using PetaPoco; @@ -541,6 +542,62 @@ public virtual Boolean DownloadClientUseSceneName set { SetValue("DownloadClientUseSceneName", value); } } + public virtual String NzbgetUsername + { + get { return GetValue("NzbgetUsername", "nzbget"); } + + set { SetValue("NzbgetUsername", value); } + } + + public virtual String NzbgetPassword + { + get { return GetValue("NzbgetPassword", ""); } + + set { SetValue("NzbgetPassword", value); } + } + + public virtual String NzbgetHost + { + get { return GetValue("NzbgetHost", "nzbget"); } + + set { SetValue("NzbgetHost", value); } + } + + public virtual Int32 NzbgetPort + { + get { return GetValueInt("NzbgetPort", 6789); } + + set { SetValue("NzbgetPort", value); } + } + + public virtual String NzbgetTvCategory + { + get { return GetValue("NzbgetTvCategory", "nzbget"); } + + set { SetValue("NzbgetTvCategory", value); } + } + + public virtual Int32 NzbgetPriority + { + get { return GetValueInt("NzbgetPriority", 0); } + + set { SetValue("NzbgetPriority", value); } + } + + public virtual PriorityType NzbgetBacklogTvPriority + { + get { return (PriorityType)GetValueInt("NzbgetBacklogTvPriority"); } + + set { SetValue("NzbgetBacklogTvPriority", (int)value); } + } + + public virtual PriorityType NzbgetRecentTvPriority + { + get { return (PriorityType)GetValueInt("NzbgetRecentTvPriority"); } + + set { SetValue("NzbgetRecentTvPriority", (int)value); } + } + private string GetValue(string key) { return GetValue(key, String.Empty); diff --git a/NzbDrone.Core/Providers/DownloadClients/NzbgetProvider.cs b/NzbDrone.Core/Providers/DownloadClients/NzbgetProvider.cs new file mode 100644 index 000000000..43a4bb7dc --- /dev/null +++ b/NzbDrone.Core/Providers/DownloadClients/NzbgetProvider.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using System.Web; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using NzbDrone.Common; +using NzbDrone.Core.Model; +using NzbDrone.Core.Model.Nzbget; +using NzbDrone.Core.Providers.Core; + +namespace NzbDrone.Core.Providers.DownloadClients +{ + public class NzbgetProvider : IDownloadClient + { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + private readonly ConfigProvider _configProvider; + private readonly HttpProvider _httpProvider; + + public NzbgetProvider(ConfigProvider configProvider, HttpProvider httpProvider) + { + _configProvider = configProvider; + _httpProvider = httpProvider; + } + + public NzbgetProvider() + { + } + + public virtual bool IsInQueue(EpisodeParseResult newParseResult) + { + try + { + var queue = GetQueue().Where(c => c.ParseResult != null); + + var matchigTitle = queue.Where(q => String.Equals(q.ParseResult.CleanTitle, newParseResult.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); + + var matchingTitleWithQuality = matchigTitle.Where(q => q.ParseResult.Quality >= newParseResult.Quality); + + + if (newParseResult.Series.IsDaily) + { + return matchingTitleWithQuality.Any(q => q.ParseResult.AirDate.Value.Date == newParseResult.AirDate.Value.Date); + } + + var matchingSeason = matchingTitleWithQuality.Where(q => q.ParseResult.SeasonNumber == newParseResult.SeasonNumber); + + if (newParseResult.FullSeason) + { + return matchingSeason.Any(); + } + + return matchingSeason.Any(q => q.ParseResult.EpisodeNumbers != null && q.ParseResult.EpisodeNumbers.Any(e => newParseResult.EpisodeNumbers.Contains(e))); + } + + catch (Exception ex) + { + logger.WarnException("Unable to connect to Nzbget to check queue.", ex); + return false; + } + } + + public virtual bool DownloadNzb(string url, string title, bool recentlyAired) + { + try + { + string cat = _configProvider.NzbgetTvCategory; + int priority = recentlyAired ? (int)_configProvider.NzbgetRecentTvPriority : (int)_configProvider.NzbgetBacklogTvPriority; + + var command = new JsonRequest + { + Method = "appendurl", + Params = new object[]{ title, cat, priority, false, url } + }; + + logger.Info("Adding report [{0}] to the queue.", title); + var response = PostCommand(JsonConvert.SerializeObject(command)); + + CheckForError(response); + + var success = JsonConvert.DeserializeObject(response).Result; + logger.Debug("Queue Response: [{0}]", success); + + return true; + } + + catch (WebException ex) + { + logger.Error("Error communicating with Nzbget: " + ex.Message); + } + + return false; + } + + public virtual List GetQueue() + { + var command = new JsonRequest + { + Method = "listgroups", + Params = null + }; + + var response = PostCommand(JsonConvert.SerializeObject(command)); + + CheckForError(response); + + return JsonConvert.DeserializeObject(response).QueueItems; + } + + public virtual VersionModel GetVersion(string host = null, int port = 0, string username = null, string password = null) + { + //Get saved values if any of these are defaults + if (host == null) + host = _configProvider.NzbgetHost; + + if (port == 0) + port = _configProvider.NzbgetPort; + + if (username == null) + username = _configProvider.NzbgetUsername; + + if (password == null) + password = _configProvider.NzbgetPassword; + + var command = new JsonRequest + { + Method = "version", + Params = null + }; + + var url = String.Format(@"http://{0}:{1}/jsonrpc", host, port); + var response = _httpProvider.PostCommand(url, username, password, JsonConvert.SerializeObject(command)); + + CheckForError(response); + + return JsonConvert.DeserializeObject(response); + } + + public virtual string Test(string host, int port, string apiKey, string username, string password) + { + try + { + var version = GetVersion(host, port, username, password); + return version.Result; + } + catch(Exception ex) + { + logger.DebugException("Failed to Test Nzbget", ex); + } + + return String.Empty; + } + + private string PostCommand(string command) + { + var url = String.Format(@"http://{0}:{1}/jsonrpc", + _configProvider.NzbgetHost, + _configProvider.NzbgetPort); + + return _httpProvider.PostCommand(url, _configProvider.NzbgetUsername, _configProvider.NzbgetPassword, command); + } + + private void CheckForError(string response) + { + var result = JsonConvert.DeserializeObject(response); + + if (result.Error != null) + throw new ApplicationException(result.Error.ToString()); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SceneMappingProvider.cs b/NzbDrone.Core/Providers/SceneMappingProvider.cs index d4f119d80..e45282a52 100644 --- a/NzbDrone.Core/Providers/SceneMappingProvider.cs +++ b/NzbDrone.Core/Providers/SceneMappingProvider.cs @@ -51,11 +51,11 @@ public virtual bool UpdateMappings() return true; } - public virtual string GetSceneName(int seriesId) + public virtual string GetSceneName(int seriesId, int seasonNumber = -1) { UpdateIfEmpty(); - var item = _database.FirstOrDefault("WHERE SeriesId = @0", seriesId); + var item = _database.FirstOrDefault("WHERE SeriesId = @0 AND SeasonNumber = @1", seriesId, seasonNumber); if (item == null) return null; diff --git a/NzbDrone.Core/Providers/Search/SearchBase.cs b/NzbDrone.Core/Providers/Search/SearchBase.cs index c97988895..9c56116ed 100644 --- a/NzbDrone.Core/Providers/Search/SearchBase.cs +++ b/NzbDrone.Core/Providers/Search/SearchBase.cs @@ -57,7 +57,8 @@ public virtual List Search(Series series, dynamic options, ProgressNotifi { SearchTime = DateTime.Now, SeriesId = series.SeriesId, - EpisodeId = options.GetType().GetProperty("Episode") != null ? options.Episode.EpisodeId : null + EpisodeId = options.GetType().GetProperty("Episode") != null ? options.Episode.EpisodeId : null, + SeasonNumber = options.GetType().GetProperty("SeasonNumber") != null ? options.SeasonNumber : null }; List reports = PerformSearch(series, options, notification); @@ -166,9 +167,12 @@ public virtual Boolean DownloadReport(ProgressNotification notification, Episode } public virtual string GetSearchTitle(Series series, int seasonNumber = -1) - { - //Todo: Add support for per season lookup (used for anime) - //Todo: Add support for multiple names + { + var seasonTitle = _sceneMappingProvider.GetSceneName(series.SeriesId, seasonNumber); + + if(!String.IsNullOrWhiteSpace(seasonTitle)) + return seasonTitle; + var title = _sceneMappingProvider.GetSceneName(series.SeriesId); if (String.IsNullOrWhiteSpace(title))