mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-16 11:37:58 +02:00
Downloading releases via Manual Search are now processed via unique id to allow caching more Release details.
This commit is contained in:
parent
9b5bf374a6
commit
518a75ea5c
@ -14,6 +14,8 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Nancy.ModelBinding;
|
using Nancy.ModelBinding;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Indexers
|
namespace NzbDrone.Api.Indexers
|
||||||
{
|
{
|
||||||
@ -27,12 +29,15 @@ public class ReleaseModule : NzbDroneRestModule<ReleaseResource>
|
|||||||
private readonly IParsingService _parsingService;
|
private readonly IParsingService _parsingService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
private readonly ICached<RemoteEpisode> _remoteEpisodeCache;
|
||||||
|
|
||||||
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
||||||
ISearchForNzb nzbSearchService,
|
ISearchForNzb nzbSearchService,
|
||||||
IMakeDownloadDecision downloadDecisionMaker,
|
IMakeDownloadDecision downloadDecisionMaker,
|
||||||
IPrioritizeDownloadDecision prioritizeDownloadDecision,
|
IPrioritizeDownloadDecision prioritizeDownloadDecision,
|
||||||
IDownloadService downloadService,
|
IDownloadService downloadService,
|
||||||
IParsingService parsingService,
|
IParsingService parsingService,
|
||||||
|
ICacheManager cacheManager,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_rssFetcherAndParser = rssFetcherAndParser;
|
_rssFetcherAndParser = rssFetcherAndParser;
|
||||||
@ -46,12 +51,21 @@ public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
|||||||
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
||||||
|
|
||||||
|
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response DownloadRelease(ReleaseResource release)
|
private Response DownloadRelease(ReleaseResource release)
|
||||||
{
|
{
|
||||||
var remoteEpisode = _parsingService.Map(release.InjectTo<ParsedEpisodeInfo>(), release.TvRageId);
|
var remoteEpisode = _remoteEpisodeCache.Find(release.Guid);
|
||||||
remoteEpisode.Release = release.InjectTo<ReleaseInfo>();
|
|
||||||
|
if (remoteEpisode == null)
|
||||||
|
{
|
||||||
|
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
|
||||||
|
|
||||||
|
return new NotFoundResponse();
|
||||||
|
}
|
||||||
|
|
||||||
_downloadService.DownloadReport(remoteEpisode);
|
_downloadService.DownloadReport(remoteEpisode);
|
||||||
|
|
||||||
return release.AsResponse();
|
return release.AsResponse();
|
||||||
@ -93,12 +107,14 @@ private List<ReleaseResource> GetRss()
|
|||||||
return MapDecisions(prioritizedDecisions);
|
return MapDecisions(prioritizedDecisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
private List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
||||||
{
|
{
|
||||||
var result = new List<ReleaseResource>();
|
var result = new List<ReleaseResource>();
|
||||||
|
|
||||||
foreach (var downloadDecision in decisions)
|
foreach (var downloadDecision in decisions)
|
||||||
{
|
{
|
||||||
|
_remoteEpisodeCache.Set(downloadDecision.RemoteEpisode.Release.Guid, downloadDecision.RemoteEpisode, TimeSpan.FromMinutes(30));
|
||||||
|
|
||||||
var release = new ReleaseResource();
|
var release = new ReleaseResource();
|
||||||
|
|
||||||
release.InjectFrom(downloadDecision.RemoteEpisode.Release);
|
release.InjectFrom(downloadDecision.RemoteEpisode.Release);
|
||||||
|
@ -9,6 +9,7 @@ namespace NzbDrone.Api.Indexers
|
|||||||
{
|
{
|
||||||
public class ReleaseResource : RestResource
|
public class ReleaseResource : RestResource
|
||||||
{
|
{
|
||||||
|
public String Guid { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public Int32 QualityWeight { get; set; }
|
public Int32 QualityWeight { get; set; }
|
||||||
public Int32 Age { get; set; }
|
public Int32 Age { get; set; }
|
||||||
|
@ -174,6 +174,8 @@ private List<ReleaseInfo> Fetch(IIndexer indexer, IEnumerable<string> urls)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = result.DistinctBy(v => v.Guid).ToList();
|
||||||
|
|
||||||
result.ForEach(c =>
|
result.ForEach(c =>
|
||||||
{
|
{
|
||||||
c.Indexer = indexer.Definition.Name;
|
c.Indexer = indexer.Definition.Name;
|
||||||
|
@ -47,8 +47,6 @@ public virtual IEnumerable<ReleaseInfo> Process(string xml, string url)
|
|||||||
|
|
||||||
if (reportInfo != null)
|
if (reportInfo != null)
|
||||||
{
|
{
|
||||||
reportInfo.DownloadUrl = GetNzbUrl(item);
|
|
||||||
reportInfo.InfoUrl = GetNzbInfoUrl(item);
|
|
||||||
result.Add(reportInfo);
|
result.Add(reportInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,11 +63,10 @@ public virtual IEnumerable<ReleaseInfo> Process(string xml, string url)
|
|||||||
|
|
||||||
private ReleaseInfo ParseFeedItem(XElement item, string url)
|
private ReleaseInfo ParseFeedItem(XElement item, string url)
|
||||||
{
|
{
|
||||||
var title = GetTitle(item);
|
|
||||||
|
|
||||||
var reportInfo = CreateNewReleaseInfo();
|
var reportInfo = CreateNewReleaseInfo();
|
||||||
|
|
||||||
reportInfo.Title = title;
|
reportInfo.Guid = GetGuid(item);
|
||||||
|
reportInfo.Title = GetTitle(item);
|
||||||
reportInfo.PublishDate = GetPublishDate(item);
|
reportInfo.PublishDate = GetPublishDate(item);
|
||||||
reportInfo.DownloadUrl = GetNzbUrl(item);
|
reportInfo.DownloadUrl = GetNzbUrl(item);
|
||||||
reportInfo.InfoUrl = GetNzbInfoUrl(item);
|
reportInfo.InfoUrl = GetNzbInfoUrl(item);
|
||||||
@ -83,11 +80,16 @@ private ReleaseInfo ParseFeedItem(XElement item, string url)
|
|||||||
throw new SizeParsingException("Unable to parse size from: {0} [{1}]", reportInfo.Title, url);
|
throw new SizeParsingException("Unable to parse size from: {0} [{1}]", reportInfo.Title, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Trace("Parsed: {0}", item.Title());
|
_logger.Trace("Parsed: {0}", reportInfo.Title);
|
||||||
|
|
||||||
return PostProcessor(item, reportInfo);
|
return PostProcessor(item, reportInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual String GetGuid(XElement item)
|
||||||
|
{
|
||||||
|
return item.TryGetValue("guid", Guid.NewGuid().ToString());
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual string GetTitle(XElement item)
|
protected virtual string GetTitle(XElement item)
|
||||||
{
|
{
|
||||||
return item.Title();
|
return item.Title();
|
||||||
|
@ -5,14 +5,15 @@ namespace NzbDrone.Core.Parser.Model
|
|||||||
{
|
{
|
||||||
public class ReleaseInfo
|
public class ReleaseInfo
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public String Guid { get; set; }
|
||||||
public long Size { get; set; }
|
public String Title { get; set; }
|
||||||
public string DownloadUrl { get; set; }
|
public Int64 Size { get; set; }
|
||||||
public string InfoUrl { get; set; }
|
public String DownloadUrl { get; set; }
|
||||||
public string CommentUrl { get; set; }
|
public String InfoUrl { get; set; }
|
||||||
|
public String CommentUrl { get; set; }
|
||||||
public String Indexer { get; set; }
|
public String Indexer { get; set; }
|
||||||
public DownloadProtocol DownloadProtocol { get; set; }
|
public DownloadProtocol DownloadProtocol { get; set; }
|
||||||
public int TvRageId { get; set; }
|
public Int32 TvRageId { get; set; }
|
||||||
public DateTime PublishDate { get; set; }
|
public DateTime PublishDate { get; set; }
|
||||||
|
|
||||||
public Int32 Age
|
public Int32 Age
|
||||||
|
@ -48,18 +48,18 @@ public PagingResource<TResource> GetPaged(int pageNumber, int pageSize, string s
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TResource Post(TResource body)
|
public TResource Post(TResource body, HttpStatusCode statusCode = HttpStatusCode.Created)
|
||||||
{
|
{
|
||||||
var request = BuildRequest();
|
var request = BuildRequest();
|
||||||
request.AddBody(body);
|
request.AddBody(body);
|
||||||
return Post<TResource>(request);
|
return Post<TResource>(request, statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TResource Put(TResource body)
|
public TResource Put(TResource body, HttpStatusCode statusCode = HttpStatusCode.Accepted)
|
||||||
{
|
{
|
||||||
var request = BuildRequest();
|
var request = BuildRequest();
|
||||||
request.AddBody(body);
|
request.AddBody(body);
|
||||||
return Put<TResource>(request);
|
return Put<TResource>(request, statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TResource Get(int id, HttpStatusCode statusCode = HttpStatusCode.OK)
|
public TResource Get(int id, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
using System.Linq;
|
using FluentAssertions;
|
||||||
using FluentAssertions;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Api.Indexers;
|
using NzbDrone.Api.Indexers;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace NzbDrone.Integration.Test
|
namespace NzbDrone.Integration.Test
|
||||||
{
|
{
|
||||||
@ -18,8 +22,31 @@ public void should_only_have_unknown_series_releases()
|
|||||||
releases.Should().OnlyContain(c => BeValidRelease(c));
|
releases.Should().OnlyContain(c => BeValidRelease(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_reject_unknown_release()
|
||||||
|
{
|
||||||
|
var result = Releases.Post(new ReleaseResource { Guid = "unknown" }, HttpStatusCode.NotFound);
|
||||||
|
|
||||||
|
result.Id.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_accept_request_with_only_guid_supplied()
|
||||||
|
{
|
||||||
|
var releases = Releases.All();
|
||||||
|
|
||||||
|
// InternalServerError is caused by the Release being invalid for download (no Series).
|
||||||
|
// But if it didn't accept it, it would return NotFound.
|
||||||
|
// TODO: Maybe we should create a full mock Newznab server endpoint.
|
||||||
|
//var result = Releases.Post(new ReleaseResource { Guid = releases.First().Guid });
|
||||||
|
//result.Guid.Should().Be(releases.First().Guid);
|
||||||
|
|
||||||
|
var result = Releases.Post(new ReleaseResource { Guid = releases.First().Guid }, HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
private bool BeValidRelease(ReleaseResource releaseResource)
|
private bool BeValidRelease(ReleaseResource releaseResource)
|
||||||
{
|
{
|
||||||
|
releaseResource.Guid.Should().NotBeNullOrEmpty();
|
||||||
releaseResource.Age.Should().BeGreaterOrEqualTo(-1);
|
releaseResource.Age.Should().BeGreaterOrEqualTo(-1);
|
||||||
releaseResource.Title.Should().NotBeNullOrWhiteSpace();
|
releaseResource.Title.Should().NotBeNullOrWhiteSpace();
|
||||||
releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace();
|
releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace();
|
||||||
|
Loading…
Reference in New Issue
Block a user