mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Align QBittorrent with upstream
This commit is contained in:
@@ -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));
|
||||
|
Reference in New Issue
Block a user