From ca8eba9cf14bb7ff83e9505b2b00187d11bf2479 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sun, 28 Apr 2013 12:46:13 -0700 Subject: [PATCH] release endpoint now returns fully parsed rss info with decisions. --- .../MappingTests/ResourceMappingFixture.cs | 5 + NzbDrone.Api/Indexers/ReleaseModule.cs | 68 ++++++++++++++ NzbDrone.Api/Mapping/CloneInjection.cs | 71 ++++++++++++++ NzbDrone.Api/NzbDrone.Api.csproj | 2 + .../Reflection/ReflectionExtensions.cs | 3 +- .../Datastore/MappingExtentionFixture.cs | 1 - .../AcceptableSizeSpecificationFixture.cs | 28 +++--- .../AllowedDownloadSpecificationFixture.cs | 46 +++++++-- .../LanguageSpecificationFixture.cs | 37 ++++---- ...ityAllowedByProfileSpecificationFixture.cs | 22 ++--- .../UpgradeDiskSpecificationFixture.cs | 6 +- .../UpgradeHistorySpecificationFixture.cs | 6 +- .../SabProviderTests/SabProviderFixture.cs | 86 ++++++++--------- .../Download/DownloadServiceFixture.cs | 4 - .../ParserTests/ParserFixture.cs | 8 +- NzbDrone.Core/Configuration/ConfigService.cs | 7 -- NzbDrone.Core/Configuration/IConfigService.cs | 1 - .../DecisionEngine/DownloadDecision.cs | 6 +- .../DecisionEngine/DownloadDecisionMaker.cs | 56 ++++++----- .../AcceptableSizeSpecification.cs | 4 +- .../Specifications/LanguageSpecification.cs | 7 +- .../Specifications/NotInQueueSpecification.cs | 17 ++-- .../QualityAllowedByProfileSpecification.cs | 6 +- .../Search/DailyEpisodeMatchSpecification.cs | 2 +- .../Search/SeasonMatchSpecification.cs | 4 +- .../SingleEpisodeSearchMatchSpecification.cs | 4 +- .../UpgradeDiskSpecification.cs | 4 +- .../UpgradeHistorySpecification.cs | 2 +- .../Download/Clients/Sabnzbd/SabnzbdClient.cs | 58 ++++++++++-- NzbDrone.Core/Download/DownloadService.cs | 4 - NzbDrone.Core/Download/SabQueueItem.cs | 6 -- .../ExternalNotificationBase.cs | 3 +- NzbDrone.Core/History/HistoryService.cs | 2 +- NzbDrone.Core/Indexers/RssSyncService.cs | 4 +- .../Parser/Model/ParsedEpisodeInfo.cs | 5 +- NzbDrone.Core/Parser/Model/RemoteEpisode.cs | 93 +------------------ NzbDrone.Core/Parser/Parser.cs | 12 +-- NzbDrone.Core/Parser/ParsingService.cs | 36 +++---- .../Client/ClientBase.cs | 17 +++- .../Client/SeriesClient - Copy.cs | 16 ++++ NzbDrone.Integration.Test/IntegrationTest.cs | 6 +- .../NzbDrone.Integration.Test.csproj | 2 + .../ReleaseIntegrationTest.cs | 17 ++++ 43 files changed, 458 insertions(+), 336 deletions(-) create mode 100644 NzbDrone.Api/Indexers/ReleaseModule.cs create mode 100644 NzbDrone.Api/Mapping/CloneInjection.cs create mode 100644 NzbDrone.Integration.Test/Client/SeriesClient - Copy.cs create mode 100644 NzbDrone.Integration.Test/ReleaseIntegrationTest.cs diff --git a/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs b/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs index 326e7be29..667c72ae8 100644 --- a/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs +++ b/NzbDrone.Api.Test/MappingTests/ResourceMappingFixture.cs @@ -6,8 +6,10 @@ using NzbDrone.Api.Mapping; using NzbDrone.Api.RootFolders; using NzbDrone.Api.Series; +using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Indexers; using NzbDrone.Core.Organizer; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.RootFolders; using NzbDrone.Test.Common; @@ -21,6 +23,9 @@ public class ResourceMappingFixture : TestBase [TestCase(typeof(RootFolder), typeof(RootFolderResource))] [TestCase(typeof(NamingConfig), typeof(NamingConfigResource))] [TestCase(typeof(IndexerDefinition), typeof(IndexerResource))] + [TestCase(typeof(ReportInfo), typeof(ReleaseResource))] + [TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))] + [TestCase(typeof(DownloadDecision), typeof(ReleaseResource))] public void matching_fields(Type modelType, Type resourceType) { MappingValidation.ValidateMapping(modelType, resourceType); diff --git a/NzbDrone.Api/Indexers/ReleaseModule.cs b/NzbDrone.Api/Indexers/ReleaseModule.cs new file mode 100644 index 000000000..0d6912a2e --- /dev/null +++ b/NzbDrone.Api/Indexers/ReleaseModule.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using NzbDrone.Api.Mapping; +using NzbDrone.Api.REST; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Parser; +using Omu.ValueInjecter; +using System.Linq; + +namespace NzbDrone.Api.Indexers +{ + public class ReleaseModule : NzbDroneRestModule + { + private readonly IFetchAndParseRss _rssFetcherAndParser; + private readonly IMakeDownloadDecision _downloadDecisionMaker; + + public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, IMakeDownloadDecision downloadDecisionMaker) + { + _rssFetcherAndParser = rssFetcherAndParser; + _downloadDecisionMaker = downloadDecisionMaker; + GetResourceAll = GetRss; + } + + private List GetRss() + { + var reports = _rssFetcherAndParser.Fetch(); + var decisions = _downloadDecisionMaker.GetRssDecision(reports); + + var result = new List(); + + foreach (var downloadDecision in decisions) + { + var release = new ReleaseResource(); + + release.InjectFrom(downloadDecision.RemoteEpisode.Report); + release.InjectFrom(downloadDecision.RemoteEpisode.ParsedEpisodeInfo); + release.InjectFrom(downloadDecision); + release.Rejections = downloadDecision.Rejections.ToList(); + + result.Add(release); + } + + return result; + } + } + + public class ReleaseResource : RestResource + { + public Int32 Age { get; set; } + public Int64 Size { get; set; } + public String Indexer { get; set; } + public String NzbInfoUrl { get; set; } + public String NzbUrl { get; set; } + public String ReleaseGroup { get; set; } + public String Title { get; set; } + public Boolean FullSeason { get; set; } + public Boolean SceneSource { get; set; } + public Int32 SeasonNumber { get; set; } + public Language Language { get; set; } + public DateTime? AirDate { get; set; } + public String OriginalString { get; set; } + public String SeriesTitle { get; set; } + public int[] EpisodeNumbers { get; set; } + public Boolean Approved { get; set; } + public List Rejections { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/Mapping/CloneInjection.cs b/NzbDrone.Api/Mapping/CloneInjection.cs new file mode 100644 index 000000000..6f728833a --- /dev/null +++ b/NzbDrone.Api/Mapping/CloneInjection.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Omu.ValueInjecter; + +namespace NzbDrone.Api.Mapping +{ + public class CloneInjection : ConventionInjection + { + protected override bool Match(ConventionInfo conventionInfo) + { + return conventionInfo.SourceProp.Name == conventionInfo.TargetProp.Name && + conventionInfo.SourceProp.Value != null; + } + + protected override object SetValue(ConventionInfo conventionInfo) + { + //for value types and string just return the value as is + if (conventionInfo.SourceProp.Type.IsValueType || conventionInfo.SourceProp.Type == typeof(string)) + return conventionInfo.SourceProp.Value; + + //handle arrays + if (conventionInfo.SourceProp.Type.IsArray) + { + var array = (Array)conventionInfo.SourceProp.Value; + var clone = (Array)array.Clone(); + + for (var index = 0; index < array.Length; index++) + { + var item = array.GetValue(index); + if (!item.GetType().IsValueType && !(item is string)) + { + clone.SetValue(Activator.CreateInstance(item.GetType()).InjectFrom(item), index); + } + } + + return clone; + } + + + if (conventionInfo.SourceProp.Type.IsGenericType) + { + //handle IEnumerable<> also ICollection<> IList<> List<> + if (conventionInfo.SourceProp.Type.GetGenericTypeDefinition().GetInterfaces().Any(d => d == typeof(IEnumerable))) + { + var t = conventionInfo.SourceProp.Type.GetGenericArguments()[0]; + if (t.IsValueType || t == typeof(string)) return conventionInfo.SourceProp.Value; + + var tlist = typeof(List<>).MakeGenericType(t); + var list = Activator.CreateInstance(tlist); + + var addMethod = tlist.GetMethod("Add"); + foreach (var o in (IEnumerable)conventionInfo.SourceProp.Value) + { + var e = Activator.CreateInstance(t).InjectFrom(o); + addMethod.Invoke(list, new[] { e }); // in 4.0 you can use dynamic and just do list.Add(e); + } + return list; + } + + //unhandled generic type, you could also return null or throw + return conventionInfo.SourceProp.Value; + } + + //for simple object types create a new instace and apply the clone injection on it + return Activator.CreateInstance(conventionInfo.SourceProp.Type) + .InjectFrom(conventionInfo.SourceProp.Value); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/NzbDrone.Api.csproj b/NzbDrone.Api/NzbDrone.Api.csproj index ec404a68c..576967a02 100644 --- a/NzbDrone.Api/NzbDrone.Api.csproj +++ b/NzbDrone.Api/NzbDrone.Api.csproj @@ -96,6 +96,8 @@ + + diff --git a/NzbDrone.Common/Reflection/ReflectionExtensions.cs b/NzbDrone.Common/Reflection/ReflectionExtensions.cs index 8f89ba788..5f8474e7b 100644 --- a/NzbDrone.Common/Reflection/ReflectionExtensions.cs +++ b/NzbDrone.Common/Reflection/ReflectionExtensions.cs @@ -22,11 +22,12 @@ public static List ImplementationsOf(this Assembly assembly) public static bool IsSimpleType(this Type type) { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>) || type.GetGenericTypeDefinition() == typeof(List<>))) { type = type.GetGenericArguments()[0]; } + return type.IsPrimitive || type.IsEnum || type == typeof(string) diff --git a/NzbDrone.Core.Test/Datastore/MappingExtentionFixture.cs b/NzbDrone.Core.Test/Datastore/MappingExtentionFixture.cs index 4b9bd4118..67f6e57d5 100644 --- a/NzbDrone.Core.Test/Datastore/MappingExtentionFixture.cs +++ b/NzbDrone.Core.Test/Datastore/MappingExtentionFixture.cs @@ -32,7 +32,6 @@ public class TypeWithAllMappableProperties public class TypeWithNoMappableProperties { public Series Series { get; set; } - public List ListOfStrings { get; set; } public int ReadOnly { get; private set; } public int WriteOnly { private get; set; } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs index 183b70262..9b890506b 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs @@ -27,14 +27,14 @@ public void Setup() parseResultMulti = new RemoteEpisode { Report = new ReportInfo(), - Quality = new QualityModel(Quality.SDTV, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) }, Episodes = new List { new Episode(), new Episode() } }; parseResultSingle = new RemoteEpisode { Report = new ReportInfo(), - Quality = new QualityModel(Quality.SDTV, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) }, Episodes = new List { new Episode() } }; @@ -115,7 +115,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute() [Test] public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute() { - + parseResultSingle.Series = series60minutes; parseResultSingle.Report.Size = 1.Gigabytes(); @@ -136,7 +136,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute() [Test] public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute() { - + parseResultMulti.Series = series30minutes; parseResultMulti.Report.Size = 184572800; @@ -157,7 +157,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute() [Test] public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute() { - + parseResultMulti.Series = series60minutes; parseResultMulti.Report.Size = 368572800; @@ -178,7 +178,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute() [Test] public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute() { - + parseResultMulti.Series = series30minutes; parseResultMulti.Report.Size = 1.Gigabytes(); @@ -199,7 +199,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute() [Test] public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute() { - + parseResultMulti.Series = series60minutes; parseResultMulti.Report.Size = 10.Gigabytes(); @@ -220,7 +220,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute() [Test] public void IsAcceptableSize_true_single_episode_first_30_minute() { - + parseResultSingle.Series = series30minutes; parseResultSingle.Report.Size = 184572800; @@ -241,7 +241,7 @@ public void IsAcceptableSize_true_single_episode_first_30_minute() [Test] public void IsAcceptableSize_true_single_episode_first_60_minute() { - + parseResultSingle.Series = series60minutes; parseResultSingle.Report.Size = 368572800; @@ -262,7 +262,7 @@ public void IsAcceptableSize_true_single_episode_first_60_minute() [Test] public void IsAcceptableSize_false_single_episode_first_30_minute() { - + parseResultSingle.Series = series30minutes; parseResultSingle.Report.Size = 1.Gigabytes(); @@ -283,7 +283,7 @@ public void IsAcceptableSize_false_single_episode_first_30_minute() [Test] public void IsAcceptableSize_false_single_episode_first_60_minute() { - + parseResultSingle.Series = series60minutes; parseResultSingle.Report.Size = 10.Gigabytes(); @@ -304,7 +304,7 @@ public void IsAcceptableSize_false_single_episode_first_60_minute() [Test] public void IsAcceptableSize_true_unlimited_30_minute() { - + parseResultSingle.Series = series30minutes; parseResultSingle.Report.Size = 18457280000; @@ -326,7 +326,7 @@ public void IsAcceptableSize_true_unlimited_30_minute() [Test] public void IsAcceptableSize_true_unlimited_60_minute() { - + parseResultSingle.Series = series60minutes; parseResultSingle.Report.Size = 36857280000; @@ -374,7 +374,7 @@ public void should_return_true_if_RAWHD() { var parseResult = new RemoteEpisode { - Quality = new QualityModel(Quality.RAWHD, false) + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.RAWHD, false) }, }; Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); diff --git a/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs index eb07c23f4..ada780810 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs @@ -7,6 +7,7 @@ using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; namespace NzbDrone.Core.Test.DecisionEngineTests { @@ -43,10 +44,10 @@ public void Setup() _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); - _reports = new List { new ReportInfo() }; - _remoteEpisode = new RemoteEpisode(); + _reports = new List { new ReportInfo { Title = "The.Office.S03E115.DVDRip.XviD-OSiTV" } }; + _remoteEpisode = new RemoteEpisode { Series = new Series() }; - Mocker.GetMock().Setup(c => c.Map(It.IsAny())) + Mocker.GetMock().Setup(c => c.Map(It.IsAny())) .Returns(_remoteEpisode); } @@ -102,21 +103,50 @@ public void should_have_same_number_of_rejections_as_specs_that_failed() [Test] - public void should_not_attempt_to_make_decision_if_remote_episode_is_null() + public void should_not_attempt_to_map_episode_if_not_parsable() { GivenSpecifications(_pass1, _pass2, _pass3); - - Mocker.GetMock().Setup(c => c.Map(It.IsAny())) - .Returns(null); + _reports[0].Title = "Not parsable"; var results = Subject.GetRssDecision(_reports).ToList(); + Mocker.GetMock().Verify(c => c.Map(It.IsAny()), Times.Never()); + _pass1.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); _pass2.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); _pass3.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); results.Should().BeEmpty(); - + } + + + [Test] + public void should_not_attempt_to_make_decision_if_series_is_unknow() + { + GivenSpecifications(_pass1, _pass2, _pass3); + + _remoteEpisode.Series = null; + + Subject.GetRssDecision(_reports); + + _pass1.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); + _pass2.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); + _pass3.Verify(c => c.IsSatisfiedBy(It.IsAny()), Times.Never()); + + } + + + [Test] + public void should_return_unknow_series_rejectio_if_series_is_unknow() + { + GivenSpecifications(_pass1, _pass2, _pass3); + + _remoteEpisode.Series = null; + + var result = Subject.GetRssDecision(_reports); + + result.Should().HaveCount(1); + } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs index 84770eede..0374f308a 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs @@ -1,43 +1,38 @@ - - -using System.Linq; -using System; -using System.Collections.Generic; -using FizzWare.NBuilder; -using FluentAssertions; -using Moq; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; -using NzbDrone.Core.Model; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.DecisionEngine; - using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - + public class LanguageSpecificationFixture : CoreTest { private RemoteEpisode parseResult; private void WithEnglishRelease() { - parseResult = Builder - .CreateNew() - .With(p => p.Language = Language.English) - .Build(); + parseResult = new RemoteEpisode + { + ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Language = Language.English + } + }; } private void WithGermanRelease() { - parseResult = Builder - .CreateNew() - .With(p => p.Language = Language.German) - .Build(); + parseResult = new RemoteEpisode + { + ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Language = Language.German + } + }; } [Test] diff --git a/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs index a5d1e5174..db4aa6360 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs @@ -1,6 +1,4 @@ - - -using System.Collections.Generic; +using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; @@ -16,7 +14,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public class QualityAllowedByProfileSpecificationFixture : CoreTest { - private RemoteEpisode parseResult; + private RemoteEpisode remoteEpisode; public static object[] AllowedTestCases = { @@ -39,29 +37,29 @@ public void Setup() .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p }) .Build(); - parseResult = new RemoteEpisode + remoteEpisode = new RemoteEpisode { Series = fakeSeries, - Quality = new QualityModel(Quality.DVD, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) }, }; } [Test, TestCaseSource("AllowedTestCases")] public void should_allow_if_quality_is_defined_in_profile(Quality qualityType) { - parseResult.Quality.Quality = qualityType; - parseResult.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; + remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; + remoteEpisode.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; - Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(remoteEpisode).Should().BeTrue(); } [Test, TestCaseSource("DeniedTestCases")] public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType) { - parseResult.Quality.Quality = qualityType; - parseResult.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; + remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; + remoteEpisode.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; - Subject.IsSatisfiedBy(parseResult).Should().BeFalse(); + Subject.IsSatisfiedBy(remoteEpisode).Should().BeFalse(); } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs index ae4196ab8..f5d881db2 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs @@ -44,14 +44,14 @@ public void Setup() parseResultMulti = new RemoteEpisode { Series = fakeSeries, - Quality = new QualityModel(Quality.DVD, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) }, Episodes = doubleEpisodeList }; parseResultSingle = new RemoteEpisode { Series = fakeSeries, - Quality = new QualityModel(Quality.DVD, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) }, Episodes = singleEpisodeList }; } @@ -113,7 +113,7 @@ public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() public void should_not_be_upgradable_if_qualities_are_the_same() { firstFile.Quality = new QualityModel(Quality.WEBDL1080p); - parseResultSingle.Quality = new QualityModel(Quality.WEBDL1080p, false); + parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false); _upgradeDisk.IsSatisfiedBy(parseResultSingle).Should().BeFalse(); } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs index 15d42760b..d072c26ca 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs @@ -44,14 +44,14 @@ public void Setup() _parseResultMulti = new RemoteEpisode { Series = _fakeSeries, - Quality = new QualityModel(Quality.DVD, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) }, Episodes = doubleEpisodeList }; _parseResultSingle = new RemoteEpisode { Series = _fakeSeries, - Quality = new QualityModel(Quality.DVD, true), + ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) }, Episodes = singleEpisodeList }; @@ -115,7 +115,7 @@ public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing() { _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p }; - _parseResultSingle.Quality = new QualityModel(Quality.WEBDL1080p, false); + _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false); _upgradableQuality = new QualityModel(Quality.WEBDL1080p, false); Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(1)).Returns(_upgradableQuality); diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs index 97962f51c..5a7a5a0f4 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs @@ -12,11 +12,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests { [TestFixture] - - public class SabProviderFixture : CoreTest + + public class SabProviderFixture : CoreTest { - private const string url = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232"; - private const string title = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]"; + private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232"; + private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]"; [SetUp] public void Setup() @@ -44,40 +44,34 @@ public void add_url_should_format_request_properly() .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 }"); - - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); + + Subject.DownloadNzb(URL, TITLE, false).Should().BeTrue(); } [Test] public void add_by_url_should_detect_and_handle_sab_errors() { WithFailResponse(); - - - Assert.Throws(() => Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse()); - //ExceptionVerification.ExpectedErrors(1); + Assert.Throws(() => Subject.DownloadNzb(URL, TITLE, false).Should().BeFalse()); } [Test] public void should_be_able_to_get_categories_when_config_is_passed_in() { - + const string host = "192.168.5.22"; const int port = 1111; const string apikey = "5c770e3197e4fe763423ee7c392c25d2"; const string username = "admin2"; const string password = "pass2"; - - Mocker.GetMock(MockBehavior.Strict) .Setup(s => s.DownloadString("http://192.168.5.22:1111/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d2&ma_username=admin2&ma_password=pass2")) - .Returns(ReadAllText("Files","Categories_json.txt")); + .Returns(ReadAllText("Files", "Categories_json.txt")); + + var result = Subject.GetCategories(host, port, apikey, username, password); - - var result = Mocker.Resolve().GetCategories(host, port, apikey, username, password); - result.Should().NotBeNull(); result.categories.Should().NotBeEmpty(); } @@ -87,12 +81,12 @@ public void should_be_able_to_get_categories_using_config() { Mocker.GetMock(MockBehavior.Strict) .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) - .Returns(ReadAllText("Files","Categories_json.txt")); + .Returns(ReadAllText("Files", "Categories_json.txt")); + + + var result = Subject.GetCategories(); - - var result = Mocker.Resolve().GetCategories(); - result.Should().NotBeNull(); result.categories.Should().NotBeEmpty(); } @@ -104,10 +98,10 @@ public void GetHistory_should_return_a_list_with_items_when_the_history_has_item .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) .Returns(ReadAllText("Files", "History.txt")); - - var result = Mocker.Resolve().GetHistory(); - + var result = Subject.GetHistory(); + + result.Should().HaveCount(1); } @@ -116,12 +110,12 @@ public void GetHistory_should_return_an_empty_list_when_the_queue_is_empty() { Mocker.GetMock() .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) - .Returns(ReadAllText("Files","HistoryEmpty.txt")); + .Returns(ReadAllText("Files", "HistoryEmpty.txt")); + + + var result = Subject.GetHistory(); - - var result = Mocker.Resolve().GetHistory(); - result.Should().BeEmpty(); } @@ -130,10 +124,10 @@ public void GetHistory_should_return_an_empty_list_when_there_is_an_error_gettin { Mocker.GetMock() .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) - .Returns(ReadAllText("Files","JsonError.txt")); + .Returns(ReadAllText("Files", "JsonError.txt")); - - Assert.Throws(() => Mocker.Resolve().GetHistory(), "API Key Incorrect"); + + Assert.Throws(() => Subject.GetHistory(), "API Key Incorrect"); } [Test] @@ -145,10 +139,10 @@ public void GetVersion_should_return_the_version_using_passed_in_values() .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) .Returns(response); - - var result = Mocker.Resolve().GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); - + var result = Subject.GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); + + result.Should().NotBeNull(); result.Version.Should().Be("0.6.9"); } @@ -162,10 +156,10 @@ public void GetVersion_should_return_the_version_using_saved_values() .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) .Returns(response); - - var result = Mocker.Resolve().GetVersion(); - + var result = Subject.GetVersion(); + + result.Should().NotBeNull(); result.Version.Should().Be("0.6.9"); } @@ -173,16 +167,16 @@ public void GetVersion_should_return_the_version_using_saved_values() [Test] public void Test_should_return_version_as_a_string() { - var response = "{ \"version\": \"0.6.9\" }"; + const string response = "{ \"version\": \"0.6.9\" }"; Mocker.GetMock() .Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass")) .Returns(response); - - var result = Mocker.Resolve().Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); - + var result = Subject.Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); + + result.Should().Be("0.6.9"); } @@ -192,7 +186,7 @@ public void should_return_false_when_WebException_is_thrown() Mocker.GetMock() .Setup(s => s.DownloadString(It.IsAny())).Throws(new WebException()); - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse(); + Subject.DownloadNzb(URL, TITLE, false).Should().BeFalse(); ExceptionVerification.ExpectedErrors(1); } @@ -211,8 +205,8 @@ public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_tru .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 }"); - - Mocker.Resolve().DownloadNzb(url, title, true).Should().BeTrue(); + + Subject.DownloadNzb(URL, TITLE, true).Should().BeTrue(); 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()); @@ -233,8 +227,8 @@ public void downloadNzb_should_use_sabBackogTvPriority_when_recentEpisode_is_fal .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 }"); - - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); + + Subject.DownloadNzb(URL, TITLE, false).Should().BeTrue(); 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()); diff --git a/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs b/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs index 233f7958e..ec5a0529d 100644 --- a/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; using System.Linq; using FizzWare.NBuilder; using Moq; using NUnit.Framework; using NzbDrone.Core.Download; -using NzbDrone.Core.Model; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Tv; @@ -31,7 +28,6 @@ public void Setup() .Build().ToList(); _parseResult = Builder.CreateNew() - .With(c => c.Quality = new QualityModel(Quality.DVD)) .With(c => c.Series = Builder.CreateNew().Build()) .With(c=>c.Report = Builder.CreateNew().Build()) .With(c => c.Episodes = episodes) diff --git a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index bcd59206d..4fbf36453 100644 --- a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -88,7 +88,6 @@ public void ParseTitle_single(string postTitle, string title, int seasonNumber, result.SeasonNumber.Should().Be(seasonNumber); result.EpisodeNumbers.First().Should().Be(episodeNumber); result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); - result.OriginalString.Should().Be(postTitle); } [TestCase(@"z:\tv shows\battlestar galactica (2003)\Season 3\S03E05 - Collaborators.mkv", 3, 5)] @@ -107,7 +106,6 @@ public void PathParse_tests(string path, int season, int episode) result.EpisodeNumbers.Should().HaveCount(1); result.SeasonNumber.Should().Be(season); result.EpisodeNumbers[0].Should().Be(episode); - result.OriginalString.Should().Be(path); ExceptionVerification.IgnoreWarns(); } @@ -159,7 +157,6 @@ public void TitleParse_multi(string postTitle, string title, int season, int[] e result.SeasonNumber.Should().Be(season); result.EpisodeNumbers.Should().BeEquivalentTo(episodes); result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); - result.OriginalString.Should().Be(postTitle); } @@ -181,7 +178,6 @@ public void parse_daily_episodes(string postTitle, string title, int year, int m result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); result.AirDate.Should().Be(airDate); result.EpisodeNumbers.Should().BeNull(); - result.OriginalString.Should().Be(postTitle); } [Test] @@ -203,9 +199,8 @@ public void full_season_release_parse(string postTitle, string title, int season var result = Parser.Parser.ParseTitle(postTitle); result.SeasonNumber.Should().Be(season); result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); - result.EpisodeNumbers.Count.Should().Be(0); + result.EpisodeNumbers.Length.Should().Be(0); result.FullSeason.Should().BeTrue(); - result.OriginalString.Should().Be(postTitle); } [TestCase("Conan", "conan")] @@ -346,7 +341,6 @@ public void parse_season_info(string postTitle, string seriesName, int seasonNum result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(seriesName)); result.SeasonNumber.Should().Be(seasonNumber); result.FullSeason.Should().BeTrue(); - result.OriginalString.Should().Be(postTitle); } [TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER")] diff --git a/NzbDrone.Core/Configuration/ConfigService.cs b/NzbDrone.Core/Configuration/ConfigService.cs index f874c90d3..3cc70d862 100644 --- a/NzbDrone.Core/Configuration/ConfigService.cs +++ b/NzbDrone.Core/Configuration/ConfigService.cs @@ -408,13 +408,6 @@ public Boolean IgnoreArticlesWhenSortingSeries set { SetValue("IgnoreArticlesWhenSortingSeries", value); } } - public Boolean DownloadClientUseSceneName - { - get { return GetValueBoolean("DownloadClientUseSceneName", false); } - - set { SetValue("DownloadClientUseSceneName", value); } - } - public String NzbgetUsername { get { return GetValue("NzbgetUsername", "nzbget"); } diff --git a/NzbDrone.Core/Configuration/IConfigService.cs b/NzbDrone.Core/Configuration/IConfigService.cs index 0742bd8f5..04fa7091a 100644 --- a/NzbDrone.Core/Configuration/IConfigService.cs +++ b/NzbDrone.Core/Configuration/IConfigService.cs @@ -68,7 +68,6 @@ public interface IConfigService string OmgwtfnzbsUsername { get; set; } string OmgwtfnzbsApiKey { get; set; } Boolean IgnoreArticlesWhenSortingSeries { get; set; } - Boolean DownloadClientUseSceneName { get; set; } String NzbgetUsername { get; set; } String NzbgetPassword { get; set; } String NzbgetHost { get; set; } diff --git a/NzbDrone.Core/DecisionEngine/DownloadDecision.cs b/NzbDrone.Core/DecisionEngine/DownloadDecision.cs index 2a7b455fa..5536445ee 100644 --- a/NzbDrone.Core/DecisionEngine/DownloadDecision.cs +++ b/NzbDrone.Core/DecisionEngine/DownloadDecision.cs @@ -1,14 +1,12 @@ using System.Collections.Generic; using System.Linq; -using NzbDrone.Core.Model; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine { public class DownloadDecision { - public RemoteEpisode Episode { get; private set; } + public RemoteEpisode RemoteEpisode { get; private set; } public IEnumerable Rejections { get; private set; } public bool Approved @@ -21,7 +19,7 @@ public bool Approved public DownloadDecision(RemoteEpisode episode, params string[] rejections) { - Episode = episode; + RemoteEpisode = episode; Rejections = rejections.ToList(); } } diff --git a/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs index 65243434b..61bc581fc 100644 --- a/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs +++ b/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using NzbDrone.Core.DecisionEngine.Specifications.Search; @@ -9,8 +10,8 @@ namespace NzbDrone.Core.DecisionEngine { public interface IMakeDownloadDecision { - IEnumerable GetRssDecision(IEnumerable reports); - IEnumerable GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase); + List GetRssDecision(IEnumerable reports); + List GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase); } public class DownloadDecisionMaker : IMakeDownloadDecision @@ -24,29 +25,19 @@ public DownloadDecisionMaker(IEnumerable specifications, IPar _parsingService = parsingService; } - public IEnumerable GetRssDecision(IEnumerable reports) + public List GetRssDecision(IEnumerable reports) { - foreach (var report in reports) - { - var parseResult = _parsingService.Map(report); - if (parseResult != null) - { - - yield return new DownloadDecision(parseResult, GetGeneralRejectionReasons(parseResult).ToArray()); - } - } + return GetDecisions(reports, GetGeneralRejectionReasons).ToList(); } - public IEnumerable GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase) + public List GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase) { - foreach (var report in reports) - { - var remoteEpisode = _parsingService.Map(report); - var generalReasons = GetGeneralRejectionReasons(remoteEpisode); - var searchReasons = GetSearchRejectionReasons(remoteEpisode, searchDefinitionBase); - - yield return new DownloadDecision(remoteEpisode, generalReasons.Union(searchReasons).ToArray()); - } + return GetDecisions(reports, remoteEpisode => + { + var generalReasons = GetGeneralRejectionReasons(remoteEpisode); + var searchReasons = GetSearchRejectionReasons(remoteEpisode, searchDefinitionBase); + return generalReasons.Union(searchReasons); + }).ToList(); } @@ -58,6 +49,29 @@ private IEnumerable GetGeneralRejectionReasons(RemoteEpisode report) .Select(spec => spec.RejectionReason); } + private IEnumerable GetDecisions(IEnumerable reports, Func> decisionCallback) + { + foreach (var report in reports) + { + var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title); + + if (parsedEpisodeInfo != null) + { + var remoteEpisode = _parsingService.Map(parsedEpisodeInfo); + remoteEpisode.Report = report; + + if (remoteEpisode.Series != null) + { + yield return new DownloadDecision(remoteEpisode, decisionCallback(remoteEpisode).ToArray()); + } + else + { + yield return new DownloadDecision(remoteEpisode, "Unknown Series"); + } + } + } + } + private IEnumerable GetSearchRejectionReasons(RemoteEpisode report, SearchDefinitionBase searchDefinitionBase) { return _specifications diff --git a/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs index d74613470..08f7c4709 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs @@ -30,13 +30,13 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Beginning size check for: {0}", subject); - if (subject.Quality.Quality == Quality.RAWHD) + if (subject.ParsedEpisodeInfo.Quality.Quality == Quality.RAWHD) { _logger.Trace("Raw-HD release found, skipping size check."); return true; } - var qualityType = _qualityTypeProvider.Get((int)subject.Quality.Quality); + var qualityType = _qualityTypeProvider.Get((int)subject.ParsedEpisodeInfo.Quality.Quality); if (qualityType.MaxSize == 0) { diff --git a/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs index 7aaeeb1e3..607f68a7f 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs @@ -1,5 +1,4 @@ using NLog; -using NzbDrone.Core.Model; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -24,10 +23,10 @@ public string RejectionReason public virtual bool IsSatisfiedBy(RemoteEpisode subject) { - _logger.Trace("Checking if report meets language requirements. {0}", subject.Language); - if (subject.Language != Language.English) + _logger.Trace("Checking if report meets language requirements. {0}", subject.ParsedEpisodeInfo.Language); + if (subject.ParsedEpisodeInfo.Language != Language.English) { - _logger.Trace("Report Language: {0} rejected because it is not English", subject.Language); + _logger.Trace("Report Language: {0} rejected because it is not English", subject.ParsedEpisodeInfo.Language); return false; } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs index 98f348439..b4565baf1 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs @@ -1,10 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using NLog; using NzbDrone.Core.Download; -using NzbDrone.Core.Model; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; @@ -27,7 +24,7 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(RemoteEpisode subject) + public bool IsSatisfiedBy(RemoteEpisode subject) { var downloadClient = _downloadClientProvider.GetDownloadClient(); @@ -36,25 +33,25 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject) return !IsInQueue(subject, queue); } - public virtual bool IsInQueue(RemoteEpisode newEpisode, IEnumerable queue) + private bool IsInQueue(RemoteEpisode newEpisode, IEnumerable queue) { var matchingTitle = queue.Where(q => String.Equals(q.SeriesTitle, newEpisode.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); - var matchingTitleWithQuality = matchingTitle.Where(q => q.Quality >= newEpisode.Quality); + var matchingTitleWithQuality = matchingTitle.Where(q => q.Quality >= newEpisode.ParsedEpisodeInfo.Quality); if (newEpisode.Series.SeriesType == SeriesTypes.Daily) { - return matchingTitleWithQuality.Any(q => q.AirDate.Value.Date == newEpisode.AirDate.Value.Date); + return matchingTitleWithQuality.Any(q => q.AirDate.Value.Date == newEpisode.ParsedEpisodeInfo.AirDate.Value.Date); } - var matchingSeason = matchingTitleWithQuality.Where(q => q.SeasonNumber == newEpisode.SeasonNumber); + var matchingSeason = matchingTitleWithQuality.Where(q => q.SeasonNumber == newEpisode.ParsedEpisodeInfo.SeasonNumber); - if (newEpisode.FullSeason) + if (newEpisode.ParsedEpisodeInfo.FullSeason) { return matchingSeason.Any(); } - return matchingSeason.Any(q => q.EpisodeNumbers != null && q.EpisodeNumbers.Any(e => newEpisode.EpisodeNumbers.Contains(e))); + return matchingSeason.Any(q => q.EpisodeNumbers != null && q.EpisodeNumbers.Any(e => newEpisode.ParsedEpisodeInfo.EpisodeNumbers.Contains(e))); } } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs index c20130016..03a025281 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs @@ -24,10 +24,10 @@ public string RejectionReason public virtual bool IsSatisfiedBy(RemoteEpisode subject) { - _logger.Trace("Checking if report meets quality requirements. {0}", subject.Quality); - if (!subject.Series.QualityProfile.Allowed.Contains(subject.Quality.Quality)) + _logger.Trace("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality); + if (!subject.Series.QualityProfile.Allowed.Contains(subject.ParsedEpisodeInfo.Quality.Quality)) { - _logger.Trace("Quality {0} rejected by Series' quality profile", subject.Quality); + _logger.Trace("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality); return false; } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs index 89075885a..e47661a57 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs @@ -31,7 +31,7 @@ public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase sear var episode = _episodeService.GetEpisode(dailySearchSpec.SeriesId, dailySearchSpec.Airtime); - if (!remoteEpisode.AirDate.HasValue || remoteEpisode.AirDate.Value != episode.AirDate.Value) + if (!remoteEpisode.ParsedEpisodeInfo.AirDate.HasValue || remoteEpisode.ParsedEpisodeInfo.AirDate.Value.Date != episode.AirDate.Value.Date) { _logger.Trace("Episode AirDate does not match searched episode number, skipping."); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs index fd9eba9cd..dffbb5f1f 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs @@ -1,7 +1,5 @@ using NLog; using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Model; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications.Search @@ -28,7 +26,7 @@ public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase sear var singleEpisodeSpec = searchDefinitionBase as SeasonSearchDefinition; if (singleEpisodeSpec == null) return true; - if (singleEpisodeSpec.SeasonNumber != remoteEpisode.SeasonNumber) + if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber) { _logger.Trace("Season number does not match searched season number, skipping."); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs index a4033c61e..76ce2f852 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs @@ -1,8 +1,6 @@ using System.Linq; using NLog; using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Model; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications.Search @@ -29,7 +27,7 @@ public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase sear var singleEpisodeSpec = searchDefinitionBase as SingleEpisodeSearchDefinition; if (singleEpisodeSpec == null) return true; - if (singleEpisodeSpec.SeasonNumber != remoteEpisode.SeasonNumber) + if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber) { _logger.Trace("Season number does not match searched season number, skipping."); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs index f3e7e1010..db792e010 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs @@ -30,12 +30,12 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Comparing file quality with report. Existing file is {0}", file.Quality); - if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, file.Quality, subject.Quality)) + if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, file.Quality, subject.ParsedEpisodeInfo.Quality)) { return false; } - if (subject.Quality.Proper && file.DateAdded < DateTime.Today.AddDays(-7)) + if (subject.ParsedEpisodeInfo.Quality.Proper && file.DateAdded < DateTime.Today.AddDays(-7)) { _logger.Trace("Proper for old file, skipping: {0}", subject); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs index ec5200c62..6bdd6ad67 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs @@ -33,7 +33,7 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject) if (bestQualityInHistory != null) { _logger.Trace("Comparing history quality with report. History is {0}", bestQualityInHistory); - if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, bestQualityInHistory, subject.Quality)) + if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, bestQualityInHistory, subject.ParsedEpisodeInfo.Quality)) return false; } } diff --git a/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs b/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs index 7d589de37..bd220f991 100644 --- a/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs +++ b/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs @@ -7,19 +7,61 @@ using NLog; using NzbDrone.Common; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser.Model; +using RestSharp; namespace NzbDrone.Core.Download.Clients.Sabnzbd { + public class SabRequestBuilder + { + private readonly IConfigService _configService; + + public SabRequestBuilder(IConfigService configService) + { + _configService = configService; + } + + public IRestRequest AddToQueueRequest(RemoteEpisode remoteEpisode) + { + string cat = _configService.SabTvCategory; + int priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.SabRecentTvPriority : (int)_configService.SabBacklogTvPriority; + + string name = remoteEpisode.Report.NzbUrl.Replace("&", "%26"); + string nzbName = HttpUtility.UrlEncode(remoteEpisode.Report.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); + + return new RestRequest(request); + } + + + private string GetSabRequest(string action) + { + return string.Format(@"http://{0}:{1}/api?{2}&apikey={3}&ma_username={4}&ma_password={5}", + _configService.SabHost, + _configService.SabPort, + action, + _configService.SabApiKey, + _configService.SabUsername, + _configService.SabPassword); + } + } + + public class SabnzbdClient : IDownloadClient { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; + private readonly Logger _logger; - public SabnzbdClient(IConfigService configService, IHttpProvider httpProvider) + public SabnzbdClient(IConfigService configService, IHttpProvider httpProvider, Logger logger) { _configService = configService; _httpProvider = httpProvider; + _logger = logger; } public virtual bool DownloadNzb(string url, string title, bool recentlyAired) @@ -36,11 +78,11 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) name, priority, cat, nzbName); string request = GetSabRequest(action); - logger.Info("Adding report [{0}] to the queue.", title); + _logger.Info("Adding report [{0}] to the queue.", title); var response = _httpProvider.DownloadString(request); - logger.Debug("Queue Response: [{0}]", response); + _logger.Debug("Queue Response: [{0}]", response); CheckForError(response); return true; @@ -48,7 +90,7 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) catch (WebException ex) { - logger.Error("Error communicating with SAB: " + ex.Message); + _logger.Error("Error communicating with SAB: " + ex.Message); } return false; @@ -62,9 +104,9 @@ public IEnumerable GetQueue() CheckForError(response); - var sabQeueu = JsonConvert.DeserializeObject(JObject.Parse(response).SelectToken("queue").ToString()).Items; + var sabQueue = JsonConvert.DeserializeObject(JObject.Parse(response).SelectToken("queue").ToString()).Items; - foreach (var sabQueueItem in sabQeueu) + foreach (var sabQueueItem in sabQueue) { var queueItem = new QueueItem(); queueItem.Id = sabQueueItem.Id; @@ -163,7 +205,7 @@ public virtual string Test(string host, int port, string apiKey, string username } catch (Exception ex) { - logger.DebugException("Failed to Test SABnzbd", ex); + _logger.DebugException("Failed to Test SABnzbd", ex); } return String.Empty; diff --git a/NzbDrone.Core/Download/DownloadService.cs b/NzbDrone.Core/Download/DownloadService.cs index d08bb4906..d2889faba 100644 --- a/NzbDrone.Core/Download/DownloadService.cs +++ b/NzbDrone.Core/Download/DownloadService.cs @@ -37,10 +37,6 @@ public DownloadService(IProvideDownloadClient downloadClientProvider, IConfigSer public bool DownloadReport(RemoteEpisode episode) { var downloadTitle = episode.Report.Title; - if (!_configService.DownloadClientUseSceneName) - { - downloadTitle = episode.GetDownloadTitle(); - } var provider = _downloadClientProvider.GetDownloadClient(); var recentEpisode = ContainsRecentEpisode(episode); diff --git a/NzbDrone.Core/Download/SabQueueItem.cs b/NzbDrone.Core/Download/SabQueueItem.cs index 03398ea4a..eed0879ab 100644 --- a/NzbDrone.Core/Download/SabQueueItem.cs +++ b/NzbDrone.Core/Download/SabQueueItem.cs @@ -1,8 +1,4 @@ using System; -using Newtonsoft.Json; -using NzbDrone.Core.Download.Clients.Sabnzbd; -using NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters; -using NzbDrone.Core.Model; namespace NzbDrone.Core.Download { @@ -14,8 +10,6 @@ public class QueueItem public decimal SizeLeft { get; set; } - public int Percentage { get; set; } - public string Id { get; set; } public TimeSpan Timeleft { get; set; } diff --git a/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs b/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs index 52a7ead41..dd4e6a824 100644 --- a/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs +++ b/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs @@ -83,7 +83,8 @@ public void Handle(EpisodeGrabbedEvent message) try { _logger.Trace("Sending grab notification to {0}", Name); - OnGrab(message.Episode.GetDownloadTitle()); + //todo: pass all the info to grab event and let the handlers deal with it. + OnGrab(message.Episode.ToString()); } catch (Exception e) diff --git a/NzbDrone.Core/History/HistoryService.cs b/NzbDrone.Core/History/HistoryService.cs index 06a478553..6bfa50b63 100644 --- a/NzbDrone.Core/History/HistoryService.cs +++ b/NzbDrone.Core/History/HistoryService.cs @@ -56,7 +56,7 @@ public void Handle(EpisodeGrabbedEvent message) { Date = DateTime.Now, Indexer = message.Episode.Report.Indexer, - Quality = message.Episode.Quality, + Quality = message.Episode.ParsedEpisodeInfo.Quality, NzbTitle = message.Episode.Report.Title, EpisodeId = episode.Id, NzbInfoUrl = message.Episode.Report.NzbInfoUrl, diff --git a/NzbDrone.Core/Indexers/RssSyncService.cs b/NzbDrone.Core/Indexers/RssSyncService.cs index 7edb96781..dc0398400 100644 --- a/NzbDrone.Core/Indexers/RssSyncService.cs +++ b/NzbDrone.Core/Indexers/RssSyncService.cs @@ -40,8 +40,8 @@ public void Sync() var qualifiedReports = decisions .Where(c => c.Approved) - .Select(c => c.Episode) - .OrderByDescending(c => c.Quality) + .Select(c => c.RemoteEpisode) + .OrderByDescending(c => c.ParsedEpisodeInfo.Quality) .ThenBy(c => c.Episodes.Select(e => e.EpisodeNumber).MinOrDefault()) .ThenBy(c => c.Report.Age); diff --git a/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs b/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs index 213e953f5..f872b381d 100644 --- a/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs +++ b/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Linq; -using NzbDrone.Core.Model; using NzbDrone.Core.Tv; namespace NzbDrone.Core.Parser.Model @@ -9,10 +7,9 @@ namespace NzbDrone.Core.Parser.Model public class ParsedEpisodeInfo { public string SeriesTitle { get; set; } - public string OriginalString { get; set; } public QualityModel Quality { get; set; } public int SeasonNumber { get; set; } - public List EpisodeNumbers { get; set; } + public int[] EpisodeNumbers { get; set; } public DateTime? AirDate { get; set; } public Language Language { get; set; } diff --git a/NzbDrone.Core/Parser/Model/RemoteEpisode.cs b/NzbDrone.Core/Parser/Model/RemoteEpisode.cs index 7f517d972..6ebc28c43 100644 --- a/NzbDrone.Core/Parser/Model/RemoteEpisode.cs +++ b/NzbDrone.Core/Parser/Model/RemoteEpisode.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Core.Organizer; using NzbDrone.Core.Tv; namespace NzbDrone.Core.Parser.Model @@ -9,100 +8,16 @@ namespace NzbDrone.Core.Parser.Model public class RemoteEpisode { public ReportInfo Report { get; set; } - - public bool FullSeason { get; set; } + + public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } public Series Series { get; set; } public List Episodes { get; set; } - public QualityModel Quality { get; set; } - - public Language Language { get; set; } - - public int SeasonNumber + public bool IsRecentEpisode() { - get { return Episodes.Select(e => e.SeasonNumber).Distinct().SingleOrDefault(); } - } - - - public DateTime? AirDate - { - get - { - return Episodes.Single().AirDate; - } - } - - public IEnumerable EpisodeNumbers - { - get - { - return Episodes.Select(c => c.EpisodeNumber).Distinct(); - } - } - - public string GetDownloadTitle() - { - var seriesTitle = FileNameBuilder.CleanFilename(Series.Title); - - //Handle Full Naming - if (FullSeason) - { - var seasonResult = String.Format("{0} - Season {1} [{2}]", seriesTitle, SeasonNumber, Quality); - - if (Quality.Proper) - seasonResult += " [Proper]"; - - return seasonResult; - } - - if (Series.SeriesType == SeriesTypes.Daily) - { - var dailyResult = String.Format("{0} - {1:yyyy-MM-dd} - {2} [{3}]", seriesTitle, - AirDate, Episodes.First().Title, Quality); - - if (Quality.Proper) - dailyResult += " [Proper]"; - - return dailyResult; - } - - //Show Name - 1x01-1x02 - Episode Name - //Show Name - 1x01 - Episode Name - var episodeString = new List(); - var episodeNames = new List(); - - foreach (var episode in Episodes) - { - episodeString.Add(String.Format("{0}x{1:00}", episode.SeasonNumber, episode.EpisodeNumber)); - episodeNames.Add(Core.Parser.Parser.CleanupEpisodeTitle(episode.Title)); - } - - var epNumberString = String.Join("-", episodeString); - string episodeName; - - - if (episodeNames.Distinct().Count() == 1) - episodeName = episodeNames.First(); - - else - episodeName = String.Join(" + ", episodeNames.Distinct()); - - var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, episodeName, Quality); - - if (Quality.Proper) - { - result += " [Proper]"; - } - - return result; - } - - - public override string ToString() - { - throw new NotImplementedException(); + return Episodes.Any(e => e.AirDate >= DateTime.Today.AddDays(-7)); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Parser/Parser.cs b/NzbDrone.Core/Parser/Parser.cs index 98a4b10ce..ffd4db16b 100644 --- a/NzbDrone.Core/Parser/Parser.cs +++ b/NzbDrone.Core/Parser/Parser.cs @@ -5,7 +5,6 @@ using System.Text.RegularExpressions; using NLog; using NzbDrone.Common; -using NzbDrone.Core.Model; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; @@ -90,11 +89,7 @@ public static ParsedEpisodeInfo ParsePath(string path) result = ParseTitle(fileInfo.FullName); } - if (result != null) - { - result.OriginalString = path; - } - else + if (result == null) { Logger.Warn("Unable to parse episode info from path {0}", path); } @@ -124,7 +119,6 @@ public static ParsedEpisodeInfo ParseTitle(string title) result.Language = ParseLanguage(title); result.Quality = ParseQuality(title); - result.OriginalString = title; return result; } } @@ -172,7 +166,7 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle result = new ParsedEpisodeInfo { SeasonNumber = seasons.First(), - EpisodeNumbers = new List() + EpisodeNumbers = new int[0], }; foreach (Match matchGroup in matchCollection) @@ -184,7 +178,7 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle { var first = Convert.ToInt32(episodeCaptures.First().Value); var last = Convert.ToInt32(episodeCaptures.Last().Value); - result.EpisodeNumbers = Enumerable.Range(first, last - first + 1).ToList(); + result.EpisodeNumbers = Enumerable.Range(first, last - first + 1).ToArray(); } else { diff --git a/NzbDrone.Core/Parser/ParsingService.cs b/NzbDrone.Core/Parser/ParsingService.cs index 692a34a52..9eb562a6c 100644 --- a/NzbDrone.Core/Parser/ParsingService.cs +++ b/NzbDrone.Core/Parser/ParsingService.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Core.Parser.Model; @@ -11,7 +10,7 @@ public interface IParsingService { LocalEpisode GetEpisodes(string fileName, Series series); Series GetSeries(string title); - RemoteEpisode Map(ReportInfo reportInfo); + RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo); } public class ParsingService : IParsingService @@ -65,32 +64,23 @@ public Series GetSeries(string title) return _seriesService.FindByTitle(searchTitle); } - public RemoteEpisode Map(ReportInfo reportInfo) + public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo) { - var parsedInfo = Parser.ParseTitle(reportInfo.Title); + var remoteEpisode = new RemoteEpisode + { + ParsedEpisodeInfo = parsedEpisodeInfo, + }; - if (parsedInfo == null) - { - return null; - } - - var series = _seriesService.FindByTitle(parsedInfo.SeriesTitle); + var series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle); if (series == null) { - _logger.Trace("No matching series {0}", parsedInfo.SeriesTitle); - return null; + _logger.Trace("No matching series {0}", parsedEpisodeInfo.SeriesTitle); + return remoteEpisode; } - var remoteEpisode = new RemoteEpisode - { - Series = series, - Episodes = GetEpisodes(parsedInfo, series), - FullSeason = parsedInfo.FullSeason, - Language = parsedInfo.Language, - Quality = parsedInfo.Quality, - Report = reportInfo - }; + remoteEpisode.Series = series; + remoteEpisode.Episodes = GetEpisodes(parsedEpisodeInfo, series); return remoteEpisode; } @@ -104,7 +94,7 @@ private List GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series se if (series.SeriesType == SeriesTypes.Standard) { //Todo: Collect this as a Series we want to treat as a daily series, or possible parsing error - _logger.Warn("Found daily-style episode for non-daily series: {0}. {1}", series.Title, parsedEpisodeInfo.OriginalString); + _logger.Warn("Found daily-style episode for non-daily series: {0}.", series.Title); return new List(); } diff --git a/NzbDrone.Integration.Test/Client/ClientBase.cs b/NzbDrone.Integration.Test/Client/ClientBase.cs index daaa6e8e9..8d26515be 100644 --- a/NzbDrone.Integration.Test/Client/ClientBase.cs +++ b/NzbDrone.Integration.Test/Client/ClientBase.cs @@ -3,6 +3,7 @@ using FluentAssertions; using NLog; using NzbDrone.Api.REST; +using NzbDrone.Common; using RestSharp; namespace NzbDrone.Integration.Test.Client @@ -13,6 +14,7 @@ namespace NzbDrone.Integration.Test.Client private readonly string _resource; private readonly Logger _logger; + private readonly JsonSerializer _jsonSerializer; public ClientBase(IRestClient restClient, string resource = null) { @@ -23,6 +25,11 @@ public ClientBase(IRestClient restClient, string resource = null) _restClient = restClient; _resource = resource; + + _jsonSerializer = new JsonSerializer(); + + + _logger = LogManager.GetLogger("REST"); } @@ -60,13 +67,13 @@ protected RestRequest BuildRequest(string command = "") }; } - protected T Get(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.OK) where T : new() + protected T Get(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.OK) where T : class, new() { request.Method = Method.GET; return Execute(request, statusCode); } - public T Post(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.Created) where T : new() + public T Post(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.Created) where T : class, new() { request.Method = Method.POST; return Execute(request, statusCode); @@ -78,11 +85,11 @@ public void Delete(IRestRequest request, HttpStatusCode statusCode = HttpStatusC Execute(request, statusCode); } - private T Execute(IRestRequest request, HttpStatusCode statusCode) where T : new() + private T Execute(IRestRequest request, HttpStatusCode statusCode) where T : class, new() { _logger.Info("{0}: {1}", request.Method, _restClient.BuildUri(request)); - var response = _restClient.Execute(request); + var response = _restClient.Execute(request); _logger.Info("Response: {0}", response.Content); response.StatusCode.Should().Be(statusCode); @@ -94,7 +101,7 @@ public void Delete(IRestRequest request, HttpStatusCode statusCode = HttpStatusC response.ErrorMessage.Should().BeBlank(); - return response.Data; + return _jsonSerializer.Deserialize(response.Content); } } diff --git a/NzbDrone.Integration.Test/Client/SeriesClient - Copy.cs b/NzbDrone.Integration.Test/Client/SeriesClient - Copy.cs new file mode 100644 index 000000000..fba274856 --- /dev/null +++ b/NzbDrone.Integration.Test/Client/SeriesClient - Copy.cs @@ -0,0 +1,16 @@ +using NzbDrone.Api.Indexers; +using RestSharp; + +namespace NzbDrone.Integration.Test.Client +{ + public class ReleaseClient : ClientBase + { + public ReleaseClient(IRestClient restClient) + : base(restClient) + { + } + + + + } +} diff --git a/NzbDrone.Integration.Test/IntegrationTest.cs b/NzbDrone.Integration.Test/IntegrationTest.cs index 5359ef15f..2d9bfdbeb 100644 --- a/NzbDrone.Integration.Test/IntegrationTest.cs +++ b/NzbDrone.Integration.Test/IntegrationTest.cs @@ -31,15 +31,16 @@ public abstract class IntegrationTest protected SeriesClient Series; protected ClientBase RootFolders; protected ClientBase Commands; + protected ReleaseClient Releases; static IntegrationTest() { if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration) { LogManager.Configuration = new LoggingConfiguration(); - var consoleTarget = new ConsoleTarget { Layout = "${logger} - ${message} ${exception}" }; + var consoleTarget = new ConsoleTarget { Layout = "${time} - ${logger} - ${message} ${exception}" }; LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget); - LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); + LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget)); } @@ -85,6 +86,7 @@ public void SmokeTestSetup() RestClient = new RestClient(url + "/api/"); Series = new SeriesClient(RestClient); + Releases = new ReleaseClient(RestClient); RootFolders = new ClientBase(RestClient); Commands = new ClientBase(RestClient); diff --git a/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj b/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj index 983820739..3392b77fa 100644 --- a/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj +++ b/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj @@ -75,8 +75,10 @@ + + diff --git a/NzbDrone.Integration.Test/ReleaseIntegrationTest.cs b/NzbDrone.Integration.Test/ReleaseIntegrationTest.cs new file mode 100644 index 000000000..df01d6be6 --- /dev/null +++ b/NzbDrone.Integration.Test/ReleaseIntegrationTest.cs @@ -0,0 +1,17 @@ +using FluentAssertions; +using NUnit.Framework; + +namespace NzbDrone.Integration.Test +{ + [TestFixture] + public class ReleaseIntegrationTest : IntegrationTest + { + [Test] + public void should_only_have_unknown_series_releases() + { + Releases.All().Should().OnlyContain(c => c.Rejections.Contains("Unknown Series")); + } + + + } +} \ No newline at end of file