Compare commits

..

1 Commits

Author SHA1 Message Date
Mark McDowall
17f28a10d5 Fixed: Normalize unicode characters when comparing paths for equality
(cherry picked from commit ceeec091f85d0094e07537b7f62f18292655a710)
2024-11-15 03:02:58 +00:00
13 changed files with 121 additions and 109 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.4.5'
majorVersion: '0.4.4'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
@@ -1211,7 +1211,7 @@ stages:
- task: SonarCloudAnalyze@2
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
- task: reportgenerator@5.3.11
- task: reportgenerator@5
displayName: Generate Coverage Report
inputs:
reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'

View File

@@ -26,7 +26,6 @@ module.exports = (env) => {
const config = {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
target: 'web',
stats: {
children: false

View File

@@ -54,7 +54,6 @@
}
.title {
text-wrap: balance;
font-weight: 300;
font-size: 50px;
line-height: 60px;
@@ -128,7 +127,6 @@
flex: 1 1 auto;
margin-top: 8px;
min-height: 0;
text-wrap: balance;
font-size: $intermediateFontSize;
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using FluentAssertions;
using Moq;
using NUnit.Framework;
@@ -316,5 +317,14 @@ namespace NzbDrone.Common.Test
result[2].Should().Be(@"Music");
result[3].Should().Be(@"Author Title");
}
[Test]
public void should_be_equal_with_different_unicode_representations()
{
var path1 = @"C:\Test\file.mkv".AsOsAgnostic().Normalize(NormalizationForm.FormC);
var path2 = @"C:\Test\file.mkv".AsOsAgnostic().Normalize(NormalizationForm.FormD);
path1.PathEquals(path2);
}
}
}

View File

@@ -60,6 +60,10 @@ namespace NzbDrone.Common.Extensions
public static bool PathEquals(this string firstPath, string secondPath, StringComparison? comparison = null)
{
// Normalize paths to ensure unicode characters are represented the same way
firstPath = firstPath.Normalize();
secondPath = secondPath?.Normalize();
if (!comparison.HasValue)
{
comparison = DiskProviderBase.PathStringComparison;

View File

@@ -21,10 +21,10 @@ namespace NzbDrone.Common
{
if (OsInfo.IsWindows)
{
return obj.CleanFilePath().ToLower().GetHashCode();
return obj.CleanFilePath().Normalize().ToLower().GetHashCode();
}
return obj.CleanFilePath().GetHashCode();
return obj.CleanFilePath().Normalize().GetHashCode();
}
}
}

View File

