From 4f384548256ab1c2177dce5ab0f649b515a04545 Mon Sep 17 00:00:00 2001 From: bitPhex Date: Fri, 19 Jun 2015 21:32:33 -0400 Subject: [PATCH 1/2] Inital work for release pushing --- .../Indexers/ReleasePushModule.cs | 58 +++++++++++++++++++ src/NzbDrone.Api/NzbDrone.Api.csproj | 1 + 2 files changed, 59 insertions(+) create mode 100644 src/NzbDrone.Api/Indexers/ReleasePushModule.cs diff --git a/src/NzbDrone.Api/Indexers/ReleasePushModule.cs b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs new file mode 100644 index 000000000..ddca17e5a --- /dev/null +++ b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs @@ -0,0 +1,58 @@ +using Nancy; +using Nancy.ModelBinding; +using FluentValidation; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Download; +using NzbDrone.Core.Parser; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Api.Mapping; +using NzbDrone.Api.Extensions; +using NLog; + +namespace NzbDrone.Api.Indexers +{ + class ReleasePushModule : NzbDroneRestModule + { + private readonly IMakeDownloadDecision _downloadDecisionMaker; + private readonly IProcessDownloadDecisions _downloadDecisionProcessor; + private readonly Logger _logger; + + public ReleasePushModule(IMakeDownloadDecision downloadDecisionMaker, + IProcessDownloadDecisions downloadDecisionProcessor, + Logger logger) + { + _downloadDecisionMaker = downloadDecisionMaker; + _downloadDecisionProcessor = downloadDecisionProcessor; + _logger = logger; + + Post["/push"] = x => ProcessRelease(this.Bind()); + + PostValidator.RuleFor(s => s.Title).NotEmpty(); + PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty(); + PostValidator.RuleFor(s => s.DownloadProtocol).NotEmpty(); + PostValidator.RuleFor(s => s.PublishDate).NotEmpty(); + } + + private Response ProcessRelease(ReleaseResource release) + { + _logger.Info("Release pushed: {0}", release.Title); + + var info = release.InjectTo(); + info.Guid = "PUSH-" + info.DownloadUrl; + + var decisions = _downloadDecisionMaker.GetRssDecision(new List { info }); + var processed = _downloadDecisionProcessor.ProcessDecisions(decisions); + + var status = processed.Grabbed.Any() ? "grabbed" : + processed.Rejected.Any() ? "rejected" : + processed.Pending.Any() ? "pending" : + "error" ; + + return status.AsResponse(); + } + } +} diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index adb826917..f322b1374 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -101,6 +101,7 @@ + From bb144a6df6311e2ac114ca9b9f3aae992a650a15 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 16 Aug 2015 22:52:26 -0700 Subject: [PATCH 2/2] New: Ability to push releases to Sonarr via API for processing Closes #419 --- src/NzbDrone.Api/Indexers/ReleaseModule.cs | 55 ++------------- .../Indexers/ReleaseModuleBase.cs | 67 +++++++++++++++++++ .../Indexers/ReleasePushModule.cs | 14 +--- src/NzbDrone.Api/NzbDrone.Api.csproj | 1 + .../Download/ProcessDownloadDecisions.cs | 2 - 5 files changed, 75 insertions(+), 64 deletions(-) create mode 100644 src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs diff --git a/src/NzbDrone.Api/Indexers/ReleaseModule.cs b/src/NzbDrone.Api/Indexers/ReleaseModule.cs index 79af69db1..ddbf8fb32 100644 --- a/src/NzbDrone.Api/Indexers/ReleaseModule.cs +++ b/src/NzbDrone.Api/Indexers/ReleaseModule.cs @@ -9,8 +9,6 @@ using NzbDrone.Core.Exceptions; using NzbDrone.Core.IndexerSearch; using NzbDrone.Core.Indexers; using NzbDrone.Core.Parser.Model; -using Omu.ValueInjecter; -using System.Linq; using Nancy.ModelBinding; using NzbDrone.Api.Extensions; using NzbDrone.Common.Cache; @@ -18,7 +16,7 @@ using HttpStatusCode = System.Net.HttpStatusCode; namespace NzbDrone.Api.Indexers { - public class ReleaseModule : NzbDroneRestModule + public class ReleaseModule : ReleaseModuleBase { private readonly IFetchAndParseRss _rssFetcherAndParser; private readonly ISearchForNzb _nzbSearchService; @@ -113,55 +111,10 @@ namespace NzbDrone.Api.Indexers return MapDecisions(prioritizedDecisions); } - private List MapDecisions(IEnumerable decisions) + protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight) { - var result = new List(); - - foreach (var downloadDecision in decisions) - { - _remoteEpisodeCache.Set(downloadDecision.RemoteEpisode.Release.Guid, downloadDecision.RemoteEpisode, TimeSpan.FromMinutes(30)); - - var release = new ReleaseResource(); - - release.InjectFrom(downloadDecision.RemoteEpisode.Release); - release.InjectFrom(downloadDecision.RemoteEpisode.ParsedEpisodeInfo); - release.InjectFrom(downloadDecision); - release.Rejections = downloadDecision.Rejections.Select(r => r.Reason).ToList(); - release.DownloadAllowed = downloadDecision.RemoteEpisode.DownloadAllowed; - - release.ReleaseWeight = result.Count; - - if (downloadDecision.RemoteEpisode.Series != null) - { - release.QualityWeight = downloadDecision.RemoteEpisode - .Series - .Profile - .Value - .Items - .FindIndex(v => v.Quality == release.Quality.Quality) * 100; - } - - release.QualityWeight += release.Quality.Revision.Real * 10; - release.QualityWeight += release.Quality.Revision.Version; - - var torrentRelease = downloadDecision.RemoteEpisode.Release as TorrentInfo; - - if (torrentRelease != null) - { - release.Protocol = DownloadProtocol.Torrent; - release.Seeders = torrentRelease.Seeders; - //TODO: move this up the chains - release.Leechers = torrentRelease.Peers - torrentRelease.Seeders; - } - else - { - release.Protocol = DownloadProtocol.Usenet; - } - - result.Add(release); - } - - return result; + _remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30)); + return base.MapDecision(decision, initialWeight); } } } \ No newline at end of file diff --git a/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs b/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs new file mode 100644 index 000000000..a1bdc24f8 --- /dev/null +++ b/src/NzbDrone.Api/Indexers/ReleaseModuleBase.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Parser.Model; +using Omu.ValueInjecter; +using System.Linq; + +namespace NzbDrone.Api.Indexers +{ + public abstract class ReleaseModuleBase : NzbDroneRestModule + { + protected virtual List MapDecisions(IEnumerable decisions) + { + var result = new List(); + + foreach (var downloadDecision in decisions) + { + var release = MapDecision(downloadDecision, result.Count); + + result.Add(release); + } + + return result; + } + + protected virtual ReleaseResource MapDecision(DownloadDecision decision, int initialWeight) + { + var release = new ReleaseResource(); + + release.InjectFrom(decision.RemoteEpisode.Release); + release.InjectFrom(decision.RemoteEpisode.ParsedEpisodeInfo); + release.InjectFrom(decision); + release.Rejections = decision.Rejections.Select(r => r.Reason).ToList(); + release.DownloadAllowed = decision.RemoteEpisode.DownloadAllowed; + release.ReleaseWeight = initialWeight; + + if (decision.RemoteEpisode.Series != null) + { + release.QualityWeight = decision.RemoteEpisode + .Series + .Profile + .Value + .Items + .FindIndex(v => v.Quality == release.Quality.Quality) * 100; + } + + release.QualityWeight += release.Quality.Revision.Real * 10; + release.QualityWeight += release.Quality.Revision.Version; + + var torrentRelease = decision.RemoteEpisode.Release as TorrentInfo; + + if (torrentRelease != null) + { + release.Protocol = DownloadProtocol.Torrent; + release.Seeders = torrentRelease.Seeders; + //TODO: move this up the chains + release.Leechers = torrentRelease.Peers - torrentRelease.Seeders; + } + else + { + release.Protocol = DownloadProtocol.Usenet; + } + + return release; + } + } +} diff --git a/src/NzbDrone.Api/Indexers/ReleasePushModule.cs b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs index ddca17e5a..b94c10d5c 100644 --- a/src/NzbDrone.Api/Indexers/ReleasePushModule.cs +++ b/src/NzbDrone.Api/Indexers/ReleasePushModule.cs @@ -3,11 +3,8 @@ using Nancy.ModelBinding; using FluentValidation; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download; -using NzbDrone.Core.Parser; -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using NzbDrone.Core.Parser.Model; using NzbDrone.Api.Mapping; using NzbDrone.Api.Extensions; @@ -15,7 +12,7 @@ using NLog; namespace NzbDrone.Api.Indexers { - class ReleasePushModule : NzbDroneRestModule + class ReleasePushModule : ReleaseModuleBase { private readonly IMakeDownloadDecision _downloadDecisionMaker; private readonly IProcessDownloadDecisions _downloadDecisionProcessor; @@ -39,7 +36,7 @@ namespace NzbDrone.Api.Indexers private Response ProcessRelease(ReleaseResource release) { - _logger.Info("Release pushed: {0}", release.Title); + _logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl); var info = release.InjectTo(); info.Guid = "PUSH-" + info.DownloadUrl; @@ -47,12 +44,7 @@ namespace NzbDrone.Api.Indexers var decisions = _downloadDecisionMaker.GetRssDecision(new List { info }); var processed = _downloadDecisionProcessor.ProcessDecisions(decisions); - var status = processed.Grabbed.Any() ? "grabbed" : - processed.Rejected.Any() ? "rejected" : - processed.Pending.Any() ? "pending" : - "error" ; - - return status.AsResponse(); + return MapDecisions(decisions).First().AsResponse(); } } } diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index f322b1374..1b1c0b95e 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -101,6 +101,7 @@ + diff --git a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs index 26635f944..09fcfb8aa 100644 --- a/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs +++ b/src/NzbDrone.Core/Download/ProcessDownloadDecisions.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Linq; using NLog; -using NzbDrone.Common; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download.Pending; -using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download {