Add nullable to the projects.

This commit is contained in:
Roger Far 2022-05-13 18:51:04 -06:00
parent e65942adb7
commit e3b38d2834
57 changed files with 945 additions and 747 deletions

View file

@ -4,6 +4,8 @@ using RdtClient.Data.Models.Data;
namespace RdtClient.Data.Data; namespace RdtClient.Data.Data;
#nullable disable
public class DataContext : IdentityDbContext public class DataContext : IdentityDbContext
{ {
public DataContext(DbContextOptions options) : base(options) public DataContext(DbContextOptions options) : base(options)

View file

@ -20,7 +20,7 @@ public class DownloadData
.ToListAsync(); .ToListAsync();
} }
public async Task<Download> GetById(Guid downloadId) public async Task<Download?> GetById(Guid downloadId)
{ {
return await _dataContext.Downloads return await _dataContext.Downloads
.Include(m => m.Torrent) .Include(m => m.Torrent)
@ -28,7 +28,7 @@ public class DownloadData
.FirstOrDefaultAsync(m => m.DownloadId == downloadId); .FirstOrDefaultAsync(m => m.DownloadId == downloadId);
} }
public async Task<Download> Get(Guid torrentId, String path) public async Task<Download?> Get(Guid torrentId, String path)
{ {
return await _dataContext.Downloads return await _dataContext.Downloads
.Include(m => m.Torrent) .Include(m => m.Torrent)
@ -176,7 +176,7 @@ public class DownloadData
await TorrentData.VoidCache(); await TorrentData.VoidCache();
} }
public async Task UpdateError(Guid downloadId, String error) public async Task UpdateError(Guid downloadId, String? error)
{ {
var dbDownload = await _dataContext.Downloads var dbDownload = await _dataContext.Downloads
.FirstOrDefaultAsync(m => m.DownloadId == downloadId); .FirstOrDefaultAsync(m => m.DownloadId == downloadId);
@ -243,6 +243,11 @@ public class DownloadData
var dbDownload = await _dataContext.Downloads var dbDownload = await _dataContext.Downloads
.FirstOrDefaultAsync(m => m.DownloadId == downloadId); .FirstOrDefaultAsync(m => m.DownloadId == downloadId);
if (dbDownload == null)
{
throw new Exception($"Cannot find download with ID {downloadId}");
}
dbDownload.RetryCount = 0; dbDownload.RetryCount = 0;
dbDownload.Link = null; dbDownload.Link = null;
dbDownload.Added = DateTimeOffset.UtcNow; dbDownload.Added = DateTimeOffset.UtcNow;

View file

@ -13,16 +13,16 @@ public class SettingData
public static DbSettings Get { get; } = new DbSettings(); public static DbSettings Get { get; } = new DbSettings();
public static IList<SettingProperty> GetAll()
{
return GetSettings(Get, null).ToList();
}
public SettingData(DataContext dataContext) public SettingData(DataContext dataContext)
{ {
_dataContext = dataContext; _dataContext = dataContext;
} }
public IList<SettingProperty> GetAll()
{
return GetSettings(Get, null).ToList();
}
public async Task Update(IList<SettingProperty> settings) public async Task Update(IList<SettingProperty> settings)
{ {
var dbSettings = await _dataContext.Settings.ToListAsync(); var dbSettings = await _dataContext.Settings.ToListAsync();
@ -33,7 +33,7 @@ public class SettingData
if (setting != null) if (setting != null)
{ {
dbSetting.Value = setting.Value.ToString(); dbSetting.Value = setting.Value?.ToString();
} }
} }
@ -42,7 +42,7 @@ public class SettingData
await ResetCache(); await ResetCache();
} }
public async Task Update(String settingId, Object value) public async Task Update(String settingId, Object? value)
{ {
var dbSetting = await _dataContext.Settings.FirstOrDefaultAsync(m => m.SettingId == settingId); var dbSetting = await _dataContext.Settings.FirstOrDefaultAsync(m => m.SettingId == settingId);
@ -51,7 +51,7 @@ public class SettingData
return; return;
} }
dbSetting.Value = value.ToString(); dbSetting.Value = value?.ToString();
await _dataContext.SaveChangesAsync(); await _dataContext.SaveChangesAsync();
@ -97,7 +97,7 @@ public class SettingData
} }
} }
private static IEnumerable<SettingProperty> GetSettings(Object defaultSetting, String parent) private static IEnumerable<SettingProperty> GetSettings(Object defaultSetting, String? parent)
{ {
var result = new List<SettingProperty>(); var result = new List<SettingProperty>();
@ -105,8 +105,8 @@ public class SettingData
foreach (var property in properties) foreach (var property in properties)
{ {
var displayName = (DisplayNameAttribute) Attribute.GetCustomAttribute(property, typeof(DisplayNameAttribute)); var displayName = Attribute.GetCustomAttribute(property, typeof(DisplayNameAttribute)) as DisplayNameAttribute;
var description = (DescriptionAttribute) Attribute.GetCustomAttribute(property, typeof(DescriptionAttribute)); var description = Attribute.GetCustomAttribute(property, typeof(DescriptionAttribute)) as DescriptionAttribute;
var propertyName = property.Name; var propertyName = property.Name;
if (parent != null) if (parent != null)
@ -137,7 +137,7 @@ public class SettingData
{ {
var enumMember = property.PropertyType.GetMember(e.ToString()).First(); var enumMember = property.PropertyType.GetMember(e.ToString()).First();
var enumDescriptionAttribute = enumMember.GetCustomAttribute<DescriptionAttribute>(); var enumDescriptionAttribute = enumMember.GetCustomAttribute<DescriptionAttribute>();
var enumName = enumDescriptionAttribute?.Description ?? Enum.GetName(property.PropertyType, e); var enumName = enumDescriptionAttribute?.Description ?? Enum.GetName(property.PropertyType, e) ?? "Unknown value";
settingProperty.EnumValues.Add((Int32)(Object)e, enumName); settingProperty.EnumValues.Add((Int32)(Object)e, enumName);
} }
} }
@ -149,7 +149,7 @@ public class SettingData
settingProperty.Type = "Object"; settingProperty.Type = "Object";
result.Add(settingProperty); result.Add(settingProperty);
var childResults = GetSettings(property.GetValue(defaultSetting), propertyName); var childResults = GetSettings(property.GetValue(defaultSetting)!, propertyName);
result.AddRange(childResults); result.AddRange(childResults);
} }
} }
@ -157,7 +157,7 @@ public class SettingData
return result; return result;
} }
private static void SetSettings(IList<Setting> settings, Object defaultSetting, String parent) private static void SetSettings(IList<Setting> settings, Object defaultSetting, String? parent)
{ {
var properties = defaultSetting.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); var properties = defaultSetting.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
@ -180,14 +180,18 @@ public class SettingData
{ {
if (property.PropertyType.IsEnum) if (property.PropertyType.IsEnum)
{ {
var newValue = Enum.Parse(property.PropertyType, setting.Value); var newValue = Enum.Parse(property.PropertyType, setting.Value ?? "0");
property.SetValue(defaultSetting, newValue); property.SetValue(defaultSetting, newValue);
} }
else else
{ {
var converter = TypeDescriptor.GetConverter(property.PropertyType); var converter = TypeDescriptor.GetConverter(property.PropertyType);
if (converter.IsValid(setting.Value)) if (setting.Value == null)
{
property.SetValue(defaultSetting, null);
}
else if (converter.IsValid(setting.Value))
{ {
var newValue = converter.ConvertFrom(setting.Value); var newValue = converter.ConvertFrom(setting.Value);
property.SetValue(defaultSetting, newValue); property.SetValue(defaultSetting, newValue);
@ -201,7 +205,7 @@ public class SettingData
} }
else else
{ {
SetSettings(settings, property.GetValue(defaultSetting), propertyName); SetSettings(settings, property.GetValue(defaultSetting)!, propertyName);
} }
} }
} }

View file

@ -5,7 +5,8 @@ namespace RdtClient.Data.Data;
public class TorrentData public class TorrentData
{ {
private static IList<Torrent> _torrentCache; private static IList<Torrent>? _torrentCache;
private static readonly SemaphoreSlim TorrentCacheLock = new(1, 1); private static readonly SemaphoreSlim TorrentCacheLock = new(1, 1);
private readonly DataContext _dataContext; private readonly DataContext _dataContext;
@ -34,7 +35,7 @@ public class TorrentData
} }
} }
public async Task<Torrent> GetById(Guid torrentId) public async Task<Torrent?> GetById(Guid torrentId)
{ {
var dbTorrent = await _dataContext.Torrents var dbTorrent = await _dataContext.Torrents
.AsNoTracking() .AsNoTracking()
@ -54,7 +55,7 @@ public class TorrentData
return dbTorrent; return dbTorrent;
} }
public async Task<Torrent> GetByHash(String hash) public async Task<Torrent?> GetByHash(String hash)
{ {
var dbTorrent = await _dataContext.Torrents var dbTorrent = await _dataContext.Torrents
.AsNoTracking() .AsNoTracking()
@ -76,7 +77,7 @@ public class TorrentData
public async Task<Torrent> Add(String realDebridId, public async Task<Torrent> Add(String realDebridId,
String hash, String hash,
String fileOrMagnetContents, String? fileOrMagnetContents,
Boolean isFile, Boolean isFile,
Torrent torrent) Torrent torrent)
{ {
@ -129,11 +130,7 @@ public class TorrentData
dbTorrent.RdEnded = torrent.RdEnded; dbTorrent.RdEnded = torrent.RdEnded;
dbTorrent.RdSpeed = torrent.RdSpeed; dbTorrent.RdSpeed = torrent.RdSpeed;
dbTorrent.RdSeeders = torrent.RdSeeders; dbTorrent.RdSeeders = torrent.RdSeeders;
dbTorrent.RdFiles = torrent.RdFiles;
if (torrent.Files != null)
{
dbTorrent.RdFiles = torrent.RdFiles;
}
await _dataContext.SaveChangesAsync(); await _dataContext.SaveChangesAsync();
@ -160,7 +157,7 @@ public class TorrentData
await VoidCache(); await VoidCache();
} }
public async Task UpdateCategory(Guid torrentId, String category) public async Task UpdateCategory(Guid torrentId, String? category)
{ {
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId); var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);
@ -176,7 +173,7 @@ public class TorrentData
await VoidCache(); await VoidCache();
} }
public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset? datetime, Boolean retry) public async Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset? datetime, Boolean retry)
{ {
var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId); var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrentId);

View file

@ -12,7 +12,7 @@ public class UserData
_dataContext = dataContext; _dataContext = dataContext;
} }
public async Task<IdentityUser> GetUser() public async Task<IdentityUser?> GetUser()
{ {
return await _dataContext.Users.FirstOrDefaultAsync(); return await _dataContext.Users.FirstOrDefaultAsync();
} }

View file

