diff --git a/code/Common/Configuration/DownloadCleaner/DownloadCleanerConfig.cs b/code/Common/Configuration/DownloadCleaner/DownloadCleanerConfig.cs
index 9641edc2..689ca73f 100644
--- a/code/Common/Configuration/DownloadCleaner/DownloadCleanerConfig.cs
+++ b/code/Common/Configuration/DownloadCleaner/DownloadCleanerConfig.cs
@@ -1,9 +1,13 @@
-using Common.Exceptions;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using ValidationException = Common.Exceptions.ValidationException;
namespace Common.Configuration.DownloadCleaner;
public sealed record DownloadCleanerConfig : IJobConfig
{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; } = Guid.NewGuid();
public bool Enabled { get; init; }
diff --git a/code/Common/Configuration/DownloadClient.cs b/code/Common/Configuration/DownloadClientConfig.cs
similarity index 86%
rename from code/Common/Configuration/DownloadClient.cs
rename to code/Common/Configuration/DownloadClientConfig.cs
index 565863e6..033f3b29 100644
--- a/code/Common/Configuration/DownloadClient.cs
+++ b/code/Common/Configuration/DownloadClientConfig.cs
@@ -9,7 +9,8 @@ namespace Common.Configuration;
///
/// Configuration for a specific download client
///
-public sealed record DownloadClient
+[Table("download_clients")]
+public sealed record DownloadClientConfig
{
///
/// Unique identifier for this client
@@ -27,6 +28,11 @@ public sealed record DownloadClient
///
public required string Name { get; init; }
+ ///
+ /// Type name of download client
+ ///
+ public required DownloadClientTypeName TypeName { get; init; }
+
///
/// Type of download client
///
@@ -52,12 +58,12 @@ public sealed record DownloadClient
///
/// The base URL path component, used by clients like Transmission and Deluge
///
- [JsonProperty("url_base")]
public string? UrlBase { get; init; }
///
/// The computed full URL for the client
///
+ [NotMapped]
public Uri Url => new($"{Host?.ToString().TrimEnd('/')}/{UrlBase.TrimStart('/').TrimEnd('/')}");
///
@@ -70,7 +76,7 @@ public sealed record DownloadClient
throw new ValidationException($"Client name cannot be empty for client ID: {Id}");
}
- if (Host is null && Type is not DownloadClientType.Usenet)
+ if (Host is null && TypeName is not DownloadClientTypeName.Usenet)
{
throw new ValidationException($"Host cannot be empty for client ID: {Id}");
}
diff --git a/code/Common/Configuration/Notification/NotificationConfig.cs b/code/Common/Configuration/Notification/NotificationConfig.cs
index 781dda0c..9032df31 100644
--- a/code/Common/Configuration/Notification/NotificationConfig.cs
+++ b/code/Common/Configuration/Notification/NotificationConfig.cs
@@ -1,7 +1,14 @@
-namespace Common.Configuration.Notification;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Common.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; }
diff --git a/code/Common/Configuration/QueueCleaner/QueueCleanerConfig.cs b/code/Common/Configuration/QueueCleaner/QueueCleanerConfig.cs
index 33da03a7..31f0ca0a 100644
--- a/code/Common/Configuration/QueueCleaner/QueueCleanerConfig.cs
+++ b/code/Common/Configuration/QueueCleaner/QueueCleanerConfig.cs
@@ -1,9 +1,12 @@
using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
namespace Common.Configuration.QueueCleaner;
public sealed record QueueCleanerConfig : IJobConfig
{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; } = Guid.NewGuid();
public bool Enabled { get; init; }
diff --git a/code/Common/Enums/DownloadClientType.cs b/code/Common/Enums/DownloadClientType.cs
index fccdc6bf..95bdf11e 100644
--- a/code/Common/Enums/DownloadClientType.cs
+++ b/code/Common/Enums/DownloadClientType.cs
@@ -2,8 +2,6 @@
public enum DownloadClientType
{
- QBittorrent,
- Deluge,
- Transmission,
- Usenet,
+ Torrent,
+ Usenet
}
\ No newline at end of file
diff --git a/code/Common/Enums/DownloadClientTypeName.cs b/code/Common/Enums/DownloadClientTypeName.cs
new file mode 100644
index 00000000..d79c5ff2
--- /dev/null
+++ b/code/Common/Enums/DownloadClientTypeName.cs
@@ -0,0 +1,9 @@
+namespace Common.Enums;
+
+public enum DownloadClientTypeName
+{
+ QBittorrent,
+ Deluge,
+ Transmission,
+ Usenet,
+}
\ No newline at end of file
diff --git a/code/Data/Data.csproj b/code/Data/Data.csproj
index 293ddcae..c20c4920 100644
--- a/code/Data/Data.csproj
+++ b/code/Data/Data.csproj
@@ -1,4 +1,4 @@
-
+
net9.0
@@ -17,4 +17,8 @@
+
+
+
+
diff --git a/code/Data/DataContext.cs b/code/Data/DataContext.cs
index 02926e95..fff2eed6 100644
--- a/code/Data/DataContext.cs
+++ b/code/Data/DataContext.cs
@@ -14,9 +14,11 @@ namespace Data;
///
public class DataContext : DbContext
{
+ public static SemaphoreSlim Lock { get; } = new(1, 1);
+
public DbSet GeneralConfigs { get; set; }
- public DbSet DownloadClients { get; set; }
+ public DbSet DownloadClients { get; set; }
public DbSet QueueCleanerConfigs { get; set; }
@@ -72,7 +74,6 @@ public class DataContext : DbContext
}
}
- modelBuilder.Entity().HasData(new QueueCleanerConfig());
modelBuilder.Entity().HasData(new DownloadCleanerConfig());
modelBuilder.Entity().HasData(new GeneralConfig());
modelBuilder.Entity().HasData(new SonarrConfig());
diff --git a/code/Data/Migrations/Data/20250614213915_InitialData.Designer.cs b/code/Data/Migrations/Data/20250614213915_InitialData.Designer.cs
new file mode 100644
index 00000000..90d6080f
--- /dev/null
+++ b/code/Data/Migrations/Data/20250614213915_InitialData.Designer.cs
@@ -0,0 +1,713 @@
+//
+using System;
+using System.Collections.Generic;
+using Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Data.Migrations.Data
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20250614213915_InitialData")]
+ partial class InitialData
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "9.0.5");
+
+ modelBuilder.Entity("Common.Configuration.Arr.ArrInstance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("LidarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("lidarr_config_id");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("RadarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("radarr_config_id");
+
+ b.Property("SonarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("sonarr_config_id");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_instance");
+
+ b.HasIndex("LidarrConfigId")
+ .HasDatabaseName("ix_arr_instance_lidarr_config_id");
+
+ b.HasIndex("RadarrConfigId")
+ .HasDatabaseName("ix_arr_instance_radarr_config_id");
+
+ b.HasIndex("SonarrConfigId")
+ .HasDatabaseName("ix_arr_instance_sonarr_config_id");
+
+ b.ToTable("arr_instance", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.LidarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.HasKey("Id")
+ .HasName("pk_lidarr_configs");
+
+ b.ToTable("lidarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("6096303a-399c-42b8-be8f-60a02cec5a51"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.RadarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.HasKey("Id")
+ .HasName("pk_radarr_configs");
+
+ b.ToTable("radarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("4fd2b82b-cffd-4b41-bcc0-204058b1e459"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.SonarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.Property("SearchType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("search_type");
+
+ b.HasKey("Id")
+ .HasName("pk_sonarr_configs");
+
+ b.ToTable("sonarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("0b38a68f-3d7b-4d98-ae96-115da62d9af2"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1,
+ SearchType = "Episode"
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.CleanCategory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DownloadCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("download_cleaner_config_id");
+
+ b.Property("MaxRatio")
+ .HasColumnType("REAL")
+ .HasColumnName("max_ratio");
+
+ b.Property("MaxSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("max_seed_time");
+
+ b.Property("MinSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("min_seed_time");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("pk_clean_category");
+
+ b.HasIndex("DownloadCleanerConfigId")
+ .HasDatabaseName("ix_clean_category_download_cleaner_config_id");
+
+ b.ToTable("clean_category", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_private");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.PrimitiveCollection("UnlinkedCategories")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_categories");
+
+ b.Property("UnlinkedEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_enabled");
+
+ b.Property("UnlinkedIgnoredRootDir")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_ignored_root_dir");
+
+ b.Property("UnlinkedTargetCategory")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_target_category");
+
+ b.Property("UnlinkedUseTag")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_use_tag");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.HasKey("Id")
+ .HasName("pk_download_cleaner_configs");
+
+ b.ToTable("download_cleaner_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("edb20d44-9d7b-478f-aec5-93a803c26fb4"),
+ CronExpression = "0 0 * * * ?",
+ DeletePrivate = false,
+ Enabled = false,
+ UnlinkedCategories = "[]",
+ UnlinkedEnabled = false,
+ UnlinkedIgnoredRootDir = "",
+ UnlinkedTargetCategory = "cleanuparr-unlinked",
+ UnlinkedUseTag = false,
+ UseAdvancedScheduling = false
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadClientConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("Host")
+ .HasColumnType("TEXT")
+ .HasColumnName("host");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Password")
+ .HasColumnType("TEXT")
+ .HasColumnName("password");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.Property("TypeName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type_name");
+
+ b.Property("UrlBase")
+ .HasColumnType("TEXT")
+ .HasColumnName("url_base");
+
+ b.Property("Username")
+ .HasColumnType("TEXT")
+ .HasColumnName("username");
+
+ b.HasKey("Id")
+ .HasName("pk_download_clients");
+
+ b.ToTable("download_clients", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.General.GeneralConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DryRun")
+ .HasColumnType("INTEGER")
+ .HasColumnName("dry_run");
+
+ b.Property("EncryptionKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("encryption_key");
+
+ b.Property("HttpCertificateValidation")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("http_certificate_validation");
+
+ b.Property("HttpMaxRetries")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_max_retries");
+
+ b.Property("HttpTimeout")
+ .HasColumnType("INTEGER")
+ .HasColumnName("http_timeout");
+
+ b.PrimitiveCollection("IgnoredDownloads")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("ignored_downloads");
+
+ b.Property("LogLevel")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("log_level");
+
+ b.Property("SearchDelay")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_delay");
+
+ b.Property("SearchEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("search_enabled");
+
+ b.HasKey("Id")
+ .HasName("pk_general_configs");
+
+ b.ToTable("general_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("1490f450-1b29-4111-ab20-8a03dbd9d366"),
+ DryRun = false,
+ EncryptionKey = "00253fe9-6c9b-4b0e-a05e-e5d2164f2389",
+ HttpCertificateValidation = "Enabled",
+ HttpMaxRetries = (ushort)0,
+ HttpTimeout = (ushort)100,
+ IgnoredDownloads = "[]",
+ LogLevel = "Information",
+ SearchDelay = (ushort)30,
+ SearchEnabled = true
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Notification.AppriseConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Key")
+ .HasColumnType("TEXT")
+ .HasColumnName("key");
+
+ b.Property("OnCategoryChanged")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_category_changed");
+
+ b.Property("OnDownloadCleaned")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_download_cleaned");
+
+ b.Property("OnFailedImportStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_failed_import_strike");
+
+ b.Property("OnQueueItemDeleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_queue_item_deleted");
+
+ b.Property("OnSlowStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_slow_strike");
+
+ b.Property("OnStalledStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_stalled_strike");
+
+ b.Property("Url")
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.HasKey("Id")
+ .HasName("pk_apprise_configs");
+
+ b.ToTable("apprise_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("9c7a346a-2b80-4935-ae4f-5400e336fd07"),
+ OnCategoryChanged = false,
+ OnDownloadCleaned = false,
+ OnFailedImportStrike = false,
+ OnQueueItemDeleted = false,
+ OnSlowStrike = false,
+ OnStalledStrike = false
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Notification.NotifiarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("ChannelId")
+ .HasColumnType("TEXT")
+ .HasColumnName("channel_id");
+
+ b.Property("OnCategoryChanged")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_category_changed");
+
+ b.Property("OnDownloadCleaned")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_download_cleaned");
+
+ b.Property("OnFailedImportStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_failed_import_strike");
+
+ b.Property("OnQueueItemDeleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_queue_item_deleted");
+
+ b.Property("OnSlowStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_slow_strike");
+
+ b.Property("OnStalledStrike")
+ .HasColumnType("INTEGER")
+ .HasColumnName("on_stalled_strike");
+
+ b.HasKey("Id")
+ .HasName("pk_notifiarr_configs");
+
+ b.ToTable("notifiarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("dd468589-e5ee-4e1b-b05e-28b461894846"),
+ OnCategoryChanged = false,
+ OnDownloadCleaned = false,
+ OnFailedImportStrike = false,
+ OnQueueItemDeleted = false,
+ OnSlowStrike = false,
+ OnStalledStrike = false
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.QueueCleaner.QueueCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.ComplexProperty>("ContentBlocker", "Common.Configuration.QueueCleaner.QueueCleanerConfig.ContentBlocker#ContentBlockerConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_delete_private");
+
+ b1.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_enabled");
+
+ b1.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_ignore_private");
+
+ b1.ComplexProperty>("Lidarr", "Common.Configuration.QueueCleaner.QueueCleanerConfig.ContentBlocker#ContentBlockerConfig.Lidarr#BlocklistSettings", b2 =>
+ {
+ b2.IsRequired();
+
+ b2.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("content_blocker_lidarr_blocklist_path");
+
+ b2.Property("BlocklistType")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_lidarr_blocklist_type");
+ });
+
+ b1.ComplexProperty>("Radarr", "Common.Configuration.QueueCleaner.QueueCleanerConfig.ContentBlocker#ContentBlockerConfig.Radarr#BlocklistSettings", b2 =>
+ {
+ b2.IsRequired();
+
+ b2.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("content_blocker_radarr_blocklist_path");
+
+ b2.Property("BlocklistType")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_radarr_blocklist_type");
+ });
+
+ b1.ComplexProperty>("Sonarr", "Common.Configuration.QueueCleaner.QueueCleanerConfig.ContentBlocker#ContentBlockerConfig.Sonarr#BlocklistSettings", b2 =>
+ {
+ b2.IsRequired();
+
+ b2.Property("BlocklistPath")
+ .HasColumnType("TEXT")
+ .HasColumnName("content_blocker_sonarr_blocklist_path");
+
+ b2.Property("BlocklistType")
+ .HasColumnType("INTEGER")
+ .HasColumnName("content_blocker_sonarr_blocklist_type");
+ });
+ });
+
+ b.ComplexProperty>("FailedImport", "Common.Configuration.QueueCleaner.QueueCleanerConfig.FailedImport#FailedImportConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_delete_private");
+
+ b1.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_ignore_private");
+
+ b1.PrimitiveCollection("IgnoredPatterns")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("failed_import_ignored_patterns");
+
+ b1.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+ });
+
+ b.ComplexProperty>("Slow", "Common.Configuration.QueueCleaner.QueueCleanerConfig.Slow#SlowConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("slow_delete_private");
+
+ b1.Property("IgnoreAboveSize")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("slow_ignore_above_size");
+
+ b1.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("slow_ignore_private");
+
+ b1.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("slow_max_strikes");
+
+ b1.Property("MaxTime")
+ .HasColumnType("REAL")
+ .HasColumnName("slow_max_time");
+
+ b1.Property("MinSpeed")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("slow_min_speed");
+
+ b1.Property("ResetStrikesOnProgress")
+ .HasColumnType("INTEGER")
+ .HasColumnName("slow_reset_strikes_on_progress");
+ });
+
+ b.ComplexProperty>("Stalled", "Common.Configuration.QueueCleaner.QueueCleanerConfig.Stalled#StalledConfig", b1 =>
+ {
+ b1.IsRequired();
+
+ b1.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("stalled_delete_private");
+
+ b1.Property("DownloadingMetadataMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("stalled_downloading_metadata_max_strikes");
+
+ b1.Property("IgnorePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("stalled_ignore_private");
+
+ b1.Property("MaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("stalled_max_strikes");
+
+ b1.Property("ResetStrikesOnProgress")
+ .HasColumnType("INTEGER")
+ .HasColumnName("stalled_reset_strikes_on_progress");
+ });
+
+ b.HasKey("Id")
+ .HasName("pk_queue_cleaner_configs");
+
+ b.ToTable("queue_cleaner_configs", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.ArrInstance", b =>
+ {
+ b.HasOne("Common.Configuration.Arr.LidarrConfig", null)
+ .WithMany("Instances")
+ .HasForeignKey("LidarrConfigId")
+ .HasConstraintName("fk_arr_instance_lidarr_configs_lidarr_config_id");
+
+ b.HasOne("Common.Configuration.Arr.RadarrConfig", null)
+ .WithMany("Instances")
+ .HasForeignKey("RadarrConfigId")
+ .HasConstraintName("fk_arr_instance_radarr_configs_radarr_config_id");
+
+ b.HasOne("Common.Configuration.Arr.SonarrConfig", null)
+ .WithMany("Instances")
+ .HasForeignKey("SonarrConfigId")
+ .HasConstraintName("fk_arr_instance_sonarr_configs_sonarr_config_id");
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.CleanCategory", b =>
+ {
+ b.HasOne("Common.Configuration.DownloadCleaner.DownloadCleanerConfig", null)
+ .WithMany("Categories")
+ .HasForeignKey("DownloadCleanerConfigId")
+ .HasConstraintName("fk_clean_category_download_cleaner_configs_download_cleaner_config_id");
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.LidarrConfig", b =>
+ {
+ b.Navigation("Instances");
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.RadarrConfig", b =>
+ {
+ b.Navigation("Instances");
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.SonarrConfig", b =>
+ {
+ b.Navigation("Instances");
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Navigation("Categories");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/code/Data/Migrations/Data/20250614213915_InitialData.cs b/code/Data/Migrations/Data/20250614213915_InitialData.cs
new file mode 100644
index 00000000..d2ea25b0
--- /dev/null
+++ b/code/Data/Migrations/Data/20250614213915_InitialData.cs
@@ -0,0 +1,336 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Data.Migrations.Data
+{
+ ///
+ public partial class InitialData : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "apprise_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ url = table.Column(type: "TEXT", nullable: true),
+ key = table.Column(type: "TEXT", nullable: true),
+ on_failed_import_strike = table.Column(type: "INTEGER", nullable: false),
+ on_stalled_strike = table.Column(type: "INTEGER", nullable: false),
+ on_slow_strike = table.Column(type: "INTEGER", nullable: false),
+ on_queue_item_deleted = table.Column(type: "INTEGER", nullable: false),
+ on_download_cleaned = table.Column(type: "INTEGER", nullable: false),
+ on_category_changed = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_apprise_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "download_cleaner_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ cron_expression = table.Column(type: "TEXT", nullable: false),
+ use_advanced_scheduling = table.Column(type: "INTEGER", nullable: false),
+ delete_private = table.Column(type: "INTEGER", nullable: false),
+ unlinked_enabled = table.Column(type: "INTEGER", nullable: false),
+ unlinked_target_category = table.Column(type: "TEXT", nullable: false),
+ unlinked_use_tag = table.Column(type: "INTEGER", nullable: false),
+ unlinked_ignored_root_dir = table.Column(type: "TEXT", nullable: false),
+ unlinked_categories = table.Column(type: "TEXT", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_download_cleaner_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "download_clients",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ name = table.Column(type: "TEXT", nullable: false),
+ type_name = table.Column(type: "TEXT", nullable: false),
+ type = table.Column(type: "TEXT", nullable: false),
+ host = table.Column(type: "TEXT", nullable: true),
+ username = table.Column(type: "TEXT", nullable: true),
+ password = table.Column(type: "TEXT", nullable: true),
+ url_base = table.Column(type: "TEXT", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_download_clients", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "general_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ dry_run = table.Column(type: "INTEGER", nullable: false),
+ http_max_retries = table.Column(type: "INTEGER", nullable: false),
+ http_timeout = table.Column(type: "INTEGER", nullable: false),
+ http_certificate_validation = table.Column(type: "TEXT", nullable: false),
+ search_enabled = table.Column(type: "INTEGER", nullable: false),
+ search_delay = table.Column(type: "INTEGER", nullable: false),
+ log_level = table.Column(type: "TEXT", nullable: false),
+ encryption_key = table.Column(type: "TEXT", nullable: false),
+ ignored_downloads = table.Column(type: "TEXT", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_general_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "lidarr_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ failed_import_max_strikes = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_lidarr_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "notifiarr_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ api_key = table.Column(type: "TEXT", nullable: true),
+ channel_id = table.Column(type: "TEXT", nullable: true),
+ on_failed_import_strike = table.Column(type: "INTEGER", nullable: false),
+ on_stalled_strike = table.Column(type: "INTEGER", nullable: false),
+ on_slow_strike = table.Column(type: "INTEGER", nullable: false),
+ on_queue_item_deleted = table.Column(type: "INTEGER", nullable: false),
+ on_download_cleaned = table.Column(type: "INTEGER", nullable: false),
+ on_category_changed = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_notifiarr_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "queue_cleaner_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ cron_expression = table.Column(type: "TEXT", nullable: false),
+ use_advanced_scheduling = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_delete_private = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_enabled = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_ignore_private = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_lidarr_blocklist_path = table.Column(type: "TEXT", nullable: true),
+ content_blocker_lidarr_blocklist_type = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_radarr_blocklist_path = table.Column(type: "TEXT", nullable: true),
+ content_blocker_radarr_blocklist_type = table.Column(type: "INTEGER", nullable: false),
+ content_blocker_sonarr_blocklist_path = table.Column(type: "TEXT", nullable: true),
+ content_blocker_sonarr_blocklist_type = table.Column(type: "INTEGER", nullable: false),
+ failed_import_delete_private = table.Column(type: "INTEGER", nullable: false),
+ failed_import_ignore_private = table.Column(type: "INTEGER", nullable: false),
+ failed_import_ignored_patterns = table.Column(type: "TEXT", nullable: false),
+ failed_import_max_strikes = table.Column(type: "INTEGER", nullable: false),
+ slow_delete_private = table.Column(type: "INTEGER", nullable: false),
+ slow_ignore_above_size = table.Column(type: "TEXT", nullable: false),
+ slow_ignore_private = table.Column(type: "INTEGER", nullable: false),
+ slow_max_strikes = table.Column(type: "INTEGER", nullable: false),
+ slow_max_time = table.Column(type: "REAL", nullable: false),
+ slow_min_speed = table.Column(type: "TEXT", nullable: false),
+ slow_reset_strikes_on_progress = table.Column(type: "INTEGER", nullable: false),
+ stalled_delete_private = table.Column(type: "INTEGER", nullable: false),
+ stalled_downloading_metadata_max_strikes = table.Column(type: "INTEGER", nullable: false),
+ stalled_ignore_private = table.Column(type: "INTEGER", nullable: false),
+ stalled_max_strikes = table.Column(type: "INTEGER", nullable: false),
+ stalled_reset_strikes_on_progress = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_queue_cleaner_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "radarr_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ failed_import_max_strikes = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_radarr_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "sonarr_configs",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ search_type = table.Column(type: "TEXT", nullable: false),
+ enabled = table.Column(type: "INTEGER", nullable: false),
+ failed_import_max_strikes = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_sonarr_configs", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "clean_category",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ name = table.Column(type: "TEXT", nullable: false),
+ max_ratio = table.Column(type: "REAL", nullable: false),
+ min_seed_time = table.Column(type: "REAL", nullable: false),
+ max_seed_time = table.Column(type: "REAL", nullable: false),
+ download_cleaner_config_id = table.Column(type: "TEXT", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_clean_category", x => x.id);
+ table.ForeignKey(
+ name: "fk_clean_category_download_cleaner_configs_download_cleaner_config_id",
+ column: x => x.download_cleaner_config_id,
+ principalTable: "download_cleaner_configs",
+ principalColumn: "id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "arr_instance",
+ columns: table => new
+ {
+ id = table.Column(type: "TEXT", nullable: false),
+ name = table.Column(type: "TEXT", nullable: false),
+ url = table.Column(type: "TEXT", nullable: false),
+ api_key = table.Column(type: "TEXT", nullable: false),
+ lidarr_config_id = table.Column(type: "TEXT", nullable: true),
+ radarr_config_id = table.Column(type: "TEXT", nullable: true),
+ sonarr_config_id = table.Column(type: "TEXT", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_arr_instance", x => x.id);
+ table.ForeignKey(
+ name: "fk_arr_instance_lidarr_configs_lidarr_config_id",
+ column: x => x.lidarr_config_id,
+ principalTable: "lidarr_configs",
+ principalColumn: "id");
+ table.ForeignKey(
+ name: "fk_arr_instance_radarr_configs_radarr_config_id",
+ column: x => x.radarr_config_id,
+ principalTable: "radarr_configs",
+ principalColumn: "id");
+ table.ForeignKey(
+ name: "fk_arr_instance_sonarr_configs_sonarr_config_id",
+ column: x => x.sonarr_config_id,
+ principalTable: "sonarr_configs",
+ principalColumn: "id");
+ });
+
+ migrationBuilder.InsertData(
+ table: "apprise_configs",
+ columns: new[] { "id", "key", "on_category_changed", "on_download_cleaned", "on_failed_import_strike", "on_queue_item_deleted", "on_slow_strike", "on_stalled_strike", "url" },
+ values: new object[] { new Guid("9c7a346a-2b80-4935-ae4f-5400e336fd07"), null, false, false, false, false, false, false, null });
+
+ migrationBuilder.InsertData(
+ table: "download_cleaner_configs",
+ columns: new[] { "id", "cron_expression", "delete_private", "enabled", "unlinked_categories", "unlinked_enabled", "unlinked_ignored_root_dir", "unlinked_target_category", "unlinked_use_tag", "use_advanced_scheduling" },
+ values: new object[] { new Guid("edb20d44-9d7b-478f-aec5-93a803c26fb4"), "0 0 * * * ?", false, false, "[]", false, "", "cleanuparr-unlinked", false, false });
+
+ migrationBuilder.InsertData(
+ table: "general_configs",
+ columns: new[] { "id", "dry_run", "encryption_key", "http_certificate_validation", "http_max_retries", "http_timeout", "ignored_downloads", "log_level", "search_delay", "search_enabled" },
+ values: new object[] { new Guid("1490f450-1b29-4111-ab20-8a03dbd9d366"), false, "00253fe9-6c9b-4b0e-a05e-e5d2164f2389", "Enabled", (ushort)0, (ushort)100, "[]", "Information", (ushort)30, true });
+
+ migrationBuilder.InsertData(
+ table: "lidarr_configs",
+ columns: new[] { "id", "enabled", "failed_import_max_strikes" },
+ values: new object[] { new Guid("6096303a-399c-42b8-be8f-60a02cec5a51"), false, (short)-1 });
+
+ migrationBuilder.InsertData(
+ table: "notifiarr_configs",
+ columns: new[] { "id", "api_key", "channel_id", "on_category_changed", "on_download_cleaned", "on_failed_import_strike", "on_queue_item_deleted", "on_slow_strike", "on_stalled_strike" },
+ values: new object[] { new Guid("dd468589-e5ee-4e1b-b05e-28b461894846"), null, null, false, false, false, false, false, false });
+
+ migrationBuilder.InsertData(
+ table: "radarr_configs",
+ columns: new[] { "id", "enabled", "failed_import_max_strikes" },
+ values: new object[] { new Guid("4fd2b82b-cffd-4b41-bcc0-204058b1e459"), false, (short)-1 });
+
+ migrationBuilder.InsertData(
+ table: "sonarr_configs",
+ columns: new[] { "id", "enabled", "failed_import_max_strikes", "search_type" },
+ values: new object[] { new Guid("0b38a68f-3d7b-4d98-ae96-115da62d9af2"), false, (short)-1, "Episode" });
+
+ migrationBuilder.CreateIndex(
+ name: "ix_arr_instance_lidarr_config_id",
+ table: "arr_instance",
+ column: "lidarr_config_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_arr_instance_radarr_config_id",
+ table: "arr_instance",
+ column: "radarr_config_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_arr_instance_sonarr_config_id",
+ table: "arr_instance",
+ column: "sonarr_config_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_clean_category_download_cleaner_config_id",
+ table: "clean_category",
+ column: "download_cleaner_config_id");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "apprise_configs");
+
+ migrationBuilder.DropTable(
+ name: "arr_instance");
+
+ migrationBuilder.DropTable(
+ name: "clean_category");
+
+ migrationBuilder.DropTable(
+ name: "download_clients");
+
+ migrationBuilder.DropTable(
+ name: "general_configs");
+
+ migrationBuilder.DropTable(
+ name: "notifiarr_configs");
+
+ migrationBuilder.DropTable(
+ name: "queue_cleaner_configs");
+
+ migrationBuilder.DropTable(
+ name: "lidarr_configs");
+
+ migrationBuilder.DropTable(
+ name: "radarr_configs");
+
+ migrationBuilder.DropTable(
+ name: "sonarr_configs");
+
+ migrationBuilder.DropTable(
+ name: "download_cleaner_configs");
+ }
+ }
+}
diff --git a/code/Data/Migrations/Data/DataContextModelSnapshot.cs b/code/Data/Migrations/Data/DataContextModelSnapshot.cs
new file mode 100644
index 00000000..a52cc75e
--- /dev/null
+++ b/code/Data/Migrations/Data/DataContextModelSnapshot.cs
@@ -0,0 +1,710 @@
+//
+using System;
+using System.Collections.Generic;
+using Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Data.Migrations.Data
+{
+ [DbContext(typeof(DataContext))]
+ partial class DataContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "9.0.5");
+
+ modelBuilder.Entity("Common.Configuration.Arr.ArrInstance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("api_key");
+
+ b.Property("LidarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("lidarr_config_id");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("RadarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("radarr_config_id");
+
+ b.Property("SonarrConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("sonarr_config_id");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("url");
+
+ b.HasKey("Id")
+ .HasName("pk_arr_instance");
+
+ b.HasIndex("LidarrConfigId")
+ .HasDatabaseName("ix_arr_instance_lidarr_config_id");
+
+ b.HasIndex("RadarrConfigId")
+ .HasDatabaseName("ix_arr_instance_radarr_config_id");
+
+ b.HasIndex("SonarrConfigId")
+ .HasDatabaseName("ix_arr_instance_sonarr_config_id");
+
+ b.ToTable("arr_instance", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.LidarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.HasKey("Id")
+ .HasName("pk_lidarr_configs");
+
+ b.ToTable("lidarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("6096303a-399c-42b8-be8f-60a02cec5a51"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.RadarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.HasKey("Id")
+ .HasName("pk_radarr_configs");
+
+ b.ToTable("radarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("4fd2b82b-cffd-4b41-bcc0-204058b1e459"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.Arr.SonarrConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("FailedImportMaxStrikes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("failed_import_max_strikes");
+
+ b.Property("SearchType")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("search_type");
+
+ b.HasKey("Id")
+ .HasName("pk_sonarr_configs");
+
+ b.ToTable("sonarr_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("0b38a68f-3d7b-4d98-ae96-115da62d9af2"),
+ Enabled = false,
+ FailedImportMaxStrikes = (short)-1,
+ SearchType = "Episode"
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.CleanCategory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("DownloadCleanerConfigId")
+ .HasColumnType("TEXT")
+ .HasColumnName("download_cleaner_config_id");
+
+ b.Property("MaxRatio")
+ .HasColumnType("REAL")
+ .HasColumnName("max_ratio");
+
+ b.Property("MaxSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("max_seed_time");
+
+ b.Property("MinSeedTime")
+ .HasColumnType("REAL")
+ .HasColumnName("min_seed_time");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("pk_clean_category");
+
+ b.HasIndex("DownloadCleanerConfigId")
+ .HasDatabaseName("ix_clean_category_download_cleaner_config_id");
+
+ b.ToTable("clean_category", (string)null);
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadCleaner.DownloadCleanerConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("cron_expression");
+
+ b.Property("DeletePrivate")
+ .HasColumnType("INTEGER")
+ .HasColumnName("delete_private");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.PrimitiveCollection("UnlinkedCategories")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_categories");
+
+ b.Property("UnlinkedEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_enabled");
+
+ b.Property("UnlinkedIgnoredRootDir")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_ignored_root_dir");
+
+ b.Property("UnlinkedTargetCategory")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("unlinked_target_category");
+
+ b.Property("UnlinkedUseTag")
+ .HasColumnType("INTEGER")
+ .HasColumnName("unlinked_use_tag");
+
+ b.Property("UseAdvancedScheduling")
+ .HasColumnType("INTEGER")
+ .HasColumnName("use_advanced_scheduling");
+
+ b.HasKey("Id")
+ .HasName("pk_download_cleaner_configs");
+
+ b.ToTable("download_cleaner_configs", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("edb20d44-9d7b-478f-aec5-93a803c26fb4"),
+ CronExpression = "0 0 * * * ?",
+ DeletePrivate = false,
+ Enabled = false,
+ UnlinkedCategories = "[]",
+ UnlinkedEnabled = false,
+ UnlinkedIgnoredRootDir = "",
+ UnlinkedTargetCategory = "cleanuparr-unlinked",
+ UnlinkedUseTag = false,
+ UseAdvancedScheduling = false
+ });
+ });
+
+ modelBuilder.Entity("Common.Configuration.DownloadClientConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("id");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("enabled");
+
+ b.Property("Host")
+ .HasColumnType("TEXT")
+ .HasColumnName("host");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.Property("Password")
+ .HasColumnType("TEXT")
+ .HasColumnName("password");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type");
+
+ b.Property("TypeName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("type_name");
+
+ b.Property("UrlBase")
+ .HasColumnType("TEXT")
+ .HasColumnName("url_base");
+
+ b.Property