From 2db0faa00c8893ac6d3dd3c59f085c61ca26a43d Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Wed, 31 Aug 2022 07:59:17 -0500 Subject: [PATCH] fix(sonarr): Error when using release profiles with Sonarr v4 Fixes #100 --- CHANGELOG.md | 1 + ...dlerTest.cs => SonarrCompatibilityTest.cs} | 45 ++++++++++++++++++- .../Services/Sonarr/Api/ISonarrApi.cs | 2 + src/TrashLib/Services/Sonarr/Api/SonarrApi.cs | 9 ++++ .../ReleaseProfile/ReleaseProfileUpdater.cs | 11 +++-- .../Services/Sonarr/SonarrCapabilities.cs | 14 ++---- .../Services/Sonarr/SonarrCompatibility.cs | 16 +++---- 7 files changed, 74 insertions(+), 24 deletions(-) rename src/TrashLib.Tests/Sonarr/{Api/SonarrReleaseProfileCompatibilityHandlerTest.cs => SonarrCompatibilityTest.cs} (70%) diff --git a/CHANGELOG.md b/CHANGELOG.md index da53793c..992d3841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Docker: Fix `/config` permissions when not using bind-mount for the volume. (#111) +- Sonarr: Error message is printed when attempting to use release profiles with Sonarr v4. (#100) ### Security diff --git a/src/TrashLib.Tests/Sonarr/Api/SonarrReleaseProfileCompatibilityHandlerTest.cs b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs similarity index 70% rename from src/TrashLib.Tests/Sonarr/Api/SonarrReleaseProfileCompatibilityHandlerTest.cs rename to src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs index 0de7ad06..568106de 100644 --- a/src/TrashLib.Tests/Sonarr/Api/SonarrReleaseProfileCompatibilityHandlerTest.cs +++ b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs @@ -1,4 +1,5 @@ using System.Reactive.Linq; +using AutoFixture.NUnit3; using AutoMapper; using FluentAssertions; using Newtonsoft.Json; @@ -6,16 +7,20 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using NSubstitute; using NUnit.Framework; +using TestLibrary.AutoFixture; +using TrashLib.ExceptionTypes; using TrashLib.Services.Sonarr; using TrashLib.Services.Sonarr.Api; using TrashLib.Services.Sonarr.Api.Objects; +using TrashLib.Services.Sonarr.Config; +using TrashLib.Services.Sonarr.ReleaseProfile; using TrashLib.Startup; -namespace TrashLib.Tests.Sonarr.Api; +namespace TrashLib.Tests.Sonarr; [TestFixture] [Parallelizable(ParallelScope.All)] -public class SonarrReleaseProfileCompatibilityHandlerTest +public class SonarrCompatibilityTest { private class TestContext : IDisposable { @@ -111,4 +116,40 @@ public class SonarrReleaseProfileCompatibilityHandlerTest result.Should().BeEquivalentTo(data); } + + [Test, AutoMockData] + public async Task Failure_when_release_profiles_used_with_sonarr_v4( + [Frozen] ISonarrApi api, + [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, + ReleaseProfileUpdater updater) + { + api.GetVersion().Returns(new Version(4, 0)); + + var config = new SonarrConfiguration + { + ReleaseProfiles = new List {new()} + }; + + var act = () => updater.Process(false, config); + + await act.Should().ThrowAsync().WithMessage("Sonarr v4*"); + } + + [Test, AutoMockData] + public async Task No_failure_when_release_profiles_used_with_sonarr_v3( + [Frozen] ISonarrApi api, + [Frozen(Matching.ImplementedInterfaces)] SonarrCompatibility compatibility, + ReleaseProfileUpdater updater) + { + api.GetVersion().Returns(new Version(3, 9)); + + var config = new SonarrConfiguration + { + ReleaseProfiles = new List {new()} + }; + + var act = () => updater.Process(false, config); + + await act.Should().NotThrowAsync(); + } } diff --git a/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs b/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs index 02708039..e1284e35 100644 --- a/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs +++ b/src/TrashLib/Services/Sonarr/Api/ISonarrApi.cs @@ -10,4 +10,6 @@ public interface ISonarrApi Task> UpdateQualityDefinition( IReadOnlyCollection newQuality); + + Task GetVersion(); } diff --git a/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs b/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs index df1e270a..cea30f5a 100644 --- a/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs +++ b/src/TrashLib/Services/Sonarr/Api/SonarrApi.cs @@ -14,6 +14,15 @@ public class SonarrApi : ISonarrApi _serverInfo = serverInfo; } + public async Task GetVersion() + { + var response = await BaseUrl() + .AppendPathSegment("system/status") + .GetJsonAsync(); + + return new Version(response.version); + } + public async Task> GetTags() { return await BaseUrl() diff --git a/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs b/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs index 0811ef82..4099974d 100644 --- a/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs +++ b/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs @@ -41,6 +41,8 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater public async Task Process(bool isPreview, SonarrConfiguration config) { + await DoVersionEnforcement(config); + var profilesFromGuide = _guide.GetReleaseProfileData(); var filteredProfiles = new List<(ReleaseProfileData Profile, IReadOnlyCollection Tags)>(); @@ -129,8 +131,6 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater private async Task ProcessReleaseProfiles( List<(ReleaseProfileData Profile, IReadOnlyCollection Tags)> profilesAndTags) { - await DoVersionEnforcement(); - // Obtain all of the existing release profiles first. If any were previously created by our program // here, we favor replacing those instead of creating new ones, which would just be mostly duplicates // (but with some differences, since there have likely been updates since the last run). @@ -196,7 +196,7 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater .ToList(); } - private async Task DoVersionEnforcement() + private async Task DoVersionEnforcement(SonarrConfiguration config) { var capabilities = await _compatibility.Capabilities.LastAsync(); if (!capabilities.SupportsNamedReleaseProfiles) @@ -205,6 +205,11 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater $"Your Sonarr version {capabilities.Version} does not meet the minimum " + $"required version of {_compatibility.MinimumVersion} to use this program"); } + + if (capabilities.SupportsCustomFormats && config.ReleaseProfiles.Any()) + { + throw new VersionException("Sonarr v4 does not support Release Profiles. Please use Sonarr v3 instead."); + } } private async Task CreateMissingTags(ICollection sonarrTags, IEnumerable configTags) diff --git a/src/TrashLib/Services/Sonarr/SonarrCapabilities.cs b/src/TrashLib/Services/Sonarr/SonarrCapabilities.cs index d8651408..42a487f8 100644 --- a/src/TrashLib/Services/Sonarr/SonarrCapabilities.cs +++ b/src/TrashLib/Services/Sonarr/SonarrCapabilities.cs @@ -1,19 +1,11 @@ namespace TrashLib.Services.Sonarr; -public record SonarrCapabilities +public record SonarrCapabilities(Version Version) { - public SonarrCapabilities() + public SonarrCapabilities() : this(new Version()) { - Version = new Version(); } - public SonarrCapabilities(Version version) - { - Version = version; - } - - public Version Version { get; } - public bool SupportsNamedReleaseProfiles { get; init; } // Background: Issue #16 filed which points to a backward-breaking API @@ -21,4 +13,6 @@ public record SonarrCapabilities // // [deed85d2f]: https://github.com/Sonarr/Sonarr/commit/deed85d2f9147e6180014507ef4f5af3695b0c61 public bool ArraysNeededForReleaseProfileRequiredAndIgnored { get; init; } + + public bool SupportsCustomFormats { get; init; } } diff --git a/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs b/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs index 4f1d2926..31316290 100644 --- a/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs +++ b/src/TrashLib/Services/Sonarr/SonarrCompatibility.cs @@ -1,8 +1,7 @@ using System.Reactive.Concurrency; using System.Reactive.Linq; -using Flurl.Http; using Serilog; -using TrashLib.Config.Services; +using TrashLib.Services.Sonarr.Api; namespace TrashLib.Services.Sonarr; @@ -10,15 +9,11 @@ public class SonarrCompatibility : ISonarrCompatibility { private readonly ILogger _log; - public SonarrCompatibility(IServerInfo serverInfo, ILogger log) + public SonarrCompatibility(ISonarrApi api, ILogger log) { _log = log; - Capabilities = Observable.FromAsync( - async () => await serverInfo.BuildRequest() - .AppendPathSegment("system/status") - .GetJsonAsync(), NewThreadScheduler.Default) + Capabilities = Observable.FromAsync(async () => await api.GetVersion(), NewThreadScheduler.Default) .Timeout(TimeSpan.FromSeconds(15)) - .Select(x => new Version(x.version)) .Select(BuildCapabilitiesObject) .Replay(1) .AutoConnect(); @@ -36,7 +31,10 @@ public class SonarrCompatibility : ISonarrCompatibility version >= MinimumVersion, ArraysNeededForReleaseProfileRequiredAndIgnored = - version >= new Version("3.0.6.1355") + version >= new Version("3.0.6.1355"), + + SupportsCustomFormats = + version >= new Version(4, 0) }; } }