Align QBittorrent with upstream

pull/1722/head
Bogdan 1 year ago
parent d5daf6791c
commit ed1fb58242

@ -48,26 +48,34 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
throw new NotSupportedException("Magnet Links without trackers not supported if DHT is disabled");
}
//var setShareLimits = release.SeedConfiguration != null && (release.SeedConfiguration.Ratio.HasValue || release.SeedConfiguration.SeedTime.HasValue);
//var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var itemToTop = Settings.Priority == (int)QBittorrentPriority.First;
var setShareLimits = release.SeedConfiguration != null && (release.SeedConfiguration.Ratio.HasValue || release.SeedConfiguration.SeedTime.HasValue);
var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var moveToTop = Settings.Priority == (int)QBittorrentPriority.First;
var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart;
var category = GetCategoryForRelease(release) ?? Settings.Category;
Proxy.AddTorrentFromUrl(magnetLink, null, Settings, category);
Proxy.AddTorrentFromUrl(magnetLink, addHasSetShareLimits && setShareLimits ? release.SeedConfiguration : null, Settings, category);
if (itemToTop || forceStart)
if ((!addHasSetShareLimits && setShareLimits) || moveToTop || forceStart)
{
if (!WaitForTorrent(hash))
{
return hash;
}
//if (!addHasSetShareLimits && setShareLimits)
//{
// Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), release.SeedConfiguration, Settings);
//}
if (itemToTop)
if (!addHasSetShareLimits && setShareLimits)
{
try
{
Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), release.SeedConfiguration, Settings);
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to set the torrent seed criteria for {0}.", hash);
}
}
if (moveToTop)
{
try
{
@ -97,26 +105,34 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
protected override string AddFromTorrentFile(TorrentInfo release, string hash, string filename, byte[] fileContent)
{
//var setShareLimits = release.SeedConfiguration != null && (release.SeedConfiguration.Ratio.HasValue || release.SeedConfiguration.SeedTime.HasValue);
//var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var itemToTop = Settings.Priority == (int)QBittorrentPriority.First;
var setShareLimits = release.SeedConfiguration != null && (release.SeedConfiguration.Ratio.HasValue || release.SeedConfiguration.SeedTime.HasValue);
var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var moveToTop = Settings.Priority == (int)QBittorrentPriority.First;
var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart;
var category = GetCategoryForRelease(release) ?? Settings.Category;
Proxy.AddTorrentFromFile(filename, fileContent, null, Settings, category);
Proxy.AddTorrentFromFile(filename, fileContent, addHasSetShareLimits ? release.SeedConfiguration : null, Settings, category);
if (itemToTop || forceStart)
if ((!addHasSetShareLimits && setShareLimits) || moveToTop || forceStart)
{
if (!WaitForTorrent(hash))
{
return hash;
}
//if (!addHasSetShareLimits && setShareLimits)
//{
// Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), release.SeedConfiguration, Settings);
//}
if (itemToTop)
if (!addHasSetShareLimits && setShareLimits)
{
try
{
Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), release.SeedConfiguration, Settings);
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to set the torrent seed criteria for {0}.", hash);
}
}
if (moveToTop)
{
try
{
@ -146,14 +162,16 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
protected bool WaitForTorrent(string hash)
{
var count = 5;
var count = 10;
while (count != 0)
{
try
{
Proxy.GetTorrentProperties(hash.ToLower(), Settings);
return true;
if (Proxy.IsTorrentLoaded(hash.ToLower(), Settings))
{
return true;
}
}
catch
{
@ -235,9 +253,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
_logger.Error(ex, "Unable to test qBittorrent");
return new NzbDroneValidationFailure("Host", "Unable to connect to qBittorrent")
{
DetailedDescription = ex.Message
};
{
DetailedDescription = ex.Message
};
}
return null;
@ -297,11 +315,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
var recentPriorityDefault = Settings.Priority == (int)QBittorrentPriority.Last;
if (recentPriorityDefault)
{
return null;
}
try
{
var config = Proxy.GetConfig(Settings);

@ -1,4 +1,4 @@
namespace NzbDrone.Core.Download.Clients.QBittorrent
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public class QBittorrentLabel
{

@ -1,4 +1,4 @@
namespace NzbDrone.Core.Download.Clients.QBittorrent
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public enum QBittorrentPriority
{

@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public interface IQBittorrentProxy
@ -15,6 +12,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
string GetVersion(QBittorrentSettings settings);
QBittorrentPreferences GetConfig(QBittorrentSettings settings);
List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings);
bool IsTorrentLoaded(string hash, QBittorrentSettings settings);
QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings);
List<QBittorrentTorrentFile> GetTorrentFiles(string hash, QBittorrentSettings settings);
@ -40,7 +38,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public class QBittorrentProxySelector : IQBittorrentProxySelector
{
private readonly IHttpClient _httpClient;
private readonly ICached<Tuple<IQBittorrentProxy, Version>> _proxyCache;
private readonly Logger _logger;
@ -49,11 +46,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public QBittorrentProxySelector(QBittorrentProxyV1 proxyV1,
QBittorrentProxyV2 proxyV2,
IHttpClient httpClient,
ICacheManager cacheManager,
Logger logger)
{
_httpClient = httpClient;
_proxyCache = cacheManager.GetCache<Tuple<IQBittorrentProxy, Version>>(GetType());
_logger = logger;

@ -97,6 +97,23 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
return response;
}
public bool IsTorrentLoaded(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource($"/query/propertiesGeneral/{hash}");
request.LogHttpError = false;
try
{
ProcessRequest(request, settings);
return true;
}
catch
{
return false;
}
}
public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource($"/query/propertiesGeneral/{hash}");
@ -295,15 +312,14 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
var request = requestBuilder.Build();
request.LogResponseContent = true;
request.SuppressHttpErrorStatusCodes = new[] { HttpStatusCode.Forbidden };
HttpResponse response;
try
{
response = _httpClient.Execute(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
if (response.StatusCode == HttpStatusCode.Forbidden)
{
_logger.Debug("Authentication required, logging in.");
@ -313,10 +329,10 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
response = _httpClient.Execute(request);
}
else
{
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
}
}
catch (HttpException ex)
{
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
}
catch (WebException ex)
{
@ -367,9 +383,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
}
// returns "Fails." on bad login
if (response.Content != "Ok.")
{
// returns "Fails." on bad login
_logger.Debug("qbitTorrent authentication failed.");
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.");
}

@ -106,6 +106,24 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
return response;
}
public bool IsTorrentLoaded(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/properties")
.AddQueryParam("hash", hash);
request.LogHttpError = false;
try
{
ProcessRequest(request, settings);
return true;
}
catch
{
return false;
}
}
public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/properties")
@ -129,24 +147,12 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
var request = BuildRequest(settings).Resource("/api/v2/torrents/add")
.Post()
.AddFormParameter("urls", torrentUrl);
if (category.IsNotNullOrWhiteSpace())
{
request.AddFormParameter("category", category);
}
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
AddTorrentDownloadFormParameters(request, settings, category);
if (seedConfiguration != null)
{
AddTorrentSeedingFormParameters(request, seedConfiguration, settings);
AddTorrentSeedingFormParameters(request, seedConfiguration);
}
var result = ProcessRequest(request, settings);
@ -164,24 +170,11 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
.Post()
.AddFormUpload("torrents", fileName, fileContent);
if (category.IsNotNullOrWhiteSpace())
{
request.AddFormParameter("category", category);
}
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
AddTorrentDownloadFormParameters(request, settings, category);
if (seedConfiguration != null)
{
AddTorrentSeedingFormParameters(request, seedConfiguration, settings);
AddTorrentSeedingFormParameters(request, seedConfiguration);
}
var result = ProcessRequest(request, settings);
@ -230,29 +223,57 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
return Json.Deserialize<Dictionary<string, QBittorrentLabel>>(ProcessRequest(request, settings));
}
private void AddTorrentSeedingFormParameters(HttpRequestBuilder request, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings)
private void AddTorrentSeedingFormParameters(HttpRequestBuilder request, TorrentSeedConfiguration seedConfiguration, bool always = false)
{
var ratioLimit = seedConfiguration.Ratio.HasValue ? seedConfiguration.Ratio : -2;
var seedingTimeLimit = seedConfiguration.SeedTime.HasValue ? (long)seedConfiguration.SeedTime.Value.TotalMinutes : -2;
if (ratioLimit != -2)
if (ratioLimit != -2 || always)
{
request.AddFormParameter("ratioLimit", ratioLimit);
}
if (seedingTimeLimit != -2)
if (seedingTimeLimit != -2 || always)
{
request.AddFormParameter("seedingTimeLimit", seedingTimeLimit);
}
}
private void AddTorrentDownloadFormParameters(HttpRequestBuilder request, QBittorrentSettings settings, string category)
{
if (category.IsNotNullOrWhiteSpace())
{
request.AddFormParameter("category", category);
}
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
if (settings.SequentialOrder)
{
request.AddFormParameter("sequentialDownload", true);
}
if (settings.FirstAndLast)
{
request.AddFormParameter("firstLastPiecePrio", true);
}
}
public void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/setShareLimits")
.Post()
.AddFormParameter("hashes", hash);
AddTorrentSeedingFormParameters(request, seedConfiguration, settings);
AddTorrentSeedingFormParameters(request, seedConfiguration, true);
try
{
@ -341,15 +362,14 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
var request = requestBuilder.Build();
request.LogResponseContent = true;
request.SuppressHttpErrorStatusCodes = new[] { HttpStatusCode.Forbidden };
HttpResponse response;
try
{
response = _httpClient.Execute(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
if (response.StatusCode == HttpStatusCode.Forbidden)
{
_logger.Debug("Authentication required, logging in.");
@ -359,10 +379,10 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
response = _httpClient.Execute(request);
}
else
{
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
}
}
catch (HttpException ex)
{
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
}
catch (WebException ex)
{
@ -418,9 +438,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
}
// returns "Fails." on bad login
if (response.Content != "Ok.")
{
// returns "Fails." on bad login
_logger.Debug("qbitTorrent authentication failed.");
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.");
}

@ -56,6 +56,12 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
[FieldDefinition(8, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(QBittorrentState), HelpText = "Initial state for torrents added to qBittorrent")]
public int InitialState { get; set; }
[FieldDefinition(9, Label = "Sequential Order", Type = FieldType.Checkbox, HelpText = "Download in sequential order (qBittorrent 4.1.0+)")]
public bool SequentialOrder { get; set; }
[FieldDefinition(10, Label = "First and Last First", Type = FieldType.Checkbox, HelpText = "Download first and last pieces first (qBittorrent 4.1.0+)")]
public bool FirstAndLast { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

Loading…
Cancel
Save