fix(tests): restore parallel execution

This commit is contained in:
Antonin Lenfant-Kodia 2026-05-18 21:30:31 +02:00
parent 284ef44e30
commit 8142225ee9
39 changed files with 635 additions and 443 deletions

View file

@ -21,4 +21,4 @@ jobs:
- name: Build - name: Build
run: dotnet build --no-restore server run: dotnet build --no-restore server
- name: Test - name: Test
run: dotnet test --no-build --verbosity normal -maxcpucount:1 server run: dotnet test --no-build --verbosity normal server

View file

@ -2,7 +2,6 @@ using System.Reflection;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using Moq;
using RdtClient.Data.Data;
using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
using RdtClient.Service.BackgroundServices; using RdtClient.Service.BackgroundServices;
@ -17,6 +16,7 @@ public class WatchFolderCheckerTests : IDisposable
private readonly Mock<IServiceProvider> _serviceProviderMock; private readonly Mock<IServiceProvider> _serviceProviderMock;
private readonly Mock<IServiceScope> _serviceScopeMock; private readonly Mock<IServiceScope> _serviceScopeMock;
private readonly String _testPath; private readonly String _testPath;
private readonly TestSettings _settings;
private readonly Mock<Torrents> _torrentsServiceMock; private readonly Mock<Torrents> _torrentsServiceMock;
public WatchFolderCheckerTests() public WatchFolderCheckerTests()
@ -25,7 +25,16 @@ public class WatchFolderCheckerTests : IDisposable
_serviceProviderMock = new(); _serviceProviderMock = new();
_serviceScopeMock = new(); _serviceScopeMock = new();
_scopeServiceProviderMock = new(); _scopeServiceProviderMock = new();
_torrentsServiceMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!); _settings = new(new DbSettings
{
Watch = new()
{
Interval = 0,
Default = new()
},
DownloadClient = new()
});
_torrentsServiceMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, _settings, new TorrentRunnerState());
_serviceProviderMock _serviceProviderMock
.Setup(x => x.GetService(typeof(IServiceScopeFactory))) .Setup(x => x.GetService(typeof(IServiceScopeFactory)))
@ -42,10 +51,8 @@ public class WatchFolderCheckerTests : IDisposable
_testPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); _testPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(_testPath); Directory.CreateDirectory(_testPath);
// Reset Settings and Startup
SetStartupReady(true); SetStartupReady(true);
ResetSettings(); _settings.Current.Watch.Path = _testPath;
Settings.Get.Watch.Path = _testPath;
} }
public void Dispose() public void Dispose()
@ -62,22 +69,6 @@ public class WatchFolderCheckerTests : IDisposable
property?.SetValue(null, ready); property?.SetValue(null, ready);
} }
private static void ResetSettings()
{
var settings = new DbSettings
{
Watch = new()
{
Interval = 0,
Default = new()
},
DownloadClient = new()
};
var property = typeof(SettingData).GetProperty("Get", BindingFlags.Public | BindingFlags.Static);
property?.SetValue(null, settings);
}
private static void ResetPrevCheck(WatchFolderChecker checker) private static void ResetPrevCheck(WatchFolderChecker checker)
{ {
var field = typeof(WatchFolderChecker).GetField("_prevCheck", BindingFlags.NonPublic | BindingFlags.Instance); var field = typeof(WatchFolderChecker).GetField("_prevCheck", BindingFlags.NonPublic | BindingFlags.Instance);
@ -92,7 +83,7 @@ public class WatchFolderCheckerTests : IDisposable
var content = "torrent content"u8.ToArray(); var content = "torrent content"u8.ToArray();
await File.WriteAllBytesAsync(filePath, content); await File.WriteAllBytesAsync(filePath, content);
var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object); var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object, _settings);
ResetPrevCheck(checker); ResetPrevCheck(checker);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@ -131,7 +122,7 @@ public class WatchFolderCheckerTests : IDisposable
var content = "magnet:?xt=urn:btih:123"; var content = "magnet:?xt=urn:btih:123";
await File.WriteAllTextAsync(filePath, content); await File.WriteAllTextAsync(filePath, content);
var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object); var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object, _settings);
ResetPrevCheck(checker); ResetPrevCheck(checker);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@ -170,7 +161,7 @@ public class WatchFolderCheckerTests : IDisposable
var content = "nzb content"u8.ToArray(); var content = "nzb content"u8.ToArray();
await File.WriteAllBytesAsync(filePath, content); await File.WriteAllBytesAsync(filePath, content);
var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object); var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object, _settings);
ResetPrevCheck(checker); ResetPrevCheck(checker);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@ -209,7 +200,7 @@ public class WatchFolderCheckerTests : IDisposable
var filePath = Path.Combine(_testPath, "test.txt"); var filePath = Path.Combine(_testPath, "test.txt");
await File.WriteAllTextAsync(filePath, "ignore me"); await File.WriteAllTextAsync(filePath, "ignore me");
var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object); var checker = new WatchFolderChecker(_loggerMock.Object, _serviceProviderMock.Object, _settings);
ResetPrevCheck(checker); ResetPrevCheck(checker);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();

View file

@ -1,3 +0,0 @@
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]

View file

@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<AssemblyName>RdtClient.Service.Test</AssemblyName> <AssemblyName>RdtClient.Service.Test</AssemblyName>
<RootNamespace>RdtClient.Service.Test</RootNamespace> <RootNamespace>RdtClient.Service.Test</RootNamespace>
</PropertyGroup> </PropertyGroup>

View file

@ -3,6 +3,8 @@ using System.Text;
using Moq; using Moq;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Data;
using TestSettings = RdtClient.Service.Services.TestSettings;
using TorrentRunnerState = RdtClient.Service.Services.TorrentRunnerState;
using TorrentsService = RdtClient.Service.Services.Torrents; using TorrentsService = RdtClient.Service.Services.Torrents;
namespace RdtClient.Service.Test.Services; namespace RdtClient.Service.Test.Services;
@ -28,7 +30,9 @@ public class NzbTorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
} }
[Fact] [Fact]

View file

