diff --git a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs index 1e98734f7..a0b1e85fd 100644 --- a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs +++ b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs @@ -39,9 +39,9 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic _logger.Debug("Downloading NZB from: {0} to: {1}", url, nzbFile); - var nzbData = await indexer.Download(url); + var downloadResponse = await indexer.Download(url); - File.WriteAllBytes(nzbFile, nzbData); + await File.WriteAllBytesAsync(nzbFile, downloadResponse.Data); _logger.Debug("NZB Download succeeded, saved to: {0}", nzbFile); diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 57e8b2d5b..223c24384 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Threading.Tasks; using NLog; using NzbDrone.Common.Http; @@ -74,9 +73,6 @@ namespace NzbDrone.Core.Download GrabTrigger = source == "Prowlarr" ? GrabTrigger.Manual : GrabTrigger.Api }; - var sw = new Stopwatch(); - sw.Start(); - string downloadClientId; try { @@ -115,11 +111,6 @@ namespace NzbDrone.Core.Download throw; } - finally - { - sw.Stop(); - grabEvent.ElapsedTime = sw.ElapsedMilliseconds; - } _logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle); @@ -153,16 +144,15 @@ namespace NzbDrone.Core.Download GrabTrigger = source == "Prowlarr" ? GrabTrigger.Manual : GrabTrigger.Api }; - var sw = new Stopwatch(); - sw.Start(); - byte[] downloadedBytes; try { - downloadedBytes = await indexer.Download(url); + var downloadResponse = await indexer.Download(url); + downloadedBytes = downloadResponse.Data; _indexerStatusService.RecordSuccess(indexerId); grabEvent.Successful = true; + grabEvent.ElapsedTime = downloadResponse.ElapsedTime; } catch (ReleaseUnavailableException) { @@ -184,11 +174,6 @@ namespace NzbDrone.Core.Download _eventAggregator.PublishEvent(grabEvent); throw; } - finally - { - sw.Stop(); - grabEvent.ElapsedTime = sw.ElapsedMilliseconds; - } _logger.Trace("Downloaded {0} bytes from {1}", downloadedBytes.Length, link); _eventAggregator.PublishEvent(grabEvent); diff --git a/src/NzbDrone.Core/Download/TorrentClientBase.cs b/src/NzbDrone.Core/Download/TorrentClientBase.cs index 26db20b44..322cc206b 100644 --- a/src/NzbDrone.Core/Download/TorrentClientBase.cs +++ b/src/NzbDrone.Core/Download/TorrentClientBase.cs @@ -127,9 +127,8 @@ namespace NzbDrone.Core.Download private async Task DownloadFromWebUrl(TorrentInfo release, IIndexer indexer, string torrentUrl) { - byte[] torrentFile = null; - - torrentFile = await indexer.Download(new Uri(torrentUrl)); + var downloadResponse = await indexer.Download(new Uri(torrentUrl)); + var torrentFile = downloadResponse.Data; // handle magnet URLs if (torrentFile.Length >= 7 diff --git a/src/NzbDrone.Core/Download/UsenetClientBase.cs b/src/NzbDrone.Core/Download/UsenetClientBase.cs index 2541c6059..ac62359aa 100644 --- a/src/NzbDrone.Core/Download/UsenetClientBase.cs +++ b/src/NzbDrone.Core/Download/UsenetClientBase.cs @@ -41,12 +41,10 @@ namespace NzbDrone.Core.Download var filename = StringUtil.CleanFileName(release.Title) + ".nzb"; - byte[] nzbData; - - nzbData = await indexer.Download(url); + var downloadResponse = await indexer.Download(url); _logger.Info("Adding report [{0}] to the queue.", release.Title); - return AddFromNzbFile(release, filename, nzbData); + return AddFromNzbFile(release, filename, downloadResponse.Data); } } } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 95ee4fb41..144258272 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -205,7 +205,11 @@ namespace NzbDrone.Core.History history.Data.Add("GrabMethod", message.Redirect ? "Redirect" : "Proxy"); history.Data.Add("GrabTitle", message.Title); history.Data.Add("Url", message.Url ?? string.Empty); - history.Data.Add("ElapsedTime", message.ElapsedTime.ToString()); + + if (message.ElapsedTime > 0) + { + history.Data.Add("ElapsedTime", message.ElapsedTime.ToString()); + } if (message.Release.InfoUrl.IsNotNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index ecfe03140..e80e35743 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new BakaBTParser(Settings, Capabilities.Categories); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { var request = new HttpRequestBuilder(link.ToString()) .SetCookies(GetCookies() ?? new Dictionary()) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleBase.cs index 711b2e152..924a67cbe 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleBase.cs @@ -82,9 +82,10 @@ public abstract class GazelleBase : TorrentIndexerBase protected virtual bool CheckForLoginError(HttpResponse response) => true; - public override async Task Download(Uri link) + public override async Task Download(Uri link) { - var response = await base.Download(link); + var downloadResponse = await base.Download(link); + var response = downloadResponse.Data; if (response.Length >= 1 && response[0] != 'd' // simple test for torrent vs HTML content @@ -99,11 +100,11 @@ public abstract class GazelleBase : TorrentIndexerBase // download again without usetoken=1 var requestLinkNew = link.ToString().Replace("&usetoken=1", ""); - response = await base.Download(new Uri(requestLinkNew)); + downloadResponse = await base.Download(new Uri(requestLinkNew)); } } - return response; + return downloadResponse; } protected override IDictionary GetCookies() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index c2e66ae08..f8028c0b8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -50,28 +50,33 @@ namespace NzbDrone.Core.Indexers.Headphones } } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); - var downloadBytes = Array.Empty(); - var request = requestBuilder.Build(); request.Credentials = new BasicNetworkCredential(Settings.Username, Settings.Password); + byte[] downloadBytes; + long elapsedTime; + try { var response = await _httpClient.ExecuteProxiedAsync(request, Definition); downloadBytes = response.ResponseData; + elapsedTime = response.ElapsedTime; } catch (Exception) { _indexerStatusService.RecordFailure(Definition.Id); _logger.Error("Download failed"); + throw; } - return downloadBytes; + ValidateDownloadData(downloadBytes); + + return new IndexerDownloadResponse(downloadBytes, elapsedTime); } private IndexerCapabilities SetCapabilities() diff --git a/src/NzbDrone.Core/Indexers/Definitions/MTeamTp.cs b/src/NzbDrone.Core/Indexers/Definitions/MTeamTp.cs index eec5203f2..42d4f5640 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MTeamTp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MTeamTp.cs @@ -59,7 +59,7 @@ public class MTeamTp : TorrentIndexerBase return new MTeamTpParser(Settings, Capabilities.Categories, BuildApiUrl(Settings)); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { var request = new HttpRequestBuilder(link.ToString()) .SetHeader("x-api-key", Settings.ApiKey) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 349648571..8c6312d29 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new MyAnonamouseParser(Settings, Capabilities.Categories, _httpClient, _cacheManager, _logger); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { if (Settings.Freeleech) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 67f8ff55a..7b26e7abf 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -89,18 +89,20 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { var request = new HttpRequestBuilder(link.AbsoluteUri) .SetHeader("Authorization", $"token {Settings.Apikey}") .Build(); - var downloadBytes = Array.Empty(); + byte[] downloadBytes; + long elapsedTime; try { var response = await _httpClient.ExecuteProxiedAsync(request, Definition); downloadBytes = response.ResponseData; + elapsedTime = response.ElapsedTime; if (downloadBytes.Length >= 1 && downloadBytes[0] != 'd' // simple test for torrent vs HTML content @@ -124,11 +126,12 @@ namespace NzbDrone.Core.Indexers.Definitions { _indexerStatusService.RecordFailure(Definition.Id); _logger.Error("Download failed"); + throw; } ValidateDownloadData(downloadBytes); - return downloadBytes; + return new IndexerDownloadResponse(downloadBytes, elapsedTime); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 78f92df52..8148b0729 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Indexers.Definitions return new RuTrackerParser(Settings, Capabilities.Categories); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { if (Settings.UseMagnetLinks && link.PathAndQuery.Contains("viewtopic.php?t=")) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Uniotaku.cs b/src/NzbDrone.Core/Indexers/Definitions/Uniotaku.cs index 9405e63c3..b38b3013b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Uniotaku.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Uniotaku.cs @@ -82,7 +82,7 @@ public class Uniotaku : TorrentIndexerBase return !httpResponse.GetCookies().ContainsKey("uid") || !httpResponse.GetCookies().ContainsKey("pass"); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { var request = new HttpRequestBuilder(link.ToString()) .SetCookies(GetCookies() ?? new Dictionary()) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 1ccc983cf..650d1a692 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -224,7 +224,7 @@ namespace NzbDrone.Core.Indexers return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria), searchCriteria); } - public override async Task Download(Uri link) + public override async Task Download(Uri link) { Cookies = GetCookies(); @@ -233,7 +233,7 @@ namespace NzbDrone.Core.Indexers if (request.Url.Scheme == "magnet") { ValidateMagnet(request.Url.FullUri); - return Encoding.UTF8.GetBytes(request.Url.FullUri); + return new IndexerDownloadResponse(Encoding.UTF8.GetBytes(request.Url.FullUri)); } if (request.RateLimit < RateLimit) @@ -244,6 +244,7 @@ namespace NzbDrone.Core.Indexers request.AllowAutoRedirect = false; byte[] fileData; + long elapsedTime; try { @@ -283,6 +284,7 @@ namespace NzbDrone.Core.Indexers } fileData = response.ResponseData; + elapsedTime = response.ElapsedTime; _logger.Debug("Downloaded for release finished ({0} bytes from {1})", fileData.Length, link.AbsoluteUri); } @@ -320,7 +322,7 @@ namespace NzbDrone.Core.Indexers ValidateDownloadData(fileData); - return fileData; + return new IndexerDownloadResponse(fileData, elapsedTime); } protected virtual Task GetDownloadRequest(Uri link) diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index 25d12db9a..e0a6b1ef1 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers Task Fetch(BookSearchCriteria searchCriteria); Task Fetch(BasicSearchCriteria searchCriteria); - Task Download(Uri link); + Task Download(Uri link); bool IsObsolete(); IndexerCapabilities GetCapabilities(); diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 1caed03b3..0330217dc 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -97,7 +97,7 @@ namespace NzbDrone.Core.Indexers public abstract Task Fetch(TvSearchCriteria searchCriteria); public abstract Task Fetch(BookSearchCriteria searchCriteria); public abstract Task Fetch(BasicSearchCriteria searchCriteria); - public abstract Task Download(Uri link); + public abstract Task Download(Uri link); public abstract IndexerCapabilities GetCapabilities(); diff --git a/src/NzbDrone.Core/Indexers/IndexerDownloadResponse.cs b/src/NzbDrone.Core/Indexers/IndexerDownloadResponse.cs new file mode 100644 index 000000000..a5660a784 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerDownloadResponse.cs @@ -0,0 +1,13 @@ +namespace NzbDrone.Core.Indexers; + +public class IndexerDownloadResponse +{ + public byte[] Data { get; private set; } + public long ElapsedTime { get; private set; } + + public IndexerDownloadResponse(byte[] data, long elapsedTime = 0) + { + Data = data; + ElapsedTime = elapsedTime; + } +}