@@ -178,9 +178,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
VerifyWarning(item);
}
[TestCase("pausedDL")]
[TestCase("stoppedDL")]
public void paused_item_should_have_required_properties(string state)
[Test]
public void paused_item_should_have_required_properties()
{
var torrent = new QBittorrentTorrent
{
@@ -189,7 +188,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
Size = 1000,
Progress = 0.7,
Eta = 8640000,
State = state,
State = "pausedDL",
Label = "",
SavePath = ""
};
@@ -201,7 +200,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
[TestCase("queuedUP")]
[TestCase("uploading")]
[TestCase("stalledUP")]
@@ -399,9 +397,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
result.OutputPath.FullPath.Should().Be(Path.Combine(torrent.SavePath, "Droned.S01.12"));
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void api_261_should_use_content_path(string state)
[Test]
public void api_261_should_use_content_path()
{
var torrent = new QBittorrentTorrent
{
@@ -410,7 +407,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
Size = 1000,
Progress = 0.7,
Eta = 8640000,
State = state,
State = "pausedUP",
Label = "",
SavePath = @"C:\Torrents".AsOsAgnostic(),
ContentPath = @"C:\Torrents\Droned.S01.12".AsOsAgnostic()
@@ -687,48 +684,44 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
item.CanMoveFiles.Should().BeFalse();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set(string state)
[Test]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set()
{
GivenGlobalSeedLimits(-1);
GivenCompletedTorrent(state, ratio: 1.0f);
GivenCompletedTorrent("pausedUP", ratio: 1.0f);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused()
{
GivenGlobalSeedLimits(1.0f);
GivenCompletedTorrent(state, ratio: 1.0f);
GivenCompletedTorrent("pausedUP", ratio: 1.0f);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused()
{
GivenGlobalSeedLimits(2.0f);
GivenCompletedTorrent(state, ratio: 1.0f, ratioLimit: 0.8f);
GivenCompletedTorrent("pausedUP", ratio: 1.0f, ratioLimit: 0.8f);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused(string state)
[Test]
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused()
{
GivenGlobalSeedLimits(0.2f);
GivenCompletedTorrent(state, ratio: 0.5f, ratioLimit: 0.8f);
GivenCompletedTorrent("pausedUP", ratio: 0.5f, ratioLimit: 0.8f);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
@@ -746,36 +739,33 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
item.CanMoveFiles.Should().BeFalse();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_and_paused()
{
GivenGlobalSeedLimits(-1, 20);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 20);
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_seedingtime_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_seedingtime_reached_and_paused()
{
GivenGlobalSeedLimits(-1, 40);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 20, seedingTimeLimit: 10);
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20, seedingTimeLimit: 10);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_not_be_removable_if_overridden_max_seedingtime_not_reached_and_paused(string state)
[Test]
public void should_not_be_removable_if_overridden_max_seedingtime_not_reached_and_paused()
{
GivenGlobalSeedLimits(-1, 20);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 30, seedingTimeLimit: 40);
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 30, seedingTimeLimit: 40);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
@@ -793,72 +783,66 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
item.CanMoveFiles.Should().BeFalse();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_max_inactive_seedingtime_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_inactive_seedingtime_reached_and_paused()
{
GivenGlobalSeedLimits(-1, maxInactiveSeedingTime: 20);
GivenCompletedTorrent(state, ratio: 2.0f, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(25)).ToUnixTimeSeconds());
GivenCompletedTorrent("pausedUP", ratio: 2.0f, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(25)).ToUnixTimeSeconds());
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_inactive_seedingtime_reached_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_inactive_seedingtime_reached_and_paused()
{
GivenGlobalSeedLimits(-1, maxInactiveSeedingTime: 40);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 20, inactiveSeedingTimeLimit: 10, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(15)).ToUnixTimeSeconds());
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20, inactiveSeedingTimeLimit: 10, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(15)).ToUnixTimeSeconds());
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_not_be_removable_if_overridden_max_inactive_seedingtime_not_reached_and_paused(string state)
[Test]
public void should_not_be_removable_if_overridden_max_inactive_seedingtime_not_reached_and_paused()
{
GivenGlobalSeedLimits(-1, maxInactiveSeedingTime: 20);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 30, inactiveSeedingTimeLimit: 40, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(30)).ToUnixTimeSeconds());
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 30, inactiveSeedingTimeLimit: 40, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(30)).ToUnixTimeSeconds());
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_but_ratio_not_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_seedingtime_reached_but_ratio_not_and_paused()
{
GivenGlobalSeedLimits(2.0f, 20);
GivenCompletedTorrent(state, ratio: 1.0f, seedingTime: 30);
GivenCompletedTorrent("pausedUP", ratio: 1.0f, seedingTime: 30);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_be_removable_and_should_allow_move_files_if_max_inactive_seedingtime_reached_but_ratio_not_and_paused(string state)
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_inactive_seedingtime_reached_but_ratio_not_and_paused()
{
GivenGlobalSeedLimits(2.0f, maxInactiveSeedingTime: 20);
GivenCompletedTorrent(state, ratio: 1.0f, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(25)).ToUnixTimeSeconds());
GivenCompletedTorrent("pausedUP", ratio: 1.0f, lastActivity: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(25)).ToUnixTimeSeconds());
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_not_fetch_details_twice(string state)
[Test]
public void should_not_fetch_details_twice()
{
GivenGlobalSeedLimits(-1, 30);
GivenCompletedTorrent(state, ratio: 2.0f, seedingTime: 20);
GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
@@ -870,9 +854,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
.Verify(p => p.GetTorrentProperties(It.IsAny<string>(), It.IsAny<QBittorrentSettings>()), Times.Once());
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_get_category_from_the_category_if_set(string state)
[Test]
public void should_get_category_from_the_category_if_set()
{
const string category = "music-readarr";
GivenGlobalSeedLimits(1.0f);
@@ -884,7 +867,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
Size = 1000,
Progress = 1.0,
Eta = 8640000,
State = state,
State = "pausedUP",
Category = category,
SavePath = "",
Ratio = 1.0f
@@ -896,9 +879,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
item.Category.Should().Be(category);
}
[TestCase("pausedUP")]
[TestCase("stoppedUP")]
public void should_get_category_from_the_label_if_the_category_is_not_available(string state)
[Test]
public void should_get_category_from_the_label_if_the_category_is_not_available()
{
const string category = "music-readarr";
GivenGlobalSeedLimits(1.0f);
@@ -910,7 +892,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
Size = 1000,
Progress = 1.0,
Eta = 8640000,
State = state,
State = "pausedUP",
Label = category,
SavePath = "",
Ratio = 1.0f

View File

@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads
[TestCase("Harry Potter and the sorcerer's stone a detailed summary", 72245296)]
[TestCase("B0192CTMYG", 61209488)]
[TestCase("9780439554930", 3)]
[TestCase("9780439554930", 48517161)]
public void successful_book_search(string title, int expected)
{
var result = Subject.Search(title);

View File

@@ -239,7 +239,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
// Avoid removing torrents that haven't reached the global max ratio.
// Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api).
item.CanMoveFiles = item.CanBeRemoved = torrent.State is "pausedUP" or "stoppedUP" && HasReachedSeedLimit(torrent, config);
item.CanMoveFiles = item.CanBeRemoved = torrent.State == "pausedUP" && HasReachedSeedLimit(torrent, config);
switch (torrent.State)
{
@@ -248,8 +248,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
item.Message = "qBittorrent is reporting an error";
break;
case "stoppedDL": // torrent is stopped and has NOT finished downloading
case "pausedDL": // torrent is paused and has NOT finished downloading (qBittorrent < 5)
case "pausedDL": // torrent is paused and has NOT finished downloading
item.Status = DownloadItemStatus.Paused;
break;
@@ -260,8 +259,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
item.Status = DownloadItemStatus.Queued;
break;
case "pausedUP": // torrent is paused and has finished downloading (qBittorent < 5)
case "stoppedUP": // torrent is stopped and has finished downloading
case "pausedUP": // torrent is paused and has finished downloading
case "uploading": // torrent is being seeded and data is being transferred
case "stalledUP": // torrent is being seeded, but no connection were made
case "queuedUP": // queuing is enabled and torrent is queued for upload

View File

@@ -26,6 +26,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
Dictionary<string, QBittorrentLabel> GetLabels(QBittorrentSettings settings);
void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings);
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
void PauseTorrent(string hash, QBittorrentSettings settings);
void ResumeTorrent(string hash, QBittorrentSettings settings);
void SetForceStart(string hash, bool enabled, QBittorrentSettings settings);
}

View File

@@ -148,7 +148,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
@@ -178,7 +178,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
@@ -214,7 +214,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// if setCategory fails due to method not being found, then try older setLabel command for qBittorrent < v.3.3.5
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
{
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
.Post()
@@ -257,7 +257,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// qBittorrent rejects all Prio commands with 403: Forbidden if Options -> BitTorrent -> Torrent Queueing is not enabled
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Forbidden)
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Forbidden)
{
return;
}
@@ -266,6 +266,22 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
}
public void PauseTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/pause")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void ResumeTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/resume")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/setForceStart")