@ -1,7 +1,6 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using Moq;
using System.Text.Json; using System.Text.Json;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.DebridClient; using RdtClient.Data.Models.DebridClient;
@ -14,15 +13,19 @@ public class QBittorrentTest
private readonly Mock<Authentication> _authenticationMock; private readonly Mock<Authentication> _authenticationMock;
private readonly Mock<ILogger<QBittorrent>> _loggerMock; private readonly Mock<ILogger<QBittorrent>> _loggerMock;
private readonly QBittorrent _qBittorrent; private readonly QBittorrent _qBittorrent;
private readonly TestSettings _settings;
private readonly TorrentRunnerState _runnerState;
private readonly Mock<Torrents> _torrentsMock; private readonly Mock<Torrents> _torrentsMock;
public QBittorrentTest() public QBittorrentTest()
{ {
_loggerMock = new(); _loggerMock = new();
_torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!); _settings = new();
_runnerState = new();
_torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, _settings, _runnerState);
_authenticationMock = new(null!, null!, null!); _authenticationMock = new(null!, null!, null!);
_qBittorrent = new(_loggerMock.Object, null!, _authenticationMock.Object, _torrentsMock.Object, null!); _qBittorrent = new(_loggerMock.Object, _settings, _authenticationMock.Object, _torrentsMock.Object, null!, _runnerState);
} }
[Fact] [Fact]
@ -214,8 +217,8 @@ public class QBittorrentTest
public async Task TorrentInfo_ShouldUseSelectedTopLevelFileName_WhenRootFileAddsOnlyTheExtension() public async Task TorrentInfo_ShouldUseSelectedTopLevelFileName_WhenRootFileAddsOnlyTheExtension()
{ {
// Arrange // Arrange
var previousMappedPath = SettingData.Get.DownloadClient.MappedPath; var previousMappedPath = _settings.Current.DownloadClient.MappedPath;
SettingData.Get.DownloadClient.MappedPath = "/data/downloads"; _settings.Current.DownloadClient.MappedPath = "/data/downloads";
try try
{ {
@ -260,16 +263,16 @@ public class QBittorrentTest
} }
finally finally
{ {
SettingData.Get.DownloadClient.MappedPath = previousMappedPath; _settings.Current.DownloadClient.MappedPath = previousMappedPath;
} }
} }
[Fact] [Fact]
public async Task TorrentInfo_ShouldUseExistingCompletedContentRoot_WhenSingleFileDirectoryDiffersFromRdName() public async Task TorrentInfo_ShouldUseExistingCompletedContentRoot_WhenSingleFileDirectoryDiffersFromRdName()
{ {
var previousMappedPath = SettingData.Get.DownloadClient.MappedPath; var previousMappedPath = _settings.Current.DownloadClient.MappedPath;
var mappedPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); var mappedPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
SettingData.Get.DownloadClient.MappedPath = mappedPath; _settings.Current.DownloadClient.MappedPath = mappedPath;
try try
{ {
@ -317,7 +320,7 @@ public class QBittorrentTest
} }
finally finally
{ {
SettingData.Get.DownloadClient.MappedPath = previousMappedPath; _settings.Current.DownloadClient.MappedPath = previousMappedPath;
if (Directory.Exists(mappedPath)) if (Directory.Exists(mappedPath))
{ {
@ -329,9 +332,9 @@ public class QBittorrentTest
[Fact] [Fact]
public async Task TorrentInfo_ShouldUseExistingCompletedContentRoot_WhenSelectedFileIsNestedUnderDifferentRoot() public async Task TorrentInfo_ShouldUseExistingCompletedContentRoot_WhenSelectedFileIsNestedUnderDifferentRoot()
{ {
var previousMappedPath = SettingData.Get.DownloadClient.MappedPath; var previousMappedPath = _settings.Current.DownloadClient.MappedPath;
var mappedPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); var mappedPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
SettingData.Get.DownloadClient.MappedPath = mappedPath; _settings.Current.DownloadClient.MappedPath = mappedPath;
try try
{ {
@ -382,7 +385,7 @@ public class QBittorrentTest
} }
finally finally
{ {
SettingData.Get.DownloadClient.MappedPath = previousMappedPath; _settings.Current.DownloadClient.MappedPath = previousMappedPath;
if (Directory.Exists(mappedPath)) if (Directory.Exists(mappedPath))
{ {

View file

@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using Moq;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
@ -16,11 +15,13 @@ public class SabnzbdTest
}; };
private readonly Mock<ILogger<Sabnzbd>> _loggerMock = new(); private readonly Mock<ILogger<Sabnzbd>> _loggerMock = new();
private readonly TestSettings _settings;
private readonly Mock<Torrents> _torrentsMock; private readonly Mock<Torrents> _torrentsMock;
public SabnzbdTest() public SabnzbdTest()
{ {
_torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!); _settings = new();
_torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, _settings, new TorrentRunnerState());
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(new List<Torrent>()); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(new List<Torrent>());
} }
@ -50,7 +51,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
_torrentsMock.Setup(t => t.GetDownloadStats(It.IsAny<Guid>())).Returns((0, 1000, 500)); _torrentsMock.Setup(t => t.GetDownloadStats(It.IsAny<Guid>())).Returns((0, 1000, 500));
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetQueue(); var result = await sabnzbd.GetQueue();
@ -90,7 +91,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetQueue(); var result = await sabnzbd.GetQueue();
@ -134,7 +135,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetQueue(); var result = await sabnzbd.GetQueue();
@ -186,7 +187,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetQueue(); var result = await sabnzbd.GetQueue();
@ -224,7 +225,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetQueue(); var result = await sabnzbd.GetQueue();
@ -260,7 +261,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetHistory(); var result = await sabnzbd.GetHistory();
@ -275,7 +276,7 @@ public class SabnzbdTest
{ {
// Arrange // Arrange
var savePath = @"C:\Downloads"; var savePath = @"C:\Downloads";
SettingData.Get.DownloadClient.MappedPath = savePath; _settings.Current.DownloadClient.MappedPath = savePath;
var torrentList = new List<Torrent> var torrentList = new List<Torrent>
{ {
@ -292,7 +293,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetHistory(); var result = await sabnzbd.GetHistory();
@ -308,7 +309,7 @@ public class SabnzbdTest
{ {
// Arrange // Arrange
var savePath = @"C:\Downloads"; var savePath = @"C:\Downloads";
SettingData.Get.DownloadClient.MappedPath = savePath; _settings.Current.DownloadClient.MappedPath = savePath;
var torrentList = new List<Torrent> var torrentList = new List<Torrent>
{ {
@ -325,7 +326,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetHistory(); var result = await sabnzbd.GetHistory();
@ -355,7 +356,7 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = await sabnzbd.GetHistory(); var result = await sabnzbd.GetHistory();
@ -369,7 +370,7 @@ public class SabnzbdTest
public void GetConfig_ShouldReturnCorrectConfig() public void GetConfig_ShouldReturnCorrectConfig()
{ {
// Arrange // Arrange
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = sabnzbd.GetConfig(); var result = sabnzbd.GetConfig();
@ -399,9 +400,9 @@ public class SabnzbdTest
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList); _torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
SettingData.Get.General.Categories = "TV, Music, *"; _settings.Current.General.Categories = "TV, Music, *";
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings); var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act // Act
var result = sabnzbd.GetCategories(); var result = sabnzbd.GetCategories();

View file

@ -8,30 +8,20 @@ using RdtClient.Service.Services.DebridClients;
namespace RdtClient.Service.Test.Services.TorrentClients; namespace RdtClient.Service.Test.Services.TorrentClients;
[CollectionDefinition(nameof(PremiumizeSettingsCollection), DisableParallelization = true)] public class PremiumizeDebridClientTest
public class PremiumizeSettingsCollection;
[Collection(nameof(PremiumizeSettingsCollection))]
public class PremiumizeDebridClientTest : IDisposable
{ {
private readonly Mock<IDownloadableFileFilter> _fileFilterMock; private readonly Mock<IDownloadableFileFilter> _fileFilterMock;
private readonly Mock<IHttpClientFactory> _httpClientFactoryMock; private readonly Mock<IHttpClientFactory> _httpClientFactoryMock;
private readonly Mock<ILogger<PremiumizeDebridClient>> _loggerMock; private readonly Mock<ILogger<PremiumizeDebridClient>> _loggerMock;
private readonly String _originalApiKey; private readonly TestSettings _settings;
public PremiumizeDebridClientTest() public PremiumizeDebridClientTest()
{ {
_loggerMock = new(); _loggerMock = new();
_httpClientFactoryMock = new(); _httpClientFactoryMock = new();
_fileFilterMock = new(); _fileFilterMock = new();
_originalApiKey = Settings.Get.Provider.ApiKey ?? String.Empty; _settings = new();
_settings.Current.Provider.ApiKey = "test-api-key";
Settings.Get.Provider.ApiKey = "test-api-key";
}
public void Dispose()
{
Settings.Get.Provider.ApiKey = _originalApiKey;
} }
[Fact] [Fact]
@ -208,7 +198,7 @@ public class PremiumizeDebridClientTest : IDisposable
{ {
_httpClientFactoryMock.Setup(m => m.CreateClient(It.IsAny<String>())).Returns(new HttpClient(handler)); _httpClientFactoryMock.Setup(m => m.CreateClient(It.IsAny<String>())).Returns(new HttpClient(handler));
return new(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object); return new(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _settings);
} }
private static HttpResponseMessage JsonResponse(String json, HttpStatusCode statusCode = HttpStatusCode.OK) private static HttpResponseMessage JsonResponse(String json, HttpStatusCode statusCode = HttpStatusCode.OK)

View file

@ -21,6 +21,7 @@ public class TorBoxDebridClientTest
private readonly Mock<IDownloadableFileFilter> _fileFilterMock; private readonly Mock<IDownloadableFileFilter> _fileFilterMock;
private readonly Mock<IHttpClientFactory> _httpClientFactoryMock; private readonly Mock<IHttpClientFactory> _httpClientFactoryMock;
private readonly Mock<ILogger<TorBoxDebridClient>> _loggerMock; private readonly Mock<ILogger<TorBoxDebridClient>> _loggerMock;
private readonly TestSettings _settings;
public TorBoxDebridClientTest() public TorBoxDebridClientTest()
{ {
@ -28,12 +29,13 @@ public class TorBoxDebridClientTest
_httpClientFactoryMock = new(); _httpClientFactoryMock = new();
_fileFilterMock = new(); _fileFilterMock = new();
_coordinatorMock = new(); _coordinatorMock = new();
_settings = new();
var httpClient = new HttpClient(); var httpClient = new HttpClient();
_httpClientFactoryMock.Setup(m => m.CreateClient(It.IsAny<String>())).Returns(httpClient); _httpClientFactoryMock.Setup(m => m.CreateClient(It.IsAny<String>())).Returns(httpClient);
Settings.Get.Provider.ApiKey = "test-api-key"; _settings.Current.Provider.ApiKey = "test-api-key";
Settings.Get.Provider.Timeout = 100; _settings.Current.Provider.Timeout = 100;
} }
[Fact] [Fact]
@ -64,7 +66,7 @@ public class TorBoxDebridClientTest
} }
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
clientMock.Protected().Setup<Task<IEnumerable<TorrentInfoResult>?>>("GetCurrentTorrents").ReturnsAsync(torrents); clientMock.Protected().Setup<Task<IEnumerable<TorrentInfoResult>?>>("GetCurrentTorrents").ReturnsAsync(torrents);
clientMock.Protected().Setup<Task<IEnumerable<TorrentInfoResult>?>>("GetQueuedTorrents").ReturnsAsync(new List<TorrentInfoResult>()); clientMock.Protected().Setup<Task<IEnumerable<TorrentInfoResult>?>>("GetQueuedTorrents").ReturnsAsync(new List<TorrentInfoResult>());
clientMock.Protected().Setup<Task<IEnumerable<UsenetInfoResult>?>>("GetCurrentUsenet").ReturnsAsync(nzbs); clientMock.Protected().Setup<Task<IEnumerable<UsenetInfoResult>?>>("GetCurrentUsenet").ReturnsAsync(nzbs);
@ -114,7 +116,7 @@ public class TorBoxDebridClientTest
} }
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(availability); clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(availability);
// Act // Act
@ -157,7 +159,7 @@ public class TorBoxDebridClientTest
} }
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(torrentAvailability); clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(torrentAvailability);
clientMock.Protected().Setup<Task<Response<List<AvailableUsenet?>>>>("GetUsenetAvailability", hash).ReturnsAsync(usenetAvailability); clientMock.Protected().Setup<Task<Response<List<AvailableUsenet?>>>>("GetUsenetAvailability", hash).ReturnsAsync(usenetAvailability);
@ -186,7 +188,7 @@ public class TorBoxDebridClientTest
Data = new() Data = new()
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(torrentAvailability); clientMock.Protected().Setup<Task<Response<List<AvailableTorrent?>>>>("GetTorrentAvailability", hash).ReturnsAsync(torrentAvailability);
clientMock.Protected().Setup<Task<Response<List<AvailableUsenet?>>>>("GetUsenetAvailability", hash).ReturnsAsync(usenetAvailability); clientMock.Protected().Setup<Task<Response<List<AvailableUsenet?>>>>("GetUsenetAvailability", hash).ReturnsAsync(usenetAvailability);
@ -208,7 +210,7 @@ public class TorBoxDebridClientTest
}; };
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -232,7 +234,7 @@ public class TorBoxDebridClientTest
}; };
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object); torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object);
@ -258,7 +260,7 @@ public class TorBoxDebridClientTest
var link = "https://torbox.app/d/123/456"; var link = "https://torbox.app/d/123/456";
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -291,7 +293,7 @@ public class TorBoxDebridClientTest
var link = "https://torbox.app/d/123/456"; var link = "https://torbox.app/d/123/456";
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object); torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object);
@ -323,7 +325,7 @@ public class TorBoxDebridClientTest
var name = "test-nzb"; var name = "test-nzb";
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -377,7 +379,7 @@ public class TorBoxDebridClientTest
}; };
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -391,7 +393,7 @@ public class TorBoxDebridClientTest
_fileFilterMock.Setup(m => m.IsDownloadable(torrent, It.IsAny<String>(), It.IsAny<Int64>())).Returns(true); _fileFilterMock.Setup(m => m.IsDownloadable(torrent, It.IsAny<String>(), It.IsAny<Int64>())).Returns(true);
Settings.Get.Provider.PreferZippedDownloads = false; _settings.Current.Provider.PreferZippedDownloads = false;
// Act // Act
var result = await clientMock.Object.GetDownloadInfos(torrent); var result = await clientMock.Object.GetDownloadInfos(torrent);
@ -425,10 +427,10 @@ public class TorBoxDebridClientTest
DownloadClient = DownloadClient.Aria2c DownloadClient = DownloadClient.Aria2c
}; };
Settings.Get.Provider.PreferZippedDownloads = true; _settings.Current.Provider.PreferZippedDownloads = true;
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -464,7 +466,7 @@ public class TorBoxDebridClientTest
var link = "https://torbox.app/fakedl/12345/6789"; var link = "https://torbox.app/fakedl/12345/6789";
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -496,7 +498,7 @@ public class TorBoxDebridClientTest
var link = "https://torbox.app/fakedl/12345/zip"; var link = "https://torbox.app/fakedl/12345/zip";
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object); torBoxClientMock.Setup(m => m.Torrents).Returns(torrentsApiMock.Object);
@ -538,7 +540,7 @@ public class TorBoxDebridClientTest
}; };
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object); torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object);
@ -556,7 +558,7 @@ public class TorBoxDebridClientTest
_fileFilterMock.Setup(m => m.IsDownloadable(torrent, It.IsAny<String>(), It.IsAny<Int64>())).Returns(true); _fileFilterMock.Setup(m => m.IsDownloadable(torrent, It.IsAny<String>(), It.IsAny<Int64>())).Returns(true);
Settings.Get.Provider.PreferZippedDownloads = false; _settings.Current.Provider.PreferZippedDownloads = false;
// Act // Act
var result = await clientMock.Object.GetDownloadInfos(torrent); var result = await clientMock.Object.GetDownloadInfos(torrent);
@ -579,7 +581,7 @@ public class TorBoxDebridClientTest
var link = "https://torbox.app/fakedl/98765/4321"; var link = "https://torbox.app/fakedl/98765/4321";
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
var torBoxClientMock = new Mock<ITorBoxNetClient>(); var torBoxClientMock = new Mock<ITorBoxNetClient>();
torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object); torBoxClientMock.Setup(m => m.Usenet).Returns(usenetApiMock.Object);
@ -607,7 +609,7 @@ public class TorBoxDebridClientTest
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var userApiMock = new Mock<IUserApi>(); var userApiMock = new Mock<IUserApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -647,7 +649,7 @@ public class TorBoxDebridClientTest
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var userApiMock = new Mock<IUserApi>(); var userApiMock = new Mock<IUserApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -685,7 +687,7 @@ public class TorBoxDebridClientTest
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var userApiMock = new Mock<IUserApi>(); var userApiMock = new Mock<IUserApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -724,7 +726,7 @@ public class TorBoxDebridClientTest
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var userApiMock = new Mock<IUserApi>(); var userApiMock = new Mock<IUserApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -767,7 +769,7 @@ public class TorBoxDebridClientTest
var torrentsApiMock = new Mock<ITorrentsApi>(); var torrentsApiMock = new Mock<ITorrentsApi>();
var userApiMock = new Mock<IUserApi>(); var userApiMock = new Mock<IUserApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -806,7 +808,7 @@ public class TorBoxDebridClientTest
var nzbLink = "https://example.com/test.nzb"; var nzbLink = "https://example.com/test.nzb";
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -837,7 +839,7 @@ public class TorBoxDebridClientTest
var name = "test.nzb"; var name = "test.nzb";
var usenetApiMock = new Mock<IUsenetApi>(); var usenetApiMock = new Mock<IUsenetApi>();
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object) var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings)
{ {
CallBase = true CallBase = true
}; };
@ -872,7 +874,7 @@ public class TorBoxDebridClientTest
Filename = "test-file" Filename = "test-file"
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
// Act // Act
var result = await clientMock.Object.UpdateData(torrent, torrentClientTorrent); var result = await clientMock.Object.UpdateData(torrent, torrentClientTorrent);
@ -898,7 +900,7 @@ public class TorBoxDebridClientTest
Filename = "test-torrent" Filename = "test-torrent"
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
// Act // Act
await clientMock.Object.UpdateData(torrent, torrentClientTorrent); await clientMock.Object.UpdateData(torrent, torrentClientTorrent);
@ -929,7 +931,7 @@ public class TorBoxDebridClientTest
Filename = "test-torrent" Filename = "test-torrent"
}; };
var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object); var clientMock = new Mock<TorBoxDebridClient>(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object, _coordinatorMock.Object, _settings);
// Act // Act
var result = await clientMock.Object.UpdateData(torrent, torrentClientTorrent); var result = await clientMock.Object.UpdateData(torrent, torrentClientTorrent);

View file

@ -13,76 +13,63 @@ public class TorrentRunnerTest
[Fact] [Fact]
public async Task Tick_ShouldNotRequeueCompletedErrorTorrent() public async Task Tick_ShouldNotRequeueCompletedErrorTorrent()
{ {
var originalApiKey = Settings.Get.Provider.ApiKey; var testSettings = new TestSettings();
var originalProvider = Settings.Get.Provider.Provider; var runnerState = new TorrentRunnerState();
var originalMaxParallelDownloads = Settings.Get.Provider.MaxParallelDownloads;
var originalDownloadPath = Settings.Get.DownloadClient.DownloadPath;
TorrentRunner.ActiveDownloadClients.Clear(); testSettings.Current.Provider.ApiKey = "test-api-key";
TorrentRunner.ActiveUnpackClients.Clear(); testSettings.Current.Provider.Provider = Provider.RealDebrid;
testSettings.Current.Provider.MaxParallelDownloads = 1;
testSettings.Current.DownloadClient.DownloadPath = "/downloads";
try var erroredTorrent = new Torrent
{ {
Settings.Get.Provider.ApiKey = "test-api-key"; TorrentId = Guid.NewGuid(),
Settings.Get.Provider.Provider = Provider.RealDebrid; Hash = "hash-1",
Settings.Get.Provider.MaxParallelDownloads = 1; RdName = "Torrent 1",
Settings.Get.DownloadClient.DownloadPath = "/downloads"; FileOrMagnet = "magnet:?xt=urn:btih:hash-1",
Type = DownloadType.Torrent,
RdStatus = TorrentStatus.Queued,
DeleteOnError = 10,
Error = "Could not add to provider: Infringing file",
Completed = DateTimeOffset.UtcNow.AddMinutes(-5),
Downloads = new List<Download>()
};
var erroredTorrent = new Torrent var torrentDataMock = new Mock<ITorrentData>(MockBehavior.Strict);
{ torrentDataMock.Setup(m => m.Get()).ReturnsAsync(new List<Torrent>
TorrentId = Guid.NewGuid(),
Hash = "hash-1",
RdName = "Torrent 1",
FileOrMagnet = "magnet:?xt=urn:btih:hash-1",
Type = DownloadType.Torrent,
RdStatus = TorrentStatus.Queued,
DeleteOnError = 10,
Error = "Could not add to provider: Infringing file",
Completed = DateTimeOffset.UtcNow.AddMinutes(-5),
Downloads = new List<Download>()
};
var torrentDataMock = new Mock<ITorrentData>(MockBehavior.Strict);
torrentDataMock.Setup(m => m.Get()).ReturnsAsync(new List<Torrent>
{
erroredTorrent
});
var torrents = new Torrents(Mock.Of<ILogger<Torrents>>(),
torrentDataMock.Object,
Mock.Of<IDownloads>(),
null!,
null!,
null!,
null!,
null!,
null!,
null!,
null!);
var torrentRunner = new TorrentRunner(Mock.Of<ILogger<TorrentRunner>>(),
torrents,
new(null!),
new(null!, torrents),
Mock.Of<IHttpClientFactory>(),
new RateLimitCoordinator());
await torrentRunner.Tick();
torrentDataMock.Verify(m => m.UpdateComplete(It.IsAny<Guid>(),
It.IsAny<String?>(),
It.IsAny<DateTimeOffset?>(),
It.IsAny<Boolean>()),
Times.Never);
}
finally
{ {
Settings.Get.Provider.ApiKey = originalApiKey; erroredTorrent
Settings.Get.Provider.Provider = originalProvider; });
Settings.Get.Provider.MaxParallelDownloads = originalMaxParallelDownloads;
Settings.Get.DownloadClient.DownloadPath = originalDownloadPath; var torrents = new Torrents(Mock.Of<ILogger<Torrents>>(),
TorrentRunner.ActiveDownloadClients.Clear(); torrentDataMock.Object,
TorrentRunner.ActiveUnpackClients.Clear(); Mock.Of<IDownloads>(),
} null!,
null!,
null!,
null!,
null!,
null!,
null!,
null!,
testSettings,
runnerState);
var torrentRunner = new TorrentRunner(Mock.Of<ILogger<TorrentRunner>>(),
torrents,
new(null!),
new(null!, torrents),
Mock.Of<IHttpClientFactory>(),
new RateLimitCoordinator(),
testSettings,
runnerState);
await torrentRunner.Tick();
torrentDataMock.Verify(m => m.UpdateComplete(It.IsAny<Guid>(),
It.IsAny<String?>(),
It.IsAny<DateTimeOffset?>(),
It.IsAny<Boolean>()),
Times.Never);
} }
} }