@ -9,6 +9,11 @@ public static class DiConfig
{ {
public static void Config(IServiceCollection services, AppSettings appSettings) public static void Config(IServiceCollection services, AppSettings appSettings)
{ {
if (String.IsNullOrWhiteSpace(appSettings.Database?.Path))
{
throw new Exception("Invalid database path found in appSettings");
}
var connectionString = $"Data Source={appSettings.Database.Path}"; var connectionString = $"Data Source={appSettings.Database.Path}";
services.AddDbContext<DataContext>(options => options.UseSqlite(connectionString)); services.AddDbContext<DataContext>(options => options.UseSqlite(connectionString));

View file

@ -1,8 +1,15 @@
namespace RdtClient.Data.Enums; using System.ComponentModel;
namespace RdtClient.Data.Enums;
public enum DownloadClient public enum DownloadClient
{ {
[Description("Simple Downloader")]
Simple, Simple,
[Description("Multi-Part Downloader")]
MultiPart, MultiPart,
[Description("Aria2c")]
Aria2c Aria2c
} }

View file

@ -11,10 +11,10 @@ public class Download
public Guid TorrentId { get; set; } public Guid TorrentId { get; set; }
[ForeignKey("TorrentId")] [ForeignKey("TorrentId")]
public Torrent Torrent { get; set; } public Torrent? Torrent { get; set; }
public String Path { get; set; } public String Path { get; set; } = null!;
public String Link { get; set; } public String? Link { get; set; }
public DateTimeOffset Added { get; set; } public DateTimeOffset Added { get; set; }
public DateTimeOffset? DownloadQueued { get; set; } public DateTimeOffset? DownloadQueued { get; set; }
@ -27,9 +27,9 @@ public class Download
public Int32 RetryCount { get; set; } public Int32 RetryCount { get; set; }
public String Error { get; set; } public String? Error { get; set; }
public String RemoteId { get; set; } public String? RemoteId { get; set; }
[NotMapped] [NotMapped]
public Int64 BytesTotal { get; set; } public Int64 BytesTotal { get; set; }

View file

@ -5,7 +5,7 @@ namespace RdtClient.Data.Models.Data;
public class Setting public class Setting
{ {
[Key] [Key]
public String SettingId { get; set; } public String SettingId { get; set; } = null!;
public String Value { get; set; } public String? Value { get; set; }
} }

View file

@ -11,21 +11,21 @@ public class Torrent
[Key] [Key]
public Guid TorrentId { get; set; } public Guid TorrentId { get; set; }
public String Hash { get; set; } public String Hash { get; set; } = null!;
public String Category { get; set; } public String? Category { get; set; }
public TorrentDownloadAction DownloadAction { get; set; } public TorrentDownloadAction DownloadAction { get; set; }
public TorrentFinishedAction FinishedAction { get; set; } public TorrentFinishedAction FinishedAction { get; set; }
public Int32 DownloadMinSize { get; set; } public Int32 DownloadMinSize { get; set; }
public String DownloadManualFiles { get; set; } public String? DownloadManualFiles { get; set; }
public DateTimeOffset Added { get; set; } public DateTimeOffset Added { get; set; }
public DateTimeOffset? FilesSelected { get; set; } public DateTimeOffset? FilesSelected { get; set; }
public DateTimeOffset? Completed { get; set; } public DateTimeOffset? Completed { get; set; }
public DateTimeOffset? Retry { get; set; } public DateTimeOffset? Retry { get; set; }
public String FileOrMagnet { get; set; } public String? FileOrMagnet { get; set; }
public Boolean IsFile { get; set; } public Boolean IsFile { get; set; }
public Int32? Priority { get; set; } public Int32? Priority { get; set; }
@ -35,24 +35,24 @@ public class Torrent
public Int32 DeleteOnError { get; set; } public Int32 DeleteOnError { get; set; }
public Int32 Lifetime { get; set; } public Int32 Lifetime { get; set; }
public String Error { get; set; } public String? Error { get; set; }
[InverseProperty("Torrent")] [InverseProperty("Torrent")]
public IList<Download> Downloads { get; set; } public IList<Download> Downloads { get; set; } = new List<Download>();
public String RdId { get; set; } public String? RdId { get; set; }
public String RdName { get; set; } public String? RdName { get; set; }
public Int64 RdSize { get; set; } public Int64? RdSize { get; set; }
public String RdHost { get; set; } public String? RdHost { get; set; }
public Int64 RdSplit { get; set; } public Int64? RdSplit { get; set; }
public Int64 RdProgress { get; set; } public Int64? RdProgress { get; set; }
public TorrentStatus RdStatus { get; set; } public TorrentStatus? RdStatus { get; set; }
public String RdStatusRaw { get; set; } public String? RdStatusRaw { get; set; }
public DateTimeOffset RdAdded { get; set; } public DateTimeOffset? RdAdded { get; set; }
public DateTimeOffset? RdEnded { get; set; } public DateTimeOffset? RdEnded { get; set; }
public Int64? RdSpeed { get; set; } public Int64? RdSpeed { get; set; }
public Int64? RdSeeders { get; set; } public Int64? RdSeeders { get; set; }
public String RdFiles { get; set; } public String? RdFiles { get; set; }
[NotMapped] [NotMapped]
public IList<TorrentClientFile> Files public IList<TorrentClientFile> Files
@ -66,7 +66,7 @@ public class Torrent
try try
{ {
return JsonSerializer.Deserialize<List<TorrentClientFile>>(RdFiles); return JsonSerializer.Deserialize<List<TorrentClientFile>>(RdFiles) ?? new List<TorrentClientFile>();
} }
catch catch
{ {

View file

@ -2,25 +2,25 @@
public class AppSettings public class AppSettings
{ {
public AppSettingsLogging Logging { get; set; } public AppSettingsLogging? Logging { get; set; }
public AppSettingsDatabase Database { get; set; } public AppSettingsDatabase? Database { get; set; }
public Int32 Port { get; set; } public Int32 Port { get; set; }
} }
public class AppSettingsLogging public class AppSettingsLogging
{ {
public AppSettingsLoggingFile File { get; set; } public AppSettingsLoggingFile? File { get; set; }
} }
public class AppSettingsLoggingFile public class AppSettingsLoggingFile
{ {
public String Path { get; set; } public String? Path { get; set; }
public Int64 FileSizeLimitBytes { get; set; } public Int64 FileSizeLimitBytes { get; set; }
public Int32 MaxRollingFiles { get; set; } public Int32 MaxRollingFiles { get; set; }
} }
public class AppSettingsDatabase public class AppSettingsDatabase
{ {
public String Path { get; set; } public String? Path { get; set; }
} }

View file

@ -2,9 +2,9 @@
public class Profile public class Profile
{ {
public String Provider { get; set; } public String? Provider { get; set; }
public String UserName { get; set; } public String? UserName { get; set; }
public DateTimeOffset? Expiration { get; set; } public DateTimeOffset? Expiration { get; set; }
public String CurrentVersion { get; set; } public String? CurrentVersion { get; set; }
public String LatestVersion { get; set; } public String? LatestVersion { get; set; }
} }

View file

@ -2,10 +2,10 @@
public class SettingProperty public class SettingProperty
{ {
public String Key { get; set; } public String Key { get; set; } = default!;
public Object Value { get; set; } public Object? Value { get; set; }
public String DisplayName { get; set; } public String? DisplayName { get; set; }
public String Description { get; set; } public String? Description { get; set; }
public String Type { get; set; } public String Type { get; set; } = default!;
public Dictionary<Int32, String> EnumValues { get; set; } public Dictionary<Int32, String>? EnumValues { get; set; }
} }

View file

@ -5,20 +5,20 @@ namespace RdtClient.Data.Models.QBittorrent;
public class AppBuildInfo public class AppBuildInfo
{ {
[JsonPropertyName("bitness")] [JsonPropertyName("bitness")]
public Int64 Bitness { get; set; } public Int64? Bitness { get; set; }
[JsonPropertyName("boost")] [JsonPropertyName("boost")]
public String Boost { get; set; } public String? Boost { get; set; }
[JsonPropertyName("libtorrent")] [JsonPropertyName("libtorrent")]
public String Libtorrent { get; set; } public String? Libtorrent { get; set; }
[JsonPropertyName("openssl")] [JsonPropertyName("openssl")]
public String Openssl { get; set; } public String? Openssl { get; set; }
[JsonPropertyName("qt")] [JsonPropertyName("qt")]
public String Qt { get; set; } public String? Qt { get; set; }
[JsonPropertyName("zlib")] [JsonPropertyName("zlib")]
public String Zlib { get; set; } public String? Zlib { get; set; }
} }

View file

@ -5,424 +5,424 @@ namespace RdtClient.Data.Models.QBittorrent;
public class AppPreferences public class AppPreferences
{ {
[JsonPropertyName("add_trackers")] [JsonPropertyName("add_trackers")]
public String AddTrackers { get; set; } public String? AddTrackers { get; set; }
[JsonPropertyName("add_trackers_enabled")] [JsonPropertyName("add_trackers_enabled")]
public Boolean AddTrackersEnabled { get; set; } public Boolean? AddTrackersEnabled { get; set; }
[JsonPropertyName("alt_dl_limit")] [JsonPropertyName("alt_dl_limit")]
public Int64 AltDlLimit { get; set; } public Int64? AltDlLimit { get; set; }
[JsonPropertyName("alt_up_limit")] [JsonPropertyName("alt_up_limit")]
public Int64 AltUpLimit { get; set; } public Int64? AltUpLimit { get; set; }
[JsonPropertyName("alternative_webui_enabled")] [JsonPropertyName("alternative_webui_enabled")]
public Boolean AlternativeWebuiEnabled { get; set; } public Boolean? AlternativeWebuiEnabled { get; set; }
[JsonPropertyName("alternative_webui_path")] [JsonPropertyName("alternative_webui_path")]
public String AlternativeWebuiPath { get; set; } public String? AlternativeWebuiPath { get; set; }
[JsonPropertyName("announce_ip")] [JsonPropertyName("announce_ip")]
public String AnnounceIp { get; set; } public String? AnnounceIp { get; set; }
[JsonPropertyName("announce_to_all_tiers")] [JsonPropertyName("announce_to_all_tiers")]
public Boolean AnnounceToAllTiers { get; set; } public Boolean? AnnounceToAllTiers { get; set; }
[JsonPropertyName("announce_to_all_trackers")] [JsonPropertyName("announce_to_all_trackers")]
public Boolean AnnounceToAllTrackers { get; set; } public Boolean? AnnounceToAllTrackers { get; set; }
[JsonPropertyName("anonymous_mode")] [JsonPropertyName("anonymous_mode")]
public Boolean AnonymousMode { get; set; } public Boolean? AnonymousMode { get; set; }
[JsonPropertyName("async_io_threads")] [JsonPropertyName("async_io_threads")]
public Int64 AsyncIoThreads { get; set; } public Int64? AsyncIoThreads { get; set; }
[JsonPropertyName("auto_delete_mode")] [JsonPropertyName("auto_delete_mode")]
public Int64 AutoDeleteMode { get; set; } public Int64? AutoDeleteMode { get; set; }
[JsonPropertyName("auto_tmm_enabled")] [JsonPropertyName("auto_tmm_enabled")]
public Boolean AutoTmmEnabled { get; set; } public Boolean? AutoTmmEnabled { get; set; }
[JsonPropertyName("autorun_enabled")] [JsonPropertyName("autorun_enabled")]
public Boolean AutorunEnabled { get; set; } public Boolean? AutorunEnabled { get; set; }
[JsonPropertyName("autorun_program")] [JsonPropertyName("autorun_program")]
public String AutorunProgram { get; set; } public String? AutorunProgram { get; set; }
[JsonPropertyName("banned_IPs")] [JsonPropertyName("banned_IPs")]
public String BannedIPs { get; set; } public String? BannedIPs { get; set; }
[JsonPropertyName("bittorrent_protocol")] [JsonPropertyName("bittorrent_protocol")]
public Int64 BittorrentProtocol { get; set; } public Int64? BittorrentProtocol { get; set; }
[JsonPropertyName("bypass_auth_subnet_whitelist")] [JsonPropertyName("bypass_auth_subnet_whitelist")]
public String BypassAuthSubnetWhitelist { get; set; } public String? BypassAuthSubnetWhitelist { get; set; }
[JsonPropertyName("bypass_auth_subnet_whitelist_enabled")] [JsonPropertyName("bypass_auth_subnet_whitelist_enabled")]
public Boolean BypassAuthSubnetWhitelistEnabled { get; set; } public Boolean? BypassAuthSubnetWhitelistEnabled { get; set; }
[JsonPropertyName("bypass_local_auth")] [JsonPropertyName("bypass_local_auth")]
public Boolean BypassLocalAuth { get; set; } public Boolean? BypassLocalAuth { get; set; }
[JsonPropertyName("category_changed_tmm_enabled")] [JsonPropertyName("category_changed_tmm_enabled")]
public Boolean CategoryChangedTmmEnabled { get; set; } public Boolean? CategoryChangedTmmEnabled { get; set; }
[JsonPropertyName("checking_memory_use")] [JsonPropertyName("checking_memory_use")]
public Int64 CheckingMemoryUse { get; set; } public Int64? CheckingMemoryUse { get; set; }
[JsonPropertyName("create_subfolder_enabled")] [JsonPropertyName("create_subfolder_enabled")]
public Boolean CreateSubfolderEnabled { get; set; } public Boolean? CreateSubfolderEnabled { get; set; }
[JsonPropertyName("current_interface_address")] [JsonPropertyName("current_interface_address")]
public String CurrentInterfaceAddress { get; set; } public String? CurrentInterfaceAddress { get; set; }
[JsonPropertyName("current_network_interface")] [JsonPropertyName("current_network_interface")]
public String CurrentNetworkInterface { get; set; } public String? CurrentNetworkInterface { get; set; }
[JsonPropertyName("dht")] [JsonPropertyName("dht")]
public Boolean Dht { get; set; } public Boolean? Dht { get; set; }
[JsonPropertyName("disk_cache")] [JsonPropertyName("disk_cache")]
public Int64 DiskCache { get; set; } public Int64? DiskCache { get; set; }
[JsonPropertyName("disk_cache_ttl")] [JsonPropertyName("disk_cache_ttl")]
public Int64 DiskCacheTtl { get; set; } public Int64? DiskCacheTtl { get; set; }
[JsonPropertyName("dl_limit")] [JsonPropertyName("dl_limit")]
public Int64 DlLimit { get; set; } public Int64? DlLimit { get; set; }
[JsonPropertyName("dont_count_slow_torrents")] [JsonPropertyName("dont_count_slow_torrents")]
public Boolean DontCountSlowTorrents { get; set; } public Boolean? DontCountSlowTorrents { get; set; }
[JsonPropertyName("dyndns_domain")] [JsonPropertyName("dyndns_domain")]
public String DyndnsDomain { get; set; } public String? DyndnsDomain { get; set; }
[JsonPropertyName("dyndns_enabled")] [JsonPropertyName("dyndns_enabled")]
public Boolean DyndnsEnabled { get; set; } public Boolean? DyndnsEnabled { get; set; }
[JsonPropertyName("dyndns_password")] [JsonPropertyName("dyndns_password")]
public String DyndnsPassword { get; set; } public String? DyndnsPassword { get; set; }
[JsonPropertyName("dyndns_service")] [JsonPropertyName("dyndns_service")]
public Int64 DyndnsService { get; set; } public Int64? DyndnsService { get; set; }
[JsonPropertyName("dyndns_username")] [JsonPropertyName("dyndns_username")]
public String DyndnsUsername { get; set; } public String? DyndnsUsername { get; set; }
[JsonPropertyName("embedded_tracker_port")] [JsonPropertyName("embedded_tracker_port")]
public Int64 EmbeddedTrackerPort { get; set; } public Int64? EmbeddedTrackerPort { get; set; }
[JsonPropertyName("enable_coalesce_read_write")] [JsonPropertyName("enable_coalesce_read_write")]
public Boolean EnableCoalesceReadWrite { get; set; } public Boolean? EnableCoalesceReadWrite { get; set; }
[JsonPropertyName("enable_embedded_tracker")] [JsonPropertyName("enable_embedded_tracker")]
public Boolean EnableEmbeddedTracker { get; set; } public Boolean? EnableEmbeddedTracker { get; set; }
[JsonPropertyName("enable_multi_connections_from_same_ip")] [JsonPropertyName("enable_multi_connections_from_same_ip")]
public Boolean EnableMultiConnectionsFromSameIp { get; set; } public Boolean? EnableMultiConnectionsFromSameIp { get; set; }
[JsonPropertyName("enable_os_cache")] [JsonPropertyName("enable_os_cache")]
public Boolean EnableOsCache { get; set; } public Boolean? EnableOsCache { get; set; }
[JsonPropertyName("enable_piece_extent_affinity")] [JsonPropertyName("enable_piece_extent_affinity")]
public Boolean EnablePieceExtentAffinity { get; set; } public Boolean? EnablePieceExtentAffinity { get; set; }
[JsonPropertyName("enable_super_seeding")] [JsonPropertyName("enable_super_seeding")]
public Boolean EnableSuperSeeding { get; set; } public Boolean? EnableSuperSeeding { get; set; }
[JsonPropertyName("enable_upload_suggestions")] [JsonPropertyName("enable_upload_suggestions")]
public Boolean EnableUploadSuggestions { get; set; } public Boolean? EnableUploadSuggestions { get; set; }
[JsonPropertyName("encryption")] [JsonPropertyName("encryption")]
public Int64 Encryption { get; set; } public Int64? Encryption { get; set; }
[JsonPropertyName("export_dir")] [JsonPropertyName("export_dir")]
public String ExportDir { get; set; } public String? ExportDir { get; set; }
[JsonPropertyName("export_dir_fin")] [JsonPropertyName("export_dir_fin")]
public String ExportDirFin { get; set; } public String? ExportDirFin { get; set; }
[JsonPropertyName("file_pool_size")] [JsonPropertyName("file_pool_size")]
public Int64 FilePoolSize { get; set; } public Int64? FilePoolSize { get; set; }
[JsonPropertyName("incomplete_files_ext")] [JsonPropertyName("incomplete_files_ext")]
public Boolean IncompleteFilesExt { get; set; } public Boolean? IncompleteFilesExt { get; set; }
[JsonPropertyName("ip_filter_enabled")] [JsonPropertyName("ip_filter_enabled")]
public Boolean IpFilterEnabled { get; set; } public Boolean? IpFilterEnabled { get; set; }
[JsonPropertyName("ip_filter_path")] [JsonPropertyName("ip_filter_path")]
public String IpFilterPath { get; set; } public String? IpFilterPath { get; set; }
[JsonPropertyName("ip_filter_trackers")] [JsonPropertyName("ip_filter_trackers")]
public Boolean IpFilterTrackers { get; set; } public Boolean? IpFilterTrackers { get; set; }
[JsonPropertyName("limit_lan_peers")] [JsonPropertyName("limit_lan_peers")]
public Boolean LimitLanPeers { get; set; } public Boolean? LimitLanPeers { get; set; }
[JsonPropertyName("limit_tcp_overhead")] [JsonPropertyName("limit_tcp_overhead")]
public Boolean LimitTcpOverhead { get; set; } public Boolean? LimitTcpOverhead { get; set; }
[JsonPropertyName("limit_utp_rate")] [JsonPropertyName("limit_utp_rate")]
public Boolean LimitUtpRate { get; set; } public Boolean? LimitUtpRate { get; set; }
[JsonPropertyName("listen_port")] [JsonPropertyName("listen_port")]
public Int64 ListenPort { get; set; } public Int64? ListenPort { get; set; }
[JsonPropertyName("locale")] [JsonPropertyName("locale")]
public String Locale { get; set; } public String? Locale { get; set; }
[JsonPropertyName("lsd")] [JsonPropertyName("lsd")]
public Boolean Lsd { get; set; } public Boolean? Lsd { get; set; }
[JsonPropertyName("mail_notification_auth_enabled")] [JsonPropertyName("mail_notification_auth_enabled")]
public Boolean MailNotificationAuthEnabled { get; set; } public Boolean? MailNotificationAuthEnabled { get; set; }
[JsonPropertyName("mail_notification_email")] [JsonPropertyName("mail_notification_email")]
public String MailNotificationEmail { get; set; } public String? MailNotificationEmail { get; set; }
[JsonPropertyName("mail_notification_enabled")] [JsonPropertyName("mail_notification_enabled")]
public Boolean MailNotificationEnabled { get; set; } public Boolean? MailNotificationEnabled { get; set; }
[JsonPropertyName("mail_notification_password")] [JsonPropertyName("mail_notification_password")]
public String MailNotificationPassword { get; set; } public String? MailNotificationPassword { get; set; }
[JsonPropertyName("mail_notification_sender")] [JsonPropertyName("mail_notification_sender")]
public String MailNotificationSender { get; set; } public String? MailNotificationSender { get; set; }
[JsonPropertyName("mail_notification_smtp")] [JsonPropertyName("mail_notification_smtp")]
public String MailNotificationSmtp { get; set; } public String? MailNotificationSmtp { get; set; }
[JsonPropertyName("mail_notification_ssl_enabled")] [JsonPropertyName("mail_notification_ssl_enabled")]
public Boolean MailNotificationSslEnabled { get; set; } public Boolean? MailNotificationSslEnabled { get; set; }
[JsonPropertyName("mail_notification_username")] [JsonPropertyName("mail_notification_username")]
public String MailNotificationUsername { get; set; } public String? MailNotificationUsername { get; set; }
[JsonPropertyName("max_active_downloads")] [JsonPropertyName("max_active_downloads")]
public Int64 MaxActiveDownloads { get; set; } public Int64? MaxActiveDownloads { get; set; }
[JsonPropertyName("max_active_torrents")] [JsonPropertyName("max_active_torrents")]
public Int64 MaxActiveTorrents { get; set; } public Int64? MaxActiveTorrents { get; set; }
[JsonPropertyName("max_active_uploads")] [JsonPropertyName("max_active_uploads")]
public Int64 MaxActiveUploads { get; set; } public Int64? MaxActiveUploads { get; set; }
[JsonPropertyName("max_connec")] [JsonPropertyName("max_connec")]
public Int64 MaxConnec { get; set; } public Int64? MaxConnec { get; set; }
[JsonPropertyName("max_connec_per_torrent")] [JsonPropertyName("max_connec_per_torrent")]
public Int64 MaxConnecPerTorrent { get; set; } public Int64? MaxConnecPerTorrent { get; set; }
[JsonPropertyName("max_ratio")] [JsonPropertyName("max_ratio")]
public Int64 MaxRatio { get; set; } public Int64? MaxRatio { get; set; }
[JsonPropertyName("max_ratio_act")] [JsonPropertyName("max_ratio_act")]
public Int64 MaxRatioAct { get; set; } public Int64? MaxRatioAct { get; set; }
[JsonPropertyName("max_ratio_enabled")] [JsonPropertyName("max_ratio_enabled")]
public Boolean MaxRatioEnabled { get; set; } public Boolean? MaxRatioEnabled { get; set; }
[JsonPropertyName("max_seeding_time")] [JsonPropertyName("max_seeding_time")]
public Int64 MaxSeedingTime { get; set; } public Int64? MaxSeedingTime { get; set; }
[JsonPropertyName("max_seeding_time_enabled")] [JsonPropertyName("max_seeding_time_enabled")]
public Boolean MaxSeedingTimeEnabled { get; set; } public Boolean? MaxSeedingTimeEnabled { get; set; }
[JsonPropertyName("max_uploads")] [JsonPropertyName("max_uploads")]
public Int64 MaxUploads { get; set; } public Int64? MaxUploads { get; set; }
[JsonPropertyName("max_uploads_per_torrent")] [JsonPropertyName("max_uploads_per_torrent")]
public Int64 MaxUploadsPerTorrent { get; set; } public Int64? MaxUploadsPerTorrent { get; set; }
[JsonPropertyName("outgoing_ports_max")] [JsonPropertyName("outgoing_ports_max")]
public Int64 OutgoingPortsMax { get; set; } public Int64? OutgoingPortsMax { get; set; }
[JsonPropertyName("outgoing_ports_min")] [JsonPropertyName("outgoing_ports_min")]
public Int64 OutgoingPortsMin { get; set; } public Int64? OutgoingPortsMin { get; set; }
[JsonPropertyName("pex")] [JsonPropertyName("pex")]
public Boolean Pex { get; set; } public Boolean? Pex { get; set; }
[JsonPropertyName("preallocate_all")] [JsonPropertyName("preallocate_all")]
public Boolean PreallocateAll { get; set; } public Boolean? PreallocateAll { get; set; }
[JsonPropertyName("proxy_auth_enabled")] [JsonPropertyName("proxy_auth_enabled")]
public Boolean ProxyAuthEnabled { get; set; } public Boolean? ProxyAuthEnabled { get; set; }
[JsonPropertyName("proxy_ip")] [JsonPropertyName("proxy_ip")]
public String ProxyIp { get; set; } public String? ProxyIp { get; set; }
[JsonPropertyName("proxy_password")] [JsonPropertyName("proxy_password")]
public String ProxyPassword { get; set; } public String? ProxyPassword { get; set; }
[JsonPropertyName("proxy_peer_connections")] [JsonPropertyName("proxy_peer_connections")]
public Boolean ProxyPeerConnections { get; set; } public Boolean? ProxyPeerConnections { get; set; }
[JsonPropertyName("proxy_port")] [JsonPropertyName("proxy_port")]
public Int64 ProxyPort { get; set; } public Int64? ProxyPort { get; set; }
[JsonPropertyName("proxy_torrents_only")] [JsonPropertyName("proxy_torrents_only")]
public Boolean ProxyTorrentsOnly { get; set; } public Boolean? ProxyTorrentsOnly { get; set; }
[JsonPropertyName("proxy_type")] [JsonPropertyName("proxy_type")]
public Int64 ProxyType { get; set; } public Int64? ProxyType { get; set; }
[JsonPropertyName("proxy_username")] [JsonPropertyName("proxy_username")]
public String ProxyUsername { get; set; } public String? ProxyUsername { get; set; }
[JsonPropertyName("queueing_enabled")] [JsonPropertyName("queueing_enabled")]
public Boolean QueueingEnabled { get; set; } public Boolean? QueueingEnabled { get; set; }
[JsonPropertyName("random_port")] [JsonPropertyName("random_port")]
public Boolean RandomPort { get; set; } public Boolean? RandomPort { get; set; }
[JsonPropertyName("recheck_completed_torrents")] [JsonPropertyName("recheck_completed_torrents")]
public Boolean RecheckCompletedTorrents { get; set; } public Boolean? RecheckCompletedTorrents { get; set; }
[JsonPropertyName("resolve_peer_countries")] [JsonPropertyName("resolve_peer_countries")]
public Boolean ResolvePeerCountries { get; set; } public Boolean? ResolvePeerCountries { get; set; }
[JsonPropertyName("rss_auto_downloading_enabled")] [JsonPropertyName("rss_auto_downloading_enabled")]
public Boolean RssAutoDownloadingEnabled { get; set; } public Boolean? RssAutoDownloadingEnabled { get; set; }
[JsonPropertyName("rss_max_articles_per_feed")] [JsonPropertyName("rss_max_articles_per_feed")]
public Int64 RssMaxArticlesPerFeed { get; set; } public Int64? RssMaxArticlesPerFeed { get; set; }
[JsonPropertyName("rss_processing_enabled")] [JsonPropertyName("rss_processing_enabled")]
public Boolean RssProcessingEnabled { get; set; } public Boolean? RssProcessingEnabled { get; set; }
[JsonPropertyName("rss_refresh_interval")] [JsonPropertyName("rss_refresh_interval")]
public Int64 RssRefreshInterval { get; set; } public Int64? RssRefreshInterval { get; set; }
[JsonPropertyName("save_path")] [JsonPropertyName("save_path")]
public String SavePath { get; set; } public String? SavePath { get; set; }
[JsonPropertyName("save_path_changed_tmm_enabled")] [JsonPropertyName("save_path_changed_tmm_enabled")]
public Boolean SavePathChangedTmmEnabled { get; set; } public Boolean? SavePathChangedTmmEnabled { get; set; }
[JsonPropertyName("save_resume_data_interval")] [JsonPropertyName("save_resume_data_interval")]
public Int64 SaveResumeDataInterval { get; set; } public Int64? SaveResumeDataInterval { get; set; }
[JsonPropertyName("scan_dirs")] [JsonPropertyName("scan_dirs")]
public ScanDirs ScanDirs { get; set; } public ScanDirs? ScanDirs { get; set; }
[JsonPropertyName("schedule_from_hour")] [JsonPropertyName("schedule_from_hour")]
public Int64 ScheduleFromHour { get; set; } public Int64? ScheduleFromHour { get; set; }
[JsonPropertyName("schedule_from_min")] [JsonPropertyName("schedule_from_min")]
public Int64 ScheduleFromMin { get; set; } public Int64? ScheduleFromMin { get; set; }
[JsonPropertyName("schedule_to_hour")] [JsonPropertyName("schedule_to_hour")]
public Int64 ScheduleToHour { get; set; } public Int64? ScheduleToHour { get; set; }
[JsonPropertyName("schedule_to_min")] [JsonPropertyName("schedule_to_min")]
public Int64 ScheduleToMin { get; set; } public Int64? ScheduleToMin { get; set; }
[JsonPropertyName("scheduler_days")] [JsonPropertyName("scheduler_days")]
public Int64 SchedulerDays { get; set; } public Int64? SchedulerDays { get; set; }
[JsonPropertyName("scheduler_enabled")] [JsonPropertyName("scheduler_enabled")]
public Boolean SchedulerEnabled { get; set; } public Boolean? SchedulerEnabled { get; set; }
[JsonPropertyName("send_buffer_low_watermark")] [JsonPropertyName("send_buffer_low_watermark")]
public Int64 SendBufferLowWatermark { get; set; } public Int64? SendBufferLowWatermark { get; set; }
[JsonPropertyName("send_buffer_watermark")] [JsonPropertyName("send_buffer_watermark")]
public Int64 SendBufferWatermark { get; set; } public Int64? SendBufferWatermark { get; set; }
[JsonPropertyName("send_buffer_watermark_factor")] [JsonPropertyName("send_buffer_watermark_factor")]
public Int64 SendBufferWatermarkFactor { get; set; } public Int64? SendBufferWatermarkFactor { get; set; }
[JsonPropertyName("slow_torrent_dl_rate_threshold")] [JsonPropertyName("slow_torrent_dl_rate_threshold")]
public Int64 SlowTorrentDlRateThreshold { get; set; } public Int64? SlowTorrentDlRateThreshold { get; set; }
[JsonPropertyName("slow_torrent_inactive_timer")] [JsonPropertyName("slow_torrent_inactive_timer")]
public Int64 SlowTorrentInactiveTimer { get; set; } public Int64? SlowTorrentInactiveTimer { get; set; }
[JsonPropertyName("slow_torrent_ul_rate_threshold")] [JsonPropertyName("slow_torrent_ul_rate_threshold")]
public Int64 SlowTorrentUlRateThreshold { get; set; } public Int64? SlowTorrentUlRateThreshold { get; set; }
[JsonPropertyName("socket_backlog_size")] [JsonPropertyName("socket_backlog_size")]
public Int64 SocketBacklogSize { get; set; } public Int64? SocketBacklogSize { get; set; }
[JsonPropertyName("start_paused_enabled")] [JsonPropertyName("start_paused_enabled")]
public Boolean StartPausedEnabled { get; set; } public Boolean? StartPausedEnabled { get; set; }
[JsonPropertyName("stop_tracker_timeout")] [JsonPropertyName("stop_tracker_timeout")]
public Int64 StopTrackerTimeout { get; set; } public Int64? StopTrackerTimeout { get; set; }
[JsonPropertyName("temp_path")] [JsonPropertyName("temp_path")]
public String TempPath { get; set; } public String? TempPath { get; set; }
[JsonPropertyName("temp_path_enabled")] [JsonPropertyName("temp_path_enabled")]
public Boolean TempPathEnabled { get; set; } public Boolean? TempPathEnabled { get; set; }
[JsonPropertyName("torrent_changed_tmm_enabled")] [JsonPropertyName("torrent_changed_tmm_enabled")]
public Boolean TorrentChangedTmmEnabled { get; set; } public Boolean? TorrentChangedTmmEnabled { get; set; }
[JsonPropertyName("up_limit")] [JsonPropertyName("up_limit")]
public Int64 UpLimit { get; set; } public Int64? UpLimit { get; set; }
[JsonPropertyName("upload_choking_algorithm")] [JsonPropertyName("upload_choking_algorithm")]
public Int64 UploadChokingAlgorithm { get; set; } public Int64? UploadChokingAlgorithm { get; set; }
[JsonPropertyName("upload_slots_behavior")] [JsonPropertyName("upload_slots_behavior")]
public Int64 UploadSlotsBehavior { get; set; } public Int64? UploadSlotsBehavior { get; set; }
[JsonPropertyName("upnp")] [JsonPropertyName("upnp")]
public Boolean Upnp { get; set; } public Boolean? Upnp { get; set; }
[JsonPropertyName("upnp_lease_duration")] [JsonPropertyName("upnp_lease_duration")]
public Int64 UpnpLeaseDuration { get; set; } public Int64? UpnpLeaseDuration { get; set; }
[JsonPropertyName("use_https")] [JsonPropertyName("use_https")]
public Boolean UseHttps { get; set; } public Boolean? UseHttps { get; set; }
[JsonPropertyName("utp_tcp_mixed_mode")] [JsonPropertyName("utp_tcp_mixed_mode")]
public Int64 UtpTcpMixedMode { get; set; } public Int64? UtpTcpMixedMode { get; set; }
[JsonPropertyName("web_ui_address")] [JsonPropertyName("web_ui_address")]
public String WebUiAddress { get; set; } public String? WebUiAddress { get; set; }
[JsonPropertyName("web_ui_ban_duration")] [JsonPropertyName("web_ui_ban_duration")]
public Int64 WebUiBanDuration { get; set; } public Int64? WebUiBanDuration { get; set; }
[JsonPropertyName("web_ui_clickjacking_protection_enabled")] [JsonPropertyName("web_ui_clickjacking_protection_enabled")]
public Boolean WebUiClickjackingProtectionEnabled { get; set; } public Boolean? WebUiClickjackingProtectionEnabled { get; set; }
[JsonPropertyName("web_ui_csrf_protection_enabled")] [JsonPropertyName("web_ui_csrf_protection_enabled")]
public Boolean WebUiCsrfProtectionEnabled { get; set; } public Boolean? WebUiCsrfProtectionEnabled { get; set; }
[JsonPropertyName("web_ui_domain_list")] [JsonPropertyName("web_ui_domain_list")]
public String WebUiDomainList { get; set; } public String? WebUiDomainList { get; set; }
[JsonPropertyName("web_ui_host_header_validation_enabled")] [JsonPropertyName("web_ui_host_header_validation_enabled")]
public Boolean WebUiHostHeaderValidationEnabled { get; set; } public Boolean? WebUiHostHeaderValidationEnabled { get; set; }
[JsonPropertyName("web_ui_https_cert_path")] [JsonPropertyName("web_ui_https_cert_path")]
public String WebUiHttpsCertPath { get; set; } public String? WebUiHttpsCertPath { get; set; }
[JsonPropertyName("web_ui_https_key_path")] [JsonPropertyName("web_ui_https_key_path")]
public String WebUiHttpsKeyPath { get; set; } public String? WebUiHttpsKeyPath { get; set; }
[JsonPropertyName("web_ui_max_auth_fail_count")] [JsonPropertyName("web_ui_max_auth_fail_count")]
public Int64 WebUiMaxAuthFailCount { get; set; } public Int64? WebUiMaxAuthFailCount { get; set; }
[JsonPropertyName("web_ui_port")] [JsonPropertyName("web_ui_port")]
public Int64 WebUiPort { get; set; } public Int64? WebUiPort { get; set; }
[JsonPropertyName("web_ui_secure_cookie_enabled")] [JsonPropertyName("web_ui_secure_cookie_enabled")]
public Boolean WebUiSecureCookieEnabled { get; set; } public Boolean? WebUiSecureCookieEnabled { get; set; }
[JsonPropertyName("web_ui_session_timeout")] [JsonPropertyName("web_ui_session_timeout")]
public Int64 WebUiSessionTimeout { get; set; } public Int64? WebUiSessionTimeout { get; set; }
[JsonPropertyName("web_ui_upnp")] [JsonPropertyName("web_ui_upnp")]
public Boolean WebUiUpnp { get; set; } public Boolean? WebUiUpnp { get; set; }
[JsonPropertyName("web_ui_username")] [JsonPropertyName("web_ui_username")]
public String WebUiUsername { get; set; } public String? WebUiUsername { get; set; }
} }
public class ScanDirs public class ScanDirs

View file

@ -5,98 +5,98 @@ namespace RdtClient.Data.Models.QBittorrent;
public class SyncMetaData public class SyncMetaData
{ {
[JsonPropertyName("categories")] [JsonPropertyName("categories")]
public IDictionary<String, TorrentCategory> Categories { get; set; } public IDictionary<String, TorrentCategory>? Categories { get; set; }
[JsonPropertyName("full_update")] [JsonPropertyName("full_update")]
public Boolean FullUpdate { get; set; } public Boolean? FullUpdate { get; set; }
[JsonPropertyName("rid")] [JsonPropertyName("rid")]
public Int64 Rid { get; set; } public Int64? Rid { get; set; }
[JsonPropertyName("server_state")] [JsonPropertyName("server_state")]
public SyncMetaDataServerState ServerState { get; set; } public SyncMetaDataServerState? ServerState { get; set; }
[JsonPropertyName("tags")] [JsonPropertyName("tags")]
public IList<Object> Tags { get; set; } public IList<Object>? Tags { get; set; }
[JsonPropertyName("torrents")] [JsonPropertyName("torrents")]
public IDictionary<String, TorrentInfo> Torrents { get; set; } public IDictionary<String, TorrentInfo>? Torrents { get; set; }
[JsonPropertyName("trackers")] [JsonPropertyName("trackers")]
public IDictionary<String, List<String>> Trackers { get; set; } public IDictionary<String, List<String>>? Trackers { get; set; }
} }
public class SyncMetaDataServerState public class SyncMetaDataServerState
{ {
[JsonPropertyName("alltime_dl")] [JsonPropertyName("alltime_dl")]
public Int64 AlltimeDl { get; set; } public Int64? AlltimeDl { get; set; }
[JsonPropertyName("alltime_ul")] [JsonPropertyName("alltime_ul")]
public Int64 AlltimeUl { get; set; } public Int64? AlltimeUl { get; set; }
[JsonPropertyName("average_time_queue")] [JsonPropertyName("average_time_queue")]
public Int64 AverageTimeQueue { get; set; } public Int64? AverageTimeQueue { get; set; }
[JsonPropertyName("connection_status")] [JsonPropertyName("connection_status")]
public String ConnectionStatus { get; set; } public String? ConnectionStatus { get; set; }
[JsonPropertyName("dht_nodes")] [JsonPropertyName("dht_nodes")]
public Int64 DhtNodes { get; set; } public Int64? DhtNodes { get; set; }
[JsonPropertyName("dl_info_data")] [JsonPropertyName("dl_info_data")]
public Int64 DlInfoData { get; set; } public Int64? DlInfoData { get; set; }
[JsonPropertyName("dl_info_speed")] [JsonPropertyName("dl_info_speed")]
public Int64 DlInfoSpeed { get; set; } public Int64? DlInfoSpeed { get; set; }
[JsonPropertyName("dl_rate_limit")] [JsonPropertyName("dl_rate_limit")]
public Int64 DlRateLimit { get; set; } public Int64? DlRateLimit { get; set; }
[JsonPropertyName("free_space_on_disk")] [JsonPropertyName("free_space_on_disk")]
public Int64 FreeSpaceOnDisk { get; set; } public Int64? FreeSpaceOnDisk { get; set; }
[JsonPropertyName("global_ratio")] [JsonPropertyName("global_ratio")]
public String GlobalRatio { get; set; } public String? GlobalRatio { get; set; }
[JsonPropertyName("queued_io_jobs")] [JsonPropertyName("queued_io_jobs")]
public Int64 QueuedIoJobs { get; set; } public Int64? QueuedIoJobs { get; set; }
[JsonPropertyName("queueing")] [JsonPropertyName("queueing")]
public Boolean Queueing { get; set; } public Boolean? Queueing { get; set; }
[JsonPropertyName("read_cache_hits")] [JsonPropertyName("read_cache_hits")]
public String ReadCacheHits { get; set; } public String? ReadCacheHits { get; set; }
[JsonPropertyName("read_cache_overload")] [JsonPropertyName("read_cache_overload")]
public String ReadCacheOverload { get; set; } public String? ReadCacheOverload { get; set; }
[JsonPropertyName("refresh_interval")] [JsonPropertyName("refresh_interval")]
public Int64 RefreshInterval { get; set; } public Int64? RefreshInterval { get; set; }
[JsonPropertyName("total_buffers_size")] [JsonPropertyName("total_buffers_size")]
public Int64 TotalBuffersSize { get; set; } public Int64? TotalBuffersSize { get; set; }
[JsonPropertyName("total_peer_connections")] [JsonPropertyName("total_peer_connections")]
public Int64 TotalPeerConnections { get; set; } public Int64? TotalPeerConnections { get; set; }
[JsonPropertyName("total_queued_size")] [JsonPropertyName("total_queued_size")]
public Int64 TotalQueuedSize { get; set; } public Int64? TotalQueuedSize { get; set; }
[JsonPropertyName("total_wasted_session")] [JsonPropertyName("total_wasted_session")]
public Int64 TotalWastedSession { get; set; } public Int64? TotalWastedSession { get; set; }
[JsonPropertyName("up_info_data")] [JsonPropertyName("up_info_data")]
public Int64 UpInfoData { get; set; } public Int64? UpInfoData { get; set; }
[JsonPropertyName("up_info_speed")] [JsonPropertyName("up_info_speed")]
public Int64 UpInfoSpeed { get; set; } public Int64? UpInfoSpeed { get; set; }
[JsonPropertyName("up_rate_limit")] [JsonPropertyName("up_rate_limit")]
public Int64 UpRateLimit { get; set; } public Int64? UpRateLimit { get; set; }
[JsonPropertyName("use_alt_speed_limits")] [JsonPropertyName("use_alt_speed_limits")]
public Boolean UseAltSpeedLimits { get; set; } public Boolean? UseAltSpeedLimits { get; set; }
[JsonPropertyName("write_cache_overload")] [JsonPropertyName("write_cache_overload")]
public String WriteCacheOverload { get; set; } public String? WriteCacheOverload { get; set; }
} }

View file

@ -5,8 +5,8 @@ namespace RdtClient.Data.Models.QBittorrent;
public class TorrentCategory public class TorrentCategory
{ {
[JsonPropertyName("name")] [JsonPropertyName("name")]
public String Name { get; set; } public String? Name { get; set; }
[JsonPropertyName("savePath")] [JsonPropertyName("savePath")]
public String SavePath { get; set; } public String? SavePath { get; set; }
} }

View file

@ -5,5 +5,5 @@ namespace RdtClient.Data.Models.QBittorrent;
public class TorrentFileItem public class TorrentFileItem
{ {
[JsonPropertyName("name")] [JsonPropertyName("name")]
public String Name { get; set; } public String? Name { get; set; }
} }

View file

@ -5,10 +5,10 @@ namespace RdtClient.Data.Models.QBittorrent;
public class TorrentInfo public class TorrentInfo
{ {
[JsonPropertyName("added_on")] [JsonPropertyName("added_on")]
public Int64 AddedOn { get; set; } public Int64? AddedOn { get; set; }
[JsonPropertyName("amount_left")] [JsonPropertyName("amount_left")]
public Int64 AmountLeft { get; set; } public Int64? AmountLeft { get; set; }
[JsonPropertyName("auto_tmm")] [JsonPropertyName("auto_tmm")]
public Boolean AutoTmm { get; set; } public Boolean AutoTmm { get; set; }
@ -17,31 +17,31 @@ public class TorrentInfo
public Decimal Availability { get; set; } public Decimal Availability { get; set; }
[JsonPropertyName("category")] [JsonPropertyName("category")]
public String Category { get; set; } public String? Category { get; set; }
[JsonPropertyName("completed")] [JsonPropertyName("completed")]
public Int64 Completed { get; set; } public Int64? Completed { get; set; }
[JsonPropertyName("completion_on")] [JsonPropertyName("completion_on")]
public Int64? CompletionOn { get; set; } public Int64? CompletionOn { get; set; }
[JsonPropertyName("content_path")] [JsonPropertyName("content_path")]
public String ContentPath { get; set; } public String? ContentPath { get; set; }
[JsonPropertyName("dl_limit")] [JsonPropertyName("dl_limit")]
public Int64 DlLimit { get; set; } public Int64? DlLimit { get; set; }
[JsonPropertyName("dlspeed")] [JsonPropertyName("dlspeed")]
public Int64 Dlspeed { get; set; } public Int64? Dlspeed { get; set; }
[JsonPropertyName("downloaded")] [JsonPropertyName("downloaded")]
public Int64 Downloaded { get; set; } public Int64? Downloaded { get; set; }
[JsonPropertyName("downloaded_session")] [JsonPropertyName("downloaded_session")]
public Int64 DownloadedSession { get; set; } public Int64? DownloadedSession { get; set; }
[JsonPropertyName("eta")] [JsonPropertyName("eta")]
public Int64 Eta { get; set; } public Int64? Eta { get; set; }
[JsonPropertyName("f_l_piece_prio")] [JsonPropertyName("f_l_piece_prio")]
public Boolean FlPiecePrio { get; set; } public Boolean FlPiecePrio { get; set; }
@ -50,89 +50,89 @@ public class TorrentInfo
public Boolean ForceStart { get; set; } public Boolean ForceStart { get; set; }
[JsonPropertyName("hash")] [JsonPropertyName("hash")]
public String Hash { get; set; } public String Hash { get; set; } = default!;
[JsonPropertyName("last_activity")] [JsonPropertyName("last_activity")]
public Int64 LastActivity { get; set; } public Int64? LastActivity { get; set; }
[JsonPropertyName("magnet_uri")] [JsonPropertyName("magnet_uri")]
public String MagnetUri { get; set; } public String? MagnetUri { get; set; }
[JsonPropertyName("max_ratio")] [JsonPropertyName("max_ratio")]
public Int64 MaxRatio { get; set; } public Int64? MaxRatio { get; set; }
[JsonPropertyName("max_seeding_time")] [JsonPropertyName("max_seeding_time")]
public Int64 MaxSeedingTime { get; set; } public Int64? MaxSeedingTime { get; set; }
[JsonPropertyName("name")] [JsonPropertyName("name")]
public String Name { get; set; } public String? Name { get; set; }
[JsonPropertyName("num_complete")] [JsonPropertyName("num_complete")]
public Int64 NumComplete { get; set; } public Int64? NumComplete { get; set; }
[JsonPropertyName("num_incomplete")] [JsonPropertyName("num_incomplete")]
public Int64 NumIncomplete { get; set; } public Int64? NumIncomplete { get; set; }
[JsonPropertyName("num_leechs")] [JsonPropertyName("num_leechs")]
public Int64 NumLeechs { get; set; } public Int64? NumLeechs { get; set; }
[JsonPropertyName("num_seeds")] [JsonPropertyName("num_seeds")]
public Int64 NumSeeds { get; set; } public Int64? NumSeeds { get; set; }
[JsonPropertyName("priority")] [JsonPropertyName("priority")]
public Int64 Priority { get; set; } public Int64? Priority { get; set; }
[JsonPropertyName("progress")] [JsonPropertyName("progress")]
public Single Progress { get; set; } public Single Progress { get; set; }
[JsonPropertyName("ratio")] [JsonPropertyName("ratio")]
public Int64 Ratio { get; set; } public Int64? Ratio { get; set; }
[JsonPropertyName("ratio_limit")] [JsonPropertyName("ratio_limit")]
public Int64 RatioLimit { get; set; } public Int64? RatioLimit { get; set; }
[JsonPropertyName("save_path")] [JsonPropertyName("save_path")]
public String SavePath { get; set; } public String? SavePath { get; set; }
[JsonPropertyName("seeding_time_limit")] [JsonPropertyName("seeding_time_limit")]
public Int64 SeedingTimeLimit { get; set; } public Int64? SeedingTimeLimit { get; set; }
[JsonPropertyName("seen_complete")] [JsonPropertyName("seen_complete")]
public Int64 SeenComplete { get; set; } public Int64? SeenComplete { get; set; }
[JsonPropertyName("seq_dl")] [JsonPropertyName("seq_dl")]
public Boolean SeqDl { get; set; } public Boolean SeqDl { get; set; }
[JsonPropertyName("size")] [JsonPropertyName("size")]
public Int64 Size { get; set; } public Int64? Size { get; set; }
[JsonPropertyName("state")] [JsonPropertyName("state")]
public String State { get; set; } public String? State { get; set; }
[JsonPropertyName("super_seeding")] [JsonPropertyName("super_seeding")]
public Boolean SuperSeeding { get; set; } public Boolean SuperSeeding { get; set; }
[JsonPropertyName("tags")] [JsonPropertyName("tags")]
public String Tags { get; set; } public String? Tags { get; set; }
[JsonPropertyName("time_active")] [JsonPropertyName("time_active")]
public Int64 TimeActive { get; set; } public Int64? TimeActive { get; set; }
[JsonPropertyName("total_size")] [JsonPropertyName("total_size")]
public Int64 TotalSize { get; set; } public Int64? TotalSize { get; set; }
[JsonPropertyName("tracker")] [JsonPropertyName("tracker")]
public String Tracker { get; set; } public String? Tracker { get; set; }
[JsonPropertyName("up_limit")] [JsonPropertyName("up_limit")]
public Int64 UpLimit { get; set; } public Int64? UpLimit { get; set; }
[JsonPropertyName("uploaded")] [JsonPropertyName("uploaded")]
public Int64 Uploaded { get; set; } public Int64? Uploaded { get; set; }
[JsonPropertyName("uploaded_session")] [JsonPropertyName("uploaded_session")]
public Int64 UploadedSession { get; set; } public Int64? UploadedSession { get; set; }
[JsonPropertyName("upspeed")] [JsonPropertyName("upspeed")]
public Int64 Upspeed { get; set; } public Int64? Upspeed { get; set; }
} }

View file

@ -5,101 +5,101 @@ namespace RdtClient.Data.Models.QBittorrent;
public class TorrentProperties public class TorrentProperties
{ {
[JsonPropertyName("addition_date")] [JsonPropertyName("addition_date")]
public Int64 AdditionDate { get; set; } public Int64? AdditionDate { get; set; }
[JsonPropertyName("comment")] [JsonPropertyName("comment")]
public String Comment { get; set; } public String? Comment { get; set; }
[JsonPropertyName("completion_date")] [JsonPropertyName("completion_date")]
public Int64 CompletionDate { get; set; } public Int64? CompletionDate { get; set; }
[JsonPropertyName("created_by")] [JsonPropertyName("created_by")]
public String CreatedBy { get; set; } public String? CreatedBy { get; set; }
[JsonPropertyName("creation_date")] [JsonPropertyName("creation_date")]
public Int64 CreationDate { get; set; } public Int64? CreationDate { get; set; }
[JsonPropertyName("dl_limit")] [JsonPropertyName("dl_limit")]
public Int64 DlLimit { get; set; } public Int64? DlLimit { get; set; }
[JsonPropertyName("dl_speed")] [JsonPropertyName("dl_speed")]
public Int64 DlSpeed { get; set; } public Int64? DlSpeed { get; set; }
[JsonPropertyName("dl_speed_avg")] [JsonPropertyName("dl_speed_avg")]
public Int64 DlSpeedAvg { get; set; } public Int64? DlSpeedAvg { get; set; }
[JsonPropertyName("eta")] [JsonPropertyName("eta")]
public Int64 Eta { get; set; } public Int64? Eta { get; set; }
[JsonPropertyName("last_seen")] [JsonPropertyName("last_seen")]
public Int64 LastSeen { get; set; } public Int64? LastSeen { get; set; }
[JsonPropertyName("nb_connections")] [JsonPropertyName("nb_connections")]
public Int64 NbConnections { get; set; } public Int64? NbConnections { get; set; }
[JsonPropertyName("nb_connections_limit")] [JsonPropertyName("nb_connections_limit")]
public Int64 NbConnectionsLimit { get; set; } public Int64? NbConnectionsLimit { get; set; }
[JsonPropertyName("peers")] [JsonPropertyName("peers")]
public Int64 Peers { get; set; } public Int64? Peers { get; set; }
[JsonPropertyName("peers_total")] [JsonPropertyName("peers_total")]
public Int64 PeersTotal { get; set; } public Int64? PeersTotal { get; set; }
[JsonPropertyName("piece_size")] [JsonPropertyName("piece_size")]
public Int64 PieceSize { get; set; } public Int64? PieceSize { get; set; }
[JsonPropertyName("pieces_have")] [JsonPropertyName("pieces_have")]
public Int64 PiecesHave { get; set; } public Int64? PiecesHave { get; set; }
[JsonPropertyName("pieces_num")] [JsonPropertyName("pieces_num")]
public Int64 PiecesNum { get; set; } public Int64? PiecesNum { get; set; }
[JsonPropertyName("reannounce")] [JsonPropertyName("reannounce")]
public Int64 Reannounce { get; set; } public Int64? Reannounce { get; set; }
[JsonPropertyName("save_path")] [JsonPropertyName("save_path")]
public String SavePath { get; set; } public String? SavePath { get; set; }
[JsonPropertyName("seeding_time")] [JsonPropertyName("seeding_time")]
public Int64 SeedingTime { get; set; } public Int64? SeedingTime { get; set; }
[JsonPropertyName("seeds")] [JsonPropertyName("seeds")]
public Int64 Seeds { get; set; } public Int64? Seeds { get; set; }
[JsonPropertyName("seeds_total")] [JsonPropertyName("seeds_total")]
public Int64 SeedsTotal { get; set; } public Int64? SeedsTotal { get; set; }
[JsonPropertyName("share_ratio")] [JsonPropertyName("share_ratio")]
public Int64 ShareRatio { get; set; } public Int64? ShareRatio { get; set; }
[JsonPropertyName("time_elapsed")] [JsonPropertyName("time_elapsed")]
public Int64 TimeElapsed { get; set; } public Int64? TimeElapsed { get; set; }
[JsonPropertyName("total_downloaded")] [JsonPropertyName("total_downloaded")]
public Int64 TotalDownloaded { get; set; } public Int64? TotalDownloaded { get; set; }
[JsonPropertyName("total_downloaded_session")] [JsonPropertyName("total_downloaded_session")]
public Int64 TotalDownloadedSession { get; set; } public Int64? TotalDownloadedSession { get; set; }
[JsonPropertyName("total_size")] [JsonPropertyName("total_size")]
public Int64 TotalSize { get; set; } public Int64? TotalSize { get; set; }
[JsonPropertyName("total_uploaded")] [JsonPropertyName("total_uploaded")]
public Int64 TotalUploaded { get; set; } public Int64? TotalUploaded { get; set; }
[JsonPropertyName("total_uploaded_session")] [JsonPropertyName("total_uploaded_session")]
public Int64 TotalUploadedSession { get; set; } public Int64? TotalUploadedSession { get; set; }
[JsonPropertyName("total_wasted")] [JsonPropertyName("total_wasted")]
public Int64 TotalWasted { get; set; } public Int64? TotalWasted { get; set; }
[JsonPropertyName("up_limit")] [JsonPropertyName("up_limit")]
public Int64 UpLimit { get; set; } public Int64? UpLimit { get; set; }
[JsonPropertyName("up_speed")] [JsonPropertyName("up_speed")]
public Int64 UpSpeed { get; set; } public Int64? UpSpeed { get; set; }
[JsonPropertyName("up_speed_avg")] [JsonPropertyName("up_speed_avg")]
public Int64 UpSpeedAvg { get; set; } public Int64? UpSpeedAvg { get; set; }
} }

View file

@ -2,7 +2,7 @@
public class TorrentClientAvailableFile public class TorrentClientAvailableFile
{ {
public String Filename { get; set; } public String Filename { get; set; } = default!;
public Int64 Filesize { get; set; } public Int64 Filesize { get; set; }
} }

View file

@ -3,7 +3,7 @@
public class TorrentClientFile public class TorrentClientFile
{ {
public Int64 Id { get; set; } public Int64 Id { get; set; }
public String Path { get; set; } public String Path { get; set; } = default!;
public Int64 Bytes { get; set; } public Int64 Bytes { get; set; }
public Boolean Selected { get; set; } public Boolean Selected { get; set; }
} }

View file

@ -2,20 +2,20 @@
public class TorrentClientTorrent public class TorrentClientTorrent
{ {
public String Id { get; set; } public String Id { get; set; } = default!;
public String Filename { get; set; } public String Filename { get; set; } = default!;
public String OriginalFilename { get; set; } public String? OriginalFilename { get; set; } = default!;
public String Hash { get; set; } public String Hash { get; set; } = default!;
public Int64 Bytes { get; set; } public Int64 Bytes { get; set; }
public Int64 OriginalBytes { get; set; } public Int64 OriginalBytes { get; set; }
public String Host { get; set; } public String? Host { get; set; }
public Int64 Split { get; set; } public Int64 Split { get; set; }
public Int64 Progress { get; set; } public Int64 Progress { get; set; }
public String Status { get; set; } public String? Status { get; set; } = default!;
public Int64 StatusCode { get; set; } public Int64 StatusCode { get; set; }
public DateTimeOffset Added { get; set; } public DateTimeOffset Added { get; set; }
public List<TorrentClientFile> Files { get; set; } public List<TorrentClientFile>? Files { get; set; }
public List<String> Links { get; set; } public List<String>? Links { get; set; }
public DateTimeOffset? Ended { get; set; } public DateTimeOffset? Ended { get; set; }
public Int64? Speed { get; set; } public Int64? Speed { get; set; }
public Int64? Seeders { get; set; } public Int64? Seeders { get; set; }

View file

@ -2,6 +2,6 @@
public class TorrentClientUser public class TorrentClientUser
{ {
public String Username { get; set; } public String? Username { get; set; }
public DateTimeOffset? Expiration { get; set; } public DateTimeOffset? Expiration { get; set; }
} }

View file

@ -2,25 +2,21 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.5" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.4" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.4"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Serilog" Version="2.11.0" /> <PackageReference Include="Serilog" Version="2.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Attributes\" />
</ItemGroup>
</Project> </Project>

View file

@ -32,7 +32,7 @@ public class Startup : IHostedService
var settings = scope.ServiceProvider.GetRequiredService<Settings>(); var settings = scope.ServiceProvider.GetRequiredService<Settings>();
await settings.Seed(); await settings.Seed();
await settings.ResetCache(); await settings.ResetCache();
await settings.Clean(); await Settings.Clean();
Ready = true; Ready = true;
} }

View file

@ -8,8 +8,8 @@ namespace RdtClient.Service.BackgroundServices;
public class UpdateChecker : BackgroundService public class UpdateChecker : BackgroundService
{ {
public static String CurrentVersion { get; private set; } public static String? CurrentVersion { get; private set; }
public static String LatestVersion { get; private set; } public static String? LatestVersion { get; private set; }
private readonly ILogger<UpdateChecker> _logger; private readonly ILogger<UpdateChecker> _logger;
@ -53,7 +53,13 @@ public class UpdateChecker : BackgroundService
return; return;
} }
var latestRelease = gitHubReleases.First().Name; var latestRelease = gitHubReleases.FirstOrDefault(m => m.Name != null)?.Name;
if (latestRelease == null)
{
_logger.LogWarning($"Unable to find latest version on GitHub");
return;
}
if (latestRelease != CurrentVersion) if (latestRelease != CurrentVersion)
{ {
@ -77,5 +83,5 @@ public class UpdateChecker : BackgroundService
public class GitHubReleasesResponse public class GitHubReleasesResponse
{ {
[JsonProperty("name")] [JsonProperty("name")]
public String Name { get; set; } public String? Name { get; set; }
} }

View file

@ -23,5 +23,6 @@ public static class DiConfig
services.AddHostedService<Startup>(); services.AddHostedService<Startup>();
services.AddHostedService<TaskRunner>(); services.AddHostedService<TaskRunner>();
services.AddHostedService<UpdateChecker>(); services.AddHostedService<UpdateChecker>();
services.AddHostedService<WatchFolderChecker>();
} }
} }

View file

@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Usage", "CA2254:Template should be a static expression", Justification = "Bug in Serilog", Scope = "NamespaceAndDescendants", Target = "N:RdtClient.Service")]

View file

@ -5,11 +5,11 @@ namespace RdtClient.Service.Helpers;
public static class DownloadHelper public static class DownloadHelper
{ {
public static String GetDownloadPath(String downloadPath, Torrent torrent, Download download) public static String? GetDownloadPath(String downloadPath, Torrent torrent, Download download)
{ {
var fileUrl = download.Link; var fileUrl = download.Link;
if (String.IsNullOrWhiteSpace(fileUrl)) if (String.IsNullOrWhiteSpace(fileUrl) || torrent.RdName == null)
{ {
return null; return null;
} }

View file

@ -16,7 +16,7 @@ public class JsonModelBinder : IModelBinder
{ {
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
var valueAsString = valueProviderResult.FirstValue; var valueAsString = valueProviderResult.FirstValue ?? "";
var result = Newtonsoft.Json.JsonConvert.DeserializeObject(valueAsString, bindingContext.ModelType); var result = Newtonsoft.Json.JsonConvert.DeserializeObject(valueAsString, bindingContext.ModelType);
if (result != null) if (result != null)
{ {

View file

@ -1,30 +0,0 @@
using RdtClient.Data.Models.Data;
namespace RdtClient.Service.Helpers;
public static class SettingsHelper
{
public static String GetString(this IList<Setting> settings, String key)
{
var setting = settings.FirstOrDefault(m => m.SettingId == key);
if (setting == null)
{
throw new Exception($"Setting with key {key} not found");
}
return setting.Value;
}
public static Int32 GetNumber(this IList<Setting> settings, String key)
{
var setting = settings.FirstOrDefault(m => m.SettingId == key);
if (setting == null)
{
throw new Exception($"Setting with key {key} not found");
}
return Int32.Parse(setting.Value);
}
}

View file

@ -2,18 +2,18 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="AllDebrid.NET" Version="1.0.7" /> <PackageReference Include="AllDebrid.NET" Version="1.0.9" />
<PackageReference Include="Aria2.NET" Version="1.0.4" /> <PackageReference Include="Aria2.NET" Version="1.0.5" />
<PackageReference Include="Downloader" Version="2.3.3" /> <PackageReference Include="Downloader" Version="2.3.5" />
<PackageReference Include="MonoTorrent" Version="2.0.5" /> <PackageReference Include="MonoTorrent" Version="2.0.5" />
<PackageReference Include="RD.NET" Version="2.1.2" /> <PackageReference Include="RD.NET" Version="2.1.3" />
<PackageReference Include="Serilog" Version="2.11.0" /> <PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.1.0" /> <PackageReference Include="Serilog.Exceptions" Version="8.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

View file

@ -37,7 +37,7 @@ public class Authentication
return result; return result;
} }
public async Task<IdentityUser> GetUser() public async Task<IdentityUser?> GetUser()
{ {
return await _userData.GetUser(); return await _userData.GetUser();
} }

View file

@ -12,7 +12,17 @@ public class DownloadClient
private readonly Download _download; private readonly Download _download;
private readonly Torrent _torrent; private readonly Torrent _torrent;
public IDownloader Downloader; public IDownloader? Downloader;
public Data.Enums.DownloadClient Type { get; set; }
public Boolean Finished { get; private set; }
public String? Error { get; private set; }
public Int64 Speed { get; private set; }
public Int64 BytesTotal { get; private set; }
public Int64 BytesDone { get; private set; }
public DownloadClient(Download download, Torrent torrent, String destinationPath) public DownloadClient(Download download, Torrent torrent, String destinationPath)
{ {
@ -21,17 +31,7 @@ public class DownloadClient
_destinationPath = destinationPath; _destinationPath = destinationPath;
} }
public Data.Enums.DownloadClient Type { get; set; } public async Task<String?> Start(DbSettings settings)
public Boolean Finished { get; private set; }
public String Error { get; private set; }
public Int64 Speed { get; private set; }
public Int64 BytesTotal { get; private set; }
public Int64 BytesDone { get; private set; }
public async Task<String> Start(DbSettings settings)
{ {
BytesDone = 0; BytesDone = 0;
BytesTotal = 0; BytesTotal = 0;
@ -39,6 +39,11 @@ public class DownloadClient
try try
{ {
if (_download.Link == null)
{
throw new Exception($"Invalid download link");
}
var filePath = DownloadHelper.GetDownloadPath(_destinationPath, _torrent, _download); var filePath = DownloadHelper.GetDownloadPath(_destinationPath, _torrent, _download);
if (filePath == null) if (filePath == null)

View file

@ -6,8 +6,8 @@ namespace RdtClient.Service.Services.Downloaders;
public class Aria2cDownloader : IDownloader public class Aria2cDownloader : IDownloader
{ {
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete; public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
public event EventHandler<DownloadProgressEventArgs> DownloadProgress; public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
private const Int32 RetryCount = 5; private const Int32 RetryCount = 5;
@ -17,9 +17,9 @@ public class Aria2cDownloader : IDownloader
private readonly String _uri; private readonly String _uri;
private readonly String _filePath; private readonly String _filePath;
private String _gid; private String? _gid;
public Aria2cDownloader(String gid, String uri, String filePath, DbSettings settings) public Aria2cDownloader(String? gid, String uri, String filePath, DbSettings settings)
{ {
_logger = Log.ForContext<Aria2cDownloader>(); _logger = Log.ForContext<Aria2cDownloader>();
_gid = gid; _gid = gid;
@ -34,9 +34,15 @@ public class Aria2cDownloader : IDownloader
_aria2NetClient = new Aria2NetClient(settings.DownloadClient.Aria2cUrl, settings.DownloadClient.Aria2cSecret, httpClient, 10); _aria2NetClient = new Aria2NetClient(settings.DownloadClient.Aria2cUrl, settings.DownloadClient.Aria2cSecret, httpClient, 10);
} }
public async Task<String> Download() public async Task<String?> Download()
{ {
var path = Path.GetDirectoryName(_filePath); var path = Path.GetDirectoryName(_filePath);
if (path == null)
{
throw new Exception($"Invalid file path {_filePath}");
}
var fileName = Path.GetFileName(_filePath); var fileName = Path.GetFileName(_filePath);
_logger.Debug($"Starting download of {_uri}, writing to path: {path}, fileName: {fileName}"); _logger.Debug($"Starting download of {_uri}, writing to path: {path}, fileName: {fileName}");
@ -60,7 +66,7 @@ public class Aria2cDownloader : IDownloader
{ {
try try
{ {
await _aria2NetClient.TellStatus(_gid); await _aria2NetClient.TellStatusAsync(_gid);
return _gid; return _gid;
} }
@ -70,23 +76,23 @@ public class Aria2cDownloader : IDownloader
} }
} }
_gid ??= await _aria2NetClient.AddUri(new List<String> _gid ??= await _aria2NetClient.AddUriAsync(new List<String>
{ {
_uri _uri
}, },
new Dictionary<String, Object> new Dictionary<String, Object>
{ {
{ {
"dir", path "dir", path
}, },
{ {
"out", fileName "out", fileName
} }
}); });
_logger.Debug($"Added download to Aria2, received ID {_gid}"); _logger.Debug($"Added download to Aria2, received ID {_gid}");
await _aria2NetClient.TellStatus(_gid); await _aria2NetClient.TellStatusAsync(_gid);
_logger.Debug($"Download with ID {_gid} found in Aria2"); _logger.Debug($"Download with ID {_gid} found in Aria2");
@ -124,7 +130,7 @@ public class Aria2cDownloader : IDownloader
try try
{ {
await _aria2NetClient.Pause(_gid); await _aria2NetClient.PauseAsync(_gid);
} }
catch catch
{ {
@ -143,7 +149,7 @@ public class Aria2cDownloader : IDownloader
try try
{ {
await _aria2NetClient.Unpause(_gid); await _aria2NetClient.UnpauseAsync(_gid);
} }
catch catch
{ {
@ -228,7 +234,7 @@ public class Aria2cDownloader : IDownloader
try try
{ {
await _aria2NetClient.ForceRemove(_gid); await _aria2NetClient.ForceRemoveAsync(_gid);
} }
catch catch
{ {
@ -237,7 +243,7 @@ public class Aria2cDownloader : IDownloader
try try
{ {
await _aria2NetClient.RemoveDownloadResult(_gid); await _aria2NetClient.RemoveDownloadResultAsync(_gid);
} }
catch catch
{ {
@ -247,11 +253,11 @@ public class Aria2cDownloader : IDownloader
private async Task<Boolean> CheckIfAdded() private async Task<Boolean> CheckIfAdded()
{ {
var allDownloads = await _aria2NetClient.TellAll(); var allDownloads = await _aria2NetClient.TellAllAsync();
foreach (var download in allDownloads.Where(m => m.Files != null)) foreach (var download in allDownloads)
{ {
foreach (var file in download.Files.Where(m => m.Uris != null)) foreach (var file in download.Files)
{ {
if (file.Uris.Any(uri => uri.Uri == _uri)) if (file.Uris.Any(uri => uri.Uri == _uri))
{ {

View file

@ -2,7 +2,7 @@
public class DownloadCompleteEventArgs public class DownloadCompleteEventArgs
{ {
public String Error { get; set; } public String? Error { get; set; }
} }
public class DownloadProgressEventArgs public class DownloadProgressEventArgs
@ -14,9 +14,9 @@ public class DownloadProgressEventArgs
public interface IDownloader public interface IDownloader
{ {
event EventHandler<DownloadCompleteEventArgs> DownloadComplete; event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
event EventHandler<DownloadProgressEventArgs> DownloadProgress; event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
Task<String> Download(); Task<String?> Download();
Task Cancel(); Task Cancel();
Task Pause(); Task Pause();
Task Resume(); Task Resume();

View file

@ -7,8 +7,8 @@ namespace RdtClient.Service.Services.Downloaders;
public class MultiDownloader : IDownloader public class MultiDownloader : IDownloader
{ {
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete; public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
public event EventHandler<DownloadProgressEventArgs> DownloadProgress; public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
private readonly DownloadService _downloadService; private readonly DownloadService _downloadService;
private readonly String _filePath; private readonly String _filePath;
@ -94,7 +94,7 @@ public class MultiDownloader : IDownloader
_downloadService.DownloadFileCompleted += (_, args) => _downloadService.DownloadFileCompleted += (_, args) =>
{ {
String error = null; String? error = null;
if (args.Cancelled) if (args.Cancelled)
{ {
@ -113,7 +113,7 @@ public class MultiDownloader : IDownloader
}; };
} }
public async Task<String> Download() public async Task<String?> Download()
{ {
_logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}"); _logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}");

View file

@ -7,8 +7,8 @@ public class SimpleDownloader : IDownloader
{ {
private const Int32 BufferSize = 8 * 1024; private const Int32 BufferSize = 8 * 1024;
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete; public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
public event EventHandler<DownloadProgressEventArgs> DownloadProgress; public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
private readonly String _uri; private readonly String _uri;
private readonly String _filePath; private readonly String _filePath;
@ -30,7 +30,7 @@ public class SimpleDownloader : IDownloader
_filePath = filePath; _filePath = filePath;
} }
public Task<String> Download() public Task<String?> Download()
{ {
_logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}"); _logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}");
@ -39,7 +39,7 @@ public class SimpleDownloader : IDownloader
await StartDownloadTask(); await StartDownloadTask();
}); });
return Task.FromResult<String>(null); return Task.FromResult<String?>(null);
} }
public Task Cancel() public Task Cancel()
@ -86,6 +86,7 @@ public class SimpleDownloader : IDownloader
while (readSize > 0 && !_cancelled) while (readSize > 0 && !_cancelled)
{ {
// ReSharper disable once ConvertToUsingDeclaration // ReSharper disable once ConvertToUsingDeclaration
#pragma warning disable IDE0063 // Use simple 'using' statement
using (var innerCts = new CancellationTokenSource(1000)) using (var innerCts = new CancellationTokenSource(1000))
{ {
readSize = await destinationStream.ReadAsync(buffer.AsMemory(0, buffer.Length), innerCts.Token).ConfigureAwait(false); readSize = await destinationStream.ReadAsync(buffer.AsMemory(0, buffer.Length), innerCts.Token).ConfigureAwait(false);
@ -115,6 +116,7 @@ public class SimpleDownloader : IDownloader
} }
} }
} }
#pragma warning restore IDE0063 // Use simple 'using' statement
} }
break; break;

View file

@ -17,12 +17,12 @@ public class Downloads
return await _downloadData.GetForTorrent(torrentId); return await _downloadData.GetForTorrent(torrentId);
} }
public async Task<Download> GetById(Guid downloadId) public async Task<Download?> GetById(Guid downloadId)
{ {
return await _downloadData.GetById(downloadId); return await _downloadData.GetById(downloadId);
} }
public async Task<Download> Get(Guid torrentId, String path) public async Task<Download?> Get(Guid torrentId, String path)
{ {
return await _downloadData.Get(torrentId, path); return await _downloadData.Get(torrentId, path);
} }
@ -67,7 +67,7 @@ public class Downloads
await _downloadData.UpdateCompleted(downloadId, dateTime); await _downloadData.UpdateCompleted(downloadId, dateTime);
} }
public async Task UpdateError(Guid downloadId, String error) public async Task UpdateError(Guid downloadId, String? error)
{ {
await _downloadData.UpdateError(downloadId, error); await _downloadData.UpdateError(downloadId, error);
} }

View file

@ -1,6 +1,5 @@
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.QBittorrent; using RdtClient.Data.Models.QBittorrent;
namespace RdtClient.Service.Services; namespace RdtClient.Service.Services;
@ -178,7 +177,7 @@ public class QBittorrent
WebUiUsername = "" WebUiUsername = ""
}; };
var savePath = AppDefaultSavePath(); var savePath = Settings.AppDefaultSavePath;
preferences.SavePath = savePath; preferences.SavePath = savePath;
preferences.TempPath = $"{savePath}temp{Path.DirectorySeparatorChar}"; preferences.TempPath = $"{savePath}temp{Path.DirectorySeparatorChar}";
@ -193,21 +192,9 @@ public class QBittorrent
return preferences; return preferences;
} }
public String AppDefaultSavePath()
{
var downloadPath = Settings.Get.DownloadClient.MappedPath;
downloadPath = downloadPath.TrimEnd('\\')
.TrimEnd('/');
downloadPath += Path.DirectorySeparatorChar;
return downloadPath;
}
public async Task<IList<TorrentInfo>> TorrentInfo() public async Task<IList<TorrentInfo>> TorrentInfo()
{ {
var savePath = AppDefaultSavePath(); var savePath = Settings.AppDefaultSavePath;
var results = new List<TorrentInfo>(); var results = new List<TorrentInfo>();
@ -241,9 +228,9 @@ public class QBittorrent
speed = (Int32) torrent.Downloads.Average(m => m.Speed); speed = (Int32) torrent.Downloads.Average(m => m.Speed);
} }
var progress = (bytesDone / (Single)bytesTotal); var progress = (bytesDone / (Single?)bytesTotal);
if (!Single.IsNormal(progress)) if (progress == null || !Single.IsNormal(progress.Value))
{ {
progress = 0; progress = 0;
} }
@ -276,7 +263,7 @@ public class QBittorrent
NumLeechs = 100, NumLeechs = 100,
NumSeeds = 100, NumSeeds = 100,
Priority = ++prio, Priority = ++prio,
Progress = progress, Progress = (Single) progress,
Ratio = 1, Ratio = 1,
RatioLimit = 1, RatioLimit = 1,
SavePath = downloadPath, SavePath = downloadPath,
@ -325,7 +312,7 @@ public class QBittorrent
return results; return results;
} }
public async Task<IList<TorrentFileItem>> TorrentFileContents(String hash) public async Task<IList<TorrentFileItem>?> TorrentFileContents(String hash)
{ {
var results = new List<TorrentFileItem>(); var results = new List<TorrentFileItem>();
@ -349,9 +336,9 @@ public class QBittorrent
return results; return results;
} }
public async Task<TorrentProperties> TorrentProperties(String hash) public async Task<TorrentProperties?> TorrentProperties(String hash)
{ {
var savePath = AppDefaultSavePath(); var savePath = Settings.AppDefaultSavePath;
var torrent = await _torrents.GetByHash(hash); var torrent = await _torrents.GetByHash(hash);
@ -428,7 +415,7 @@ public class QBittorrent
await _torrents.Delete(torrent.TorrentId, true, true, deleteFiles); await _torrents.Delete(torrent.TorrentId, true, true, deleteFiles);
} }
public async Task TorrentsAddMagnet(String magnetLink, String category, Int32? priority) public async Task TorrentsAddMagnet(String magnetLink, String? category, Int32? priority)
{ {
var torrent = new Torrent var torrent = new Torrent
{ {
@ -446,7 +433,7 @@ public class QBittorrent
await _torrents.UploadMagnet(magnetLink, torrent); await _torrents.UploadMagnet(magnetLink, torrent);
} }
public async Task TorrentsAddFile(Byte[] fileBytes, String category, Int32? priority) public async Task TorrentsAddFile(Byte[] fileBytes, String? category, Int32? priority)
{ {
var torrent = new Torrent var torrent = new Torrent
{ {
@ -464,7 +451,7 @@ public class QBittorrent
await _torrents.UploadFile(fileBytes, torrent); await _torrents.UploadFile(fileBytes, torrent);
} }
public async Task TorrentsSetCategory(String hash, String category) public async Task TorrentsSetCategory(String hash, String? category)
{ {
await _torrents.UpdateCategory(hash, category); await _torrents.UpdateCategory(hash, category);
} }
@ -474,7 +461,7 @@ public class QBittorrent
var torrents = await _torrents.Get(); var torrents = await _torrents.Get();
var torrentsToGroup = torrents.Where(m => !String.IsNullOrWhiteSpace(m.Category)) var torrentsToGroup = torrents.Where(m => !String.IsNullOrWhiteSpace(m.Category))
.Select(m => m.Category.ToLower()) .Select(m => m.Category!.ToLower())
.ToList(); .ToList();
var categoryList = (Settings.Get.General.Categories ?? "") var categoryList = (Settings.Get.General.Categories ?? "")
@ -494,14 +481,14 @@ public class QBittorrent
m => new TorrentCategory m => new TorrentCategory
{ {
Name = m, Name = m,
SavePath = Path.Combine(AppDefaultSavePath(), m) SavePath = Path.Combine(Settings.AppDefaultSavePath, m)
}); });
} }
return results; return results;
} }
public async Task CategoryCreate(String category) public async Task CategoryCreate(String? category)
{ {
if (category == null) if (category == null)
{ {
@ -528,7 +515,7 @@ public class QBittorrent
await _settings.Update("General:Categories", categoriesSetting); await _settings.Update("General:Categories", categoriesSetting);
} }
public async Task CategoryRemove(String category) public async Task CategoryRemove(String? category)
{ {
if (category == null) if (category == null)
{ {

View file

@ -15,7 +15,7 @@ public class RdtHub : Hub
await base.OnConnectedAsync(); await base.OnConnectedAsync();
} }
public override async Task OnDisconnectedAsync(Exception exception) public override async Task OnDisconnectedAsync(Exception? exception)
{ {
Users.TryRemove(Context.ConnectionId, out _); Users.TryRemove(Context.ConnectionId, out _);
await base.OnDisconnectedAsync(exception); await base.OnDisconnectedAsync(exception);

View file

@ -1,11 +1,7 @@
using System.Diagnostics; using RdtClient.Data.Data;
using Aria2NET;
using RdtClient.Data.Data;
using RdtClient.Data.Enums; using RdtClient.Data.Enums;
using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
using RdtClient.Service.Helpers; using RdtClient.Service.Helpers;
using RdtClient.Service.Services.Downloaders;
using Serilog.Core; using Serilog.Core;
using Serilog.Events; using Serilog.Events;
@ -24,9 +20,19 @@ public class Settings
public static DbSettings Get => SettingData.Get; public static DbSettings Get => SettingData.Get;
public IList<SettingProperty> GetAll() public static String AppDefaultSavePath
{ {
return _settingData.GetAll(); get
{
var downloadPath = Get.DownloadClient.MappedPath;
downloadPath = downloadPath.TrimEnd('\\')
.TrimEnd('/');
downloadPath += Path.DirectorySeparatorChar;
return downloadPath;
}
} }
public async Task Update(IList<SettingProperty> settings) public async Task Update(IList<SettingProperty> settings)
@ -34,137 +40,12 @@ public class Settings
await _settingData.Update(settings); await _settingData.Update(settings);
} }
public async Task Update(String settingId, Object value) public async Task Update(String settingId, Object? value)
{ {
await _settingData.Update(settingId, value); await _settingData.Update(settingId, value);
} }
public async Task TestPath(String path) public static async Task Clean()
{
if (String.IsNullOrWhiteSpace(path))
{
throw new Exception("Path is not set");
}
path = path.TrimEnd('/').TrimEnd('\\');
if (!Directory.Exists(path))
{
throw new Exception($"Path {path} does not exist");
}
var testFile = $"{path}/test.txt";
await File.WriteAllTextAsync(testFile, "RealDebridClient Test File, you can remove this file.");
await FileHelper.Delete(testFile);
}
public async Task<Double> TestDownloadSpeed(CancellationToken cancellationToken)
{
var downloadPath = Get.DownloadClient.DownloadPath;
var testFilePath = Path.Combine(downloadPath, "testDefault.rar");
await FileHelper.Delete(testFilePath);
var download = new Download
{
Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar",
Torrent = new Torrent
{
RdName = ""
}
};
var downloadClient = new DownloadClient(download, download.Torrent, downloadPath);
await downloadClient.Start(Get);
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
while (!downloadClient.Finished)
{
await Task.Delay(1000, CancellationToken.None);
if (cancellationToken.IsCancellationRequested)
{
await downloadClient.Cancel();
}
if (downloadClient.Downloader is Aria2cDownloader aria2Downloader)
{
var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1);
var allDownloads = await aria2NetClient.TellAll(cancellationToken);
await aria2Downloader.Update(allDownloads);
}
if (downloadClient.BytesDone > 1024 * 1024 * 50)
{
await downloadClient.Cancel();
break;
}
}
await FileHelper.Delete(testFilePath);
await Clean();
return downloadClient.Speed;
}
public async Task<Double> TestWriteSpeed()
{
var downloadPath = Get.DownloadClient.DownloadPath;
var testFilePath = Path.Combine(downloadPath, "test.tmp");
await FileHelper.Delete(testFilePath);
const Int32 testFileSize = 64 * 1024 * 1024;
var watch = new Stopwatch();
watch.Start();
var rnd = new Random();
await using var fileStream = new FileStream(testFilePath, FileMode.Create, FileAccess.Write, FileShare.Write);
var buffer = new Byte[64 * 1024];
while (fileStream.Length < testFileSize)
{
rnd.NextBytes(buffer);
await fileStream.WriteAsync(buffer.AsMemory(0, buffer.Length));
}
watch.Stop();
var writeSpeed = fileStream.Length / watch.Elapsed.TotalSeconds;
fileStream.Close();
await FileHelper.Delete(testFilePath);
return writeSpeed;
}
public async Task<VersionResult> GetAria2cVersion(String url, String secret)
{
var client = new Aria2NetClient(url, secret);
return await client.GetVersion();
}
public async Task Clean()
{ {
try try
{ {

View file

@ -6,9 +6,9 @@
/// </summary> /// </summary>
public class ThrottledStream : Stream public class ThrottledStream : Stream
{ {
public Int64 Speed => (Int64)_bandwidth.AverageSpeed; public Int64 Speed => (Int64) (_bandwidth?.AverageSpeed ?? 0);
private Bandwidth _bandwidth; private Bandwidth? _bandwidth;
private Int64 _bandwidthLimit; private Int64 _bandwidthLimit;
private readonly Stream _baseStream; private readonly Stream _baseStream;
@ -90,7 +90,6 @@ public class ThrottledStream : Stream
public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count) public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count)
{ {
Throttle(count).Wait(); Throttle(count).Wait();
return _baseStream.Read(buffer, offset, count); return _baseStream.Read(buffer, offset, count);
} }
@ -100,8 +99,13 @@ public class ThrottledStream : Stream
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await Throttle(count).ConfigureAwait(false); await Throttle(count).ConfigureAwait(false);
return await _baseStream.ReadAsync(new Memory<Byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
}
return await _baseStream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); public override async ValueTask<Int32> ReadAsync(Memory<Byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
await Throttle(buffer.Length).ConfigureAwait(false);
return await base.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -115,7 +119,13 @@ public class ThrottledStream : Stream
public override async Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken) public override async Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
{ {
await Throttle(count).ConfigureAwait(false); await Throttle(count).ConfigureAwait(false);
await _baseStream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); await _baseStream.WriteAsync(new ReadOnlyMemory<Byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
}
public override async ValueTask WriteAsync(ReadOnlyMemory<Byte> buffer, CancellationToken cancellationToken = new CancellationToken())
{
await Throttle(buffer.Length).ConfigureAwait(false);
await base.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
} }
private async Task Throttle(Int32 transmissionVolume) private async Task Throttle(Int32 transmissionVolume)
@ -124,9 +134,8 @@ public class ThrottledStream : Stream
if (BandwidthLimit > 0 && transmissionVolume > 0) if (BandwidthLimit > 0 && transmissionVolume > 0)
{ {
// Calculate the time to sleep. // Calculate the time to sleep.
_bandwidth.CalculateSpeed(transmissionVolume); _bandwidth!.CalculateSpeed(transmissionVolume);
await Sleep(_bandwidth!.PopSpeedRetrieveTime()).ConfigureAwait(false);
await Sleep(_bandwidth.PopSpeedRetrieveTime()).ConfigureAwait(false);
} }
} }
@ -139,7 +148,7 @@ public class ThrottledStream : Stream
} }
/// <inheritdoc /> /// <inheritdoc />
public override String ToString() public override String? ToString()
{ {
return _baseStream.ToString(); return _baseStream.ToString();
} }

View file

@ -70,14 +70,14 @@ public class AllDebridTorrentClient : ITorrentClient
Status = torrent.Status, Status = torrent.Status,
StatusCode = torrent.StatusCode, StatusCode = torrent.StatusCode,
Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate), Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate),
Files = (torrent.Links ?? new List<Link>()).Select((m, i) => new TorrentClientFile Files = torrent.Links.Select((m, i) => new TorrentClientFile
{ {
Path = m.Filename, Path = m.Filename,
Bytes = m.Size, Bytes = m.Size,
Id = i, Id = i,
Selected = true, Selected = true,
}).ToList(), }).ToList(),
Links = (torrent.Links ?? new List<Link>()).Select(m => m.LinkUrl.ToString()).ToList(), Links = torrent.Links.Select(m => m.LinkUrl.ToString()).ToList(),
Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate), Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate),
Speed = torrent.DownloadSpeed, Speed = torrent.DownloadSpeed,
Seeders = torrent.Seeders Seeders = torrent.Seeders
@ -94,6 +94,11 @@ public class AllDebridTorrentClient : ITorrentClient
{ {
var user = await GetClient().User.GetAsync(); var user = await GetClient().User.GetAsync();
if (user == null)
{
throw new Exception("Unable to get user");
}
return new TorrentClientUser return new TorrentClientUser
{ {
Username = user.Username, Username = user.Username,
@ -105,14 +110,38 @@ public class AllDebridTorrentClient : ITorrentClient
{ {
var result = await GetClient().Magnet.UploadMagnetAsync(magnetLink); var result = await GetClient().Magnet.UploadMagnetAsync(magnetLink);
return result.Id.ToString(); if (result?.Id == null)
{
throw new Exception("Unable to add magnet link");
}
var resultId = result.Id.ToString();
if (resultId == null)
{
throw new Exception($"Invalid responseID {result.Id}");
}
return resultId;
} }
public async Task<String> AddFile(Byte[] bytes) public async Task<String> AddFile(Byte[] bytes)
{ {
var result = await GetClient().Magnet.UploadFileAsync(bytes); var result = await GetClient().Magnet.UploadFileAsync(bytes);
return result.Id.ToString(); if (result?.Id == null)
{
throw new Exception("Unable to add torrent file");
}
var resultId = result.Id.ToString();
if (resultId == null)
{
throw new Exception($"Invalid responseID {result.Id}");
}
return resultId;
} }
public async Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash) public async Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
@ -143,6 +172,11 @@ public class AllDebridTorrentClient : ITorrentClient
{ {
var result = await GetClient().Magnet.StatusAsync(torrentId); var result = await GetClient().Magnet.StatusAsync(torrentId);
if (result == null)
{
throw new Exception($"Unable to find magnet with ID {torrentId}");
}
return Map(result); return Map(result);
} }
@ -155,13 +189,23 @@ public class AllDebridTorrentClient : ITorrentClient
{ {
var result = await GetClient().Links.DownloadLinkAsync(link); var result = await GetClient().Links.DownloadLinkAsync(link);
if (result.Link == null)
{
throw new Exception("Invalid result link");
}
return result.Link; return result.Link;
} }
public async Task<Torrent> UpdateData(Torrent torrent, TorrentClientTorrent torrentClientTorrent) public async Task<Torrent> UpdateData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent)
{ {
try try
{ {
if (torrent.RdId == null)
{
return torrent;
}
torrentClientTorrent ??= await GetInfo(torrent.RdId); torrentClientTorrent ??= await GetInfo(torrent.RdId);
if (!String.IsNullOrWhiteSpace(torrentClientTorrent.Filename)) if (!String.IsNullOrWhiteSpace(torrentClientTorrent.Filename))
@ -231,10 +275,20 @@ public class AllDebridTorrentClient : ITorrentClient
return torrent; return torrent;
} }
public async Task<IList<String>> GetDownloadLinks(Torrent torrent) public async Task<IList<String>?> GetDownloadLinks(Torrent torrent)
{ {
if (torrent.RdId == null)
{
return null;
}
var magnet = await GetClient().Magnet.StatusAsync(torrent.RdId); var magnet = await GetClient().Magnet.StatusAsync(torrent.RdId);
if (magnet == null)
{
return null;
}
var links = magnet.Links; var links = magnet.Links;
Log($"Getting download links", torrent); Log($"Getting download links", torrent);
@ -262,11 +316,6 @@ public class AllDebridTorrentClient : ITorrentClient
foreach (var link in links) foreach (var link in links)
{ {
if (link.Files == null)
{
continue;
}
var fileList = GetFiles(link.Files, ""); var fileList = GetFiles(link.Files, "");
Log($"{link.Filename} ({link.Size}b) {link.LinkUrl}, contains files:{Environment.NewLine}{String.Join(Environment.NewLine, fileList)}"); Log($"{link.Filename} ({link.Size}b) {link.LinkUrl}, contains files:{Environment.NewLine}{String.Join(Environment.NewLine, fileList)}");
@ -332,7 +381,7 @@ public class AllDebridTorrentClient : ITorrentClient
return result; return result;
} }
private void Log(String message, Torrent torrent = null) private void Log(String message, Torrent? torrent = null)
{ {
if (torrent != null) if (torrent != null)
{ {

View file

@ -11,9 +11,8 @@ public interface ITorrentClient
Task<String> AddFile(Byte[] bytes); Task<String> AddFile(Byte[] bytes);
Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash); Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash);
Task SelectFiles(Torrent torrent); Task SelectFiles(Torrent torrent);
Task<TorrentClientTorrent> GetInfo(String torrentId);
Task Delete(String torrentId); Task Delete(String torrentId);
Task<String> Unrestrict(String link); Task<String> Unrestrict(String link);
Task<Torrent> UpdateData(Torrent torrent, TorrentClientTorrent torrentClientTorrent); Task<Torrent> UpdateData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent);
Task<IList<String>> GetDownloadLinks(Torrent torrent); Task<IList<String>?> GetDownloadLinks(Torrent torrent);
} }

View file

@ -141,11 +141,11 @@ public class RealDebridTorrentClient : ITorrentClient
var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values); var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values);
var groups = files.GroupBy(m => $"{m.Filename}-{m.Filesize}"); var groups = files.Where(m => m.Filename != null).GroupBy(m => $"{m.Filename}-{m.Filesize}");
var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile
{ {
Filename = m.First().Filename, Filename = m.First().Filename!,
Filesize = m.First().Filesize Filesize = m.First().Filesize
} ).ToList(); } ).ToList();
@ -211,7 +211,7 @@ public class RealDebridTorrentClient : ITorrentClient
Log("", torrent); Log("", torrent);
await GetClient().Torrents.SelectFilesAsync(torrent.RdId, fileIds.ToArray()); await GetClient().Torrents.SelectFilesAsync(torrent.RdId!, fileIds.ToArray());
} }
public async Task<TorrentClientTorrent> GetInfo(String torrentId) public async Task<TorrentClientTorrent> GetInfo(String torrentId)
@ -230,23 +230,28 @@ public class RealDebridTorrentClient : ITorrentClient
{ {
var result = await GetClient().Unrestrict.LinkAsync(link); var result = await GetClient().Unrestrict.LinkAsync(link);
if (result.Download == null)
{
throw new Exception($"Unrestrict returned an invalid download");
}
return result.Download; return result.Download;
} }
public async Task<Data.Models.Data.Torrent> UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent torrentClientTorrent) public async Task<Data.Models.Data.Torrent> UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent? torrentClientTorrent)
{ {
try try
{ {
if (torrent == null) if (torrent.RdId == null)
{ {
return null; return torrent;
} }
var rdTorrent = await GetInfo(torrent.RdId); var rdTorrent = await GetInfo(torrent.RdId);
if (rdTorrent == null) if (rdTorrent == null)
{ {
return torrent; throw new Exception($"Resource not found");
} }
if (!String.IsNullOrWhiteSpace(rdTorrent.Filename)) if (!String.IsNullOrWhiteSpace(rdTorrent.Filename))
@ -302,10 +307,7 @@ public class RealDebridTorrentClient : ITorrentClient
{ {
if (ex.Message == "Resource not found") if (ex.Message == "Resource not found")
{ {
if (torrent != null) torrent.RdStatusRaw = "deleted";
{
torrent.RdStatusRaw = "deleted";
}
} }
else else
{ {
@ -316,10 +318,20 @@ public class RealDebridTorrentClient : ITorrentClient
return torrent; return torrent;
} }
public async Task<IList<String>> GetDownloadLinks(Data.Models.Data.Torrent torrent) public async Task<IList<String>?> GetDownloadLinks(Data.Models.Data.Torrent torrent)
{ {
if (torrent.RdId == null)
{
return null;
}
var rdTorrent = await GetInfo(torrent.RdId); var rdTorrent = await GetInfo(torrent.RdId);
if (rdTorrent.Links == null)
{
return null;
}
var downloadLinks = rdTorrent.Links.Where(m => !String.IsNullOrWhiteSpace(m)).ToList(); var downloadLinks = rdTorrent.Links.Where(m => !String.IsNullOrWhiteSpace(m)).ToList();
Log($"Found {downloadLinks.Count} links", torrent); Log($"Found {downloadLinks.Count} links", torrent);
@ -360,7 +372,7 @@ public class RealDebridTorrentClient : ITorrentClient
return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value); return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value);
} }
private void Log(String message, Data.Models.Data.Torrent torrent = null) private void Log(String message, Data.Models.Data.Torrent? torrent = null)
{ {
if (torrent != null) if (torrent != null)
{ {

View file

@ -121,7 +121,7 @@ public class TorrentRunner
var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, _httpClient, 1); var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, _httpClient, 1);
var allDownloads = await aria2NetClient.TellAll(); var allDownloads = await aria2NetClient.TellAllAsync();
Log($"Found {allDownloads.Count} Aria2 downloads"); Log($"Found {allDownloads.Count} Aria2 downloads");
@ -162,7 +162,7 @@ public class TorrentRunner
{ {
// Retry the download if an error is encountered. // Retry the download if an error is encountered.
Log($"Download reported an error: {downloadClient.Error}", download, download.Torrent); Log($"Download reported an error: {downloadClient.Error}", download, download.Torrent);
Log($"Download retry count {download.RetryCount}/{download.Torrent.DownloadRetryAttempts}, torrent retry count {download.Torrent.RetryCount}/{download.Torrent.TorrentRetryAttempts}", download, download.Torrent); Log($"Download retry count {download.RetryCount}/{download.Torrent!.DownloadRetryAttempts}, torrent retry count {download.Torrent.RetryCount}/{download.Torrent.TorrentRetryAttempts}", download, download.Torrent);
if (download.RetryCount < download.Torrent.DownloadRetryAttempts) if (download.RetryCount < download.Torrent.DownloadRetryAttempts)
{ {
@ -570,7 +570,7 @@ public class TorrentRunner
} }
} }
private void Log(String message, Download download, Torrent torrent) private void Log(String message, Download? download, Torrent? torrent)
{ {
if (download != null) if (download != null)
{ {
@ -585,7 +585,7 @@ public class TorrentRunner
_logger.LogDebug(message); _logger.LogDebug(message);
} }
private void Log(String message, Torrent torrent = null) private void Log(String message, Torrent? torrent = null)
{ {
if (torrent != null) if (torrent != null)
{ {

View file

@ -42,7 +42,7 @@ public class Torrents
{ {
Provider.RealDebrid => realDebridTorrentClient, Provider.RealDebrid => realDebridTorrentClient,
Provider.AllDebrid => allDebridTorrentClient, Provider.AllDebrid => allDebridTorrentClient,
_ => null _ => throw new Exception("Invalid Provider")
}; };
} }
@ -72,7 +72,7 @@ public class Torrents
return torrents; return torrents;
} }
public async Task<Torrent> GetByHash(String hash) public async Task<Torrent?> GetByHash(String hash)
{ {
var torrent = await _torrentData.GetByHash(hash); var torrent = await _torrentData.GetByHash(hash);
@ -84,7 +84,7 @@ public class Torrents
return torrent; return torrent;
} }
public async Task UpdateCategory(String hash, String category) public async Task UpdateCategory(String hash, String? category)
{ {
var torrent = await _torrentData.GetByHash(hash); var torrent = await _torrentData.GetByHash(hash);
@ -256,7 +256,7 @@ public class Torrents
await _torrentData.Delete(torrentId); await _torrentData.Delete(torrentId);
} }
if (deleteRdTorrent) if (deleteRdTorrent && torrent.RdId != null)
{ {
Log($"Deleting RealDebrid Torrent", torrent); Log($"Deleting RealDebrid Torrent", torrent);
@ -495,13 +495,16 @@ public class Torrents
await Task.Delay(100); await Task.Delay(100);
} }
var downloadPath = DownloadPath(download.Torrent); var downloadPath = DownloadPath(download.Torrent!);
var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent, download); var filePath = DownloadHelper.GetDownloadPath(downloadPath, download.Torrent!, download);
Log($"Deleting {filePath}", download, download.Torrent); if (filePath != null)
{
Log($"Deleting {filePath}", download, download.Torrent);
await FileHelper.Delete(filePath); await FileHelper.Delete(filePath);
}
Log($"Resetting", download, download.Torrent); Log($"Resetting", download, download.Torrent);
@ -510,7 +513,7 @@ public class Torrents
await _torrentData.UpdateComplete(download.TorrentId, null, null, false); await _torrentData.UpdateComplete(download.TorrentId, null, null, false);
} }
public async Task UpdateComplete(Guid torrentId, String error, DateTimeOffset datetime, Boolean retry) public async Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset datetime, Boolean retry)
{ {
await _torrentData.UpdateComplete(torrentId, error, datetime, retry); await _torrentData.UpdateComplete(torrentId, error, datetime, retry);
} }
@ -542,7 +545,7 @@ public class Torrents
await _torrentData.UpdateError(torrentId, error); await _torrentData.UpdateError(torrentId, error);
} }
public async Task<Torrent> GetById(Guid torrentId) public async Task<Torrent?> GetById(Guid torrentId)
{ {
var torrent = await _torrentData.GetById(torrentId); var torrent = await _torrentData.GetById(torrentId);
@ -630,6 +633,12 @@ public class Torrents
} }
var torrent = await _torrentData.GetById(torrentId); var torrent = await _torrentData.GetById(torrentId);
if (torrent == null)
{
throw new Exception($"Cannot find Torrent with ID {torrentId}");
}
var downloads = await _downloads.GetForTorrent(torrentId); var downloads = await _downloads.GetForTorrent(torrentId);
var fileName = Settings.Get.General.RunOnTorrentCompleteFileName; var fileName = Settings.Get.General.RunOnTorrentCompleteFileName;
@ -638,7 +647,7 @@ public class Torrents
Log($"Parsing external program {fileName} with arguments {arguments}", torrent); Log($"Parsing external program {fileName} with arguments {arguments}", torrent);
var downloadPath = DownloadPath(torrent); var downloadPath = DownloadPath(torrent);
var torrentPath = Path.Combine(downloadPath, torrent.RdName); var torrentPath = Path.Combine(downloadPath, torrent.RdName ?? "Unknown");
arguments = arguments.Replace("%N", $"\"{torrent.RdName}\""); arguments = arguments.Replace("%N", $"\"{torrent.RdName}\"");
arguments = arguments.Replace("%L", $"\"{torrent.Category}\""); arguments = arguments.Replace("%L", $"\"{torrent.Category}\"");
@ -646,7 +655,7 @@ public class Torrents
arguments = arguments.Replace("%R", $"\"{downloadPath}\""); arguments = arguments.Replace("%R", $"\"{downloadPath}\"");
arguments = arguments.Replace("%D", $"\"{torrentPath}\""); arguments = arguments.Replace("%D", $"\"{torrentPath}\"");
arguments = arguments.Replace("%C", downloads.Count.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", "")); arguments = arguments.Replace("%C", downloads.Count.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", ""));
arguments = arguments.Replace("%Z", torrent.RdSize.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", "")); arguments = arguments.Replace("%Z", torrent.RdSize?.ToString(CultureInfo.InvariantCulture).Replace(",", "").Replace(".", ""));
arguments = arguments.Replace("%I", torrent.Hash); arguments = arguments.Replace("%I", torrent.Hash);
Log($"Executing external program {fileName} with arguments {arguments}", torrent); Log($"Executing external program {fileName} with arguments {arguments}", torrent);
@ -707,7 +716,7 @@ public class Torrents
} }
} }
private async Task UpdateTorrentClientData(Torrent torrent, TorrentClientTorrent torrentClientTorrent = null) private async Task UpdateTorrentClientData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent = null)
{ {
try try
{ {
@ -736,7 +745,7 @@ public class Torrents
} }
} }
private void Log(String message, Data.Models.Data.Download download, Torrent torrent) private void Log(String message, Data.Models.Data.Download? download, Torrent? torrent)
{ {
if (download != null) if (download != null)
{ {
@ -751,7 +760,7 @@ public class Torrents
_logger.LogDebug(message); _logger.LogDebug(message);
} }
private void Log(String message, Torrent torrent = null) private void Log(String message, Torrent? torrent = null)
{ {
if (torrent != null) if (torrent != null)
{ {

View file

@ -10,7 +10,7 @@ public class UnpackClient
{ {
public Boolean Finished { get; private set; } public Boolean Finished { get; private set; }
public String Error { get; private set; } public String? Error { get; private set; }
public Int64 BytesTotal { get; private set; } public Int64 BytesTotal { get; private set; }
public Int64 BytesDone { get; private set; } public Int64 BytesDone { get; private set; }
@ -21,14 +21,14 @@ public class UnpackClient
private Boolean _cancelled; private Boolean _cancelled;
private RarArchiveEntry _rarCurrentEntry; private RarArchiveEntry? _rarCurrentEntry;
private Dictionary<String, Int64> _rarfileStatus; private Dictionary<String, Int64>? _rarfileStatus;
public UnpackClient(Download download, String destinationPath) public UnpackClient(Download download, String destinationPath)
{ {
_download = download; _download = download;
_destinationPath = destinationPath; _destinationPath = destinationPath;
_torrent = download.Torrent; _torrent = download.Torrent ?? throw new Exception($"Torrent is null");
} }
public void Start() public void Start()
@ -91,7 +91,7 @@ public class UnpackClient
if (!entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"\")) && !entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"/"))) if (!entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"\")) && !entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"/")))
{ {
extractPath = Path.Combine(_destinationPath, _torrent.RdName); extractPath = Path.Combine(_destinationPath, _torrent.RdName!);
} }
if (entries.Any(m => m.Key.Contains(".r00"))) if (entries.Any(m => m.Key.Contains(".r00")))
@ -129,14 +129,14 @@ public class UnpackClient
} }
} }
private void ArchiveOnCompressedBytesRead(Object sender, CompressedBytesReadEventArgs e) private void ArchiveOnCompressedBytesRead(Object? sender, CompressedBytesReadEventArgs e)
{ {
if (_rarCurrentEntry == null) if (_rarCurrentEntry == null)
{ {
return; return;
} }
_rarfileStatus[_rarCurrentEntry.Key] = e.CompressedBytesRead; _rarfileStatus![_rarCurrentEntry.Key] = e.CompressedBytesRead;
BytesDone = _rarfileStatus.Sum(m => m.Value); BytesDone = _rarfileStatus.Sum(m => m.Value);
} }

View file

@ -1,7 +1,5 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.Internal;
using RdtClient.Service.Services; using RdtClient.Service.Services;
namespace RdtClient.Web.Controllers; namespace RdtClient.Web.Controllers;
@ -41,8 +39,13 @@ public class AuthController : Controller
[AllowAnonymous] [AllowAnonymous]
[Route("Create")] [Route("Create")]
[HttpPost] [HttpPost]
public async Task<ActionResult> Create([FromBody] AuthControllerLoginRequest request) public async Task<ActionResult> Create([FromBody] AuthControllerLoginRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
var user = await _authentication.GetUser(); var user = await _authentication.GetUser();
if (user != null) if (user != null)
@ -50,6 +53,11 @@ public class AuthController : Controller
return StatusCode(401); return StatusCode(401);
} }
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return BadRequest("Invalid UserName or Password");
}
var registerResult = await _authentication.Register(request.UserName, request.Password); var registerResult = await _authentication.Register(request.UserName, request.Password);
if (!registerResult.Succeeded) if (!registerResult.Succeeded)
@ -65,8 +73,13 @@ public class AuthController : Controller
[AllowAnonymous] [AllowAnonymous]
[Route("SetupProvider")] [Route("SetupProvider")]
[HttpPost] [HttpPost]
public async Task<ActionResult> SetupProvider([FromBody] AuthControllerSetupProviderRequest request) public async Task<ActionResult> SetupProvider([FromBody] AuthControllerSetupProviderRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
if (!String.IsNullOrEmpty(Settings.Get.Provider.ApiKey)) if (!String.IsNullOrEmpty(Settings.Get.Provider.ApiKey))
{ {
return StatusCode(401); return StatusCode(401);
@ -81,8 +94,13 @@ public class AuthController : Controller
[AllowAnonymous] [AllowAnonymous]
[Route("Login")] [Route("Login")]
[HttpPost] [HttpPost]
public async Task<ActionResult> Login([FromBody] AuthControllerLoginRequest request) public async Task<ActionResult> Login([FromBody] AuthControllerLoginRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
var user = await _authentication.GetUser(); var user = await _authentication.GetUser();
if (user == null) if (user == null)
@ -90,6 +108,11 @@ public class AuthController : Controller
return StatusCode(402); return StatusCode(402);
} }
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return BadRequest("Invalid credentials");
}
var result = await _authentication.Login(request.UserName, request.Password); var result = await _authentication.Login(request.UserName, request.Password);
if (!result.Succeeded) if (!result.Succeeded)
@ -110,8 +133,18 @@ public class AuthController : Controller
[Route("Update")] [Route("Update")]
[HttpPost] [HttpPost]
public async Task<ActionResult> Update([FromBody] AuthControllerUpdateRequest request) public async Task<ActionResult> Update([FromBody] AuthControllerUpdateRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return BadRequest("Invalid UserName or Password");
}
var updateResult = await _authentication.Update(request.UserName, request.Password); var updateResult = await _authentication.Update(request.UserName, request.Password);
if (!updateResult.Succeeded) if (!updateResult.Succeeded)
@ -125,18 +158,18 @@ public class AuthController : Controller
public class AuthControllerLoginRequest public class AuthControllerLoginRequest
{ {
public String UserName { get; set; } public String? UserName { get; set; }
public String Password { get; set; } public String? Password { get; set; }
} }
public class AuthControllerSetupProviderRequest public class AuthControllerSetupProviderRequest
{ {
public Int32 Provider { get; set; } public Int32 Provider { get; set; }
public String Token { get; set; } public String? Token { get; set; }
} }
public class AuthControllerUpdateRequest public class AuthControllerUpdateRequest
{ {
public String UserName { get; set; } public String? UserName { get; set; }
public String Password { get; set; } public String? Password { get; set; }
} }

View file

@ -26,6 +26,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> AuthLogin([FromQuery] QBAuthLoginRequest request) public async Task<ActionResult> AuthLogin([FromQuery] QBAuthLoginRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return Ok("Fails.");
}
var result = await _qBittorrent.AuthLogin(request.UserName, request.Password); var result = await _qBittorrent.AuthLogin(request.UserName, request.Password);
if (result) if (result)
@ -121,7 +126,7 @@ public class QBittorrentController : Controller
[HttpPost] [HttpPost]
public ActionResult<AppPreferences> AppDefaultSavePath() public ActionResult<AppPreferences> AppDefaultSavePath()
{ {
var result = _qBittorrent.AppDefaultSavePath(); var result = Settings.AppDefaultSavePath;
return Ok(result); return Ok(result);
} }
@ -154,6 +159,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult<IList<TorrentFileItem>>> TorrentsFiles([FromQuery] QBTorrentsHashRequest request) public async Task<ActionResult<IList<TorrentFileItem>>> TorrentsFiles([FromQuery] QBTorrentsHashRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hash))
{
return BadRequest();
}
var result = await _qBittorrent.TorrentFileContents(request.Hash); var result = await _qBittorrent.TorrentFileContents(request.Hash);
if (result == null) if (result == null)
@ -177,6 +187,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult<IList<TorrentInfo>>> TorrentsProperties([FromQuery] QBTorrentsHashRequest request) public async Task<ActionResult<IList<TorrentInfo>>> TorrentsProperties([FromQuery] QBTorrentsHashRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hash))
{
return BadRequest();
}
var result = await _qBittorrent.TorrentProperties(request.Hash); var result = await _qBittorrent.TorrentProperties(request.Hash);
if (result == null) if (result == null)
@ -200,6 +215,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsPause([FromQuery] QBTorrentsHashesRequest request) public async Task<ActionResult> TorrentsPause([FromQuery] QBTorrentsHashesRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hashes))
{
return BadRequest();
}
var hashes = request.Hashes.Split("|"); var hashes = request.Hashes.Split("|");
foreach (var hash in hashes) foreach (var hash in hashes)
@ -223,6 +243,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsResume([FromQuery] QBTorrentsHashesRequest request) public async Task<ActionResult> TorrentsResume([FromQuery] QBTorrentsHashesRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hashes))
{
return BadRequest();
}
var hashes = request.Hashes.Split("|"); var hashes = request.Hashes.Split("|");
foreach (var hash in hashes) foreach (var hash in hashes)
@ -255,6 +280,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsDelete([FromQuery] QBTorrentsDeleteRequest request) public async Task<ActionResult> TorrentsDelete([FromQuery] QBTorrentsDeleteRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hashes))
{
return BadRequest();
}
var hashes = request.Hashes.Split("|"); var hashes = request.Hashes.Split("|");
foreach (var hash in hashes) foreach (var hash in hashes)
@ -278,6 +308,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsAdd([FromQuery] QBTorrentsAddRequest request) public async Task<ActionResult> TorrentsAdd([FromQuery] QBTorrentsAddRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Urls))
{
return BadRequest();
}
var urls = request.Urls.Split("\n"); var urls = request.Urls.Split("\n");
foreach (var url in urls) foreach (var url in urls)
@ -294,7 +329,7 @@ public class QBittorrentController : Controller
} }
else else
{ {
throw new Exception($"Invalid torrent link format {url}"); return BadRequest($"Invalid torrent link format {url}");
} }
} }
@ -332,6 +367,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsSetCategory([FromQuery] QBTorrentsSetCategoryRequest request) public async Task<ActionResult> TorrentsSetCategory([FromQuery] QBTorrentsSetCategoryRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hashes))
{
return BadRequest();
}
var hashes = request.Hashes.Split("|"); var hashes = request.Hashes.Split("|");
foreach (var hash in hashes) foreach (var hash in hashes)
@ -412,6 +452,11 @@ public class QBittorrentController : Controller
[HttpGet] [HttpGet]
public async Task<ActionResult> TorrentsTopPrio([FromQuery] QBTorrentsHashesRequest request) public async Task<ActionResult> TorrentsTopPrio([FromQuery] QBTorrentsHashesRequest request)
{ {
if (String.IsNullOrWhiteSpace(request.Hashes))
{
return BadRequest();
}
var hashes = request.Hashes.Split("|"); var hashes = request.Hashes.Split("|");
foreach (var hash in hashes) foreach (var hash in hashes)
@ -451,51 +496,50 @@ public class QBittorrentController : Controller
public class QBAuthLoginRequest public class QBAuthLoginRequest
{ {
public String UserName { get; set; } public String? UserName { get; set; }
public String Password { get; set; } public String? Password { get; set; }
} }
public class QBTorrentsInfoRequest public class QBTorrentsInfoRequest
{ {
public String Category { get; set; } public String? Category { get; set; }
} }
public class QBTorrentsHashRequest public class QBTorrentsHashRequest
{ {
public String Hash { get; set; } public String? Hash { get; set; }
public String Category { get; set; }
} }
public class QBTorrentsDeleteRequest public class QBTorrentsDeleteRequest
{ {
public String Hashes { get; set; } public String? Hashes { get; set; }
public Boolean DeleteFiles { get; set; } public Boolean DeleteFiles { get; set; }
} }
public class QBTorrentsAddRequest public class QBTorrentsAddRequest
{ {
public String Urls { get; set; } public String? Urls { get; set; }
public String Category { get; set; } public String? Category { get; set; }
public Int32? Priority { get; set; } public Int32? Priority { get; set; }
} }
public class QBTorrentsSetCategoryRequest public class QBTorrentsSetCategoryRequest
{ {
public String Hashes { get; set; } public String? Hashes { get; set; }
public String Category { get; set; } public String? Category { get; set; }
} }
public class QBTorrentsCreateCategoryRequest public class QBTorrentsCreateCategoryRequest
{ {
public String Category { get; set; } public String? Category { get; set; }
} }
public class QBTorrentsRemoveCategoryRequest public class QBTorrentsRemoveCategoryRequest
{ {
public String Categories { get; set; } public String? Categories { get; set; }
} }
public class QBTorrentsHashesRequest public class QBTorrentsHashesRequest
{ {
public String Hashes { get; set; } public String? Hashes { get; set; }
} }

View file

@ -1,7 +1,13 @@
using Microsoft.AspNetCore.Authorization; using System.Diagnostics;
using Aria2NET;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RdtClient.Data.Data;
using RdtClient.Data.Models.Data;
using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Internal;
using RdtClient.Service.Helpers;
using RdtClient.Service.Services; using RdtClient.Service.Services;
using RdtClient.Service.Services.Downloaders;
namespace RdtClient.Web.Controllers; namespace RdtClient.Web.Controllers;
@ -22,14 +28,19 @@ public class SettingsController : Controller
[Route("")] [Route("")]
public ActionResult Get() public ActionResult Get()
{ {
var result = _settings.GetAll(); var result = SettingData.GetAll();
return Ok(result); return Ok(result);
} }
[HttpPut] [HttpPut]
[Route("")] [Route("")]
public async Task<ActionResult> Update([FromBody] IList<SettingProperty> settings) public async Task<ActionResult> Update([FromBody] IList<SettingProperty>? settings)
{ {
if (settings == null)
{
return BadRequest();
}
await _settings.Update(settings); await _settings.Update(settings);
return Ok(); return Ok();
@ -45,9 +56,30 @@ public class SettingsController : Controller
[HttpPost] [HttpPost]
[Route("TestPath")] [Route("TestPath")]
public async Task<ActionResult> TestPath([FromBody] SettingsControllerTestPathRequest request) public async Task<ActionResult> TestPath([FromBody] SettingsControllerTestPathRequest? request)
{ {
await _settings.TestPath(request.Path); if (request == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(request.Path))
{
return BadRequest("Invalid path");
}
var path = request.Path.TrimEnd('/').TrimEnd('\\');
if (!Directory.Exists(path))
{
throw new Exception($"Path {path} does not exist");
}
var testFile = $"{path}/test.txt";
await System.IO.File.WriteAllTextAsync(testFile, "RealDebridClient Test File, you can remove this file.");
await FileHelper.Delete(testFile);
return Ok(); return Ok();
} }
@ -56,25 +88,120 @@ public class SettingsController : Controller
[Route("TestDownloadSpeed")] [Route("TestDownloadSpeed")]
public async Task<ActionResult> TestDownloadSpeed(CancellationToken cancellationToken) public async Task<ActionResult> TestDownloadSpeed(CancellationToken cancellationToken)
{ {
var downloadSpeed = await _settings.TestDownloadSpeed(cancellationToken); var downloadPath = Settings.Get.DownloadClient.DownloadPath;
return Ok(downloadSpeed); var testFilePath = Path.Combine(downloadPath, "testDefault.rar");
await FileHelper.Delete(testFilePath);
var download = new Download
{
Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar",
Torrent = new Torrent
{
RdName = ""
}
};
var downloadClient = new DownloadClient(download, download.Torrent, downloadPath);
await downloadClient.Start(Settings.Get);
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
while (!downloadClient.Finished)
{
await Task.Delay(1000, CancellationToken.None);
if (cancellationToken.IsCancellationRequested)
{
await downloadClient.Cancel();
}
if (downloadClient.Downloader is Aria2cDownloader aria2Downloader)
{
var aria2NetClient = new Aria2NetClient(Settings.Get.DownloadClient.Aria2cUrl, Settings.Get.DownloadClient.Aria2cSecret, httpClient, 1);
var allDownloads = await aria2NetClient.TellAllAsync(cancellationToken);
await aria2Downloader.Update(allDownloads);
}
if (downloadClient.BytesDone > 1024 * 1024 * 50)
{
await downloadClient.Cancel();
break;
}
}
await FileHelper.Delete(testFilePath);
await Settings.Clean();
return Ok(downloadClient.Speed);
} }
[HttpGet] [HttpGet]
[Route("TestWriteSpeed")] [Route("TestWriteSpeed")]
public async Task<ActionResult> TestWriteSpeed() public async Task<ActionResult> TestWriteSpeed()
{ {
var writeSpeed = await _settings.TestWriteSpeed(); var downloadPath = Settings.Get.DownloadClient.DownloadPath;
var testFilePath = Path.Combine(downloadPath, "test.tmp");
await FileHelper.Delete(testFilePath);
const Int32 testFileSize = 64 * 1024 * 1024;
var watch = new Stopwatch();
watch.Start();
var rnd = new Random();
await using var fileStream = new FileStream(testFilePath, FileMode.Create, FileAccess.Write, FileShare.Write);
var buffer = new Byte[64 * 1024];
while (fileStream.Length < testFileSize)
{
rnd.NextBytes(buffer);
await fileStream.WriteAsync(buffer.AsMemory(0, buffer.Length));
}
watch.Stop();
var writeSpeed = fileStream.Length / watch.Elapsed.TotalSeconds;
fileStream.Close();
await FileHelper.Delete(testFilePath);
return Ok(writeSpeed); return Ok(writeSpeed);
} }
[HttpPost] [HttpPost]
[Route("TestAria2cConnection")] [Route("TestAria2cConnection")]
public async Task<ActionResult<String>> TestAria2cConnection([FromBody] SettingsControllerTestAria2cConnectionRequest request) public async Task<ActionResult<String>> TestAria2cConnection([FromBody] SettingsControllerTestAria2cConnectionRequest? request)
{ {
var version = await _settings.GetAria2cVersion(request.Url, request.Secret); if (request == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(request.Url))
{
return BadRequest("Invalid Url");
}
var client = new Aria2NetClient(request.Url, request.Secret);
var version = await client.GetVersionAsync();
return Ok(version); return Ok(version);
} }
@ -82,11 +209,11 @@ public class SettingsController : Controller
public class SettingsControllerTestPathRequest public class SettingsControllerTestPathRequest
{ {
public String Path { get; set; } public String? Path { get; set; }
} }
public class SettingsControllerTestAria2cConnectionRequest public class SettingsControllerTestAria2cConnectionRequest
{ {
public String Url { get; set; } public String? Url { get; set; }
public String Secret { get; set; } public String? Secret { get; set; }
} }

View file

@ -67,22 +67,25 @@ public class TorrentsController : Controller
[HttpPost] [HttpPost]
[Route("UploadFile")] [Route("UploadFile")]
public async Task<ActionResult> UploadFile([FromForm] IFormFile file, public async Task<ActionResult> UploadFile([FromForm] IFormFile? file,
[ModelBinder(BinderType = typeof(JsonModelBinder))] [ModelBinder(BinderType = typeof(JsonModelBinder))]
TorrentControllerUploadFileRequest formData) TorrentControllerUploadFileRequest? formData)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
var errors = ModelState.Select(x => x.Value.Errors) var errors = ModelState.Select(x => x.Value?.Errors.Select(m => m.ErrorMessage)).ToList();
.Where(y => y.Count > 0)
.ToList();
return BadRequest(errors); return BadRequest(errors);
} }
if (file == null || file.Length <= 0) if (file == null || file.Length <= 0)
{ {
throw new Exception("Invalid torrent file"); return BadRequest("Invalid torrent file");
}
if (formData?.Torrent == null)
{
return BadRequest("Invalid Torrent");
} }
var fileStream = file.OpenReadStream(); var fileStream = file.OpenReadStream();
@ -100,17 +103,29 @@ public class TorrentsController : Controller
[HttpPost] [HttpPost]
[Route("UploadMagnet")] [Route("UploadMagnet")]
public async Task<ActionResult> UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest request) public async Task<ActionResult> UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
var errors = ModelState.Select(x => x.Value.Errors) var errors = ModelState.Select(x => x.Value?.Errors.Select(m => m.ErrorMessage)).ToList();
.Where(y => y.Count > 0)
.ToList();
return BadRequest(errors); return BadRequest(errors);
} }
if (String.IsNullOrEmpty(request.MagnetLink))
{
return BadRequest("Invalid magnet link");
}
if (request.Torrent == null)
{
return BadRequest("Invalid Torrent");
}
await _torrents.UploadMagnet(request.MagnetLink, request.Torrent); await _torrents.UploadMagnet(request.MagnetLink, request.Torrent);
return Ok(); return Ok();
@ -118,11 +133,11 @@ public class TorrentsController : Controller
[HttpPost] [HttpPost]
[Route("CheckFiles")] [Route("CheckFiles")]
public async Task<ActionResult> CheckFiles([FromForm] IFormFile file) public async Task<ActionResult> CheckFiles([FromForm] IFormFile? file)
{ {
if (file == null || file.Length <= 0) if (file == null || file.Length <= 0)
{ {
throw new Exception("Invalid torrent file"); return BadRequest("Invalid torrent file");
} }
var fileStream = file.OpenReadStream(); var fileStream = file.OpenReadStream();
@ -142,8 +157,13 @@ public class TorrentsController : Controller
[HttpPost] [HttpPost]
[Route("CheckFilesMagnet")] [Route("CheckFilesMagnet")]
public async Task<ActionResult> CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest request) public async Task<ActionResult> CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
var magnet = MagnetLink.Parse(request.MagnetLink); var magnet = MagnetLink.Parse(request.MagnetLink);
var result = await _torrents.GetAvailableFiles(magnet.InfoHash.ToHex()); var result = await _torrents.GetAvailableFiles(magnet.InfoHash.ToHex());
@ -153,8 +173,13 @@ public class TorrentsController : Controller
[HttpPost] [HttpPost]
[Route("Delete/{torrentId:guid}")] [Route("Delete/{torrentId:guid}")]
public async Task<ActionResult> Delete(Guid torrentId, [FromBody] TorrentControllerDeleteRequest request) public async Task<ActionResult> Delete(Guid torrentId, [FromBody] TorrentControllerDeleteRequest? request)
{ {
if (request == null)
{
return BadRequest();
}
await _torrents.Delete(torrentId, request.DeleteData, request.DeleteRdTorrent, request.DeleteLocalFiles); await _torrents.Delete(torrentId, request.DeleteData, request.DeleteRdTorrent, request.DeleteLocalFiles);
return Ok(); return Ok();
@ -181,8 +206,13 @@ public class TorrentsController : Controller
[HttpPut] [HttpPut]
[Route("Update")] [Route("Update")]
public async Task<ActionResult> Update([FromBody] Torrent torrent) public async Task<ActionResult> Update([FromBody] Torrent? torrent)
{ {
if (torrent == null)
{
return BadRequest();
}
await _torrents.Update(torrent); await _torrents.Update(torrent);
return Ok(); return Ok();
@ -191,13 +221,13 @@ public class TorrentsController : Controller
public class TorrentControllerUploadFileRequest public class TorrentControllerUploadFileRequest
{ {
public Torrent Torrent { get; set; } public Torrent? Torrent { get; set; }
} }
public class TorrentControllerUploadMagnetRequest public class TorrentControllerUploadMagnetRequest
{ {
public String MagnetLink { get; set; } public String? MagnetLink { get; set; }
public Torrent Torrent { get; set; } public Torrent? Torrent { get; set; }
} }
public class TorrentControllerDeleteRequest public class TorrentControllerDeleteRequest
@ -209,5 +239,5 @@ public class TorrentControllerDeleteRequest
public class TorrentControllerCheckFilesRequest public class TorrentControllerCheckFilesRequest
{ {
public String MagnetLink { get; set; } public String? MagnetLink { get; set; }
} }

View file

@ -32,17 +32,20 @@ builder.WebHost.ConfigureKestrel(options =>
options.ListenAnyIP(appSettings.Port); options.ListenAnyIP(appSettings.Port);
}); });
builder.Host.UseSerilog((_, lc) => lc.Enrich.FromLogContext() if (appSettings.Logging?.File?.Path != null)
.Enrich.WithExceptionDetails() {
.WriteTo.File(appSettings.Logging.File.Path, builder.Host.UseSerilog((_, lc) => lc.Enrich.FromLogContext()
rollOnFileSizeLimit: true, .Enrich.WithExceptionDetails()
fileSizeLimitBytes: appSettings.Logging.File.FileSizeLimitBytes, .WriteTo.File(appSettings.Logging.File.Path,
retainedFileCountLimit: appSettings.Logging.File.MaxRollingFiles, rollOnFileSizeLimit: true,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}") fileSizeLimitBytes: appSettings.Logging.File.FileSizeLimitBytes,
.WriteTo.Console() retainedFileCountLimit: appSettings.Logging.File.MaxRollingFiles,
.MinimumLevel.ControlledBy(Settings.LoggingLevelSwitch) outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}")
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .WriteTo.Console()
.MinimumLevel.Override("System.Net.Http", LogEventLevel.Warning)); .MinimumLevel.ControlledBy(Settings.LoggingLevelSwitch)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http", LogEventLevel.Warning));
}
Serilog.Debugging.SelfLog.Enable(msg => Serilog.Debugging.SelfLog.Enable(msg =>
{ {

View file

@ -5,7 +5,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId> <UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
<Version>2.0.12</Version> <Version>2.0.12</Version>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
@ -29,15 +29,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.4" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.4"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.4" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.5" />
<PackageReference Include="Serilog" Version="2.11.0" /> <PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

View file

@ -179,6 +179,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QB/@EntryIndexedValue">QB</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QB/@EntryIndexedValue">QB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=US/@EntryIndexedValue">US</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=US/@EntryIndexedValue">US</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XML/@EntryIndexedValue">XML</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XML/@EntryIndexedValue">XML</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XML/@EntryIndexedValue">Aria2c</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>