View File

@@ -246,20 +246,14 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
request.AddFormParameter("category", settings.MusicCategory);
}
// Avoid extraneous API version check if initial state is ForceStart
if ((QBittorrentState)settings.InitialState is QBittorrentState.Start or QBittorrentState.Stop)
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
var stoppedParameterName = GetApiVersion(settings) >= new Version(2, 11, 0) ? "stopped" : "paused";
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
request.AddFormParameter(stoppedParameterName, false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
{
request.AddFormParameter(stoppedParameterName, true);
}
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
}
if (settings.SequentialOrder)
@@ -297,7 +291,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// setShareLimits was added in api v2.0.1 so catch it case of the unlikely event that someone has api v2.0
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
{
return;
}
@@ -319,7 +313,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// qBittorrent rejects all Prio commands with 409: Conflict if Options -> BitTorrent -> Torrent Queueing is not enabled
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Conflict)
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Conflict)
{
return;
}
@@ -328,6 +322,22 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
}
public void PauseTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/pause")
.Post()
.AddFormParameter("hashes", hash);
ProcessRequest(request, settings);
}
public void ResumeTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/resume")
.Post()
.AddFormParameter("hashes", hash);
ProcessRequest(request, settings);
}
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/setForceStart")

View File

@@ -1,16 +1,9 @@
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public enum QBittorrentState
{
[FieldOption(Label = "Started")]
Start = 0,
[FieldOption(Label = "Force Started")]
ForceStart = 1,
[FieldOption(Label = "Stopped")]
Stop = 2
Pause = 2
}
}