View file

@ -120,7 +120,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>())).Returns(true); mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>())).Returns(true);
@ -186,7 +188,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
//Act //Act
await torrents.RunTorrentComplete(torrent.TorrentId, settings); await torrents.RunTorrentComplete(torrent.TorrentId, settings);
@ -234,7 +238,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>())) mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>()))
.Callback(() => .Callback(() =>
@ -301,7 +307,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>())) mocks.ProcessMock.Setup(p => p.WaitForExit(It.IsAny<Int32>()))
.Callback(() => .Callback(() =>
@ -364,7 +372,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
// Act // Act
await torrents.AddNzbFileToDebridQueue(bytes, "filename.nzb", torrent); await torrents.AddNzbFileToDebridQueue(bytes, "filename.nzb", torrent);
@ -412,7 +422,9 @@ public class TorrentsTest
null!, null!,
null!, null!,
null!, null!,
null!); null!,
new TestSettings(),
new TorrentRunnerState());
// Act // Act
await torrents.AddNzbLinkToDebridQueue(link, torrent); await torrents.AddNzbLinkToDebridQueue(link, torrent);

View file

@ -0,0 +1,58 @@
using RdtClient.Data.Models.Internal;
namespace RdtClient.Service.Services;
internal sealed class TestSettings(DbSettings? settings = null) : ISettings
{
public DbSettings Current { get; } = settings ?? new();
public String DefaultSavePath
{
get
{
var downloadPath = Current.DownloadClient.MappedPath.TrimEnd('\\').TrimEnd('/');
return downloadPath + Path.DirectorySeparatorChar;
}
}
public IList<SettingProperty> GetAll()
{
return [];
}
public Task Update(IList<SettingProperty> settings)
{
return Task.CompletedTask;
}
public Task Update(String settingId, Object? value)
{
SetValue(Current, settingId.Split(':'), 0, value);
return Task.CompletedTask;
}
private static void SetValue(Object target, IReadOnlyList<String> path, Int32 index, Object? value)
{
var property = target.GetType().GetProperty(path[index]) ?? throw new($"Unknown setting {String.Join(":", path)}");
if (index < path.Count - 1)
{
SetValue(property.GetValue(target)!, path, index + 1, value);
return;
}
if (value == null)
{
property.SetValue(target, null);
return;
}
var propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
var convertedValue = propertyType.IsEnum ? Enum.Parse(propertyType, value.ToString()!) : Convert.ChangeType(value, propertyType);
property.SetValue(target, convertedValue);
}
}

View file

