mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-03-04 14:27:52 -05:00
combine arr configs #1
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using Common.Configuration.Arr;
|
||||
using Data.Models.Configuration.Arr;
|
||||
|
||||
namespace Data.Models.Arr;
|
||||
|
||||
|
||||
25
code/Data/Models/Configuration/Arr/ArrConfig.cs
Normal file
25
code/Data/Models/Configuration/Arr/ArrConfig.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Configuration;
|
||||
using Data.Enums;
|
||||
|
||||
namespace Data.Models.Configuration.Arr;
|
||||
|
||||
public class ArrConfig : IConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public required InstanceType Type { get; set; }
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public short FailedImportMaxStrikes { get; set; } = -1;
|
||||
|
||||
public List<ArrInstance> Instances { get; set; } = [];
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
}
|
||||
}
|
||||
23
code/Data/Models/Configuration/Arr/ArrInstance.cs
Normal file
23
code/Data/Models/Configuration/Arr/ArrInstance.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Attributes;
|
||||
|
||||
namespace Data.Models.Configuration.Arr;
|
||||
|
||||
public sealed class ArrInstance
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public Guid ArrConfigId { get; set; }
|
||||
|
||||
public ArrConfig ArrConfig { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
|
||||
public required Uri Url { get; set; }
|
||||
|
||||
[SensitiveData]
|
||||
public required string ApiKey { get; set; }
|
||||
}
|
||||
8
code/Data/Models/Configuration/Arr/SonarrSearchType.cs
Normal file
8
code/Data/Models/Configuration/Arr/SonarrSearchType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Data.Models.Configuration.Arr;
|
||||
|
||||
public enum SonarrSearchType
|
||||
{
|
||||
Episode,
|
||||
Season,
|
||||
Series
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Configuration;
|
||||
using ValidationException = Common.Exceptions.ValidationException;
|
||||
|
||||
namespace Data.Models.Configuration.DownloadCleaner;
|
||||
|
||||
public sealed record CleanCategory : IConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Max ratio before removing a download.
|
||||
/// </summary>
|
||||
public required double MaxRatio { get; init; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Min number of hours to seed before removing a download, if the ratio has been met.
|
||||
/// </summary>
|
||||
public required double MinSeedTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of hours to seed before removing a download.
|
||||
/// </summary>
|
||||
public required double MaxSeedTime { get; init; } = -1;
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name.Trim()))
|
||||
{
|
||||
throw new ValidationException("Category name can not be empty");
|
||||
}
|
||||
|
||||
if (MaxRatio < 0 && MaxSeedTime < 0)
|
||||
{
|
||||
throw new ValidationException("Both max ratio and max seed time are disabled");
|
||||
}
|
||||
|
||||
if (MinSeedTime < 0)
|
||||
{
|
||||
throw new ValidationException("Min seed time can not be negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Configuration;
|
||||
using ValidationException = Common.Exceptions.ValidationException;
|
||||
|
||||
namespace Data.Models.Configuration.DownloadCleaner;
|
||||
|
||||
public sealed record DownloadCleanerConfig : IJobConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
|
||||
public bool Enabled { get; init; }
|
||||
|
||||
public string CronExpression { get; init; } = "0 0 * * * ?";
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether to use the CronExpression directly or convert from a user-friendly schedule
|
||||
/// </summary>
|
||||
public bool UseAdvancedScheduling { get; init; }
|
||||
|
||||
public List<CleanCategory> Categories { get; init; } = [];
|
||||
|
||||
public bool DeletePrivate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether unlinked download handling is enabled
|
||||
/// </summary>
|
||||
public bool UnlinkedEnabled { get; init; } = false;
|
||||
|
||||
public string UnlinkedTargetCategory { get; init; } = "cleanuparr-unlinked";
|
||||
|
||||
public bool UnlinkedUseTag { get; init; }
|
||||
|
||||
public string UnlinkedIgnoredRootDir { get; init; } = string.Empty;
|
||||
|
||||
public List<string> UnlinkedCategories { get; init; } = [];
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Categories.GroupBy(x => x.Name).Any(x => x.Count() > 1))
|
||||
{
|
||||
throw new ValidationException("duplicated clean categories found");
|
||||
}
|
||||
|
||||
Categories.ForEach(x => x.Validate());
|
||||
|
||||
// Only validate unlinked settings if unlinked handling is enabled
|
||||
if (!UnlinkedEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(UnlinkedTargetCategory))
|
||||
{
|
||||
throw new ValidationException("unlinked target category is required");
|
||||
}
|
||||
|
||||
if (UnlinkedCategories?.Count is null or 0)
|
||||
{
|
||||
throw new ValidationException("no unlinked categories configured");
|
||||
}
|
||||
|
||||
if (UnlinkedCategories.Contains(UnlinkedTargetCategory))
|
||||
{
|
||||
throw new ValidationException($"The unlinked target category should not be present in unlinked categories");
|
||||
}
|
||||
|
||||
if (UnlinkedCategories.Any(string.IsNullOrEmpty))
|
||||
{
|
||||
throw new ValidationException("empty unlinked category filter found");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(UnlinkedIgnoredRootDir) && !Directory.Exists(UnlinkedIgnoredRootDir))
|
||||
{
|
||||
throw new ValidationException($"{UnlinkedIgnoredRootDir} root directory does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
85
code/Data/Models/Configuration/DownloadClientConfig.cs
Normal file
85
code/Data/Models/Configuration/DownloadClientConfig.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using Common.Attributes;
|
||||
using Common.Enums;
|
||||
using Common.Exceptions;
|
||||
|
||||
namespace Common.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for a specific download client
|
||||
/// </summary>
|
||||
[Table("download_clients")]
|
||||
public sealed record DownloadClientConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this client
|
||||
/// </summary>
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this client is enabled
|
||||
/// </summary>
|
||||
public bool Enabled { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Friendly name for this client
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Type name of download client
|
||||
/// </summary>
|
||||
public required DownloadClientTypeName TypeName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of download client
|
||||
/// </summary>
|
||||
public required DownloadClientType Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Host address for the download client
|
||||
/// </summary>
|
||||
public Uri? Host { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Username for authentication
|
||||
/// </summary>
|
||||
[SensitiveData]
|
||||
public string? Username { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Password for authentication
|
||||
/// </summary>
|
||||
[SensitiveData]
|
||||
public string? Password { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The base URL path component, used by clients like Transmission and Deluge
|
||||
/// </summary>
|
||||
public string? UrlBase { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The computed full URL for the client
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public Uri Url => new($"{Host?.ToString().TrimEnd('/')}/{UrlBase.TrimStart('/').TrimEnd('/')}");
|
||||
|
||||
/// <summary>
|
||||
/// Validates the configuration
|
||||
/// </summary>
|
||||
public void Validate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Name))
|
||||
{
|
||||
throw new ValidationException($"Client name cannot be empty for client ID: {Id}");
|
||||
}
|
||||
|
||||
if (Host is null && TypeName is not DownloadClientTypeName.Usenet)
|
||||
{
|
||||
throw new ValidationException($"Host cannot be empty for client ID: {Id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
41
code/Data/Models/Configuration/General/GeneralConfig.cs
Normal file
41
code/Data/Models/Configuration/General/GeneralConfig.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Configuration;
|
||||
using Common.Enums;
|
||||
using Serilog.Events;
|
||||
using ValidationException = Common.Exceptions.ValidationException;
|
||||
|
||||
namespace Data.Models.Configuration.General;
|
||||
|
||||
public sealed record GeneralConfig : IConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public bool DryRun { get; set; }
|
||||
|
||||
public ushort HttpMaxRetries { get; set; }
|
||||
|
||||
public ushort HttpTimeout { get; set; } = 100;
|
||||
|
||||
public CertificateValidationType HttpCertificateValidation { get; set; } = CertificateValidationType.Enabled;
|
||||
|
||||
public bool SearchEnabled { get; set; } = true;
|
||||
|
||||
public ushort SearchDelay { get; set; } = 30;
|
||||
|
||||
public LogEventLevel LogLevel { get; set; } = LogEventLevel.Information;
|
||||
|
||||
public string EncryptionKey { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
public List<string> IgnoredDownloads { get; set; } = [];
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (HttpTimeout is 0)
|
||||
{
|
||||
throw new ValidationException("HTTP_TIMEOUT must be greater than 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
6
code/Data/Models/Configuration/IConfig.cs
Normal file
6
code/Data/Models/Configuration/IConfig.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Common.Configuration;
|
||||
|
||||
public interface IConfig
|
||||
{
|
||||
void Validate();
|
||||
}
|
||||
13
code/Data/Models/Configuration/IJobConfig.cs
Normal file
13
code/Data/Models/Configuration/IJobConfig.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Common.Configuration;
|
||||
|
||||
public interface IJobConfig : IConfig
|
||||
{
|
||||
bool Enabled { get; init; }
|
||||
|
||||
string CronExpression { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether to use the CronExpression directly (true) or convert from JobSchedule (false)
|
||||
/// </summary>
|
||||
bool UseAdvancedScheduling { get; init; }
|
||||
}
|
||||
23
code/Data/Models/Configuration/Notification/AppriseConfig.cs
Normal file
23
code/Data/Models/Configuration/Notification/AppriseConfig.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Data.Models.Configuration.Notification;
|
||||
|
||||
public sealed record AppriseConfig : NotificationConfig
|
||||
{
|
||||
public Uri? Url { get; init; }
|
||||
|
||||
public string? Key { get; init; }
|
||||
|
||||
public override bool IsValid()
|
||||
{
|
||||
if (Url is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Key?.Trim()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Data.Models.Configuration.Notification;
|
||||
|
||||
public sealed record NotifiarrConfig : NotificationConfig
|
||||
{
|
||||
public string? ApiKey { get; init; }
|
||||
|
||||
public string? ChannelId { get; init; }
|
||||
|
||||
public override bool IsValid()
|
||||
{
|
||||
if (string.IsNullOrEmpty(ApiKey?.Trim()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ChannelId?.Trim()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Configuration.Notification;
|
||||
|
||||
public abstract record NotificationConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
|
||||
public bool OnFailedImportStrike { get; init; }
|
||||
|
||||
public bool OnStalledStrike { get; init; }
|
||||
|
||||
public bool OnSlowStrike { get; init; }
|
||||
|
||||
public bool OnQueueItemDeleted { get; init; }
|
||||
|
||||
public bool OnDownloadCleaned { get; init; }
|
||||
|
||||
public bool OnCategoryChanged { get; init; }
|
||||
|
||||
public bool IsEnabled =>
|
||||
OnFailedImportStrike ||
|
||||
OnStalledStrike ||
|
||||
OnSlowStrike ||
|
||||
OnQueueItemDeleted ||
|
||||
OnDownloadCleaned ||
|
||||
OnCategoryChanged;
|
||||
|
||||
public abstract bool IsValid();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
/// <summary>
|
||||
/// Settings for a blocklist
|
||||
/// </summary>
|
||||
[ComplexType]
|
||||
public sealed record BlocklistSettings
|
||||
{
|
||||
public BlocklistType BlocklistType { get; init; }
|
||||
|
||||
public string? BlocklistPath { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
public enum BlocklistType
|
||||
{
|
||||
Blacklist,
|
||||
Whitelist
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
[ComplexType]
|
||||
public sealed record ContentBlockerConfig
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
|
||||
public bool IgnorePrivate { get; init; }
|
||||
|
||||
public bool DeletePrivate { get; init; }
|
||||
|
||||
public BlocklistSettings Sonarr { get; init; } = new();
|
||||
|
||||
public BlocklistSettings Radarr { get; init; } = new();
|
||||
|
||||
public BlocklistSettings Lidarr { get; init; } = new();
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Exceptions;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
[ComplexType]
|
||||
public sealed record FailedImportConfig
|
||||
{
|
||||
public ushort MaxStrikes { get; init; }
|
||||
|
||||
public bool IgnorePrivate { get; init; }
|
||||
|
||||
public bool DeletePrivate { get; init; }
|
||||
|
||||
public IReadOnlyList<string> IgnoredPatterns { get; init; } = [];
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (MaxStrikes is > 0 and < 3)
|
||||
{
|
||||
throw new ValidationException("the minimum value for failed imports max strikes must be 3");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Configuration;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
public sealed record QueueCleanerConfig : IJobConfig
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
|
||||
public bool Enabled { get; init; }
|
||||
|
||||
public string CronExpression { get; init; } = "0 0/5 * * * ?";
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether to use the CronExpression directly or convert from a user-friendly schedule
|
||||
/// </summary>
|
||||
public bool UseAdvancedScheduling { get; init; } = false;
|
||||
|
||||
public FailedImportConfig FailedImport { get; init; } = new();
|
||||
|
||||
public StalledConfig Stalled { get; init; } = new();
|
||||
|
||||
public SlowConfig Slow { get; init; } = new();
|
||||
|
||||
public ContentBlockerConfig ContentBlocker { get; init; } = new();
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
FailedImport.Validate();
|
||||
Stalled.Validate();
|
||||
Slow.Validate();
|
||||
ContentBlocker.Validate();
|
||||
}
|
||||
}
|
||||
65
code/Data/Models/Configuration/QueueCleaner/SlowConfig.cs
Normal file
65
code/Data/Models/Configuration/QueueCleaner/SlowConfig.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using Common.CustomDataTypes;
|
||||
using Common.Exceptions;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
[ComplexType]
|
||||
public sealed record SlowConfig
|
||||
{
|
||||
public ushort MaxStrikes { get; init; }
|
||||
|
||||
public bool ResetStrikesOnProgress { get; init; }
|
||||
|
||||
public bool IgnorePrivate { get; init; }
|
||||
|
||||
public bool DeletePrivate { get; init; }
|
||||
|
||||
public string MinSpeed { get; init; } = string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public ByteSize MinSpeedByteSize => string.IsNullOrEmpty(MinSpeed) ? new ByteSize(0) : ByteSize.Parse(MinSpeed);
|
||||
|
||||
public double MaxTime { get; init; }
|
||||
|
||||
public string IgnoreAboveSize { get; init; } = string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public ByteSize? IgnoreAboveSizeByteSize => string.IsNullOrEmpty(IgnoreAboveSize) ? null : ByteSize.Parse(IgnoreAboveSize);
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (MaxStrikes is > 0 and < 3)
|
||||
{
|
||||
throw new ValidationException("the minimum value for slow max strikes must be 3");
|
||||
}
|
||||
|
||||
if (MaxStrikes > 0)
|
||||
{
|
||||
bool isSpeedSet = !string.IsNullOrEmpty(MinSpeed);
|
||||
|
||||
if (isSpeedSet && ByteSize.TryParse(MinSpeed, out _) is false)
|
||||
{
|
||||
throw new ValidationException("invalid value for slow min speed");
|
||||
}
|
||||
|
||||
if (MaxTime < 0)
|
||||
{
|
||||
throw new ValidationException("invalid value for slow max time");
|
||||
}
|
||||
|
||||
if (!isSpeedSet && MaxTime is 0)
|
||||
{
|
||||
throw new ValidationException("either slow min speed or slow max time must be set");
|
||||
}
|
||||
|
||||
bool isIgnoreAboveSizeSet = !string.IsNullOrEmpty(IgnoreAboveSize);
|
||||
|
||||
if (isIgnoreAboveSizeSet && ByteSize.TryParse(IgnoreAboveSize, out _) is false)
|
||||
{
|
||||
throw new ValidationException($"invalid value for slow ignore above size: {IgnoreAboveSize}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
code/Data/Models/Configuration/QueueCleaner/StalledConfig.cs
Normal file
31
code/Data/Models/Configuration/QueueCleaner/StalledConfig.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Common.Exceptions;
|
||||
|
||||
namespace Data.Models.Configuration.QueueCleaner;
|
||||
|
||||
[ComplexType]
|
||||
public sealed record StalledConfig
|
||||
{
|
||||
public ushort MaxStrikes { get; init; }
|
||||
|
||||
public bool ResetStrikesOnProgress { get; init; }
|
||||
|
||||
public bool IgnorePrivate { get; init; }
|
||||
|
||||
public bool DeletePrivate { get; init; }
|
||||
|
||||
public ushort DownloadingMetadataMaxStrikes { get; init; }
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (MaxStrikes is > 0 and < 3)
|
||||
{
|
||||
throw new ValidationException("the minimum value for stalled max strikes must be 3");
|
||||
}
|
||||
|
||||
if (DownloadingMetadataMaxStrikes is > 0 and < 3)
|
||||
{
|
||||
throw new ValidationException("the minimum value for downloading metadata max strikes must be 3");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Common.Configuration.Arr;
|
||||
using Data.Models.Configuration.Arr;
|
||||
|
||||
namespace Data.Models.Sonarr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user