added sonarr search mode setting

This commit is contained in:
Flaminel committed 2026-10-21 22:11:04 +03:00
1 parent a5c2e840a0
commit e235527859
13 files changed
+4311 -1

No files matched your search

@@ -57,6 +57,7 @@ public class SeekerConfigControllerTests : IDisposable
instance.IgnoreStruckDownloads.ShouldBeFalse();
instance.MinCycleTimeDays.ShouldBe(7);
instance.RecentGrabWindowHours.ShouldBe(24);
instance.SonarrSearchMode.ShouldBe(SonarrSearchMode.Auto);
}
[Fact]
@@ -116,6 +117,25 @@ public class SeekerConfigControllerTests : IDisposable
response.Instances.ShouldHaveSingleItem().RecentGrabWindowHours.ShouldBe(48);
}
[Fact]
public async Task GetSeekerConfig_WithSonarrSearchMode_ReturnsStoredValue()
{
ArrInstance sonarr = SeekerTestDataFactory.AddSonarrInstance(_dataContext);
_dataContext.SeekerInstanceConfigs.Add(new SeekerInstanceConfig
{
ArrInstanceId = sonarr.Id,
Enabled = true,
SonarrSearchMode = SonarrSearchMode.Episode
});
await _dataContext.SaveChangesAsync();
IActionResult result = await _controller.GetSeekerConfig();
OkObjectResult okResult = result.ShouldBeOfType<OkObjectResult>();
SeekerConfigResponse response = okResult.Value.ShouldBeOfType<SeekerConfigResponse>();
response.Instances.ShouldHaveSingleItem().SonarrSearchMode.ShouldBe(SonarrSearchMode.Episode);
}
[Fact]
public async Task GetSeekerConfig_OnlyReturnsSonarrAndRadarrInstances()
{
@@ -431,7 +451,8 @@ public class SeekerConfigControllerTests : IDisposable
IncludeTags = ["sonarr-include"],
ActiveDownloadLimit = 3,
MinCycleTimeDays = 7,
RecentGrabWindowHours = 6
RecentGrabWindowHours = 6,
SonarrSearchMode = SonarrSearchMode.Episode
}
]
};
@@ -456,6 +477,41 @@ public class SeekerConfigControllerTests : IDisposable
sonarrConfig.IncludeTags.ShouldBe(["sonarr-include"]);
sonarrConfig.IgnoreStruckDownloads.ShouldBeFalse();
sonarrConfig.RecentGrabWindowHours.ShouldBe(6);
sonarrConfig.SonarrSearchMode.ShouldBe(SonarrSearchMode.Episode);
}
[Fact]
public async Task UpdateSeekerConfig_WithSonarrSearchMode_OnExistingInstance_PersistsValue()
{
ArrInstance sonarr = SeekerTestDataFactory.AddSonarrInstance(_dataContext);
_dataContext.SeekerInstanceConfigs.Add(new SeekerInstanceConfig
{
ArrInstanceId = sonarr.Id,
Enabled = true,
SonarrSearchMode = SonarrSearchMode.Auto
});
await _dataContext.SaveChangesAsync();
UpdateSeekerConfigRequest request = new()
{
SearchEnabled = true,
SearchInterval = 3,
ProactiveSearchEnabled = true,
Instances =
[
new UpdateSeekerInstanceConfigRequest
{
ArrInstanceId = sonarr.Id,
Enabled = true,
SonarrSearchMode = SonarrSearchMode.Season
}
]
};
await _controller.UpdateSeekerConfig(request);
SeekerInstanceConfig config = await _dataContext.SeekerInstanceConfigs.SingleAsync();
config.SonarrSearchMode.ShouldBe(SonarrSearchMode.Season);
}
[Theory]
@@ -1,3 +1,5 @@
using Cleanuparr.Domain.Enums;
namespace Cleanuparr.Api.Features.Seeker.Contracts.Requests;
public sealed record UpdateSeekerInstanceConfigRequest
@@ -23,4 +25,6 @@ public sealed record UpdateSeekerInstanceConfigRequest
public bool UseCustomFormatScore { get; init; }
public int RecentGrabWindowHours { get; init; } = 24;
public SonarrSearchMode SonarrSearchMode { get; init; } = SonarrSearchMode.Auto;
}
@@ -33,4 +33,6 @@ public sealed record SeekerInstanceConfigResponse
public bool UseCustomFormatScore { get; init; }
public int RecentGrabWindowHours { get; init; }
public SonarrSearchMode SonarrSearchMode { get; init; }
}
@@ -71,6 +71,7 @@ public sealed class SeekerConfigController : ControllerBase
UseCutoff = seekerConfig?.UseCutoff ?? false,
UseCustomFormatScore = seekerConfig?.UseCustomFormatScore ?? false,
RecentGrabWindowHours = seekerConfig?.RecentGrabWindowHours ?? 24,
SonarrSearchMode = seekerConfig?.SonarrSearchMode ?? SonarrSearchMode.Auto,
};
}).ToList();
@@ -136,6 +137,7 @@ public sealed class SeekerConfigController : ControllerBase
existing.UseCutoff = instanceReq.UseCutoff;
existing.UseCustomFormatScore = instanceReq.UseCustomFormatScore;
existing.RecentGrabWindowHours = instanceReq.RecentGrabWindowHours;
existing.SonarrSearchMode = instanceReq.SonarrSearchMode;
existing.Validate();
}
else
@@ -153,6 +155,7 @@ public sealed class SeekerConfigController : ControllerBase
UseCutoff = instanceReq.UseCutoff,
UseCustomFormatScore = instanceReq.UseCustomFormatScore,
RecentGrabWindowHours = instanceReq.RecentGrabWindowHours,
SonarrSearchMode = instanceReq.SonarrSearchMode,
};
newInstanceConfig.Validate();
await _dataContext.SeekerInstanceConfigs.AddAsync(newInstanceConfig);
@@ -0,0 +1,20 @@
namespace Cleanuparr.Domain.Enums;
public enum SonarrSearchMode
{
/// <summary>
/// Searches a whole season when it has finished airing and every aired monitored episode needs a search.
/// Otherwise searches one episode per run.
/// </summary>
Auto,
/// <summary>
/// Always searches the whole season.
/// </summary>
Season,
/// <summary>
/// Always searches one episode per run.
/// </summary>
Episode,
}
@@ -31,6 +31,7 @@ public class EnumFallbackParityTests
["UTorrentSeedingRule.PrivacyType"] = TorrentPrivacyType.Public,
["RTorrentSeedingRule.PrivacyType"] = TorrentPrivacyType.Public,
["SeekerConfig.SelectionStrategy"] = SelectionStrategy.BalancedWeighted,
["SeekerInstanceConfig.SonarrSearchMode"] = SonarrSearchMode.Auto,
["NtfyConfig.AuthenticationType"] = NtfyAuthenticationType.None,
["NtfyConfig.Priority"] = NtfyPriority.Default,
["PushoverConfig.Priority"] = PushoverPriority.Normal,
@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Cleanuparr.Persistence.Postgres.Migrations.Data
{
/// <inheritdoc />
public partial class AddSeekerSonarrSearchMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "sonarr_search_mode",
schema: "data",
table: "seeker_instance_configs",
type: "text",
nullable: false,
defaultValue: "auto");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "sonarr_search_mode",
schema: "data",
table: "seeker_instance_configs");
}
}
}
@@ -1744,6 +1744,11 @@ namespace Cleanuparr.Persistence.Postgres.Migrations.Data
.HasColumnType("text[]")
.HasColumnName("skip_tags");
b.Property<string>("SonarrSearchMode")
.IsRequired()
.HasColumnType("text")
.HasColumnName("sonarr_search_mode");
b.Property<bool>("UseCustomFormatScore")
.HasColumnType("boolean")
.HasColumnName("use_custom_format_score");
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Cleanuparr.Persistence.Migrations.Data
{
/// <inheritdoc />
public partial class AddSeekerSonarrSearchMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "sonarr_search_mode",
table: "seeker_instance_configs",
type: "TEXT",
nullable: false,
defaultValue: "auto");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "sonarr_search_mode",
table: "seeker_instance_configs");
}
}
}
@@ -1740,6 +1740,11 @@ namespace Cleanuparr.Persistence.Migrations.Data
.HasColumnType("TEXT")
.HasColumnName("skip_tags");
b.Property<string>("SonarrSearchMode")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("sonarr_search_mode");
b.Property<bool>("UseCustomFormatScore")
.HasColumnType("INTEGER")
.HasColumnName("use_custom_format_score");
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Cleanuparr.Domain.Enums;
using Cleanuparr.Domain.Exceptions;
using Cleanuparr.Persistence.Models.Configuration.Arr;
@@ -91,6 +92,11 @@ public sealed record SeekerInstanceConfig
/// </summary>
public int RecentGrabWindowHours { get; set; } = 24;
/// <summary>
/// How Sonarr seasons are searched. Ignored for Radarr.
/// </summary>
public SonarrSearchMode SonarrSearchMode { get; set; } = SonarrSearchMode.Auto;
/// <summary>
/// Validates this instance's configuration, throwing <see cref="CustomValidationException"/> on failure.
/// </summary>