@ -8,7 +8,7 @@ using DownloadClient = RdtClient.Data.Enums.DownloadClient;
namespace RdtClient.Service.BackgroundServices; namespace RdtClient.Service.BackgroundServices;
public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider serviceProvider) : BackgroundService public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider serviceProvider, ISettings settings, ITorrentRunnerState runnerState) : BackgroundService
{ {
private static DiskSpaceStatus? _lastStatus; private static DiskSpaceStatus? _lastStatus;
private Boolean _isPausedForLowDiskSpace; private Boolean _isPausedForLowDiskSpace;
@ -34,7 +34,7 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
{ {
try try
{ {
var minimumFreeSpaceGB = Settings.Get.DownloadClient.MinimumFreeSpaceGB; var minimumFreeSpaceGB = settings.Current.DownloadClient.MinimumFreeSpaceGB;
if (minimumFreeSpaceGB <= 0) if (minimumFreeSpaceGB <= 0)
{ {
@ -43,14 +43,14 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
continue; continue;
} }
var intervalMinutes = Settings.Get.DownloadClient.DiskSpaceCheckIntervalMinutes; var intervalMinutes = settings.Current.DownloadClient.DiskSpaceCheckIntervalMinutes;
if (intervalMinutes < 1) if (intervalMinutes < 1)
{ {
intervalMinutes = 1; intervalMinutes = 1;
} }
var downloadPath = Settings.Get.DownloadClient.DownloadPath; var downloadPath = settings.Current.DownloadClient.DownloadPath;
logger.LogDebug($"Checking disk space for path: {downloadPath}"); logger.LogDebug($"Checking disk space for path: {downloadPath}");
if (!Directory.Exists(downloadPath)) if (!Directory.Exists(downloadPath))
@ -78,7 +78,7 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
var pausedCount = 0; var pausedCount = 0;
foreach (var download in TorrentRunner.ActiveDownloadClients) foreach (var download in runnerState.ActiveDownloadClients)
{ {
if (download.Value.Type == DownloadClient.Bezzad) if (download.Value.Type == DownloadClient.Bezzad)
{ {
@ -90,7 +90,7 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
logger.LogInformation($"Paused {pausedCount} active Bezzad downloads"); logger.LogInformation($"Paused {pausedCount} active Bezzad downloads");
TorrentRunner.IsPausedForLowDiskSpace = true; runnerState.IsPausedForLowDiskSpace = true;
_isPausedForLowDiskSpace = true; _isPausedForLowDiskSpace = true;
var status = new DiskSpaceStatus var status = new DiskSpaceStatus
@ -125,7 +125,7 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
var resumedCount = 0; var resumedCount = 0;
foreach (var download in TorrentRunner.ActiveDownloadClients) foreach (var download in runnerState.ActiveDownloadClients)
{ {
if (download.Value.Type == DownloadClient.Bezzad) if (download.Value.Type == DownloadClient.Bezzad)
{ {
@ -137,7 +137,7 @@ public class DiskSpaceMonitor(ILogger<DiskSpaceMonitor> logger, IServiceProvider
logger.LogInformation($"Resumed {resumedCount} Bezzad downloads"); logger.LogInformation($"Resumed {resumedCount} Bezzad downloads");
TorrentRunner.IsPausedForLowDiskSpace = false; runnerState.IsPausedForLowDiskSpace = false;
_isPausedForLowDiskSpace = false; _isPausedForLowDiskSpace = false;
var status = new DiskSpaceStatus var status = new DiskSpaceStatus

View file

@ -7,7 +7,7 @@ using RdtClient.Service.Services;
namespace RdtClient.Service.BackgroundServices; namespace RdtClient.Service.BackgroundServices;
public class ProviderUpdater(ILogger<ProviderUpdater> logger, IServiceProvider serviceProvider) : BackgroundService public class ProviderUpdater(ILogger<ProviderUpdater> logger, IServiceProvider serviceProvider, ISettings settings) : BackgroundService
{ {
private static DateTime _nextUpdate = DateTime.UtcNow; private static DateTime _nextUpdate = DateTime.UtcNow;
@ -30,11 +30,11 @@ public class ProviderUpdater(ILogger<ProviderUpdater> logger, IServiceProvider s
{ {
var torrents = await torrentService.Get(); var torrents = await torrentService.Get();
if (_nextUpdate < DateTime.UtcNow && (Settings.Get.Provider.AutoImport || torrents.Any(t => t.RdStatus != TorrentStatus.Finished) || RdtHub.HasConnections)) if (_nextUpdate < DateTime.UtcNow && (settings.Current.Provider.AutoImport || torrents.Any(t => t.RdStatus != TorrentStatus.Finished) || RdtHub.HasConnections))
{ {
logger.LogDebug($"Updating torrent info from debrid provider"); logger.LogDebug($"Updating torrent info from debrid provider");
var updateTime = Settings.Get.Provider.CheckInterval * 3; var updateTime = settings.Current.Provider.CheckInterval * 3;
if (updateTime < 30) if (updateTime < 30)
{ {
@ -43,7 +43,7 @@ public class ProviderUpdater(ILogger<ProviderUpdater> logger, IServiceProvider s
if (RdtHub.HasConnections) if (RdtHub.HasConnections)
{ {
updateTime = Settings.Get.Provider.CheckInterval; updateTime = settings.Current.Provider.CheckInterval;
if (updateTime < 5) if (updateTime < 5)
{ {

View file

@ -8,7 +8,7 @@ using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace RdtClient.Service.BackgroundServices; namespace RdtClient.Service.BackgroundServices;
public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProvider serviceProvider) : BackgroundService public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProvider serviceProvider, ISettings settings) : BackgroundService
{ {
private DateTime _prevCheck = DateTime.MinValue; private DateTime _prevCheck = DateTime.MinValue;
@ -28,7 +28,7 @@ public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProv
{ {
try try
{ {
var nextCheck = _prevCheck.AddSeconds(Math.Max(Settings.Get.Watch.Interval, 10)); var nextCheck = _prevCheck.AddSeconds(Math.Max(settings.Current.Watch.Interval, 10));
if (DateTime.Now < nextCheck) if (DateTime.Now < nextCheck)
{ {
@ -38,25 +38,25 @@ public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProv
_prevCheck = DateTime.Now; _prevCheck = DateTime.Now;
if (String.IsNullOrWhiteSpace(Settings.Get.Watch.Path)) if (String.IsNullOrWhiteSpace(settings.Current.Watch.Path))
{ {
continue; continue;
} }
var processedStorePath = Path.Combine(Settings.Get.Watch.Path, "processed"); var processedStorePath = Path.Combine(settings.Current.Watch.Path, "processed");
var errorStorePath = Path.Combine(Settings.Get.Watch.Path, "error"); var errorStorePath = Path.Combine(settings.Current.Watch.Path, "error");
if (!String.IsNullOrWhiteSpace(Settings.Get.Watch.ProcessedPath)) if (!String.IsNullOrWhiteSpace(settings.Current.Watch.ProcessedPath))
{ {
processedStorePath = Settings.Get.Watch.ProcessedPath; processedStorePath = settings.Current.Watch.ProcessedPath;
} }
if (!String.IsNullOrWhiteSpace(Settings.Get.Watch.ErrorPath)) if (!String.IsNullOrWhiteSpace(settings.Current.Watch.ErrorPath))
{ {
errorStorePath = Settings.Get.Watch.ErrorPath; errorStorePath = settings.Current.Watch.ErrorPath;
} }
var torrentFiles = Directory.GetFiles(Settings.Get.Watch.Path, "*.*", SearchOption.TopDirectoryOnly); var torrentFiles = Directory.GetFiles(settings.Current.Watch.Path, "*.*", SearchOption.TopDirectoryOnly);
foreach (var torrentFile in torrentFiles) foreach (var torrentFile in torrentFiles)
{ {
@ -78,22 +78,22 @@ public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProv
var torrent = new Torrent var torrent = new Torrent
{ {
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
Category = Settings.Get.Watch.Default.Category, Category = settings.Current.Watch.Default.Category,
HostDownloadAction = Settings.Get.Watch.Default.HostDownloadAction, HostDownloadAction = settings.Current.Watch.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Watch.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Watch.Default.FinishedActionDelay,
DownloadAction = Settings.Get.Watch.Default.OnlyDownloadAvailableFiles DownloadAction = settings.Current.Watch.Default.OnlyDownloadAvailableFiles
? TorrentDownloadAction.DownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles
: TorrentDownloadAction.DownloadAll, : TorrentDownloadAction.DownloadAll,
FinishedAction = Settings.Get.Watch.Default.FinishedAction, FinishedAction = settings.Current.Watch.Default.FinishedAction,
DownloadMinSize = Settings.Get.Watch.Default.MinFileSize, DownloadMinSize = settings.Current.Watch.Default.MinFileSize,
IncludeRegex = Settings.Get.Watch.Default.IncludeRegex, IncludeRegex = settings.Current.Watch.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Watch.Default.ExcludeRegex, ExcludeRegex = settings.Current.Watch.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Watch.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Watch.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Watch.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Watch.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Watch.Default.DeleteOnError, DeleteOnError = settings.Current.Watch.Default.DeleteOnError,
Lifetime = Settings.Get.Watch.Default.TorrentLifetime, Lifetime = settings.Current.Watch.Default.TorrentLifetime,
Priority = Settings.Get.Watch.Default.Priority > 0 ? Settings.Get.Watch.Default.Priority : null Priority = settings.Current.Watch.Default.Priority > 0 ? settings.Current.Watch.Default.Priority : null
}; };
if (fileInfo.Extension == ".torrent") if (fileInfo.Extension == ".torrent")

View file

@ -30,6 +30,7 @@ public static class DiConfig
services.AddScoped<AllDebridDebridClient>(); services.AddScoped<AllDebridDebridClient>();
services.AddSingleton<IRateLimitCoordinator, RateLimitCoordinator>(); services.AddSingleton<IRateLimitCoordinator, RateLimitCoordinator>();
services.AddSingleton<ITorrentRunnerState>(TorrentRunner.SharedState);
services.AddSingleton<IProcessFactory, ProcessFactory>(); services.AddSingleton<IProcessFactory, ProcessFactory>();
services.AddSingleton<IFileSystem, FileSystem>(); services.AddSingleton<IFileSystem, FileSystem>();
@ -41,7 +42,8 @@ public static class DiConfig
services.AddScoped<Sabnzbd>(); services.AddScoped<Sabnzbd>();
services.AddScoped<RemoteService>(); services.AddScoped<RemoteService>();
services.AddScoped<RealDebridDebridClient>(); services.AddScoped<RealDebridDebridClient>();
services.AddScoped<Settings>(); services.AddSingleton<Settings>();
services.AddSingleton<ISettings>(serviceProvider => serviceProvider.GetRequiredService<Settings>());
services.AddScoped<TorBoxDebridClient>(); services.AddScoped<TorBoxDebridClient>();
services.AddScoped<Torrents>(); services.AddScoped<Torrents>();
services.AddScoped<TorrentRunner>(); services.AddScoped<TorrentRunner>();
@ -51,7 +53,7 @@ public static class DiConfig
services.AddSingleton<ITrackerListGrabber, TrackerListGrabber>(); services.AddSingleton<ITrackerListGrabber, TrackerListGrabber>();
services.AddSingleton<IEnricher, Enricher>(); services.AddSingleton<IEnricher, Enricher>();
services.AddSingleton<IAuthorizationHandler, AuthSettingHandler>(); services.AddScoped<IAuthorizationHandler, AuthSettingHandler>();
services.AddScoped<IAuthorizationHandler, SabnzbdHandler>(); services.AddScoped<IAuthorizationHandler, SabnzbdHandler>();
services.AddHostedService<DiskSpaceMonitor>(); services.AddHostedService<DiskSpaceMonitor>();

View file

@ -8,7 +8,7 @@ public class AuthSettingRequirement : IAuthorizationRequirement
{ {
} }
public class AuthSettingHandler : AuthorizationHandler<AuthSettingRequirement> public class AuthSettingHandler(ISettings settings) : AuthorizationHandler<AuthSettingRequirement>
{ {
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthSettingRequirement requirement) protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthSettingRequirement requirement)
{ {
@ -17,7 +17,7 @@ public class AuthSettingHandler : AuthorizationHandler<AuthSettingRequirement>
context.Succeed(requirement); context.Succeed(requirement);
} }
if (Settings.Get.General.AuthenticationType == AuthenticationType.None) if (settings.Current.General.AuthenticationType == AuthenticationType.None)
{ {
context.Succeed(requirement); context.Succeed(requirement);
} }

View file

@ -9,7 +9,7 @@ public class SabnzbdRequirement : IAuthorizationRequirement
{ {
} }
public class SabnzbdHandler(Authentication authentication, IHttpContextAccessor httpContextAccessor) : AuthorizationHandler<SabnzbdRequirement> public class SabnzbdHandler(Authentication authentication, IHttpContextAccessor httpContextAccessor, ISettings settings) : AuthorizationHandler<SabnzbdRequirement>
{ {
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, SabnzbdRequirement requirement) protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, SabnzbdRequirement requirement)
{ {
@ -22,7 +22,7 @@ public class SabnzbdHandler(Authentication authentication, IHttpContextAccessor
return; return;
} }
if (Settings.Get.General.AuthenticationType == AuthenticationType.None) if (settings.Current.General.AuthenticationType == AuthenticationType.None)
{ {
context.Succeed(requirement); context.Succeed(requirement);

View file

@ -17,13 +17,13 @@ public interface IAllDebridNetClientFactory
public IAllDebridNETClient GetClient(); public IAllDebridNETClient GetClient();
} }
public class AllDebridNetClientFactory(ILogger<AllDebridNetClientFactory> logger, IHttpClientFactory httpClientFactory) : IAllDebridNetClientFactory public class AllDebridNetClientFactory(ILogger<AllDebridNetClientFactory> logger, IHttpClientFactory httpClientFactory, ISettings settings) : IAllDebridNetClientFactory
{ {
public IAllDebridNETClient GetClient() public IAllDebridNETClient GetClient()
{ {
try try
{ {
var apiKey = Settings.Get.Provider.ApiKey; var apiKey = settings.Current.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey)) if (String.IsNullOrWhiteSpace(apiKey))
{ {

View file

@ -12,7 +12,7 @@ using Torrent = DebridLinkFrNET.Models.Torrent;
namespace RdtClient.Service.Services.DebridClients; namespace RdtClient.Service.Services.DebridClients;
public class DebridLinkClient(ILogger<DebridLinkClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter) : IDebridClient public class DebridLinkClient(ILogger<DebridLinkClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter, ISettings settings) : IDebridClient
{ {
public async Task<IList<DebridClientTorrent>> GetDownloads() public async Task<IList<DebridClientTorrent>> GetDownloads()
{ {
@ -228,7 +228,7 @@ public class DebridLinkClient(ILogger<DebridLinkClient> logger, IHttpClientFacto
{ {
try try
{ {
var apiKey = Settings.Get.Provider.ApiKey; var apiKey = settings.Current.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey)) if (String.IsNullOrWhiteSpace(apiKey))
{ {
@ -236,7 +236,7 @@ public class DebridLinkClient(ILogger<DebridLinkClient> logger, IHttpClientFacto
} }
var httpClient = httpClientFactory.CreateClient(); var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(Settings.Get.Provider.Timeout); httpClient.Timeout = TimeSpan.FromSeconds(settings.Current.Provider.Timeout);
var debridLinkClient = new DebridLinkFrNETClient(apiKey, httpClient); var debridLinkClient = new DebridLinkFrNETClient(apiKey, httpClient);

View file

@ -12,7 +12,7 @@ using Torrent = RdtClient.Data.Models.Data.Torrent;
namespace RdtClient.Service.Services.DebridClients; namespace RdtClient.Service.Services.DebridClients;
public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter) : IDebridClient public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter, ISettings settings) : IDebridClient
{ {
private const String TransferCreateUrl = "https://www.premiumize.me/api/transfer/create"; private const String TransferCreateUrl = "https://www.premiumize.me/api/transfer/create";
@ -216,9 +216,9 @@ public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHtt
} }
} }
private static String GetApiKey() private String GetApiKey()
{ {
var apiKey = Settings.Get.Provider.ApiKey; var apiKey = settings.Current.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey)) if (String.IsNullOrWhiteSpace(apiKey))
{ {

View file

@ -12,7 +12,7 @@ using Torrent = RDNET.Torrent;
namespace RdtClient.Service.Services.DebridClients; namespace RdtClient.Service.Services.DebridClients;
public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter) : IDebridClient public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter, ISettings settings) : IDebridClient
{ {
private TimeSpan? _offset; private TimeSpan? _offset;
@ -53,7 +53,7 @@ public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHtt
{ {
try try
{ {
var timeoutCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(Settings.Get.Provider.Timeout)); var timeoutCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(settings.Current.Provider.Timeout));
var result = await GetClient().Torrents.AddMagnetAsync(magnetLink, timeoutCancellationToken.Token); var result = await GetClient().Torrents.AddMagnetAsync(magnetLink, timeoutCancellationToken.Token);
@ -70,7 +70,7 @@ public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHtt
{ {
try try
{ {
var timeoutCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(Settings.Get.Provider.Timeout)); var timeoutCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(settings.Current.Provider.Timeout));
var result = await GetClient().Torrents.AddFileAsync(bytes, timeoutCancellationToken.Token); var result = await GetClient().Torrents.AddFileAsync(bytes, timeoutCancellationToken.Token);
@ -314,7 +314,7 @@ public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHtt
{ {
try try
{ {
var apiKey = Settings.Get.Provider.ApiKey; var apiKey = settings.Current.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey)) if (String.IsNullOrWhiteSpace(apiKey))
{ {
@ -322,9 +322,9 @@ public class RealDebridDebridClient(ILogger<RealDebridDebridClient> logger, IHtt
} }
var httpClient = httpClientFactory.CreateClient(DiConfig.RD_CLIENT); var httpClient = httpClientFactory.CreateClient(DiConfig.RD_CLIENT);
httpClient.Timeout = TimeSpan.FromSeconds(Settings.Get.Provider.Timeout); httpClient.Timeout = TimeSpan.FromSeconds(settings.Current.Provider.Timeout);
var rdtNetClient = new RdNetClient(null, httpClient, 5, Settings.Get.Provider.ApiHostname); var rdtNetClient = new RdNetClient(null, httpClient, 5, settings.Current.Provider.ApiHostname);
rdtNetClient.UseApiAuthentication(apiKey); rdtNetClient.UseApiAuthentication(apiKey);
// Get the server time to fix up the timezones on results // Get the server time to fix up the timezones on results

View file

@ -11,7 +11,7 @@ using Torrent = RdtClient.Data.Models.Data.Torrent;
namespace RdtClient.Service.Services.DebridClients; namespace RdtClient.Service.Services.DebridClients;
public class TorBoxDebridClient(ILogger<TorBoxDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter, IRateLimitCoordinator coordinator) public class TorBoxDebridClient(ILogger<TorBoxDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter, IRateLimitCoordinator coordinator, ISettings settings)
: IDebridClient : IDebridClient
{ {
private const String TorBoxApiHost = "api.torbox.app"; private const String TorBoxApiHost = "api.torbox.app";
@ -327,7 +327,7 @@ public class TorBoxDebridClient(ILogger<TorBoxDebridClient> logger, IHttpClientF
var downloadableFiles = torrent.Files.Where(file => fileFilter.IsDownloadable(torrent, file.Path, file.Bytes)).ToList(); var downloadableFiles = torrent.Files.Where(file => fileFilter.IsDownloadable(torrent, file.Path, file.Bytes)).ToList();
if (downloadableFiles.Count == torrent.Files.Count && torrent.DownloadClient != Data.Enums.DownloadClient.Symlink && Settings.Get.Provider.PreferZippedDownloads) if (downloadableFiles.Count == torrent.Files.Count && torrent.DownloadClient != Data.Enums.DownloadClient.Symlink && settings.Current.Provider.PreferZippedDownloads)
{ {
logger.LogDebug("Downloading files from TorBox as a zip."); logger.LogDebug("Downloading files from TorBox as a zip.");
@ -364,7 +364,7 @@ public class TorBoxDebridClient(ILogger<TorBoxDebridClient> logger, IHttpClientF
{ {
try try
{ {
var apiKey = Settings.Get.Provider.ApiKey; var apiKey = settings.Current.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey)) if (String.IsNullOrWhiteSpace(apiKey))
{ {

View file

@ -5,7 +5,7 @@ using RdtClient.Data.Models.QBittorrent;
namespace RdtClient.Service.Services; namespace RdtClient.Service.Services;
public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authentication authentication, Torrents torrents, Downloads downloads) public class QBittorrent(ILogger<QBittorrent> logger, ISettings settings, Authentication authentication, Torrents torrents, Downloads downloads, ITorrentRunnerState runnerState)
{ {
public async Task<Boolean> AuthLogin(String userName, String password) public async Task<Boolean> AuthLogin(String userName, String password)
{ {
@ -168,7 +168,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
WebUiUsername = "" WebUiUsername = ""
}; };
var savePath = Settings.AppDefaultSavePath; var savePath = settings.DefaultSavePath;
preferences.SavePath = savePath; preferences.SavePath = savePath;
preferences.TempPath = $"{savePath}temp{Path.DirectorySeparatorChar}"; preferences.TempPath = $"{savePath}temp{Path.DirectorySeparatorChar}";
@ -185,7 +185,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
public virtual async Task<IList<TorrentInfo>> TorrentInfo() public virtual async Task<IList<TorrentInfo>> TorrentInfo()
{ {
var savePath = Settings.AppDefaultSavePath; var savePath = settings.DefaultSavePath;
var results = new List<TorrentInfo>(); var results = new List<TorrentInfo>();
@ -515,7 +515,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
public async Task<TorrentProperties?> TorrentProperties(String hash) public async Task<TorrentProperties?> TorrentProperties(String hash)
{ {
var savePath = Settings.AppDefaultSavePath; var savePath = settings.DefaultSavePath;
var torrent = await torrents.GetByHash(hash); var torrent = await torrents.GetByHash(hash);
@ -605,7 +605,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
return; return;
} }
switch (Settings.Get.Integrations.Default.FinishedAction) switch (settings.Current.Integrations.Default.FinishedAction)
{ {
case TorrentFinishedAction.RemoveAllTorrents: case TorrentFinishedAction.RemoveAllTorrents:
logger.LogDebug("Removing torrents from debrid provider and RDT-Client, no files"); logger.LogDebug("Removing torrents from debrid provider and RDT-Client, no files");
@ -640,19 +640,19 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
var torrent = new Torrent var torrent = new Torrent
{ {
Category = category, Category = category,
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, HostDownloadAction = settings.Current.Integrations.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Integrations.Default.FinishedActionDelay,
DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, DownloadAction = settings.Current.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
FinishedAction = TorrentFinishedAction.None, FinishedAction = TorrentFinishedAction.None,
DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, DownloadMinSize = settings.Current.Integrations.Default.MinFileSize,
IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, IncludeRegex = settings.Current.Integrations.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, ExcludeRegex = settings.Current.Integrations.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Integrations.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Integrations.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, DeleteOnError = settings.Current.Integrations.Default.DeleteOnError,
Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Lifetime = settings.Current.Integrations.Default.TorrentLifetime,
Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null) Priority = priority ?? (settings.Current.Integrations.Default.Priority > 0 ? settings.Current.Integrations.Default.Priority : null)
}; };
await torrents.AddMagnetToDebridQueue(magnetLink, torrent); await torrents.AddMagnetToDebridQueue(magnetLink, torrent);
@ -665,19 +665,19 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
var torrent = new Torrent var torrent = new Torrent
{ {
Category = category, Category = category,
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, HostDownloadAction = settings.Current.Integrations.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Integrations.Default.FinishedActionDelay,
DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, DownloadAction = settings.Current.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
FinishedAction = TorrentFinishedAction.None, FinishedAction = TorrentFinishedAction.None,
DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, DownloadMinSize = settings.Current.Integrations.Default.MinFileSize,
IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, IncludeRegex = settings.Current.Integrations.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, ExcludeRegex = settings.Current.Integrations.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Integrations.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Integrations.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, DeleteOnError = settings.Current.Integrations.Default.DeleteOnError,
Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Lifetime = settings.Current.Integrations.Default.TorrentLifetime,
Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null) Priority = priority ?? (settings.Current.Integrations.Default.Priority > 0 ? settings.Current.Integrations.Default.Priority : null)
}; };
await torrents.AddFileToDebridQueue(fileBytes, torrent); await torrents.AddFileToDebridQueue(fileBytes, torrent);
@ -696,7 +696,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
.Select(m => m.Category!.ToLower()) .Select(m => m.Category!.ToLower())
.ToList(); .ToList();
var categoryList = (Settings.Get.General.Categories ?? "") var categoryList = (settings.Current.General.Categories ?? "")
.Split(",", StringSplitOptions.RemoveEmptyEntries) .Split(",", StringSplitOptions.RemoveEmptyEntries)
.Distinct(StringComparer.CurrentCultureIgnoreCase) .Distinct(StringComparer.CurrentCultureIgnoreCase)
.Select(m => m.Trim()) .Select(m => m.Trim())
@ -713,7 +713,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
m => new TorrentCategory m => new TorrentCategory
{ {
Name = m, Name = m,
SavePath = Path.Combine(Settings.AppDefaultSavePath, m) SavePath = Path.Combine(settings.DefaultSavePath, m)
}); });
} }
@ -729,7 +729,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
category = category.Trim(); category = category.Trim();
var categoriesSetting = Settings.Get.General.Categories; var categoriesSetting = settings.Current.General.Categories;
var categoryList = (categoriesSetting ?? "") var categoryList = (categoriesSetting ?? "")
.Split(",", StringSplitOptions.RemoveEmptyEntries) .Split(",", StringSplitOptions.RemoveEmptyEntries)
@ -756,7 +756,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
category = category.Trim(); category = category.Trim();
var categoriesSetting = Settings.Get.General.Categories; var categoriesSetting = settings.Current.General.Categories;
var categoryList = (categoriesSetting ?? "") var categoryList = (categoriesSetting ?? "")
.Split(",", StringSplitOptions.RemoveEmptyEntries) .Split(",", StringSplitOptions.RemoveEmptyEntries)
@ -796,7 +796,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
foreach (var download in downloadsForTorrent) foreach (var download in downloadsForTorrent)
{ {
if (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) if (runnerState.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
{ {
await downloadClient.Pause(); await downloadClient.Pause();
} }
@ -816,7 +816,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
foreach (var download in downloadsForTorrent) foreach (var download in downloadsForTorrent)
{ {
if (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) if (runnerState.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
{ {
await downloadClient.Resume(); await downloadClient.Resume();
} }
@ -829,7 +829,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
var categories = await TorrentsCategories(); var categories = await TorrentsCategories();
var activeDownloads = TorrentRunner.ActiveDownloadClients.Sum(m => m.Value.Speed); var activeDownloads = runnerState.ActiveDownloadClients.Sum(m => m.Value.Speed);
return new() return new()
{ {
@ -847,16 +847,16 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
}; };
} }
public static TransferInfo TransferInfo() public virtual TransferInfo TransferInfo()
{ {
var activeDownloads = TorrentRunner.ActiveDownloadClients.Sum(m => m.Value.Speed); var activeDownloads = runnerState.ActiveDownloadClients.Sum(m => m.Value.Speed);
return new() return new()
{ {
ConnectionStatus = "connected", ConnectionStatus = "connected",
DlInfoData = DownloadClient.GetTotalBytesDownloadedThisSession(), DlInfoData = DownloadClient.GetTotalBytesDownloadedThisSession(),
DlInfoSpeed = activeDownloads, DlInfoSpeed = activeDownloads,
DlRateLimit = Settings.Get.DownloadClient.MaxSpeed DlRateLimit = settings.Current.DownloadClient.MaxSpeed
}; };
} }

View file

@ -7,7 +7,7 @@ using RdtClient.Service.Helpers;
namespace RdtClient.Service.Services; namespace RdtClient.Service.Services;
public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings appSettings) public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings appSettings, ISettings settings)
{ {
public virtual async Task<SabnzbdQueue> GetQueue() public virtual async Task<SabnzbdQueue> GetQueue()
{ {
@ -87,7 +87,7 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
var allTorrents = await torrents.Get(); var allTorrents = await torrents.Get();
var completedTorrents = allTorrents.Where(t => t.Type == DownloadType.Nzb && t.Completed != null).ToList(); var completedTorrents = allTorrents.Where(t => t.Type == DownloadType.Nzb && t.Completed != null).ToList();
var savePath = Settings.AppDefaultSavePath; var savePath = settings.DefaultSavePath;
var history = new SabnzbdHistory var history = new SabnzbdHistory
{ {
@ -130,19 +130,19 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
var torrent = new Torrent var torrent = new Torrent
{ {
Category = category, Category = category,
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, HostDownloadAction = settings.Current.Integrations.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Integrations.Default.FinishedActionDelay,
DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, DownloadAction = settings.Current.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
FinishedAction = TorrentFinishedAction.None, FinishedAction = TorrentFinishedAction.None,
DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, DownloadMinSize = settings.Current.Integrations.Default.MinFileSize,
IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, IncludeRegex = settings.Current.Integrations.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, ExcludeRegex = settings.Current.Integrations.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Integrations.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Integrations.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, DeleteOnError = settings.Current.Integrations.Default.DeleteOnError,
Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Lifetime = settings.Current.Integrations.Default.TorrentLifetime,
Priority = (priority ?? Settings.Get.Integrations.Default.Priority) > 0 ? 1 : null Priority = (priority ?? settings.Current.Integrations.Default.Priority) > 0 ? 1 : null
}; };
var result = await torrents.AddNzbFileToDebridQueue(fileBytes, fileName, torrent); var result = await torrents.AddNzbFileToDebridQueue(fileBytes, fileName, torrent);
@ -157,19 +157,19 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
var torrent = new Torrent var torrent = new Torrent
{ {
Category = category, Category = category,
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, HostDownloadAction = settings.Current.Integrations.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Integrations.Default.FinishedActionDelay,
DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, DownloadAction = settings.Current.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
FinishedAction = TorrentFinishedAction.None, FinishedAction = TorrentFinishedAction.None,
DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, DownloadMinSize = settings.Current.Integrations.Default.MinFileSize,
IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, IncludeRegex = settings.Current.Integrations.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, ExcludeRegex = settings.Current.Integrations.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Integrations.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Integrations.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, DeleteOnError = settings.Current.Integrations.Default.DeleteOnError,
Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Lifetime = settings.Current.Integrations.Default.TorrentLifetime,
Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null) Priority = priority ?? (settings.Current.Integrations.Default.Priority > 0 ? settings.Current.Integrations.Default.Priority : null)
}; };
var result = await torrents.AddNzbLinkToDebridQueue(url, torrent); var result = await torrents.AddNzbLinkToDebridQueue(url, torrent);
@ -186,7 +186,7 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
return; return;
} }
switch (Settings.Get.Integrations.Default.FinishedAction) switch (settings.Current.Integrations.Default.FinishedAction)
{ {
case TorrentFinishedAction.RemoveAllTorrents: case TorrentFinishedAction.RemoveAllTorrents:
logger.LogDebug("Removing nzb from debrid provider and RDT-Client, no files"); logger.LogDebug("Removing nzb from debrid provider and RDT-Client, no files");
@ -216,7 +216,7 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
public virtual List<String> GetCategories() public virtual List<String> GetCategories()
{ {
var categoryList = (Settings.Get.General.Categories ?? "") var categoryList = (settings.Current.General.Categories ?? "")
.Split(",", StringSplitOptions.RemoveEmptyEntries) .Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(m => m.Trim()) .Select(m => m.Trim())
.Where(m => m != "*") .Where(m => m != "*")
@ -230,7 +230,7 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
public virtual SabnzbdConfig GetConfig() public virtual SabnzbdConfig GetConfig()
{ {
var savePath = Settings.AppDefaultSavePath; var savePath = settings.DefaultSavePath;
var categoryList = GetCategories(); var categoryList = GetCategories();

View file

@ -1,49 +1,83 @@
using RdtClient.Data.Data; using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
using Microsoft.Extensions.DependencyInjection;
using Serilog.Core; using Serilog.Core;
using Serilog.Events; using Serilog.Events;
namespace RdtClient.Service.Services; namespace RdtClient.Service.Services;
public class Settings(SettingData settingData) public interface ISettings
{
DbSettings Current { get; }
String DefaultSavePath { get; }
IList<SettingProperty> GetAll();
Task Update(IList<SettingProperty> settings);
Task Update(String settingId, Object? value);
}
public class Settings(IServiceScopeFactory serviceScopeFactory) : ISettings
{ {
public static readonly LoggingLevelSwitch LoggingLevelSwitch = new(LogEventLevel.Debug); public static readonly LoggingLevelSwitch LoggingLevelSwitch = new(LogEventLevel.Debug);
public static DbSettings Get => SettingData.Get; public static DbSettings Get => SettingData.Get;
public static String AppDefaultSavePath public DbSettings Current => Get;
public static String AppDefaultSavePath => GetDefaultSavePath(Get);
public String DefaultSavePath => GetDefaultSavePath(Current);
public IList<SettingProperty> GetAll()
{ {
get return SettingData.GetAll();
{ }
var downloadPath = Get.DownloadClient.MappedPath;
downloadPath = downloadPath.TrimEnd('\\') private static String GetDefaultSavePath(DbSettings settings)
.TrimEnd('/'); {
var downloadPath = settings.DownloadClient.MappedPath;
downloadPath += Path.DirectorySeparatorChar; downloadPath = downloadPath.TrimEnd('\\')
.TrimEnd('/');
return downloadPath; downloadPath += Path.DirectorySeparatorChar;
}
return downloadPath;
} }
public async Task Update(IList<SettingProperty> settings) public async Task Update(IList<SettingProperty> settings)
{ {
using var scope = serviceScopeFactory.CreateScope();
var settingData = scope.ServiceProvider.GetRequiredService<SettingData>();
await settingData.Update(settings); await settingData.Update(settings);
} }
public async Task Update(String settingId, Object? value) public async Task Update(String settingId, Object? value)
{ {
using var scope = serviceScopeFactory.CreateScope();
var settingData = scope.ServiceProvider.GetRequiredService<SettingData>();
await settingData.Update(settingId, value); await settingData.Update(settingId, value);
} }
public async Task Seed() public async Task Seed()
{ {
using var scope = serviceScopeFactory.CreateScope();
var settingData = scope.ServiceProvider.GetRequiredService<SettingData>();
await settingData.Seed(); await settingData.Seed();
} }
public async Task ResetCache() public async Task ResetCache()
{ {
using var scope = serviceScopeFactory.CreateScope();
var settingData = scope.ServiceProvider.GetRequiredService<SettingData>();
await settingData.ResetCache(); await settingData.ResetCache();
LoggingLevelSwitch.MinimumLevel = Get.General.LogLevel switch LoggingLevelSwitch.MinimumLevel = Get.General.LogLevel switch

View file

@ -17,34 +17,34 @@ public class TorrentRunner(
Downloads downloads, Downloads downloads,
RemoteService remoteService, RemoteService remoteService,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
IRateLimitCoordinator coordinator) IRateLimitCoordinator coordinator,
ISettings settings,
ITorrentRunnerState runnerState)
{ {
public static readonly ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients = new(); public static readonly ITorrentRunnerState SharedState = new TorrentRunnerState();
public static readonly ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients = new();
public static ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients => SharedState.ActiveDownloadClients;
public static ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients => SharedState.ActiveUnpackClients;
private DateTimeOffset? _lastNextAllowedAt; private DateTimeOffset? _lastNextAllowedAt;
public static Boolean IsPausedForLowDiskSpace { get; set; } public static Boolean IsPausedForLowDiskSpace
{
get => SharedState.IsPausedForLowDiskSpace;
set => SharedState.IsPausedForLowDiskSpace = value;
}
public static (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetStats(Guid downloadId) public static (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetStats(Guid downloadId)
{ {
if (ActiveDownloadClients.TryGetValue(downloadId, out var downloadClient)) return SharedState.GetStats(downloadId);
{
return (downloadClient.Speed, downloadClient.BytesTotal, downloadClient.BytesDone);
}
if (ActiveUnpackClients.TryGetValue(downloadId, out var unpackClient))
{
return (0, 100, unpackClient.Progess);
}
return (0, 0, 0);
} }
public async Task Initialize() public async Task Initialize()
{ {
Log("Initializing TorrentRunner"); Log("Initializing TorrentRunner");
var settingsCopy = JsonSerializer.Deserialize<DbSettings>(JsonSerializer.Serialize(Settings.Get)); var settingsCopy = JsonSerializer.Deserialize<DbSettings>(JsonSerializer.Serialize(settings.Current));
if (settingsCopy != null) if (settingsCopy != null)
{ {
@ -87,28 +87,28 @@ public class TorrentRunner(
public async Task Tick() public async Task Tick()
{ {
if (String.IsNullOrWhiteSpace(Settings.Get.Provider.ApiKey)) if (String.IsNullOrWhiteSpace(settings.Current.Provider.ApiKey))
{ {
Log($"No RealDebridApiKey set in settings"); Log($"No RealDebridApiKey set in settings");
return; return;
} }
var settingDownloadLimit = Settings.Get.General.DownloadLimit; var settingDownloadLimit = settings.Current.General.DownloadLimit;
if (settingDownloadLimit < 1) if (settingDownloadLimit < 1)
{ {
settingDownloadLimit = 1; settingDownloadLimit = 1;
} }
var settingUnpackLimit = Settings.Get.General.UnpackLimit; var settingUnpackLimit = settings.Current.General.UnpackLimit;
if (settingUnpackLimit < 0) if (settingUnpackLimit < 0)
{ {
settingUnpackLimit = 0; settingUnpackLimit = 0;
} }
var settingDownloadPath = Settings.Get.DownloadClient.DownloadPath; var settingDownloadPath = settings.Current.DownloadClient.DownloadPath;
if (String.IsNullOrWhiteSpace(settingDownloadPath)) if (String.IsNullOrWhiteSpace(settingDownloadPath))
{ {
@ -141,25 +141,25 @@ public class TorrentRunner(
_lastNextAllowedAt = currentNextAllowedAt; _lastNextAllowedAt = currentNextAllowedAt;
} }
if (!ActiveDownloadClients.IsEmpty || !ActiveUnpackClients.IsEmpty) if (!runnerState.ActiveDownloadClients.IsEmpty || !runnerState.ActiveUnpackClients.IsEmpty)
{ {
Log($"TorrentRunner Tick Start, {ActiveDownloadClients.Count} active downloads, {ActiveUnpackClients.Count} active unpacks"); Log($"TorrentRunner Tick Start, {runnerState.ActiveDownloadClients.Count} active downloads, {runnerState.ActiveUnpackClients.Count} active unpacks");
} }
if (ActiveDownloadClients.Any(m => m.Value.Type == Data.Enums.DownloadClient.Aria2c)) if (runnerState.ActiveDownloadClients.Any(m => m.Value.Type == Data.Enums.DownloadClient.Aria2c))
{ {
Log("Updating Aria2 status"); Log("Updating Aria2 status");
var httpClient = httpClientFactory.CreateClient(); var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(10); httpClient.Timeout = TimeSpan.FromSeconds(10);
var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1); var aria2NetClient = new Aria2NetClient(settings.Current.DownloadClient.Aria2cUrl, settings.Current.DownloadClient.Aria2cSecret, httpClient, 1);
var allDownloads = await aria2NetClient.TellAllAsync(); var allDownloads = await aria2NetClient.TellAllAsync();
Log($"Found {allDownloads.Count} Aria2 downloads"); Log($"Found {allDownloads.Count} Aria2 downloads");
foreach (var activeDownload in ActiveDownloadClients) foreach (var activeDownload in runnerState.ActiveDownloadClients)
{ {
if (activeDownload.Value.Downloader is Aria2cDownloader aria2Downloader) if (activeDownload.Value.Downloader is Aria2cDownloader aria2Downloader)
{ {
@ -170,11 +170,11 @@ public class TorrentRunner(
Log("Finished updating Aria2 status"); Log("Finished updating Aria2 status");
} }
if (ActiveDownloadClients.Any(m => m.Value.Type == Data.Enums.DownloadClient.DownloadStation)) if (runnerState.ActiveDownloadClients.Any(m => m.Value.Type == Data.Enums.DownloadClient.DownloadStation))
{ {
Log("Updating DownloadStation status"); Log("Updating DownloadStation status");
foreach (var activeDownload in ActiveDownloadClients) foreach (var activeDownload in runnerState.ActiveDownloadClients)
{ {
if (activeDownload.Value.Downloader is DownloadStationDownloader downloadStationDownloader) if (activeDownload.Value.Downloader is DownloadStationDownloader downloadStationDownloader)
{ {
@ -184,7 +184,7 @@ public class TorrentRunner(
} }
// Check if any torrents are finished downloading to the host, remove them from the active download list. // Check if any torrents are finished downloading to the host, remove them from the active download list.
var completedActiveDownloads = ActiveDownloadClients.Where(m => m.Value.Finished).ToList(); var completedActiveDownloads = runnerState.ActiveDownloadClients.Where(m => m.Value.Finished).ToList();
if (completedActiveDownloads.Count > 0) if (completedActiveDownloads.Count > 0)
{ {
@ -196,7 +196,7 @@ public class TorrentRunner(
if (download == null) if (download == null)
{ {
ActiveDownloadClients.TryRemove(downloadId, out _); runnerState.ActiveDownloadClients.TryRemove(downloadId, out _);
Log($"Download with ID {downloadId} not found! Removed from download queue"); Log($"Download with ID {downloadId} not found! Removed from download queue");
@ -237,14 +237,14 @@ public class TorrentRunner(
await downloads.UpdateUnpackingQueued(downloadId, DateTimeOffset.UtcNow); await downloads.UpdateUnpackingQueued(downloadId, DateTimeOffset.UtcNow);
} }
ActiveDownloadClients.TryRemove(downloadId, out _); runnerState.ActiveDownloadClients.TryRemove(downloadId, out _);
Log($"Removed from ActiveDownloadClients", download, download.Torrent); Log($"Removed from ActiveDownloadClients", download, download.Torrent);
} }
} }
// Check if any torrents are finished unpacking, remove them from the active unpack list. // Check if any torrents are finished unpacking, remove them from the active unpack list.
var completedUnpacks = ActiveUnpackClients.Where(m => m.Value.Finished).ToList(); var completedUnpacks = runnerState.ActiveUnpackClients.Where(m => m.Value.Finished).ToList();
if (completedUnpacks.Count > 0) if (completedUnpacks.Count > 0)
{ {
@ -256,7 +256,7 @@ public class TorrentRunner(
if (download == null) if (download == null)
{ {
ActiveUnpackClients.TryRemove(downloadId, out _); runnerState.ActiveUnpackClients.TryRemove(downloadId, out _);
Log($"Download with ID {downloadId} not found! Removed from unpack queue"); Log($"Download with ID {downloadId} not found! Removed from unpack queue");
@ -278,7 +278,7 @@ public class TorrentRunner(
await downloads.UpdateCompleted(downloadId, DateTimeOffset.UtcNow); await downloads.UpdateCompleted(downloadId, DateTimeOffset.UtcNow);
ActiveUnpackClients.TryRemove(downloadId, out _); runnerState.ActiveUnpackClients.TryRemove(downloadId, out _);
Log($"Removed from ActiveUnpackClients", download, download.Torrent); Log($"Removed from ActiveUnpackClients", download, download.Torrent);
} }
@ -288,23 +288,23 @@ public class TorrentRunner(
var downloadsById = allTorrents.SelectMany(m => m.Downloads).ToDictionary(m => m.DownloadId, m => m); var downloadsById = allTorrents.SelectMany(m => m.Downloads).ToDictionary(m => m.DownloadId, m => m);
// Check for deleted torrents that are stuck in the ActiveDownloads or ActiveUnpacks // Check for deleted torrents that are stuck in the ActiveDownloads or ActiveUnpacks
foreach (var activeDownload in ActiveDownloadClients) foreach (var activeDownload in runnerState.ActiveDownloadClients)
{ {
if (!downloadsById.ContainsKey(activeDownload.Key)) if (!downloadsById.ContainsKey(activeDownload.Key))
{ {
await activeDownload.Value.Cancel(); await activeDownload.Value.Cancel();
ActiveDownloadClients.TryRemove(activeDownload.Key, out _); runnerState.ActiveDownloadClients.TryRemove(activeDownload.Key, out _);
break; break;
} }
} }
foreach (var activeUnpacks in ActiveUnpackClients) foreach (var activeUnpacks in runnerState.ActiveUnpackClients)
{ {
if (!downloadsById.ContainsKey(activeUnpacks.Key)) if (!downloadsById.ContainsKey(activeUnpacks.Key))
{ {
activeUnpacks.Value.Cancel(); activeUnpacks.Value.Cancel();
ActiveUnpackClients.TryRemove(activeUnpacks.Key, out _); runnerState.ActiveUnpackClients.TryRemove(activeUnpacks.Key, out _);
break; break;
} }
@ -382,7 +382,7 @@ public class TorrentRunner(
{ {
var downloadingTorrentsCount = allTorrents.Count(m => m.RdStatus is not (TorrentStatus.Queued or TorrentStatus.Finished or TorrentStatus.Error)); var downloadingTorrentsCount = allTorrents.Count(m => m.RdStatus is not (TorrentStatus.Queued or TorrentStatus.Finished or TorrentStatus.Error));
var maxParallelDownloads = Settings.Get.Provider.MaxParallelDownloads; var maxParallelDownloads = settings.Current.Provider.MaxParallelDownloads;
logger.LogDebug("Currently downloading {downloadingTorrentCount}/{maxParallelDownloads} torrents, {queuedCount} queued.", logger.LogDebug("Currently downloading {downloadingTorrentCount}/{maxParallelDownloads} torrents, {queuedCount} queued.",
downloadingTorrentsCount, downloadingTorrentsCount,
@ -481,27 +481,27 @@ public class TorrentRunner(
.OrderBy(m => m.DownloadQueued) .OrderBy(m => m.DownloadQueued)
.ToList(); .ToList();
Log($"Currently {queuedDownloads.Count} queued downloads and {ActiveDownloadClients.Count} total active downloads", torrent); Log($"Currently {queuedDownloads.Count} queued downloads and {runnerState.ActiveDownloadClients.Count} total active downloads", torrent);
foreach (var download in queuedDownloads) foreach (var download in queuedDownloads)
{ {
Log($"Processing to download", download, torrent); Log($"Processing to download", download, torrent);
if (ActiveDownloadClients.Count >= settingDownloadLimit && torrent.DownloadClient != Data.Enums.DownloadClient.Symlink) if (runnerState.ActiveDownloadClients.Count >= settingDownloadLimit && torrent.DownloadClient != Data.Enums.DownloadClient.Symlink)
{ {
Log($"Not starting download because there are already the max number of downloads active", download, torrent); Log($"Not starting download because there are already the max number of downloads active", download, torrent);
return; return;
} }
if (IsPausedForLowDiskSpace && torrent.DownloadClient == Data.Enums.DownloadClient.Bezzad) if (runnerState.IsPausedForLowDiskSpace && torrent.DownloadClient == Data.Enums.DownloadClient.Bezzad)
{ {
logger.LogInformation($"Not starting Bezzad download because of low disk space {download.ToLog()} {torrent.ToLog()}"); logger.LogInformation($"Not starting Bezzad download because of low disk space {download.ToLog()} {torrent.ToLog()}");
return; return;
} }
if (ActiveDownloadClients.ContainsKey(download.DownloadId)) if (runnerState.ActiveDownloadClients.ContainsKey(download.DownloadId))
{ {
Log($"Not starting download because this download is already active", download, torrent); Log($"Not starting download because this download is already active", download, torrent);
@ -553,7 +553,7 @@ public class TorrentRunner(
// Start the download process // Start the download process
var downloadClient = new DownloadClient(download, torrent, downloadPath, torrent.Category); var downloadClient = new DownloadClient(download, torrent, downloadPath, torrent.Category);
if (ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient)) if (runnerState.ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient))
{ {
Log($"Starting download", download, torrent); Log($"Starting download", download, torrent);
@ -573,7 +573,7 @@ public class TorrentRunner(
await downloads.UpdateRemoteId(download.DownloadId, remoteId); await downloads.UpdateRemoteId(download.DownloadId, remoteId);
} }
if (IsPausedForLowDiskSpace && downloadClient.Type == Data.Enums.DownloadClient.Bezzad) if (runnerState.IsPausedForLowDiskSpace && downloadClient.Type == Data.Enums.DownloadClient.Bezzad)
{ {
logger.LogInformation($"Pausing new Bezzad download due to low disk space {download.ToLog()} {torrent.ToLog()}"); logger.LogInformation($"Pausing new Bezzad download due to low disk space {download.ToLog()} {torrent.ToLog()}");
await downloadClient.Pause(); await downloadClient.Pause();
@ -633,14 +633,14 @@ public class TorrentRunner(
} }
// Check if we have reached the download limit, if so queue the download, but don't start it. // Check if we have reached the download limit, if so queue the download, but don't start it.
if (ActiveUnpackClients.Count >= settingUnpackLimit) if (runnerState.ActiveUnpackClients.Count >= settingUnpackLimit)
{ {
Log($"Not starting unpack because there are already the max number of unpacks active", download, torrent); Log($"Not starting unpack because there are already the max number of unpacks active", download, torrent);
continue; continue;
} }
if (ActiveUnpackClients.ContainsKey(download.DownloadId)) if (runnerState.ActiveUnpackClients.ContainsKey(download.DownloadId))
{ {
Log($"Not starting unpack because this download is already active", download, torrent); Log($"Not starting unpack because this download is already active", download, torrent);
@ -662,7 +662,7 @@ public class TorrentRunner(
// Start the unpacking process // Start the unpacking process
var unpackClient = new UnpackClient(download, downloadPath); var unpackClient = new UnpackClient(download, downloadPath);
if (ActiveUnpackClients.TryAdd(download.DownloadId, unpackClient)) if (runnerState.ActiveUnpackClients.TryAdd(download.DownloadId, unpackClient))
{ {
Log($"Starting unpack", download, torrent); Log($"Starting unpack", download, torrent);
@ -720,8 +720,8 @@ public class TorrentRunner(
var completePerc = 0; var completePerc = 0;
var totalDownloadBytes = torrent.Downloads.Sum(m => GetStats(m.DownloadId).BytesTotal); var totalDownloadBytes = torrent.Downloads.Sum(m => runnerState.GetStats(m.DownloadId).BytesTotal);
var totalDoneBytes = torrent.Downloads.Sum(m => GetStats(m.DownloadId).BytesDone); var totalDoneBytes = torrent.Downloads.Sum(m => runnerState.GetStats(m.DownloadId).BytesDone);
if (totalDownloadBytes > 0) if (totalDownloadBytes > 0)
{ {

View file

@ -0,0 +1,47 @@
using System.Collections.Concurrent;
namespace RdtClient.Service.Services;
public interface ITorrentRunnerState
{
ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients { get; }
ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients { get; }
Boolean IsPausedForLowDiskSpace { get; set; }
(Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetStats(Guid downloadId);
void Clear();
}
public class TorrentRunnerState : ITorrentRunnerState
{
public ConcurrentDictionary<Guid, DownloadClient> ActiveDownloadClients { get; } = new();
public ConcurrentDictionary<Guid, UnpackClient> ActiveUnpackClients { get; } = new();
public Boolean IsPausedForLowDiskSpace { get; set; }
public (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetStats(Guid downloadId)
{
if (ActiveDownloadClients.TryGetValue(downloadId, out var downloadClient))
{
return (downloadClient.Speed, downloadClient.BytesTotal, downloadClient.BytesDone);
}
if (ActiveUnpackClients.TryGetValue(downloadId, out var unpackClient))
{
return (0, 100, unpackClient.Progess);
}
return (0, 0, 0);
}
public void Clear()
{
ActiveDownloadClients.Clear();
ActiveUnpackClients.Clear();
IsPausedForLowDiskSpace = false;
}
}

View file

@ -32,7 +32,9 @@ public class Torrents(
PremiumizeDebridClient premiumizeDebridClient, PremiumizeDebridClient premiumizeDebridClient,
RealDebridDebridClient realDebridDebridClient, RealDebridDebridClient realDebridDebridClient,
DebridLinkClient debridLinkClient, DebridLinkClient debridLinkClient,
TorBoxDebridClient torBoxDebridClient) TorBoxDebridClient torBoxDebridClient,
ISettings settings,
ITorrentRunnerState runnerState)
{ {
private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1); private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1);
@ -47,7 +49,7 @@ public class Torrents(
{ {
get get
{ {
return Settings.Get.Provider.Provider switch return settings.Current.Provider.Provider switch
{ {
Provider.Premiumize => premiumizeDebridClient, Provider.Premiumize => premiumizeDebridClient,
Provider.RealDebrid => realDebridDebridClient, Provider.RealDebrid => realDebridDebridClient,
@ -61,7 +63,7 @@ public class Torrents(
public virtual (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetDownloadStats(Guid downloadId) public virtual (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetDownloadStats(Guid downloadId)
{ {
return TorrentRunner.GetStats(downloadId); return runnerState.GetStats(downloadId);
} }
public virtual async Task<IList<Torrent>> Get() public virtual async Task<IList<Torrent>> Get()
@ -197,9 +199,9 @@ public class Torrents(
throw new($"{ex.Message}, trying to parse {magnetLink}"); throw new($"{ex.Message}, trying to parse {magnetLink}");
} }
if (!String.IsNullOrWhiteSpace(Settings.Get.General.BannedTrackers)) if (!String.IsNullOrWhiteSpace(settings.Current.General.BannedTrackers))
{ {
var bannedTrackers = Settings.Get.General.BannedTrackers.Split(','); var bannedTrackers = settings.Current.General.BannedTrackers.Split(',');
foreach (var bannedTracker in bannedTrackers) foreach (var bannedTracker in bannedTrackers)
{ {
@ -264,9 +266,9 @@ public class Torrents(
throw new($"{ex.Message}, trying to parse {fileAsBase64}"); throw new($"{ex.Message}, trying to parse {fileAsBase64}");
} }
if (!String.IsNullOrWhiteSpace(Settings.Get.General.BannedTrackers)) if (!String.IsNullOrWhiteSpace(settings.Current.General.BannedTrackers))
{ {
var bannedTrackers = Settings.Get.General.BannedTrackers.Split(','); var bannedTrackers = settings.Current.General.BannedTrackers.Split(',');
foreach (var bannedTracker in bannedTrackers) foreach (var bannedTracker in bannedTrackers)
{ {
@ -312,16 +314,16 @@ public class Torrents(
private async Task CopyAddedTorrent(Torrent torrent) private async Task CopyAddedTorrent(Torrent torrent)
{ {
if (String.IsNullOrWhiteSpace(Settings.Get.General.CopyAddedTorrents) || String.IsNullOrWhiteSpace(torrent.FileOrMagnet) || String.IsNullOrWhiteSpace(torrent.RdName)) if (String.IsNullOrWhiteSpace(settings.Current.General.CopyAddedTorrents) || String.IsNullOrWhiteSpace(torrent.FileOrMagnet) || String.IsNullOrWhiteSpace(torrent.RdName))
{ {
return; return;
} }
try try
{ {
if (!fileSystem.Directory.Exists(Settings.Get.General.CopyAddedTorrents)) if (!fileSystem.Directory.Exists(settings.Current.General.CopyAddedTorrents))
{ {
fileSystem.Directory.CreateDirectory(Settings.Get.General.CopyAddedTorrents); fileSystem.Directory.CreateDirectory(settings.Current.General.CopyAddedTorrents);
} }
var extension = torrent.Type switch var extension = torrent.Type switch
@ -331,7 +333,7 @@ public class Torrents(
_ => throw new ArgumentException("Unexpected DownloadType") _ => throw new ArgumentException("Unexpected DownloadType")
}; };
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, FileHelper.RemoveInvalidFileNameChars(torrent.RdName)); var copyFileName = Path.Combine(settings.Current.General.CopyAddedTorrents, FileHelper.RemoveInvalidFileNameChars(torrent.RdName));
if (!copyFileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase)) if (!copyFileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
{ {
@ -355,7 +357,7 @@ public class Torrents(
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex, $"Unable to create torrent blackhole directory: {Settings.Get.General.CopyAddedTorrents}: {ex.Message}"); logger.LogError(ex, $"Unable to create torrent blackhole directory: {settings.Current.General.CopyAddedTorrents}: {ex.Message}");
} }
} }
@ -511,7 +513,7 @@ public class Torrents(
{ {
var retry = 10; var retry = 10;
while (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient)) while (runnerState.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
{ {
Log($"Cancelling download", download, torrent); Log($"Cancelling download", download, torrent);
@ -529,7 +531,7 @@ public class Torrents(
retry = 10; retry = 10;
while (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient)) while (runnerState.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient))
{ {
Log($"Cancelling unpack", download, torrent); Log($"Cancelling unpack", download, torrent);
@ -569,7 +571,7 @@ public class Torrents(
if (deleteLocalFiles && !String.IsNullOrWhiteSpace(torrent.RdName)) if (deleteLocalFiles && !String.IsNullOrWhiteSpace(torrent.RdName))
{ {
var downloadPath = DownloadPath(torrent, Settings.Get); var downloadPath = DownloadPath(torrent, settings.Current);
downloadPath = Path.Combine(downloadPath, torrent.RdName); downloadPath = Path.Combine(downloadPath, torrent.RdName);
Log($"Deleting local files in {downloadPath}", torrent); Log($"Deleting local files in {downloadPath}", torrent);
@ -634,13 +636,13 @@ public class Torrents(
var profile = new Profile var profile = new Profile
{ {
Provider = Enum.GetName(Settings.Get.Provider.Provider), Provider = Enum.GetName(settings.Current.Provider.Provider),
UserName = user.Username, UserName = user.Username,
Expiration = user.Expiration, Expiration = user.Expiration,
CurrentVersion = UpdateChecker.CurrentVersion, CurrentVersion = UpdateChecker.CurrentVersion,
LatestVersion = UpdateChecker.LatestVersion, LatestVersion = UpdateChecker.LatestVersion,
IsInsecure = UpdateChecker.IsInsecure, IsInsecure = UpdateChecker.IsInsecure,
DisableUpdateNotification = Settings.Get.General.DisableUpdateNotifications DisableUpdateNotification = settings.Current.General.DisableUpdateNotifications
}; };
return profile; return profile;
@ -663,25 +665,25 @@ public class Torrents(
torrentsByRdId.TryGetValue(rdTorrent.Id, out var torrent); torrentsByRdId.TryGetValue(rdTorrent.Id, out var torrent);
// Auto import torrents only torrents that have their files selected // Auto import torrents only torrents that have their files selected
if (torrent == null && Settings.Get.Provider.AutoImport) if (torrent == null && settings.Current.Provider.AutoImport)
{ {
var newTorrent = new Torrent var newTorrent = new Torrent
{ {
Category = Settings.Get.Provider.Default.Category, Category = settings.Current.Provider.Default.Category,
DownloadClient = Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client,
DownloadAction = DownloadAction =
Settings.Get.Provider.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, settings.Current.Provider.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
HostDownloadAction = Settings.Get.Provider.Default.HostDownloadAction, HostDownloadAction = settings.Current.Provider.Default.HostDownloadAction,
FinishedActionDelay = Settings.Get.Provider.Default.FinishedActionDelay, FinishedActionDelay = settings.Current.Provider.Default.FinishedActionDelay,
FinishedAction = Settings.Get.Provider.Default.FinishedAction, FinishedAction = settings.Current.Provider.Default.FinishedAction,
DownloadMinSize = Settings.Get.Provider.Default.MinFileSize, DownloadMinSize = settings.Current.Provider.Default.MinFileSize,
IncludeRegex = Settings.Get.Provider.Default.IncludeRegex, IncludeRegex = settings.Current.Provider.Default.IncludeRegex,
ExcludeRegex = Settings.Get.Provider.Default.ExcludeRegex, ExcludeRegex = settings.Current.Provider.Default.ExcludeRegex,
TorrentRetryAttempts = Settings.Get.Provider.Default.TorrentRetryAttempts, TorrentRetryAttempts = settings.Current.Provider.Default.TorrentRetryAttempts,
DownloadRetryAttempts = Settings.Get.Provider.Default.DownloadRetryAttempts, DownloadRetryAttempts = settings.Current.Provider.Default.DownloadRetryAttempts,
DeleteOnError = Settings.Get.Provider.Default.DeleteOnError, DeleteOnError = settings.Current.Provider.Default.DeleteOnError,
Lifetime = Settings.Get.Provider.Default.TorrentLifetime, Lifetime = settings.Current.Provider.Default.TorrentLifetime,
Priority = Settings.Get.Provider.Default.Priority > 0 ? Settings.Get.Provider.Default.Priority : null, Priority = settings.Current.Provider.Default.Priority > 0 ? settings.Current.Provider.Default.Priority : null,
RdId = rdTorrent.Id RdId = rdTorrent.Id
}; };
@ -690,7 +692,7 @@ public class Torrents(
continue; continue;
} }
torrent = await torrentData.Add(rdTorrent.Id, rdTorrent.Hash, null, false, DownloadType.Torrent, Settings.Get.DownloadClient.Client, newTorrent); torrent = await torrentData.Add(rdTorrent.Id, rdTorrent.Hash, null, false, DownloadType.Torrent, settings.Current.DownloadClient.Client, newTorrent);
torrentsByRdId[rdTorrent.Id] = torrent; torrentsByRdId[rdTorrent.Id] = torrent;
torrents.Add(torrent); torrents.Add(torrent);
@ -706,7 +708,7 @@ public class Torrents(
{ {
var rdTorrent = torrent.RdId != null && providerTorrentsById.TryGetValue(torrent.RdId, out var providerTorrent) ? providerTorrent : null; var rdTorrent = torrent.RdId != null && providerTorrentsById.TryGetValue(torrent.RdId, out var providerTorrent) ? providerTorrent : null;
if (rdTorrent == null && Settings.Get.Provider.AutoDelete && torrent.RdStatus != TorrentStatus.Queued) if (rdTorrent == null && settings.Current.Provider.AutoDelete && torrent.RdStatus != TorrentStatus.Queued)
{ {
await Delete(torrent.TorrentId, true, false, true); await Delete(torrent.TorrentId, true, false, true);
} }
@ -744,14 +746,14 @@ public class Torrents(
foreach (var download in torrent.Downloads) foreach (var download in torrent.Downloads)
{ {
while (TorrentRunner.ActiveDownloadClients.TryRemove(download.DownloadId, out var downloadClient)) while (runnerState.ActiveDownloadClients.TryRemove(download.DownloadId, out var downloadClient))
{ {
await downloadClient.Cancel(); await downloadClient.Cancel();
await Task.Delay(100); await Task.Delay(100);
} }
while (TorrentRunner.ActiveUnpackClients.TryRemove(download.DownloadId, out var unpackClient)) while (runnerState.ActiveUnpackClients.TryRemove(download.DownloadId, out var unpackClient))
{ {
unpackClient.Cancel(); unpackClient.Cancel();
@ -814,21 +816,21 @@ public class Torrents(
Log($"Retrying Download", download, download.Torrent); Log($"Retrying Download", download, download.Torrent);
while (TorrentRunner.ActiveDownloadClients.TryRemove(download.DownloadId, out var downloadClient)) while (runnerState.ActiveDownloadClients.TryRemove(download.DownloadId, out var downloadClient))
{ {
await downloadClient.Cancel(); await downloadClient.Cancel();
await Task.Delay(100); await Task.Delay(100);
} }
while (TorrentRunner.ActiveUnpackClients.TryRemove(download.DownloadId, out var unpackClient)) while (runnerState.ActiveUnpackClients.TryRemove(download.DownloadId, out var unpackClient))
{ {
unpackClient.Cancel(); unpackClient.Cancel();
await Task.Delay(100); await Task.Delay(100);
} }
var downloadPath = DownloadPath(download.Torrent!, Settings.Get); var downloadPath = DownloadPath(download.Torrent!, settings.Current);
var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent!, download); var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent!, download);
@ -970,11 +972,11 @@ public class Torrents(
await torrentData.Update(torrent); await torrentData.Update(torrent);
} }
public async Task RunTorrentComplete(Guid torrentId, DbSettings? settings = null) public async Task RunTorrentComplete(Guid torrentId, DbSettings? runSettings = null)
{ {
settings ??= Settings.Get; runSettings ??= settings.Current;
if (String.IsNullOrWhiteSpace(settings.General.RunOnTorrentCompleteFileName)) if (String.IsNullOrWhiteSpace(runSettings.General.RunOnTorrentCompleteFileName))
{ {
return; return;
} }
@ -983,12 +985,12 @@ public class Torrents(
var downloadsForTorrent = await downloads.GetForTorrent(torrentId); var downloadsForTorrent = await downloads.GetForTorrent(torrentId);
var fileName = settings.General.RunOnTorrentCompleteFileName; var fileName = runSettings.General.RunOnTorrentCompleteFileName;
var arguments = settings.General.RunOnTorrentCompleteArguments ?? ""; var arguments = runSettings.General.RunOnTorrentCompleteArguments ?? "";
Log($"Parsing external program {fileName} with arguments {arguments}", torrent); Log($"Parsing external program {fileName} with arguments {arguments}", torrent);
var downloadPath = DownloadPath(torrent, settings); var downloadPath = DownloadPath(torrent, runSettings);
var torrentPath = Path.Combine(downloadPath, torrent.RdName ?? "Unknown"); var torrentPath = Path.Combine(downloadPath, torrent.RdName ?? "Unknown");
var filePath = torrentPath; var filePath = torrentPath;

View file

@ -12,15 +12,18 @@ public class QBittorrentControllerTest
{ {
private readonly QBittorrentController _controller; private readonly QBittorrentController _controller;
private readonly Mock<QBittorrent> _qBittorrentMock; private readonly Mock<QBittorrent> _qBittorrentMock;
private readonly TestSettings _settings;
public QBittorrentControllerTest() public QBittorrentControllerTest()
{ {
_qBittorrentMock = new(new Mock<ILogger<QBittorrent>>().Object, null!, null!, null!, null!); _settings = new();
_qBittorrentMock = new(new Mock<ILogger<QBittorrent>>().Object, _settings, null!, null!, null!, new TorrentRunnerState());
_controller = new( _controller = new(
new Mock<ILogger<QBittorrentController>>().Object, new Mock<ILogger<QBittorrentController>>().Object,
_qBittorrentMock.Object, _qBittorrentMock.Object,
new Mock<IHttpClientFactory>().Object); new Mock<IHttpClientFactory>().Object,
_settings);
_controller.ControllerContext = new() _controller.ControllerContext = new()
{ {
@ -88,4 +91,4 @@ public class QBittorrentControllerTest
Assert.Single(payload); Assert.Single(payload);
Assert.Equal("hash1", payload[0].Hash); Assert.Equal("hash1", payload[0].Hash);
} }
} }

View file

@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using Moq;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Sabnzbd; using RdtClient.Data.Models.Sabnzbd;
using RdtClient.Service.Services; using RdtClient.Service.Services;
@ -17,15 +16,17 @@ public class SabnzbdControllerTest
private readonly Mock<Authentication> _authenticationMock; private readonly Mock<Authentication> _authenticationMock;
private readonly SabnzbdController _controller; private readonly SabnzbdController _controller;
private readonly Mock<Sabnzbd> _sabnzbdMock; private readonly Mock<Sabnzbd> _sabnzbdMock;
private readonly TestSettings _settings;
public SabnzbdControllerTest() public SabnzbdControllerTest()
{ {
SettingData.Get.General.AuthenticationType = AuthenticationType.None; _settings = new();
SettingData.Get.Provider.ApiKey = "test-api-key"; _settings.Current.General.AuthenticationType = AuthenticationType.None;
_settings.Current.Provider.ApiKey = "test-api-key";
var torrentsMock = new Mock<Torrents>(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!); var torrentsMock = new Mock<Torrents>(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, _settings, new TorrentRunnerState());
var sabnzbdLoggerMock = new Mock<ILogger<Sabnzbd>>(); var sabnzbdLoggerMock = new Mock<ILogger<Sabnzbd>>();
_sabnzbdMock = new(sabnzbdLoggerMock.Object, torrentsMock.Object, null!); _sabnzbdMock = new(sabnzbdLoggerMock.Object, torrentsMock.Object, null!, _settings);
var loggerMock = new Mock<ILogger<SabnzbdController>>(); var loggerMock = new Mock<ILogger<SabnzbdController>>();
_authenticationMock = new(null!, null!, null!); _authenticationMock = new(null!, null!, null!);
@ -64,7 +65,7 @@ public class SabnzbdControllerTest
public async Task GetQueue_Unauthorized_ReturnsOk_BecauseFilterIsSkippedInUnitTests() public async Task GetQueue_Unauthorized_ReturnsOk_BecauseFilterIsSkippedInUnitTests()
{ {
// Arrange // Arrange
SettingData.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var queue = new SabnzbdQueue var queue = new SabnzbdQueue
{ {
@ -86,7 +87,7 @@ public class SabnzbdControllerTest
public async Task GetQueue_WithMaAuth_ReturnsOk() public async Task GetQueue_WithMaAuth_ReturnsOk()
{ {
// Arrange // Arrange
SettingData.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new("?ma_username=user&ma_password=pass"); httpContext.Request.QueryString = new("?ma_username=user&ma_password=pass");
_controller.ControllerContext.HttpContext = httpContext; _controller.ControllerContext.HttpContext = httpContext;
@ -146,7 +147,7 @@ public class SabnzbdControllerTest
public void GetVersion_ReturnsOk() public void GetVersion_ReturnsOk()
{ {
// Arrange // Arrange
SettingData.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
// Act // Act
var result = _controller.Version(); var result = _controller.Version();

View file

@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Moq; using Moq;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Service.Middleware; using RdtClient.Service.Middleware;
using RdtClient.Service.Services; using RdtClient.Service.Services;
@ -15,20 +14,22 @@ public class SabnzbdHandlerTest
private readonly Mock<Authentication> _authenticationMock; private readonly Mock<Authentication> _authenticationMock;
private readonly SabnzbdHandler _handler; private readonly SabnzbdHandler _handler;
private readonly Mock<IHttpContextAccessor> _httpContextAccessorMock; private readonly Mock<IHttpContextAccessor> _httpContextAccessorMock;
private readonly TestSettings _settings;
public SabnzbdHandlerTest() public SabnzbdHandlerTest()
{ {
_authenticationMock = new(null!, null!, null!); _authenticationMock = new(null!, null!, null!);
_httpContextAccessorMock = new(); _httpContextAccessorMock = new();
_handler = new(_authenticationMock.Object, _httpContextAccessorMock.Object); _settings = new();
SettingData.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _handler = new(_authenticationMock.Object, _httpContextAccessorMock.Object, _settings);
_settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
} }
[Fact] [Fact]
public async Task HandleAsync_AuthNone_Succeeds() public async Task HandleAsync_AuthNone_Succeeds()
{ {
// Arrange // Arrange
SettingData.Get.General.AuthenticationType = AuthenticationType.None; _settings.Current.General.AuthenticationType = AuthenticationType.None;
var context = CreateContext(); var context = CreateContext();
// Act // Act
@ -42,7 +43,7 @@ public class SabnzbdHandlerTest
public async Task HandleAsync_ValidCredentials_Succeeds() public async Task HandleAsync_ValidCredentials_Succeeds()
{ {
// Arrange // Arrange
Settings.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var httpContext = new DefaultHttpContext var httpContext = new DefaultHttpContext
{ {
Request = Request =
@ -67,7 +68,7 @@ public class SabnzbdHandlerTest
public async Task HandleAsync_AlreadyAuthenticated_Succeeds() public async Task HandleAsync_AlreadyAuthenticated_Succeeds()
{ {
// Arrange // Arrange
Settings.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity("TestAuth")); var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity("TestAuth"));
httpContext.User = claimsPrincipal; httpContext.User = claimsPrincipal;
@ -86,7 +87,7 @@ public class SabnzbdHandlerTest
public async Task HandleAsync_InvalidCredentials_DoesNotSucceed() public async Task HandleAsync_InvalidCredentials_DoesNotSucceed()
{ {
// Arrange // Arrange
Settings.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var httpContext = new DefaultHttpContext var httpContext = new DefaultHttpContext
{ {
Request = Request =
@ -111,7 +112,7 @@ public class SabnzbdHandlerTest
public async Task HandleAsync_MissingCredentials_DoesNotSucceed() public async Task HandleAsync_MissingCredentials_DoesNotSucceed()
{ {
// Arrange // Arrange
Settings.Get.General.AuthenticationType = AuthenticationType.UserNamePassword; _settings.Current.General.AuthenticationType = AuthenticationType.UserNamePassword;
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
_httpContextAccessorMock.Setup(a => a.HttpContext).Returns(httpContext); _httpContextAccessorMock.Setup(a => a.HttpContext).Returns(httpContext);

View file

@ -17,7 +17,7 @@ public class TorrentsControllerNzbTest
public TorrentsControllerNzbTest() public TorrentsControllerNzbTest()
{ {
_torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!); _torrentsMock = new(null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, new TestSettings(), new TorrentRunnerState());
_loggerMock = new(); _loggerMock = new();
_coordinatorMock = new(); _coordinatorMock = new();
_controller = new(_loggerMock.Object, _torrentsMock.Object, null!, _coordinatorMock.Object); _controller = new(_loggerMock.Object, _torrentsMock.Object, null!, _coordinatorMock.Object);

View file

@ -1,3 +0,0 @@
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]

View file

@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<AssemblyName>RdtClient.Web.Test</AssemblyName> <AssemblyName>RdtClient.Web.Test</AssemblyName>
<RootNamespace>RdtClient.Web.Test</RootNamespace> <RootNamespace>RdtClient.Web.Test</RootNamespace>
</PropertyGroup> </PropertyGroup>

View file

@ -0,0 +1,58 @@
using RdtClient.Data.Models.Internal;
namespace RdtClient.Service.Services;
internal sealed class TestSettings(DbSettings? settings = null) : ISettings
{
public DbSettings Current { get; } = settings ?? new();
public String DefaultSavePath
{
get
{
var downloadPath = Current.DownloadClient.MappedPath.TrimEnd('\\').TrimEnd('/');
return downloadPath + Path.DirectorySeparatorChar;
}
}
public IList<SettingProperty> GetAll()
{
return [];
}
public Task Update(IList<SettingProperty> settings)
{
return Task.CompletedTask;
}
public Task Update(String settingId, Object? value)
{
SetValue(Current, settingId.Split(':'), 0, value);
return Task.CompletedTask;
}
private static void SetValue(Object target, IReadOnlyList<String> path, Int32 index, Object? value)
{
var property = target.GetType().GetProperty(path[index]) ?? throw new($"Unknown setting {String.Join(":", path)}");
if (index < path.Count - 1)
{
SetValue(property.GetValue(target)!, path, index + 1, value);
return;
}
if (value == null)
{
property.SetValue(target, null);
return;
}
var propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
var convertedValue = propertyType.IsEnum ? Enum.Parse(propertyType, value.ToString()!) : Convert.ChangeType(value, propertyType);
property.SetValue(target, convertedValue);
}
}

View file

@ -6,14 +6,14 @@ using RdtClient.Service.Services;
namespace RdtClient.Web.Controllers; namespace RdtClient.Web.Controllers;
[Route("Api/Authentication")] [Route("Api/Authentication")]
public class AuthController(Authentication authentication, Settings settings) : Controller public class AuthController(Authentication authentication, ISettings settings) : Controller
{ {
[AllowAnonymous] [AllowAnonymous]
[Route("IsLoggedIn")] [Route("IsLoggedIn")]
[HttpGet] [HttpGet]
public async Task<ActionResult> IsLoggedIn() public async Task<ActionResult> IsLoggedIn()
{ {
if (Settings.Get.General.AuthenticationType == AuthenticationType.None) if (settings.Current.General.AuthenticationType == AuthenticationType.None)
{ {
return Ok(); return Ok();
} }
@ -77,7 +77,7 @@ public class AuthController(Authentication authentication, Settings settings) :
return BadRequest(); return BadRequest();
} }
if (!String.IsNullOrEmpty(Settings.Get.Provider.ApiKey)) if (!String.IsNullOrEmpty(settings.Current.Provider.ApiKey))
{ {
return StatusCode(401); return StatusCode(401);
} }

View file

@ -14,7 +14,7 @@ namespace RdtClient.Web.Controllers;
[ApiController] [ApiController]
[Route("api/v2")] [Route("api/v2")]
[Route("qbittorrent/api/v2")] [Route("qbittorrent/api/v2")]
public class QBittorrentController(ILogger<QBittorrentController> logger, QBittorrent qBittorrent, IHttpClientFactory httpClientFactory) : Controller public class QBittorrentController(ILogger<QBittorrentController> logger, QBittorrent qBittorrent, IHttpClientFactory httpClientFactory, ISettings settings) : Controller
{ {
[AllowAnonymous] [AllowAnonymous]
[Route("/version/api")] [Route("/version/api")]
@ -33,7 +33,7 @@ public class QBittorrentController(ILogger<QBittorrentController> logger, QBitto
{ {
logger.LogDebug($"Auth login"); logger.LogDebug($"Auth login");
if (Settings.Get.General.AuthenticationType == AuthenticationType.None) if (settings.Current.General.AuthenticationType == AuthenticationType.None)
{ {
return Content("Ok.", "text/plain"); return Content("Ok.", "text/plain");
} }
@ -146,7 +146,7 @@ public class QBittorrentController(ILogger<QBittorrentController> logger, QBitto
[HttpPost] [HttpPost]
public ActionResult<AppPreferences> AppDefaultSavePath() public ActionResult<AppPreferences> AppDefaultSavePath()
{ {
var result = Settings.AppDefaultSavePath; var result = settings.DefaultSavePath;
return Ok(result); return Ok(result);
} }
@ -613,7 +613,7 @@ public class QBittorrentController(ILogger<QBittorrentController> logger, QBitto
[HttpGet] [HttpGet]
public ActionResult TransferInfo() public ActionResult TransferInfo()
{ {
return Ok(QBittorrent.TransferInfo()); return Ok(qBittorrent.TransferInfo());
} }
[Authorize(Policy = "AuthSetting")] [Authorize(Policy = "AuthSetting")]

View file

@ -15,13 +15,13 @@ namespace RdtClient.Web.Controllers;
[Authorize(Policy = "AuthSetting")] [Authorize(Policy = "AuthSetting")]
[Route("Api/Settings")] [Route("Api/Settings")]
public class SettingsController(Settings settings, Torrents torrents) : Controller public class SettingsController(ISettings settings, Torrents torrents) : Controller
{ {
[HttpGet] [HttpGet]
[Route("")] [Route("")]
public ActionResult Get() public ActionResult Get()
{ {
var result = SettingData.GetAll(); var result = settings.GetAll();
return Ok(result); return Ok(result);
} }
@ -95,7 +95,7 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll
[Route("TestDownloadSpeed")] [Route("TestDownloadSpeed")]
public async Task<ActionResult> TestDownloadSpeed(CancellationToken cancellationToken) public async Task<ActionResult> TestDownloadSpeed(CancellationToken cancellationToken)
{ {
var downloadPath = Settings.Get.DownloadClient.DownloadPath; var downloadPath = settings.Current.DownloadClient.DownloadPath;
var testFilePath = Path.Combine(downloadPath, "testDefault.rar"); var testFilePath = Path.Combine(downloadPath, "testDefault.rar");
@ -106,7 +106,7 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll
Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar", Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar",
Torrent = new() Torrent = new()
{ {
DownloadClient = Settings.Get.DownloadClient.Client == DownloadClient.Symlink ? DownloadClient.Bezzad : Settings.Get.DownloadClient.Client, DownloadClient = settings.Current.DownloadClient.Client == DownloadClient.Symlink ? DownloadClient.Bezzad : settings.Current.DownloadClient.Client,
RdName = "testDefault.rar" RdName = "testDefault.rar"
} }
}; };
@ -131,7 +131,7 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll
if (downloadClient.Downloader is Aria2cDownloader aria2Downloader) if (downloadClient.Downloader is Aria2cDownloader aria2Downloader)
{ {
var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1); var aria2NetClient = new Aria2NetClient(settings.Current.DownloadClient.Aria2cUrl, settings.Current.DownloadClient.Aria2cSecret, httpClient, 1);
var allDownloads = await aria2NetClient.TellAllAsync(cancellationToken); var allDownloads = await aria2NetClient.TellAllAsync(cancellationToken);
@ -155,7 +155,7 @@ public class SettingsController(Settings settings, Torrents torrents) : Controll
[Route("TestWriteSpeed")] [Route("TestWriteSpeed")]
public async Task<ActionResult> TestWriteSpeed() public async Task<ActionResult> TestWriteSpeed()
{ {
var downloadPath = Settings.Get.DownloadClient.DownloadPath; var downloadPath = settings.Current.DownloadClient.DownloadPath;
var testFilePath = Path.Combine(downloadPath, "test.tmp"); var testFilePath = Path.Combine(downloadPath, "test.tmp");