diff --git a/.gitattributes b/.gitattributes
index e536e1f9..6623402f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,8 @@
* text=auto
+# Files that require LF line endings
*.sh eol=lf
Dockerfile eol=lf
+
+# Ignore whitespace in these files
+*.sln -whitespace
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cfe64d33..b2956c8e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Settings: New `log_janitor` setting that allows you to specify how many log files are kept when
cleaning up (deleting) old log files. See the [Settings Reference] wiki page for more details.
(#91)
+- Sonarr: Custom Formats can now be synced to Version 4.
### Fixed
diff --git a/debugging/docker-compose.yml b/debugging/docker-compose.yml
index 3fa8009c..5db5f5de 100644
--- a/debugging/docker-compose.yml
+++ b/debugging/docker-compose.yml
@@ -6,60 +6,37 @@ networks:
volumes:
radarr_nightly:
- radarr_latest:
sonarr_nightly:
- sonarr_latest:
+ sonarr_v4:
services:
- radarr_latest:
- image: ghcr.io/hotio/radarr
- networks:
- recyclarr:
- aliases:
- - radarr_latest
- ports:
- - 7879:7878
- volumes:
- - radarr_latest:/config
- environment:
- - TZ=America/Chicago
-
radarr_nightly:
image: ghcr.io/hotio/radarr:nightly
- networks:
- recyclarr:
- aliases:
- - radarr_nightly
- ports:
- - 7878:7878
+ container_name: radarr_nightly
+ networks: [recyclarr]
+ ports: [7878:7878]
volumes:
- radarr_nightly:/config
- ./certs:/certs:ro
environment:
- TZ=America/Chicago
- sonarr_latest:
- image: ghcr.io/hotio/sonarr
- networks:
- recyclarr:
- aliases:
- - sonarr_latest
- ports:
- - 8990:8989
+ sonarr_nightly:
+ image: ghcr.io/hotio/sonarr:nightly
+ container_name: sonarr_nightly
+ networks: [recyclarr]
+ ports: [8989:8989]
volumes:
- - sonarr_latest:/config
+ - sonarr_nightly:/config
environment:
- TZ=America/Chicago
- sonarr_nightly:
- image: ghcr.io/hotio/sonarr:nightly
- networks:
- recyclarr:
- aliases:
- - sonarr_nightly
- ports:
- - 8989:8989
+ sonarr_v4:
+ image: ghcr.io/hotio/sonarr:v4
+ container_name: sonarr_v4
+ networks: [recyclarr]
+ ports: [8990:8989]
volumes:
- - sonarr_nightly:/config
+ - sonarr_v4:/config
environment:
- TZ=America/Chicago
diff --git a/schemas/config-schema.json b/schemas/config-schema.json
index 3252911a..a0d5065c 100644
--- a/schemas/config-schema.json
+++ b/schemas/config-schema.json
@@ -28,14 +28,24 @@
"quality_definition": {
"type": "string"
},
+ "delete_old_custom_formats": {
+ "$ref": "#/$defs/delete_old_custom_formats"
+ },
+ "custom_formats": {
+ "$ref": "#/$defs/custom_formats"
+ },
"release_profiles": {
"type": "array",
"minItems": 1,
"items": {
"additionalProperties": false,
"anyOf": [
- {"required": ["trash_ids"]},
- {"required": ["names"]}
+ {
+ "required": ["trash_ids"]
+ },
+ {
+ "required": ["names"]
+ }
],
"properties": {
"trash_ids": {
@@ -58,8 +68,12 @@
"additionalProperties": false,
"description": "Defines various ways that release profile terms from the guide are synchronized with Sonarr.",
"oneOf": [
- {"required": ["include"]},
- {"required": ["exclude"]}
+ {
+ "required": ["include"]
+ },
+ {
+ "required": ["exclude"]
+ }
],
"properties": {
"include": {
@@ -116,58 +130,10 @@
}
},
"delete_old_custom_formats": {
- "type": "boolean",
- "description": "If enabled, custom formats that you remove from your YAML configuration OR that are removed from the guide will be deleted from your Radarr instance.",
- "default": false
+ "$ref": "#/$defs/delete_old_custom_formats"
},
"custom_formats": {
- "type": "array",
- "minItems": 1,
- "items": {
- "type": "object",
- "additionalProperties": false,
- "description": "A list of one or more sets of custom formats each with an optional set of quality profiles names that identify which quality profiles to assign the scores for those custom formats to.",
- "anyOf": [
- {"required": ["trash_ids"]},
- {"required": ["names"]}
- ],
- "properties": {
- "names": {
- "type": "array",
- "uniqueItems": true,
- "description": "A list of one or more custom format names to synchronize to Radarr. The names must be taken from the JSON itself in the guide.",
- "minItems": 1,
- "items": {
- "type": "string"
- }
- },
- "trash_ids": {
- "$ref": "#/$defs/trash_ids_list"
- },
- "quality_profiles": {
- "type": "array",
- "description": "One or more quality profiles to update with the scores from the specified custom formats.",
- "minItems": 1,
- "items": {
- "properties": {
- "name": {
- "type": "string",
- "description": "The name of one of the quality profiles in Radarr."
- },
- "score": {
- "type": "integer",
- "description": "A positive or negative number representing the score to apply to *all* custom formats listed in the names list."
- },
- "reset_unmatched_scores": {
- "type": "boolean",
- "description": "If set to true, enables setting scores to 0 in quality profiles where either a name was not mentioned in the names array or it was in that list but did not get a score (e.g. no score in guide).",
- "default": false
- }
- }
- }
- }
- }
- }
+ "$ref": "#/$defs/custom_formats"
}
}
}
@@ -192,6 +158,64 @@
"type": "string",
"pattern": "^https?",
"description": "The base URL of your instance. Basically this is the URL you bookmark to get to the front page."
+ },
+ "delete_old_custom_formats": {
+ "type": "boolean",
+ "description": "If enabled, custom formats that you remove from your YAML configuration OR that are removed from the guide will be deleted from your Radarr instance.",
+ "default": false
+ },
+ "custom_formats": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "A list of one or more sets of custom formats each with an optional set of quality profiles names that identify which quality profiles to assign the scores for those custom formats to.",
+ "anyOf": [
+ {
+ "required": ["trash_ids"]
+ },
+ {
+ "required": ["names"]
+ }
+ ],
+ "properties": {
+ "names": {
+ "type": "array",
+ "uniqueItems": true,
+ "description": "A list of one or more custom format names to synchronize to Radarr. The names must be taken from the JSON itself in the guide.",
+ "minItems": 1,
+ "items": {
+ "type": "string"
+ }
+ },
+ "trash_ids": {
+ "$ref": "#/$defs/trash_ids_list"
+ },
+ "quality_profiles": {
+ "type": "array",
+ "description": "One or more quality profiles to update with the scores from the specified custom formats.",
+ "minItems": 1,
+ "items": {
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of one of the quality profiles in Radarr."
+ },
+ "score": {
+ "type": "integer",
+ "description": "A positive or negative number representing the score to apply to *all* custom formats listed in the names list."
+ },
+ "reset_unmatched_scores": {
+ "type": "boolean",
+ "description": "If set to true, enables setting scores to 0 in quality profiles where either a name was not mentioned in the names array or it was in that list but did not get a score (e.g. no score in guide).",
+ "default": false
+ }
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/src/Common.TestLibrary/Common.TestLibrary.csproj b/src/Common.TestLibrary/Common.TestLibrary.csproj
new file mode 100644
index 00000000..cade29ea
--- /dev/null
+++ b/src/Common.TestLibrary/Common.TestLibrary.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Common.TestLibrary/CommonMockFileSystemExtensions.cs b/src/Common.TestLibrary/CommonMockFileSystemExtensions.cs
new file mode 100644
index 00000000..1e0c25b0
--- /dev/null
+++ b/src/Common.TestLibrary/CommonMockFileSystemExtensions.cs
@@ -0,0 +1,32 @@
+using System.IO.Abstractions;
+using System.IO.Abstractions.TestingHelpers;
+using System.Reflection;
+
+namespace Common.TestLibrary;
+
+public static class CommonMockFileSystemExtensions
+{
+ public static void AddFileFromResource(this MockFileSystem fs, string resourceFilename)
+ {
+ fs.AddFileFromResource(resourceFilename, resourceFilename, Assembly.GetCallingAssembly());
+ }
+
+ public static void AddFileFromResource(this MockFileSystem fs, IFileInfo file, string resourceFilename,
+ string resourceDir = "Data")
+ {
+ fs.AddFileFromResource(file.FullName, resourceFilename, Assembly.GetCallingAssembly(), resourceDir);
+ }
+
+ public static void AddFileFromResource(this MockFileSystem fs, string file, string resourceFilename,
+ string resourceDir = "Data")
+ {
+ fs.AddFileFromResource(file, resourceFilename, Assembly.GetCallingAssembly(), resourceDir);
+ }
+
+ public static void AddFileFromResource(this MockFileSystem fs, string file, string resourceFilename,
+ Assembly assembly, string resourceDir = "Data")
+ {
+ var resourceReader = new ResourceDataReader(assembly, resourceDir);
+ fs.AddFile(file, new MockFileData(resourceReader.ReadData(resourceFilename)));
+ }
+}
diff --git a/src/Common/ResourceDataReader.cs b/src/Common/ResourceDataReader.cs
index f354fb6d..fe15c0ba 100644
--- a/src/Common/ResourceDataReader.cs
+++ b/src/Common/ResourceDataReader.cs
@@ -9,6 +9,12 @@ public class ResourceDataReader
private readonly string? _namespace;
private readonly string _subdirectory;
+ public ResourceDataReader(Assembly assembly, string subdirectory = "")
+ {
+ _subdirectory = subdirectory;
+ _assembly = assembly;
+ }
+
public ResourceDataReader(Type typeWithNamespaceToUse, string subdirectory = "")
{
_subdirectory = subdirectory;
@@ -17,21 +23,48 @@ public class ResourceDataReader
}
public string ReadData(string filename)
+ {
+ var resourcePath = BuildResourceName(filename);
+ var foundResource = FindResourcePath(resourcePath);
+ return GetResourceData(foundResource);
+ }
+
+ private string BuildResourceName(string filename)
{
var nameBuilder = new StringBuilder();
- nameBuilder.Append(_namespace);
+
+ if (!string.IsNullOrEmpty(_namespace))
+ {
+ nameBuilder.Append($"{_namespace}.");
+ }
+
if (!string.IsNullOrEmpty(_subdirectory))
{
- nameBuilder.Append($".{_subdirectory}");
+ nameBuilder.Append($"{_subdirectory}.");
}
- nameBuilder.Append($".{filename}");
+ nameBuilder.Append(filename);
+ return nameBuilder.ToString();
+ }
- var resourceName = nameBuilder.ToString();
- using var stream = _assembly?.GetManifestResourceStream(resourceName);
- if (stream == null)
+ private string FindResourcePath(string resourcePath)
+ {
+ var foundResource = _assembly?.GetManifestResourceNames()
+ .FirstOrDefault(x => x.EndsWith(resourcePath));
+ if (foundResource is null)
+ {
+ throw new ArgumentException($"Embedded resource not found: {resourcePath}");
+ }
+
+ return foundResource;
+ }
+
+ private string GetResourceData(string resourcePath)
+ {
+ using var stream = _assembly?.GetManifestResourceStream(resourcePath);
+ if (stream is null)
{
- throw new ArgumentException($"Embedded resource not found: {resourceName}");
+ throw new ArgumentException($"Unable to open embedded resource: {resourcePath}");
}
using var reader = new StreamReader(stream);
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 078256dc..0d4d923d 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -37,10 +37,7 @@
-
-
-
-
+
@@ -61,7 +58,7 @@
-
+
diff --git a/src/Recyclarr.TestLibrary/Data/metadata.json b/src/Recyclarr.TestLibrary/Data/metadata.json
new file mode 100644
index 00000000..326a8299
--- /dev/null
+++ b/src/Recyclarr.TestLibrary/Data/metadata.json
@@ -0,0 +1,13 @@
+{
+ "json_paths": {
+ "radarr": {
+ "custom_formats": ["docs/json/radarr/cf"],
+ "qualities": ["docs/json/radarr/quality-size"]
+ },
+ "sonarr": {
+ "release_profiles": ["docs/json/sonarr/rp"],
+ "custom_formats": ["docs/json/sonarr/cf"],
+ "qualities": ["docs/json/sonarr/quality-size"]
+ }
+ }
+}
diff --git a/src/Recyclarr.TestLibrary/IntegrationFixture.cs b/src/Recyclarr.TestLibrary/IntegrationFixture.cs
index 21442a86..d618eb35 100644
--- a/src/Recyclarr.TestLibrary/IntegrationFixture.cs
+++ b/src/Recyclarr.TestLibrary/IntegrationFixture.cs
@@ -3,8 +3,13 @@ using System.IO.Abstractions.TestingHelpers;
using Autofac;
using Autofac.Features.ResolveAnything;
using CliFx.Infrastructure;
+using Common.TestLibrary;
+using NSubstitute;
using NUnit.Framework;
using Serilog.Events;
+using TrashLib.Startup;
+using VersionControl;
+using VersionControl.Wrappers;
namespace Recyclarr.TestLibrary;
@@ -12,20 +17,38 @@ namespace Recyclarr.TestLibrary;
public abstract class IntegrationFixture : IDisposable
{
private readonly ILifetimeScope _container;
- private readonly FakeConsole _console = new();
protected IntegrationFixture()
{
var compRoot = new CompositionRoot();
- _container = compRoot.Setup(default, _console, LogEventLevel.Debug).Container
+ _container = compRoot.Setup(default, Console, LogEventLevel.Debug).Container
.BeginLifetimeScope(builder =>
{
builder.RegisterSource();
builder.RegisterInstance(Fs).As();
+
+ RegisterMockFor(builder);
+ RegisterMockFor(builder);
+ RegisterMockFor(builder);
});
+
+ SetupMetadataJson();
+ }
+
+ private void SetupMetadataJson()
+ {
+ var paths = Resolve();
+ var metadataFile = paths.RepoDirectory.File("metadata.json");
+ Fs.AddFileFromResource(metadataFile, "metadata.json");
}
protected MockFileSystem Fs { get; } = new();
+ protected FakeInMemoryConsole Console { get; } = new();
+
+ private static void RegisterMockFor(ContainerBuilder builder) where T : class
+ {
+ builder.RegisterInstance(Substitute.For()).As();
+ }
protected T Resolve(Action customRegistrations) where T : notnull
{
@@ -46,7 +69,7 @@ public abstract class IntegrationFixture : IDisposable
}
_container.Dispose();
- _console.Dispose();
+ Console.Dispose();
}
public void Dispose()
diff --git a/src/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj b/src/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj
index 6cb7803a..289d6f05 100644
--- a/src/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj
+++ b/src/Recyclarr.TestLibrary/Recyclarr.TestLibrary.csproj
@@ -1,9 +1,6 @@
+
-
-
-
-
diff --git a/src/Recyclarr.Tests/Config/Services/ConfigurationLoaderTest.cs b/src/Recyclarr.Tests/Config/Services/ConfigurationLoaderTest.cs
index 7ad36265..9b9d00e4 100644
--- a/src/Recyclarr.Tests/Config/Services/ConfigurationLoaderTest.cs
+++ b/src/Recyclarr.Tests/Config/Services/ConfigurationLoaderTest.cs
@@ -50,6 +50,8 @@ public class ConfigurationLoaderTest
{
public string BaseUrl => "";
public string ApiKey => "";
+ public ICollection CustomFormats => new List();
+ public bool DeleteOldCustomFormats => false;
}
[Test, AutoMockData(typeof(ConfigurationLoaderTest), nameof(BuildContainer))]
diff --git a/src/Recyclarr.Tests/ServiceCompatibilityIntegrationTest.cs b/src/Recyclarr.Tests/ServiceCompatibilityIntegrationTest.cs
index fcc9c2d2..a03d9b36 100644
--- a/src/Recyclarr.Tests/ServiceCompatibilityIntegrationTest.cs
+++ b/src/Recyclarr.Tests/ServiceCompatibilityIntegrationTest.cs
@@ -12,7 +12,7 @@ namespace Recyclarr.Tests;
public class ServiceCompatibilityIntegrationTest : IntegrationFixture
{
[Test]
- public void Load_data_correctly_when_file_exists()
+ public void Load_settings_yml_correctly_when_file_exists()
{
var sut = Resolve();
var paths = Resolve();
diff --git a/src/Recyclarr.sln b/src/Recyclarr.sln
index c4925c7f..e6176bde 100644
--- a/src/Recyclarr.sln
+++ b/src/Recyclarr.sln
@@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Recyclarr.TestLibrary", "Re
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Recyclarr.Gui", "Recyclarr.Gui\Recyclarr.Gui.csproj", "{53EECBC0-E0EA-4D6C-925C-5DB8C42CCB85}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.TestLibrary", "Common.TestLibrary\Common.TestLibrary.csproj", "{A92321B5-2796-467B-B5A5-2BFC41167A25}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -91,6 +93,10 @@ Global
{53EECBC0-E0EA-4D6C-925C-5DB8C42CCB85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53EECBC0-E0EA-4D6C-925C-5DB8C42CCB85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53EECBC0-E0EA-4D6C-925C-5DB8C42CCB85}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A92321B5-2796-467B-B5A5-2BFC41167A25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A92321B5-2796-467B-B5A5-2BFC41167A25}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A92321B5-2796-467B-B5A5-2BFC41167A25}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A92321B5-2796-467B-B5A5-2BFC41167A25}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
diff --git a/src/Recyclarr/Command/RadarrCommand.cs b/src/Recyclarr/Command/RadarrCommand.cs
index ac23db89..8caef3ab 100644
--- a/src/Recyclarr/Command/RadarrCommand.cs
+++ b/src/Recyclarr/Command/RadarrCommand.cs
@@ -3,8 +3,9 @@ using JetBrains.Annotations;
using Recyclarr.Config;
using Serilog;
using TrashLib.Extensions;
+using TrashLib.Services.CustomFormat;
+using TrashLib.Services.Radarr;
using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat;
using TrashLib.Services.Radarr.QualityDefinition;
namespace Recyclarr.Command;
@@ -32,6 +33,7 @@ internal class RadarrCommand : ServiceCommand
var customFormatUpdaterFactory = container.Resolve>();
var qualityUpdaterFactory = container.Resolve>();
var configLoader = container.Resolve>();
+ var guideService = container.Resolve();
if (ListCustomFormats)
{
@@ -56,7 +58,7 @@ internal class RadarrCommand : ServiceCommand
if (config.CustomFormats.Count > 0)
{
- await customFormatUpdaterFactory().Process(Preview, config);
+ await customFormatUpdaterFactory().Process(Preview, config.CustomFormats, guideService);
}
}
}
diff --git a/src/Recyclarr/Command/SonarrCommand.cs b/src/Recyclarr/Command/SonarrCommand.cs
index 7c3a7c23..2ee139ab 100644
--- a/src/Recyclarr/Command/SonarrCommand.cs
+++ b/src/Recyclarr/Command/SonarrCommand.cs
@@ -4,10 +4,12 @@ using JetBrains.Annotations;
using Recyclarr.Config;
using Serilog;
using TrashLib.Extensions;
+using TrashLib.Services.CustomFormat;
using TrashLib.Services.Sonarr;
using TrashLib.Services.Sonarr.Config;
using TrashLib.Services.Sonarr.QualityDefinition;
using TrashLib.Services.Sonarr.ReleaseProfile;
+using TrashLib.Services.Sonarr.ReleaseProfile.Guide;
namespace Recyclarr.Command;
@@ -30,6 +32,10 @@ public class SonarrCommand : ServiceCommand
"List available quality definition types from the guide.")]
public bool ListQualities { get; [UsedImplicitly] set; }
+ [CommandOption("list-custom-formats", Description =
+ "List available custom formats from the guide in YAML format.")]
+ public bool ListCustomFormats { get; [UsedImplicitly] set; }
+
public override string Name => "Sonarr";
public override async Task Process(IServiceLocatorProxy container)
@@ -41,6 +47,8 @@ public class SonarrCommand : ServiceCommand
var qualityUpdaterFactory = container.Resolve>();
var configLoader = container.Resolve>();
var log = container.Resolve();
+ var customFormatUpdaterFactory = container.Resolve>();
+ var guideService = container.Resolve();
if (ListReleaseProfiles)
{
@@ -54,6 +62,12 @@ public class SonarrCommand : ServiceCommand
return;
}
+ if (ListCustomFormats)
+ {
+ lister.ListCustomFormats();
+ return;
+ }
+
if (ListTerms != "empty")
{
if (!string.IsNullOrEmpty(ListTerms))
@@ -82,6 +96,11 @@ public class SonarrCommand : ServiceCommand
{
await qualityUpdaterFactory().Process(Preview, config);
}
+
+ if (config.CustomFormats.Count > 0)
+ {
+ await customFormatUpdaterFactory().Process(Preview, config.CustomFormats, guideService);
+ }
}
}
}
diff --git a/src/Recyclarr/CompositionRoot.cs b/src/Recyclarr/CompositionRoot.cs
index 3c694bf0..fe4701e6 100644
--- a/src/Recyclarr/CompositionRoot.cs
+++ b/src/Recyclarr/CompositionRoot.cs
@@ -16,7 +16,10 @@ using Serilog.Events;
using TrashLib;
using TrashLib.Cache;
using TrashLib.Config;
+using TrashLib.Config.Services;
using TrashLib.Repo;
+using TrashLib.Services.Common;
+using TrashLib.Services.CustomFormat;
using TrashLib.Services.Radarr;
using TrashLib.Services.Sonarr;
using TrashLib.Startup;
@@ -45,12 +48,15 @@ public class CompositionRoot : ICompositionRoot
builder.RegisterModule();
builder.RegisterModule();
builder.RegisterModule();
+ builder.RegisterModule();
+ builder.RegisterModule();
// Needed for Autofac.Extras.Ordering
builder.RegisterSource();
builder.RegisterModule();
builder.RegisterType().As();
+ builder.RegisterType().As();
builder.RegisterType();
ConfigurationRegistrations(builder);
diff --git a/src/TrashLib.TestLibrary/CfTestUtils.cs b/src/TrashLib.TestLibrary/CfTestUtils.cs
index ebbc389a..2bb7c8b9 100644
--- a/src/TrashLib.TestLibrary/CfTestUtils.cs
+++ b/src/TrashLib.TestLibrary/CfTestUtils.cs
@@ -1,4 +1,4 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models;
namespace TrashLib.TestLibrary;
diff --git a/src/TrashLib.TestLibrary/NewCf.cs b/src/TrashLib.TestLibrary/NewCf.cs
index 6d7314ff..1405a5e6 100644
--- a/src/TrashLib.TestLibrary/NewCf.cs
+++ b/src/TrashLib.TestLibrary/NewCf.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
namespace TrashLib.TestLibrary;
diff --git a/src/TrashLib.Tests/Config/Settings/SettingsPersisterTest.cs b/src/TrashLib.Tests/Config/Settings/SettingsPersisterTest.cs
index e1b1459a..25ada313 100644
--- a/src/TrashLib.Tests/Config/Settings/SettingsPersisterTest.cs
+++ b/src/TrashLib.Tests/Config/Settings/SettingsPersisterTest.cs
@@ -19,7 +19,7 @@ public class SettingsPersisterTest
[Frozen] IAppPaths paths,
SettingsProvider sut)
{
- var settings = sut.Settings;
+ _ = sut.Settings;
fileSystem.AllFiles.Should().ContainSingle(paths.SettingsPath.FullName);
}
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/CachePersisterTest.cs b/src/TrashLib.Tests/CustomFormat/CachePersisterTest.cs
similarity index 94%
rename from src/TrashLib.Tests/Radarr/CustomFormat/CachePersisterTest.cs
rename to src/TrashLib.Tests/CustomFormat/CachePersisterTest.cs
index 60c2d1b2..c19e0cb6 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/CachePersisterTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/CachePersisterTest.cs
@@ -5,12 +5,12 @@ using NSubstitute;
using NUnit.Framework;
using Serilog;
using TrashLib.Cache;
-using TrashLib.Services.Radarr.CustomFormat;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
-namespace TrashLib.Tests.Radarr.CustomFormat;
+namespace TrashLib.Tests.CustomFormat;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/CustomFormatGroupParserTest.cs b/src/TrashLib.Tests/CustomFormat/Guide/CustomFormatGroupParserTest.cs
similarity index 97%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Guide/CustomFormatGroupParserTest.cs
rename to src/TrashLib.Tests/CustomFormat/Guide/CustomFormatGroupParserTest.cs
index 25de7b69..0eb52100 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/CustomFormatGroupParserTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Guide/CustomFormatGroupParserTest.cs
@@ -4,10 +4,10 @@ using AutoFixture.NUnit3;
using FluentAssertions;
using NUnit.Framework;
using TestLibrary.AutoFixture;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
+using TrashLib.Services.CustomFormat.Guide;
using TrashLib.Startup;
-namespace TrashLib.Tests.Radarr.CustomFormat.Guide;
+namespace TrashLib.Tests.CustomFormat.Guide;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/CustomFormat/Guide/CustomFormatLoaderTest.cs b/src/TrashLib.Tests/CustomFormat/Guide/CustomFormatLoaderTest.cs
new file mode 100644
index 00000000..9071b34b
--- /dev/null
+++ b/src/TrashLib.Tests/CustomFormat/Guide/CustomFormatLoaderTest.cs
@@ -0,0 +1,55 @@
+using System.IO.Abstractions.Extensions;
+using System.IO.Abstractions.TestingHelpers;
+using FluentAssertions;
+using Newtonsoft.Json.Linq;
+using NUnit.Framework;
+using Recyclarr.TestLibrary;
+using TestLibrary.FluentAssertions;
+using TrashLib.Services.CustomFormat.Guide;
+using TrashLib.TestLibrary;
+
+namespace TrashLib.Tests.CustomFormat.Guide;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class CustomFormatLoaderTest : IntegrationFixture
+{
+ [Test]
+ public void Get_custom_format_json_works()
+ {
+ var sut = Resolve();
+ Fs.AddFile("first.json", new MockFileData("{'name':'first','trash_id':'1'}"));
+ Fs.AddFile("second.json", new MockFileData("{'name':'second','trash_id':'2'}"));
+
+ var results = sut.LoadAllCustomFormatsAtPaths(new[] {Fs.CurrentDirectory()});
+
+ results.Should().BeEquivalentTo(new[]
+ {
+ NewCf.Data("first", "1"),
+ NewCf.Data("second", "2")
+ });
+ }
+
+ [Test]
+ public void Trash_properties_are_removed()
+ {
+ Fs.AddFile("first.json", new MockFileData(@"
+{
+ 'name':'first',
+ 'trash_id':'1',
+ 'trash_foo': 'foo',
+ 'trash_bar': 'bar',
+ 'extra': 'e1'
+}"));
+
+ var sut = Resolve();
+
+ var results = sut.LoadAllCustomFormatsAtPaths(new[] {Fs.CurrentDirectory()});
+
+ const string expectedExtraJson = @"{'name':'first','extra': 'e1'}";
+
+ results.Should()
+ .ContainSingle().Which.ExtraJson.Should()
+ .BeEquivalentTo(JObject.Parse(expectedExtraJson), op => op.Using(new JsonEquivalencyStep()));
+ }
+}
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/RadarrGuideDataListerTest.cs b/src/TrashLib.Tests/CustomFormat/GuideDataListerTest.cs
similarity index 63%
rename from src/TrashLib.Tests/Radarr/CustomFormat/RadarrGuideDataListerTest.cs
rename to src/TrashLib.Tests/CustomFormat/GuideDataListerTest.cs
index c8081670..3c99dfa8 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/RadarrGuideDataListerTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/GuideDataListerTest.cs
@@ -1,24 +1,21 @@
using AutoFixture.NUnit3;
using CliFx.Infrastructure;
using FluentAssertions;
-using NSubstitute;
using NUnit.Framework;
using TestLibrary.AutoFixture;
-using TrashLib.Services.Radarr.CustomFormat;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
+using TrashLib.Services.Common;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat;
+namespace TrashLib.Tests.CustomFormat;
[TestFixture]
[Parallelizable(ParallelScope.All)]
-public class RadarrGuideDataListerTest
+public class GuideDataListerTest
{
[Test, AutoMockData]
public void Custom_formats_appear_in_console_output(
- [Frozen] IRadarrGuideService guide,
[Frozen(Matching.ImplementedInterfaces)] FakeInMemoryConsole console,
- RadarrGuideDataLister sut)
+ GuideDataLister sut)
{
var testData = new[]
{
@@ -26,9 +23,7 @@ public class RadarrGuideDataListerTest
NewCf.Data("Second", "456")
};
- guide.GetCustomFormatData().Returns(testData);
-
- sut.ListCustomFormats();
+ sut.ListCustomFormats(testData);
console.ReadOutputString().Should().ContainAll(
testData.SelectMany(x => new[] {x.Name, x.TrashId}));
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat1.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat1.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat1.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat1.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat1_Processed.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat1_Processed.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat1_Processed.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat1_Processed.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat2.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat2.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat2.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat2.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat2_Processed.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat2_Processed.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/ImportableCustomFormat2_Processed.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/ImportableCustomFormat2_Processed.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/NoScore.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/NoScore.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/NoScore.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/NoScore.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/WontBeInConfig.json b/src/TrashLib.Tests/CustomFormat/Processors/Data/WontBeInConfig.json
similarity index 100%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/Data/WontBeInConfig.json
rename to src/TrashLib.Tests/CustomFormat/Processors/Data/WontBeInConfig.json
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideProcessorTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/GuideProcessorTest.cs
similarity index 89%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideProcessorTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/GuideProcessorTest.cs
index 49eb4573..d6c9b513 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideProcessorTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/GuideProcessorTest.cs
@@ -6,14 +6,15 @@ using NSubstitute;
using NUnit.Framework;
using Serilog;
using TestLibrary.FluentAssertions;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Processors;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Guide;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Processors;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
+using TrashLib.Services.Radarr;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors;
+namespace TrashLib.Tests.CustomFormat.Processors;
[TestFixture]
[Parallelizable(ParallelScope.All)]
@@ -35,8 +36,11 @@ public class GuideProcessorTest
public ResourceDataReader Data { get; }
- public CustomFormatData ReadCustomFormat(string textFile) =>
- LocalRepoRadarrGuideService.ParseCustomFormatData(ReadText(textFile));
+ public CustomFormatData ReadCustomFormat(string textFile)
+ {
+ var parser = new CustomFormatParser();
+ return parser.ParseCustomFormatData(ReadText(textFile));
+ }
public string ReadText(string textFile) => Data.ReadData(textFile);
public JObject ReadJson(string jsonFile) => JObject.Parse(ReadText(jsonFile));
@@ -48,7 +52,7 @@ public class GuideProcessorTest
{
var ctx = new Context();
var guideService = Substitute.For();
- var guideProcessor = new GuideProcessor(guideService, () => new TestGuideProcessorSteps());
+ var guideProcessor = new GuideProcessor(() => new TestGuideProcessorSteps());
// simulate guide data
guideService.GetCustomFormatData().Returns(new[]
@@ -82,7 +86,7 @@ public class GuideProcessorTest
}
};
- await guideProcessor.BuildGuideDataAsync(config, null);
+ await guideProcessor.BuildGuideDataAsync(config, null, guideService);
var expectedProcessedCustomFormatData = new List
{
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs
similarity index 95%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs
index e089c882..d7a2e8c1 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/ConfigStepTest.cs
@@ -2,13 +2,13 @@ using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using TestLibrary.AutoFixture;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.GuideSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs
similarity index 97%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs
index d125a951..ced529a9 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/CustomFormatStepTest.cs
@@ -4,13 +4,13 @@ using Newtonsoft.Json.Linq;
using NUnit.Framework;
using TestLibrary.AutoFixture;
using TestLibrary.FluentAssertions;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.GuideSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs
similarity index 94%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs
index c006103a..f002c667 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/GuideSteps/QualityProfileStepTest.cs
@@ -1,11 +1,11 @@
using FluentAssertions;
using NUnit.Framework;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.GuideSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceProcessorTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceProcessorTest.cs
similarity index 92%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceProcessorTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/PersistenceProcessorTest.cs
index f034da79..c018f15a 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceProcessorTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceProcessorTest.cs
@@ -3,13 +3,13 @@ using Newtonsoft.Json.Linq;
using NSubstitute;
using NUnit.Framework;
using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors;
using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors;
+namespace TrashLib.Tests.CustomFormat.Processors;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs
similarity index 81%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs
index ffa7c608..b3e9987e 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStepTest.cs
@@ -1,12 +1,12 @@
using NSubstitute;
using NUnit.Framework;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.PersistenceSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs
similarity index 97%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs
index d8577ece..bb1193ab 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/JsonTransactionStepTest.cs
@@ -3,9 +3,9 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using TestLibrary.FluentAssertions;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
using TrashLib.TestLibrary;
/* Sample Custom Format response from Radarr API
@@ -36,7 +36,7 @@ using TrashLib.TestLibrary;
}
*/
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.PersistenceSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs
similarity index 95%
rename from src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs
rename to src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs
index 95d3fb70..ee3e9e9d 100644
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs
+++ b/src/TrashLib.Tests/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStepTest.cs
@@ -5,13 +5,13 @@ using Newtonsoft.Json.Linq;
using NSubstitute;
using NUnit.Framework;
using TestLibrary.NSubstitute;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
using TrashLib.TestLibrary;
-namespace TrashLib.Tests.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Tests.CustomFormat.Processors.PersistenceSteps;
[TestFixture]
[Parallelizable(ParallelScope.All)]
diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideServiceTest.cs b/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideServiceTest.cs
deleted file mode 100644
index 16fdfa76..00000000
--- a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideServiceTest.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System.IO.Abstractions;
-using System.IO.Abstractions.TestingHelpers;
-using AutoFixture.NUnit3;
-using FluentAssertions;
-using Newtonsoft.Json.Linq;
-using NSubstitute;
-using NUnit.Framework;
-using TestLibrary.AutoFixture;
-using TestLibrary.FluentAssertions;
-using TrashLib.Repo;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
-using TrashLib.Startup;
-using TrashLib.TestLibrary;
-
-namespace TrashLib.Tests.Radarr.CustomFormat.Guide;
-
-[TestFixture]
-[Parallelizable(ParallelScope.All)]
-public class LocalRepoRadarrGuideServiceTest
-{
- [Test, AutoMockData]
- public void Get_custom_format_json_works(
- [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
- [Frozen] IAppPaths appPaths,
- [Frozen] IRepoPaths repoPaths,
- LocalRepoRadarrGuideService sut)
- {
- var jsonDir = appPaths.RepoDirectory
- .SubDirectory("docs")
- .SubDirectory("json")
- .SubDirectory("radarr");
-
- fs.AddFile(jsonDir.File("first.json").FullName, new MockFileData("{'name':'first','trash_id':'1'}"));
- fs.AddFile(jsonDir.File("second.json").FullName, new MockFileData("{'name':'second','trash_id':'2'}"));
-
- repoPaths.RadarrCustomFormatPaths.Returns(new[] {jsonDir});
-
- var results = sut.GetCustomFormatData();
-
- results.Should().BeEquivalentTo(new[]
- {
- NewCf.Data("first", "1"),
- NewCf.Data("second", "2")
- });
- }
-
- [Test, AutoMockData]
- public void Trash_properties_are_removed(
- [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
- [Frozen] IAppPaths appPaths,
- [Frozen] IRepoPaths repoPaths,
- LocalRepoRadarrGuideService sut)
- {
- var jsonDir = appPaths.RepoDirectory
- .SubDirectory("docs")
- .SubDirectory("json")
- .SubDirectory("radarr");
-
- fs.AddFile(jsonDir.File("first.json").FullName, new MockFileData(@"
-{
- 'name':'first',
- 'trash_id':'1',
- 'trash_foo': 'foo',
- 'trash_bar': 'bar',
- 'extra': 'e1'
-}"));
-
- repoPaths.RadarrCustomFormatPaths.Returns(new[] {jsonDir});
-
- var results = sut.GetCustomFormatData();
-
- const string expectedExtraJson = @"{'name':'first','extra': 'e1'}";
-
- results.Should()
- .ContainSingle().Which.ExtraJson.Should()
- .BeEquivalentTo(JObject.Parse(expectedExtraJson), op => op.Using(new JsonEquivalencyStep()));
- }
-}
diff --git a/src/TrashLib.Tests/Radarr/RadarrConfigurationTest.cs b/src/TrashLib.Tests/Radarr/RadarrConfigurationTest.cs
index 61b3ce22..40f62250 100644
--- a/src/TrashLib.Tests/Radarr/RadarrConfigurationTest.cs
+++ b/src/TrashLib.Tests/Radarr/RadarrConfigurationTest.cs
@@ -4,6 +4,7 @@ using FluentAssertions;
using FluentValidation;
using NUnit.Framework;
using TrashLib.Config;
+using TrashLib.Config.Services;
using TrashLib.Services.Radarr;
using TrashLib.Services.Radarr.Config;
diff --git a/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs
index 568106de..48407028 100644
--- a/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs
+++ b/src/TrashLib.Tests/Sonarr/SonarrCompatibilityTest.cs
@@ -8,6 +8,7 @@ using Newtonsoft.Json.Serialization;
using NSubstitute;
using NUnit.Framework;
using TestLibrary.AutoFixture;
+using TrashLib.Config.Services;
using TrashLib.ExceptionTypes;
using TrashLib.Services.Sonarr;
using TrashLib.Services.Sonarr.Api;
@@ -152,4 +153,40 @@ public class SonarrCompatibilityTest
await act.Should().NotThrowAsync();
}
+
+ [Test, AutoMockData]
+ public async Task Failure_when_custom_formats_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
+ {
+ CustomFormats = new List {new()}
+ };
+
+ var act = () => updater.Process(false, config);
+
+ await act.Should().ThrowAsync().WithMessage("Sonarr v3*custom format*use*v4*");
+ }
+
+ [Test, AutoMockData]
+ public async Task No_failure_when_custom_formats_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
+ {
+ CustomFormats = new List {new()}
+ };
+
+ var act = () => updater.Process(false, config);
+
+ await act.Should().NotThrowAsync();
+ }
}
diff --git a/src/TrashLib/Config/Services/IServerInfo.cs b/src/TrashLib/Config/Services/IServerInfo.cs
index dd1c4b8f..11e810cf 100644
--- a/src/TrashLib/Config/Services/IServerInfo.cs
+++ b/src/TrashLib/Config/Services/IServerInfo.cs
@@ -5,4 +5,5 @@ namespace TrashLib.Config.Services;
public interface IServerInfo
{
Url BuildRequest();
+ string SanitizedBaseUrl { get; }
}
diff --git a/src/TrashLib/Config/Services/IServiceConfiguration.cs b/src/TrashLib/Config/Services/IServiceConfiguration.cs
index 76dfb169..fe03bd9e 100644
--- a/src/TrashLib/Config/Services/IServiceConfiguration.cs
+++ b/src/TrashLib/Config/Services/IServiceConfiguration.cs
@@ -4,4 +4,6 @@ public interface IServiceConfiguration
{
string BaseUrl { get; }
string ApiKey { get; }
+ ICollection CustomFormats { get; }
+ bool DeleteOldCustomFormats { get; }
}
diff --git a/src/TrashLib/Config/Services/ServerInfo.cs b/src/TrashLib/Config/Services/ServerInfo.cs
index 67428e56..d7487328 100644
--- a/src/TrashLib/Config/Services/ServerInfo.cs
+++ b/src/TrashLib/Config/Services/ServerInfo.cs
@@ -1,8 +1,9 @@
using Flurl;
+using TrashLib.Extensions;
namespace TrashLib.Config.Services;
-internal class ServerInfo : IServerInfo
+public class ServerInfo : IServerInfo
{
private readonly IConfigurationProvider _config;
@@ -20,4 +21,6 @@ internal class ServerInfo : IServerInfo
.AppendPathSegment("api/v3")
.SetQueryParams(new {apikey = apiKey});
}
+
+ public string SanitizedBaseUrl => FlurlLogging.SanitizeUrl(_config.ActiveConfiguration.BaseUrl);
}
diff --git a/src/TrashLib/Config/Services/ServiceConfiguration.cs b/src/TrashLib/Config/Services/ServiceConfiguration.cs
index 47757eab..e6371943 100644
--- a/src/TrashLib/Config/Services/ServiceConfiguration.cs
+++ b/src/TrashLib/Config/Services/ServiceConfiguration.cs
@@ -1,7 +1,27 @@
+using JetBrains.Annotations;
+
namespace TrashLib.Config.Services;
public abstract class ServiceConfiguration : IServiceConfiguration
{
public string BaseUrl { get; init; } = "";
public string ApiKey { get; init; } = "";
+ public ICollection CustomFormats { get; init; } = new List();
+ public bool DeleteOldCustomFormats { get; init; }
+}
+
+[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
+public class CustomFormatConfig
+{
+ public ICollection Names { get; init; } = new List();
+ public ICollection TrashIds { get; init; } = new List();
+ public ICollection QualityProfiles { get; init; } = new List();
+}
+
+[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
+public class QualityProfileConfig
+{
+ public string Name { get; init; } = "";
+ public int? Score { get; init; }
+ public bool ResetUnmatchedScores { get; init; }
}
diff --git a/src/TrashLib/Repo/IRepoPaths.cs b/src/TrashLib/Repo/IRepoPaths.cs
index b5711881..856ec2a9 100644
--- a/src/TrashLib/Repo/IRepoPaths.cs
+++ b/src/TrashLib/Repo/IRepoPaths.cs
@@ -8,4 +8,5 @@ public interface IRepoPaths
IReadOnlyCollection SonarrReleaseProfilePaths { get; }
IReadOnlyCollection SonarrQualityPaths { get; }
IReadOnlyCollection RadarrQualityPaths { get; }
+ IReadOnlyCollection SonarrCustomFormatPaths { get; }
}
diff --git a/src/TrashLib/Repo/RepoMetadata.cs b/src/TrashLib/Repo/RepoMetadata.cs
index d6e14c26..18cb69a3 100644
--- a/src/TrashLib/Repo/RepoMetadata.cs
+++ b/src/TrashLib/Repo/RepoMetadata.cs
@@ -7,7 +7,8 @@ public record RadarrMetadata(
public record SonarrMetadata(
IReadOnlyCollection ReleaseProfiles,
- IReadOnlyCollection Qualities
+ IReadOnlyCollection Qualities,
+ IReadOnlyCollection CustomFormats
);
public record JsonPaths(
diff --git a/src/TrashLib/Repo/RepoPaths.cs b/src/TrashLib/Repo/RepoPaths.cs
index d61a8357..1f3aad89 100644
--- a/src/TrashLib/Repo/RepoPaths.cs
+++ b/src/TrashLib/Repo/RepoPaths.cs
@@ -6,5 +6,6 @@ public record RepoPaths(
IReadOnlyCollection RadarrCustomFormatPaths,
IReadOnlyCollection SonarrReleaseProfilePaths,
IReadOnlyCollection RadarrQualityPaths,
- IReadOnlyCollection SonarrQualityPaths
+ IReadOnlyCollection SonarrQualityPaths,
+ IReadOnlyCollection SonarrCustomFormatPaths
) : IRepoPaths;
diff --git a/src/TrashLib/Repo/RepoPathsFactory.cs b/src/TrashLib/Repo/RepoPathsFactory.cs
index bf395e5f..cbc9056b 100644
--- a/src/TrashLib/Repo/RepoPathsFactory.cs
+++ b/src/TrashLib/Repo/RepoPathsFactory.cs
@@ -29,7 +29,8 @@ public class RepoPathsFactory : IRepoPathsFactory
ToDirectoryInfoList(metadata.JsonPaths.Radarr.CustomFormats),
ToDirectoryInfoList(metadata.JsonPaths.Sonarr.ReleaseProfiles),
ToDirectoryInfoList(metadata.JsonPaths.Radarr.Qualities),
- ToDirectoryInfoList(metadata.JsonPaths.Sonarr.Qualities)
+ ToDirectoryInfoList(metadata.JsonPaths.Sonarr.Qualities),
+ ToDirectoryInfoList(metadata.JsonPaths.Sonarr.CustomFormats)
);
}
}
diff --git a/src/TrashLib/Services/Common/GuideDataLister.cs b/src/TrashLib/Services/Common/GuideDataLister.cs
new file mode 100644
index 00000000..002f4314
--- /dev/null
+++ b/src/TrashLib/Services/Common/GuideDataLister.cs
@@ -0,0 +1,28 @@
+using CliFx.Infrastructure;
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.Common;
+
+public class GuideDataLister : IGuideDataLister
+{
+ private readonly IConsole _console;
+
+ public GuideDataLister(IConsole console)
+ {
+ _console = console;
+ }
+
+ public void ListCustomFormats(IEnumerable customFormats)
+ {
+ _console.Output.WriteLine("\nList of Custom Formats in the TRaSH Guides:\n");
+
+ foreach (var cf in customFormats)
+ {
+ _console.Output.WriteLine($" - {cf.TrashId} # {cf.Name}");
+ }
+
+ _console.Output.WriteLine(
+ "\nThe above Custom Formats are in YAML format and ready to be copied & pasted " +
+ "under the `trash_ids:` property.");
+ }
+}
diff --git a/src/TrashLib/Services/Common/GuideServicesAutofacModule.cs b/src/TrashLib/Services/Common/GuideServicesAutofacModule.cs
new file mode 100644
index 00000000..e4ce44d3
--- /dev/null
+++ b/src/TrashLib/Services/Common/GuideServicesAutofacModule.cs
@@ -0,0 +1,12 @@
+using Autofac;
+
+namespace TrashLib.Services.Common;
+
+public class GuideServicesAutofacModule : Module
+{
+ protected override void Load(ContainerBuilder builder)
+ {
+ base.Load(builder);
+ builder.RegisterType().As();
+ }
+}
diff --git a/src/TrashLib/Services/Common/IGuideDataLister.cs b/src/TrashLib/Services/Common/IGuideDataLister.cs
new file mode 100644
index 00000000..483392d0
--- /dev/null
+++ b/src/TrashLib/Services/Common/IGuideDataLister.cs
@@ -0,0 +1,8 @@
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.Common;
+
+public interface IGuideDataLister
+{
+ void ListCustomFormats(IEnumerable customFormats);
+}
diff --git a/src/TrashLib/Services/Common/IGuideService.cs b/src/TrashLib/Services/Common/IGuideService.cs
new file mode 100644
index 00000000..736ec9a8
--- /dev/null
+++ b/src/TrashLib/Services/Common/IGuideService.cs
@@ -0,0 +1,8 @@
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.Common;
+
+public interface IGuideService
+{
+ ICollection GetCustomFormatData();
+}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Api/CustomFormatService.cs b/src/TrashLib/Services/CustomFormat/Api/CustomFormatService.cs
similarity index 92%
rename from src/TrashLib/Services/Radarr/CustomFormat/Api/CustomFormatService.cs
rename to src/TrashLib/Services/CustomFormat/Api/CustomFormatService.cs
index 73d97ba9..7d619dc1 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Api/CustomFormatService.cs
+++ b/src/TrashLib/Services/CustomFormat/Api/CustomFormatService.cs
@@ -2,9 +2,9 @@ using Flurl;
using Flurl.Http;
using Newtonsoft.Json.Linq;
using TrashLib.Config.Services;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Api;
+namespace TrashLib.Services.CustomFormat.Api;
internal class CustomFormatService : ICustomFormatService
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Api/ICustomFormatService.cs b/src/TrashLib/Services/CustomFormat/Api/ICustomFormatService.cs
similarity index 72%
rename from src/TrashLib/Services/Radarr/CustomFormat/Api/ICustomFormatService.cs
rename to src/TrashLib/Services/CustomFormat/Api/ICustomFormatService.cs
index 463e6a44..30798ef0 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Api/ICustomFormatService.cs
+++ b/src/TrashLib/Services/CustomFormat/Api/ICustomFormatService.cs
@@ -1,7 +1,7 @@
using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Api;
+namespace TrashLib.Services.CustomFormat.Api;
public interface ICustomFormatService
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Api/IQualityProfileService.cs b/src/TrashLib/Services/CustomFormat/Api/IQualityProfileService.cs
similarity index 78%
rename from src/TrashLib/Services/Radarr/CustomFormat/Api/IQualityProfileService.cs
rename to src/TrashLib/Services/CustomFormat/Api/IQualityProfileService.cs
index 65414491..ce2e21b1 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Api/IQualityProfileService.cs
+++ b/src/TrashLib/Services/CustomFormat/Api/IQualityProfileService.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json.Linq;
-namespace TrashLib.Services.Radarr.CustomFormat.Api;
+namespace TrashLib.Services.CustomFormat.Api;
public interface IQualityProfileService
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Api/QualityProfileService.cs b/src/TrashLib/Services/CustomFormat/Api/QualityProfileService.cs
similarity index 94%
rename from src/TrashLib/Services/Radarr/CustomFormat/Api/QualityProfileService.cs
rename to src/TrashLib/Services/CustomFormat/Api/QualityProfileService.cs
index 6c2c12d4..31a4f3ff 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Api/QualityProfileService.cs
+++ b/src/TrashLib/Services/CustomFormat/Api/QualityProfileService.cs
@@ -3,7 +3,7 @@ using Flurl.Http;
using Newtonsoft.Json.Linq;
using TrashLib.Config.Services;
-namespace TrashLib.Services.Radarr.CustomFormat.Api;
+namespace TrashLib.Services.CustomFormat.Api;
internal class QualityProfileService : IQualityProfileService
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/CachePersister.cs b/src/TrashLib/Services/CustomFormat/CachePersister.cs
similarity index 91%
rename from src/TrashLib/Services/Radarr/CustomFormat/CachePersister.cs
rename to src/TrashLib/Services/CustomFormat/CachePersister.cs
index 29e2bb68..1bec73dc 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/CachePersister.cs
+++ b/src/TrashLib/Services/CustomFormat/CachePersister.cs
@@ -1,10 +1,10 @@
using Common.Extensions;
using Serilog;
using TrashLib.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat;
+namespace TrashLib.Services.CustomFormat;
internal class CachePersister : ICachePersister
{
diff --git a/src/TrashLib/Services/CustomFormat/CustomFormatAutofacModule.cs b/src/TrashLib/Services/CustomFormat/CustomFormatAutofacModule.cs
new file mode 100644
index 00000000..ca12180f
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/CustomFormatAutofacModule.cs
@@ -0,0 +1,34 @@
+using Autofac;
+using Autofac.Extras.AggregateService;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Guide;
+using TrashLib.Services.CustomFormat.Processors;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
+
+namespace TrashLib.Services.CustomFormat;
+
+public class CustomFormatAutofacModule : Module
+{
+ protected override void Load(ContainerBuilder builder)
+ {
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+
+ builder.RegisterAggregateService();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+
+ builder.RegisterAggregateService();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ builder.RegisterType().As();
+ }
+}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/CustomFormatUpdater.cs b/src/TrashLib/Services/CustomFormat/CustomFormatUpdater.cs
similarity index 91%
rename from src/TrashLib/Services/Radarr/CustomFormat/CustomFormatUpdater.cs
rename to src/TrashLib/Services/CustomFormat/CustomFormatUpdater.cs
index 84bd44fe..9d71f627 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/CustomFormatUpdater.cs
+++ b/src/TrashLib/Services/CustomFormat/CustomFormatUpdater.cs
@@ -1,12 +1,12 @@
using CliFx.Infrastructure;
using Common.Extensions;
using Serilog;
-using TrashLib.Extensions;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Processors;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.Common;
+using TrashLib.Services.CustomFormat.Processors;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
-namespace TrashLib.Services.Radarr.CustomFormat;
+namespace TrashLib.Services.CustomFormat;
internal class CustomFormatUpdater : ICustomFormatUpdater
{
@@ -14,30 +14,33 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
private readonly IGuideProcessor _guideProcessor;
private readonly IPersistenceProcessor _persistenceProcessor;
private readonly IConsole _console;
+ private readonly IServerInfo _serverInfo;
public CustomFormatUpdater(
ILogger log,
ICachePersister cache,
IGuideProcessor guideProcessor,
IPersistenceProcessor persistenceProcessor,
- IConsole console)
+ IConsole console,
+ IServerInfo serverInfo)
{
Log = log;
_cache = cache;
_guideProcessor = guideProcessor;
_persistenceProcessor = persistenceProcessor;
_console = console;
+ _serverInfo = serverInfo;
}
private ILogger Log { get; }
- public async Task Process(bool isPreview, RadarrConfiguration config)
+ public async Task Process(bool isPreview, IEnumerable customFormats, IGuideService guideService)
{
_cache.Load();
- await _guideProcessor.BuildGuideDataAsync(config.CustomFormats.AsReadOnly(), _cache.CfCache);
+ await _guideProcessor.BuildGuideDataAsync(customFormats, _cache.CfCache, guideService);
- if (!ValidateGuideDataAndCheckShouldProceed(config))
+ if (!ValidateGuideDataAndCheckShouldProceed())
{
return;
}
@@ -127,7 +130,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
var totalCount = created.Count + updated.Count;
if (totalCount > 0)
{
- Log.Information("Total of {Count} custom formats synced to Radarr", totalCount);
+ Log.Information("Total of {Count} custom formats were synced", totalCount);
}
else
{
@@ -135,7 +138,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
}
}
- private bool ValidateGuideDataAndCheckShouldProceed(RadarrConfiguration config)
+ private bool ValidateGuideDataAndCheckShouldProceed()
{
_console.Output.WriteLine("");
@@ -186,14 +189,14 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
if (_guideProcessor.ConfigData.Count == 0)
{
Log.Error("Guide processing yielded no custom formats for configured instance host {BaseUrl}",
- FlurlLogging.SanitizeUrl(config.BaseUrl));
+ _serverInfo.SanitizedBaseUrl);
return false;
}
if (_guideProcessor.CustomFormatsWithoutScore.Count > 0)
{
Log.Information("The below custom formats have no score in the guide or in your YAML config. They will " +
- "still be synced to Radarr, but no score will be set in your chosen quality profiles");
+ "still be synced, but no score will be set in your chosen quality profiles");
foreach (var tuple in _guideProcessor.CustomFormatsWithoutScore)
{
Log.Information("{CfList}", tuple);
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Guide/CustomFormatGroupParser.cs b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatGroupParser.cs
similarity index 98%
rename from src/TrashLib/Services/Radarr/CustomFormat/Guide/CustomFormatGroupParser.cs
rename to src/TrashLib/Services/CustomFormat/Guide/CustomFormatGroupParser.cs
index 87884450..fcd22ed7 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Guide/CustomFormatGroupParser.cs
+++ b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatGroupParser.cs
@@ -4,7 +4,7 @@ using System.Text.RegularExpressions;
using Common.Extensions;
using TrashLib.Startup;
-namespace TrashLib.Services.Radarr.CustomFormat.Guide;
+namespace TrashLib.Services.CustomFormat.Guide;
public record CustomFormatGroupItem(string Name, string Anchor);
diff --git a/src/TrashLib/Services/CustomFormat/Guide/CustomFormatLoader.cs b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatLoader.cs
new file mode 100644
index 00000000..923dcb21
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatLoader.cs
@@ -0,0 +1,44 @@
+using System.IO.Abstractions;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+using Common.Extensions;
+using Newtonsoft.Json;
+using Serilog;
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.CustomFormat.Guide;
+
+public class CustomFormatLoader : ICustomFormatLoader
+{
+ private readonly ILogger _log;
+ private readonly ICustomFormatParser _parser;
+
+ public CustomFormatLoader(ILogger log, ICustomFormatParser parser)
+ {
+ _log = log;
+ _parser = parser;
+ }
+
+ public ICollection LoadAllCustomFormatsAtPaths(IEnumerable jsonPaths)
+ {
+ var jsonFiles = jsonPaths.SelectMany(x => x.GetFiles("*.json"));
+ return jsonFiles.ToObservable()
+ .Select(x => Observable.Defer(() => LoadJsonFromFile(x)))
+ .Merge(8)
+ .NotNull()
+ .ToEnumerable()
+ .ToList();
+ }
+
+ private IObservable LoadJsonFromFile(IFileInfo file)
+ {
+ return Observable.Using(file.OpenText, x => x.ReadToEndAsync().ToObservable())
+ .Do(_ => _log.Debug("Parsing CF Json: {Name}", file.Name))
+ .Select(_parser.ParseCustomFormatData)
+ .Catch((JsonException e) =>
+ {
+ _log.Warning("Failed to parse JSON file: {File} ({Reason})", file.Name, e.Message);
+ return Observable.Empty();
+ });
+ }
+}
diff --git a/src/TrashLib/Services/CustomFormat/Guide/CustomFormatParser.cs b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatParser.cs
new file mode 100644
index 00000000..f7e9381f
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/Guide/CustomFormatParser.cs
@@ -0,0 +1,34 @@
+using System.Text.RegularExpressions;
+using Common.Extensions;
+using Newtonsoft.Json.Linq;
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.CustomFormat.Guide;
+
+public class CustomFormatParser : ICustomFormatParser
+{
+ public CustomFormatData ParseCustomFormatData(string guideData)
+ {
+ var obj = JObject.Parse(guideData);
+
+ var name = obj.ValueOrThrow("name");
+ var trashId = obj.ValueOrThrow("trash_id");
+ int? finalScore = null;
+
+ if (obj.TryGetValue("trash_score", out var score))
+ {
+ finalScore = (int) score;
+ }
+
+ // Remove any properties starting with "trash_". Those are metadata that are not meant for the remote service
+ // itself. The service supposedly drops this anyway, but I prefer it to be removed. ToList() is important here
+ // since removing the property itself modifies the collection, and we don't want the collection to get modified
+ // while still looping over it.
+ foreach (var trashProperty in obj.Properties().Where(x => Regex.IsMatch(x.Name, @"^trash_")).ToList())
+ {
+ trashProperty.Remove();
+ }
+
+ return new CustomFormatData(name, trashId, finalScore, obj);
+ }
+}
diff --git a/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatLoader.cs b/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatLoader.cs
new file mode 100644
index 00000000..19d8038b
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatLoader.cs
@@ -0,0 +1,9 @@
+using System.IO.Abstractions;
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.CustomFormat.Guide;
+
+public interface ICustomFormatLoader
+{
+ ICollection LoadAllCustomFormatsAtPaths(IEnumerable jsonPaths);
+}
diff --git a/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatParser.cs b/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatParser.cs
new file mode 100644
index 00000000..6e9825d9
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/Guide/ICustomFormatParser.cs
@@ -0,0 +1,8 @@
+using TrashLib.Services.CustomFormat.Models;
+
+namespace TrashLib.Services.CustomFormat.Guide;
+
+public interface ICustomFormatParser
+{
+ CustomFormatData ParseCustomFormatData(string guideData);
+}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/ICachePersister.cs b/src/TrashLib/Services/CustomFormat/ICachePersister.cs
similarity index 53%
rename from src/TrashLib/Services/Radarr/CustomFormat/ICachePersister.cs
rename to src/TrashLib/Services/CustomFormat/ICachePersister.cs
index bc96236b..db176f95 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/ICachePersister.cs
+++ b/src/TrashLib/Services/CustomFormat/ICachePersister.cs
@@ -1,7 +1,7 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat;
+namespace TrashLib.Services.CustomFormat;
public interface ICachePersister
{
diff --git a/src/TrashLib/Services/CustomFormat/ICustomFormatUpdater.cs b/src/TrashLib/Services/CustomFormat/ICustomFormatUpdater.cs
new file mode 100644
index 00000000..d6d22914
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/ICustomFormatUpdater.cs
@@ -0,0 +1,9 @@
+using TrashLib.Config.Services;
+using TrashLib.Services.Common;
+
+namespace TrashLib.Services.CustomFormat;
+
+public interface ICustomFormatUpdater
+{
+ Task Process(bool isPreview, IEnumerable config, IGuideService guideService);
+}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/Cache/CustomFormatCache.cs b/src/TrashLib/Services/CustomFormat/Models/Cache/CustomFormatCache.cs
similarity index 91%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/Cache/CustomFormatCache.cs
rename to src/TrashLib/Services/CustomFormat/Models/Cache/CustomFormatCache.cs
index 2429e948..389e1f63 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/Cache/CustomFormatCache.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/Cache/CustomFormatCache.cs
@@ -1,7 +1,7 @@
using System.Collections.ObjectModel;
using TrashLib.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+namespace TrashLib.Services.CustomFormat.Models.Cache;
[CacheObjectName("custom-format-cache")]
public class CustomFormatCache
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/CustomFormatData.cs b/src/TrashLib/Services/CustomFormat/Models/CustomFormatData.cs
similarity index 77%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/CustomFormatData.cs
rename to src/TrashLib/Services/CustomFormat/Models/CustomFormatData.cs
index 5ea94ebb..c4798d16 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/CustomFormatData.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/CustomFormatData.cs
@@ -1,7 +1,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
-namespace TrashLib.Services.Radarr.CustomFormat.Models;
+namespace TrashLib.Services.CustomFormat.Models;
public record CustomFormatData(
string Name,
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedConfigData.cs b/src/TrashLib/Services/CustomFormat/Models/ProcessedConfigData.cs
similarity index 75%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedConfigData.cs
rename to src/TrashLib/Services/CustomFormat/Models/ProcessedConfigData.cs
index 689211c3..5c8ef965 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedConfigData.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/ProcessedConfigData.cs
@@ -1,6 +1,6 @@
-using TrashLib.Services.Radarr.Config;
+using TrashLib.Config.Services;
-namespace TrashLib.Services.Radarr.CustomFormat.Models;
+namespace TrashLib.Services.CustomFormat.Models;
public class ProcessedConfigData
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedCustomFormatData.cs b/src/TrashLib/Services/CustomFormat/Models/ProcessedCustomFormatData.cs
similarity index 89%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedCustomFormatData.cs
rename to src/TrashLib/Services/CustomFormat/Models/ProcessedCustomFormatData.cs
index 0af581f7..85d23d60 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/ProcessedCustomFormatData.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/ProcessedCustomFormatData.cs
@@ -1,8 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Models;
+namespace TrashLib.Services.CustomFormat.Models;
public class ProcessedCustomFormatData
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs b/src/TrashLib/Services/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs
similarity index 88%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs
rename to src/TrashLib/Services/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs
index acf6975d..a2183bd4 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/QualityProfileCustomFormatScoreMapping.cs
@@ -1,4 +1,4 @@
-namespace TrashLib.Services.Radarr.CustomFormat.Models;
+namespace TrashLib.Services.CustomFormat.Models;
public record FormatMappingEntry(ProcessedCustomFormatData CustomFormat, int Score);
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Models/UpdatedFormatScore.cs b/src/TrashLib/Services/CustomFormat/Models/UpdatedFormatScore.cs
similarity index 76%
rename from src/TrashLib/Services/Radarr/CustomFormat/Models/UpdatedFormatScore.cs
rename to src/TrashLib/Services/CustomFormat/Models/UpdatedFormatScore.cs
index 67ea9d01..2f4f9cbe 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Models/UpdatedFormatScore.cs
+++ b/src/TrashLib/Services/CustomFormat/Models/UpdatedFormatScore.cs
@@ -1,4 +1,4 @@
-namespace TrashLib.Services.Radarr.CustomFormat.Models;
+namespace TrashLib.Services.CustomFormat.Models;
public enum FormatScoreUpdateReason
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideProcessor.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideProcessor.cs
similarity index 75%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideProcessor.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideProcessor.cs
index 8919524a..f08d71e5 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideProcessor.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideProcessor.cs
@@ -1,10 +1,10 @@
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+using TrashLib.Config.Services;
+using TrashLib.Services.Common;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.GuideSteps;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors;
+namespace TrashLib.Services.CustomFormat.Processors;
public interface IGuideProcessorSteps
{
@@ -15,14 +15,12 @@ public interface IGuideProcessorSteps
internal class GuideProcessor : IGuideProcessor
{
- private readonly IRadarrGuideService _guideService;
private readonly Func _stepsFactory;
private IList? _guideCustomFormatJson;
private IGuideProcessorSteps _steps;
- public GuideProcessor(IRadarrGuideService guideService, Func stepsFactory)
+ public GuideProcessor(Func stepsFactory)
{
- _guideService = guideService;
_stepsFactory = stepsFactory;
_steps = stepsFactory();
}
@@ -51,16 +49,16 @@ internal class GuideProcessor : IGuideProcessor
public IDictionary> DuplicatedCustomFormats
=> _steps.CustomFormat.DuplicatedCustomFormats;
- public Task BuildGuideDataAsync(IReadOnlyCollection config, CustomFormatCache? cache)
+ public Task BuildGuideDataAsync(IEnumerable config, CustomFormatCache? cache,
+ IGuideService guideService)
{
- if (_guideCustomFormatJson == null)
- {
- _guideCustomFormatJson = _guideService.GetCustomFormatData().ToList();
- }
+ _guideCustomFormatJson ??= guideService.GetCustomFormatData().ToList();
+
+ var listOfConfigs = config.ToList();
// Step 1: Process and filter the custom formats from the guide.
// Custom formats in the guide not mentioned in the config are filtered out.
- _steps.CustomFormat.Process(_guideCustomFormatJson, config, cache);
+ _steps.CustomFormat.Process(_guideCustomFormatJson, listOfConfigs, cache);
// todo: Process cache entries that do not exist in the guide. Those should be deleted
// This might get taken care of when we rebuild the cache based on what is actually updated when
@@ -69,7 +67,7 @@ internal class GuideProcessor : IGuideProcessor
// Step 2: Use the processed custom formats from step 1 to process the configuration.
// CFs in config not in the guide are filtered out.
// Actual CF objects are associated to the quality profile objects to reduce lookups
- _steps.Config.Process(_steps.CustomFormat.ProcessedCustomFormats, config);
+ _steps.Config.Process(_steps.CustomFormat.ProcessedCustomFormats, listOfConfigs);
// Step 3: Use the processed config (which contains processed CFs) to process the quality profile scores.
// Score precedence logic is utilized here to decide the CF score per profile (same CF can actually have
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ConfigStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ConfigStep.cs
similarity index 93%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ConfigStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ConfigStep.cs
index 9c5106c0..d87e7777 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ConfigStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ConfigStep.cs
@@ -1,9 +1,9 @@
using Common.Extensions;
using Serilog;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
public class ConfigStep : IConfigStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs
similarity index 95%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs
index ab004f98..8ce6ec75 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/CustomFormatStep.cs
@@ -1,9 +1,9 @@
using Common.Extensions;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
public class CustomFormatStep : ICustomFormatStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IConfigStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IConfigStep.cs
similarity index 65%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IConfigStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IConfigStep.cs
index 5e11f165..be454a7b 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IConfigStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IConfigStep.cs
@@ -1,7 +1,7 @@
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
public interface IConfigStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs
similarity index 70%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs
index d462cfe7..8815f523 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/ICustomFormatStep.cs
@@ -1,8 +1,8 @@
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Config.Services;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
public interface ICustomFormatStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs
similarity index 71%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs
index d92084f8..dfd9da1d 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/IQualityProfileStep.cs
@@ -1,6 +1,6 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
public interface IQualityProfileStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs
similarity index 93%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs
index 34f16a4c..f5931e50 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/GuideSteps/QualityProfileStep.cs
@@ -1,6 +1,6 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
+namespace TrashLib.Services.CustomFormat.Processors.GuideSteps;
internal class QualityProfileStep : IQualityProfileStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/IGuideProcessor.cs b/src/TrashLib/Services/CustomFormat/Processors/IGuideProcessor.cs
similarity index 67%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/IGuideProcessor.cs
rename to src/TrashLib/Services/CustomFormat/Processors/IGuideProcessor.cs
index 53869f47..b2380edd 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/IGuideProcessor.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/IGuideProcessor.cs
@@ -1,8 +1,9 @@
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Config.Services;
+using TrashLib.Services.Common;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors;
+namespace TrashLib.Services.CustomFormat.Processors;
internal interface IGuideProcessor
{
@@ -15,6 +16,8 @@ internal interface IGuideProcessor
IReadOnlyCollection<(string, string)> CustomFormatsWithOutdatedNames { get; }
IDictionary> DuplicatedCustomFormats { get; }
- Task BuildGuideDataAsync(IReadOnlyCollection config, CustomFormatCache? cache);
+ Task BuildGuideDataAsync(IEnumerable config, CustomFormatCache? cache,
+ IGuideService guideService);
+
void Reset();
}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/IPersistenceProcessor.cs b/src/TrashLib/Services/CustomFormat/Processors/IPersistenceProcessor.cs
similarity index 66%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/IPersistenceProcessor.cs
rename to src/TrashLib/Services/CustomFormat/Processors/IPersistenceProcessor.cs
index 4798e14a..9e790365 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/IPersistenceProcessor.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/IPersistenceProcessor.cs
@@ -1,8 +1,8 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors;
+namespace TrashLib.Services.CustomFormat.Processors;
public interface IPersistenceProcessor
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceProcessor.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceProcessor.cs
similarity index 83%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceProcessor.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceProcessor.cs
index 539e3bed..780fde49 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceProcessor.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceProcessor.cs
@@ -1,11 +1,10 @@
using TrashLib.Config.Services;
-using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors;
+namespace TrashLib.Services.CustomFormat.Processors;
public interface IPersistenceProcessorSteps
{
@@ -53,18 +52,18 @@ internal class PersistenceProcessor : IPersistenceProcessor
IEnumerable deletedCfsInCache,
IDictionary profileScores)
{
- var radarrCfs = await _customFormatService.GetCustomFormats();
+ var serviceCfs = await _customFormatService.GetCustomFormats();
// Step 1: Match CFs between the guide & Radarr and merge the data. The goal is to retain as much of the
// original data from Radarr as possible. There are many properties in the response JSON that we don't
// directly care about. We keep those and just update the ones we do care about.
- _steps.JsonTransactionStep.Process(guideCfs, radarrCfs);
+ _steps.JsonTransactionStep.Process(guideCfs, serviceCfs);
// Step 1.1: Optionally record deletions of custom formats in cache but not in the guide
- var config = (RadarrConfiguration) _configProvider.ActiveConfiguration;
+ var config = _configProvider.ActiveConfiguration;
if (config.DeleteOldCustomFormats)
{
- _steps.JsonTransactionStep.RecordDeletions(deletedCfsInCache, radarrCfs);
+ _steps.JsonTransactionStep.RecordDeletions(deletedCfsInCache, serviceCfs);
}
// Step 2: For each merged CF, persist it to Radarr via its API. This will involve a combination of updates
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs
similarity index 82%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs
index 0ec7f655..e30ccdbf 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/CustomFormatApiPersistenceStep.cs
@@ -1,6 +1,6 @@
-using TrashLib.Services.Radarr.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Api;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
internal class CustomFormatApiPersistenceStep : ICustomFormatApiPersistenceStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs
similarity index 52%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs
index 6c427477..710fe07e 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/ICustomFormatApiPersistenceStep.cs
@@ -1,6 +1,6 @@
-using TrashLib.Services.Radarr.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Api;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
public interface ICustomFormatApiPersistenceStep
{
diff --git a/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs
new file mode 100644
index 00000000..63882509
--- /dev/null
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json.Linq;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
+
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
+
+public interface IJsonTransactionStep
+{
+ CustomFormatTransactionData Transactions { get; }
+
+ void Process(IEnumerable guideCfs,
+ IReadOnlyCollection serviceCfs);
+
+ void RecordDeletions(IEnumerable deletedCfsInCache, IEnumerable serviceCfs);
+}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs
similarity index 63%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs
index be3140db..14e9c56b 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/IQualityProfileApiPersistenceStep.cs
@@ -1,7 +1,7 @@
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
public interface IQualityProfileApiPersistenceStep
{
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs
similarity index 65%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs
index 9d941551..e6606ecb 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/JsonTransactionStep.cs
@@ -1,10 +1,10 @@
using System.Collections.ObjectModel;
using Common.Extensions;
using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Models.Cache;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
public class CustomFormatTransactionData
{
@@ -19,15 +19,15 @@ internal class JsonTransactionStep : IJsonTransactionStep
public CustomFormatTransactionData Transactions { get; } = new();
public void Process(IEnumerable guideCfs,
- IReadOnlyCollection radarrCfs)
+ IReadOnlyCollection serviceCfs)
{
- foreach (var (guideCf, radarrCf) in guideCfs
- .Select(gcf => (GuideCf: gcf, RadarrCf: FindRadarrCf(radarrCfs, gcf))))
+ foreach (var (guideCf, serviceCf) in guideCfs
+ .Select(gcf => (GuideCf: gcf, ServiceCf: FindServiceCf(serviceCfs, gcf))))
{
- var guideCfJson = BuildNewRadarrCf(guideCf.Json);
+ var guideCfJson = BuildNewServiceCf(guideCf.Json);
// no match; we add this CF as brand new
- if (radarrCf == null)
+ if (serviceCf == null)
{
guideCf.Json = guideCfJson;
Transactions.NewCustomFormats.Add(guideCf);
@@ -35,8 +35,8 @@ internal class JsonTransactionStep : IJsonTransactionStep
// found match in radarr CFs; update the existing CF
else
{
- guideCf.Json = (JObject) radarrCf.DeepClone();
- UpdateRadarrCf(guideCf.Json, guideCfJson);
+ guideCf.Json = (JObject) serviceCf.DeepClone();
+ UpdateServiceCf(guideCf.Json, guideCfJson);
// Set the cache for use later (like updating scores) if it hasn't been updated already.
// This handles CFs that already exist in Radarr but aren't cached (they will be added to cache
@@ -46,7 +46,7 @@ internal class JsonTransactionStep : IJsonTransactionStep
guideCf.SetCache(guideCf.Json.Value("id"));
}
- if (!JToken.DeepEquals(radarrCf, guideCf.Json))
+ if (!JToken.DeepEquals(serviceCf, guideCf.Json))
{
Transactions.UpdatedCustomFormats.Add(guideCf);
}
@@ -58,96 +58,96 @@ internal class JsonTransactionStep : IJsonTransactionStep
}
}
- public void RecordDeletions(IEnumerable deletedCfsInCache, IEnumerable radarrCfs)
+ public void RecordDeletions(IEnumerable deletedCfsInCache, IEnumerable serviceCfs)
{
- var cfs = radarrCfs.ToList();
+ var cfs = serviceCfs.ToList();
// The 'Where' excludes cached CFs that were deleted manually by the user in Radarr
// FindRadarrCf() specifies 'null' for name because we should never delete unless an ID is found
foreach (var del in deletedCfsInCache.Where(
- del => FindRadarrCf(cfs, del.CustomFormatId, null) != null))
+ del => FindServiceCf(cfs, del.CustomFormatId, null) != null))
{
Transactions.DeletedCustomFormatIds.Add(del);
}
}
- private static JObject? FindRadarrCf(IReadOnlyCollection radarrCfs, ProcessedCustomFormatData guideCf)
+ private static JObject? FindServiceCf(IReadOnlyCollection serviceCfs, ProcessedCustomFormatData guideCf)
{
- return FindRadarrCf(radarrCfs, guideCf.CacheEntry?.CustomFormatId, guideCf.Name);
+ return FindServiceCf(serviceCfs, guideCf.CacheEntry?.CustomFormatId, guideCf.Name);
}
- private static JObject? FindRadarrCf(IReadOnlyCollection radarrCfs, int? cfId, string? cfName)
+ private static JObject? FindServiceCf(IReadOnlyCollection serviceCfs, int? cfId, string? cfName)
{
JObject? match = null;
// Try to find match in cache first
if (cfId != null)
{
- match = radarrCfs.FirstOrDefault(rcf => cfId == rcf.Value("id"));
+ match = serviceCfs.FirstOrDefault(rcf => cfId == rcf.Value("id"));
}
// If we don't find by ID, search by name (if a name was given)
if (match == null && cfName != null)
{
- match = radarrCfs.FirstOrDefault(rcf => cfName.EqualsIgnoreCase(rcf.Value("name")));
+ match = serviceCfs.FirstOrDefault(rcf => cfName.EqualsIgnoreCase(rcf.Value("name")));
}
return match;
}
- private static void UpdateRadarrCf(JObject cfToModify, JObject cfToMergeFrom)
+ private static void UpdateServiceCf(JObject cfToModify, JObject cfToMergeFrom)
{
MergeProperties(cfToModify, cfToMergeFrom, JTokenType.Array);
- var radarrSpecs = cfToModify["specifications"]?.Children() ?? new JEnumerable();
+ var serviceSpecs = cfToModify["specifications"]?.Children() ?? new JEnumerable();
var guideSpecs = cfToMergeFrom["specifications"]?.Children() ?? new JEnumerable();
var matchedGuideSpecs = guideSpecs
- .GroupBy(gs => radarrSpecs.FirstOrDefault(gss => KeyMatch(gss, gs, "name")))
- .SelectMany(kvp => kvp.Select(gs => new {GuideSpec = gs, RadarrSpec = kvp.Key}));
+ .GroupBy(gs => serviceSpecs.FirstOrDefault(gss => KeyMatch(gss, gs, "name")))
+ .SelectMany(kvp => kvp.Select(gs => new {GuideSpec = gs, ServiceSpec = kvp.Key}));
- var newRadarrSpecs = new JArray();
+ var newServiceSpecs = new JArray();
foreach (var match in matchedGuideSpecs)
{
- if (match.RadarrSpec != null)
+ if (match.ServiceSpec != null)
{
- MergeProperties(match.RadarrSpec, match.GuideSpec);
- newRadarrSpecs.Add(match.RadarrSpec);
+ MergeProperties(match.ServiceSpec, match.GuideSpec);
+ newServiceSpecs.Add(match.ServiceSpec);
}
else
{
- newRadarrSpecs.Add(match.GuideSpec);
+ newServiceSpecs.Add(match.GuideSpec);
}
}
- cfToModify["specifications"] = newRadarrSpecs;
+ cfToModify["specifications"] = newServiceSpecs;
}
private static bool KeyMatch(JObject left, JObject right, string keyName)
=> left.Value(keyName) == right.Value(keyName);
- private static void MergeProperties(JObject radarrCf, JObject guideCfJson,
+ private static void MergeProperties(JObject serviceCf, JObject guideCfJson,
JTokenType exceptType = JTokenType.None)
{
foreach (var guideProp in guideCfJson.Properties().Where(p => p.Value.Type != exceptType))
{
if (guideProp.Value.Type == JTokenType.Array &&
- radarrCf.TryGetValue(guideProp.Name, out var radarrArray))
+ serviceCf.TryGetValue(guideProp.Name, out var serviceArray))
{
- ((JArray) radarrArray).Merge(guideProp.Value, new JsonMergeSettings
+ ((JArray) serviceArray).Merge(guideProp.Value, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Merge
});
}
else
{
- radarrCf[guideProp.Name] = guideProp.Value;
+ serviceCf[guideProp.Name] = guideProp.Value;
}
}
}
- private static JObject BuildNewRadarrCf(JObject jsonPayload)
+ private static JObject BuildNewServiceCf(JObject jsonPayload)
{
// Information on required fields from nitsua
/*
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs
similarity index 91%
rename from src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs
rename to src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs
index 5348ca02..3700eb99 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs
+++ b/src/TrashLib/Services/CustomFormat/Processors/PersistenceSteps/QualityProfileApiPersistenceStep.cs
@@ -1,9 +1,9 @@
using Common.Extensions;
using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Models;
+using TrashLib.Services.CustomFormat.Api;
+using TrashLib.Services.CustomFormat.Models;
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
+namespace TrashLib.Services.CustomFormat.Processors.PersistenceSteps;
internal class QualityProfileApiPersistenceStep : IQualityProfileApiPersistenceStep
{
@@ -16,13 +16,13 @@ internal class QualityProfileApiPersistenceStep : IQualityProfileApiPersistenceS
public async Task Process(IQualityProfileService api,
IDictionary cfScores)
{
- var radarrProfiles = await api.GetQualityProfiles();
+ var serviceProfiles = await api.GetQualityProfiles();
// Match quality profiles in Radarr to ones the user put in their config.
// For each match, we return a tuple including the list of custom format scores ("formatItems").
// Using GroupJoin() because we want a LEFT OUTER JOIN so we can list which quality profiles in config
// do not match profiles in Radarr.
- var profileScores = cfScores.GroupJoin(radarrProfiles,
+ var profileScores = cfScores.GroupJoin(serviceProfiles,
s => s.Key,
p => p.Value("name"),
(s, p) => (s.Key, s.Value, p.SelectMany(pi => pi.Children("formatItems")).ToList()),
diff --git a/src/TrashLib/Services/Radarr/Config/RadarrConfiguration.cs b/src/TrashLib/Services/Radarr/Config/RadarrConfiguration.cs
index 1ca36a93..8e996dd8 100644
--- a/src/TrashLib/Services/Radarr/Config/RadarrConfiguration.cs
+++ b/src/TrashLib/Services/Radarr/Config/RadarrConfiguration.cs
@@ -7,24 +7,6 @@ namespace TrashLib.Services.Radarr.Config;
public class RadarrConfiguration : ServiceConfiguration
{
public QualityDefinitionConfig? QualityDefinition { get; init; }
- public ICollection CustomFormats { get; init; } = new List();
- public bool DeleteOldCustomFormats { get; init; }
-}
-
-[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
-public class CustomFormatConfig
-{
- public ICollection Names { get; init; } = new List();
- public ICollection TrashIds { get; init; } = new List();
- public ICollection QualityProfiles { get; init; } = new List();
-}
-
-[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
-public class QualityProfileConfig
-{
- public string Name { get; init; } = "";
- public int? Score { get; init; }
- public bool ResetUnmatchedScores { get; init; }
}
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
diff --git a/src/TrashLib/Services/Radarr/Config/RadarrConfigurationValidator.cs b/src/TrashLib/Services/Radarr/Config/RadarrConfigurationValidator.cs
index be2257cf..e901ed86 100644
--- a/src/TrashLib/Services/Radarr/Config/RadarrConfigurationValidator.cs
+++ b/src/TrashLib/Services/Radarr/Config/RadarrConfigurationValidator.cs
@@ -1,6 +1,7 @@
using Common.FluentValidation;
using FluentValidation;
using JetBrains.Annotations;
+using TrashLib.Config.Services;
namespace TrashLib.Services.Radarr.Config;
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/ApiOperationType.cs b/src/TrashLib/Services/Radarr/CustomFormat/ApiOperationType.cs
deleted file mode 100644
index 965bbcb6..00000000
--- a/src/TrashLib/Services/Radarr/CustomFormat/ApiOperationType.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace TrashLib.Services.Radarr.CustomFormat;
-
-public enum ApiOperationType
-{
- Create,
- Update,
- NoChange,
- Delete
-}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Guide/IRadarrGuideService.cs b/src/TrashLib/Services/Radarr/CustomFormat/Guide/IRadarrGuideService.cs
deleted file mode 100644
index 6c0f259d..00000000
--- a/src/TrashLib/Services/Radarr/CustomFormat/Guide/IRadarrGuideService.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.QualityDefinition;
-
-namespace TrashLib.Services.Radarr.CustomFormat.Guide;
-
-public interface IRadarrGuideService
-{
- ICollection GetCustomFormatData();
- ICollection GetQualities();
-}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideService.cs b/src/TrashLib/Services/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideService.cs
deleted file mode 100644
index 8c138d8e..00000000
--- a/src/TrashLib/Services/Radarr/CustomFormat/Guide/LocalRepoRadarrGuideService.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System.IO.Abstractions;
-using System.Reactive.Linq;
-using System.Reactive.Threading.Tasks;
-using System.Text.RegularExpressions;
-using Common.Extensions;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Serilog;
-using TrashLib.Repo;
-using TrashLib.Services.Common.QualityDefinition;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.QualityDefinition;
-
-namespace TrashLib.Services.Radarr.CustomFormat.Guide;
-
-public class LocalRepoRadarrGuideService : IRadarrGuideService
-{
- private readonly IRepoPathsFactory _pathsFactory;
- private readonly ILogger _log;
- private readonly QualityGuideParser _parser;
-
- public LocalRepoRadarrGuideService(IRepoPathsFactory pathsFactory, ILogger log)
- {
- _pathsFactory = pathsFactory;
- _log = log;
- _parser = new QualityGuideParser(log);
- }
-
- public ICollection GetQualities()
- => _parser.GetQualities(_pathsFactory.Create().RadarrQualityPaths);
-
- public ICollection GetCustomFormatData()
- {
- var paths = _pathsFactory.Create();
- var jsonFiles = paths.RadarrCustomFormatPaths
- .SelectMany(x => x.GetFiles("*.json"));
-
- return jsonFiles.ToObservable()
- .Select(x => Observable.Defer(() => LoadJsonFromFile(x)))
- .Merge(8)
- .NotNull()
- .ToEnumerable()
- .ToList();
- }
-
- private IObservable LoadJsonFromFile(IFileInfo file)
- {
- return Observable.Using(file.OpenText, x => x.ReadToEndAsync().ToObservable())
- .Do(_ => _log.Debug("Parsing CF Json: {Name}", file.Name))
- .Select(ParseCustomFormatData)
- .Catch((JsonException e) =>
- {
- _log.Warning("Failed to parse JSON file: {File} ({Reason})", file.Name, e.Message);
- return Observable.Empty();
- });
- }
-
- public static CustomFormatData ParseCustomFormatData(string guideData)
- {
- var obj = JObject.Parse(guideData);
-
- var name = obj.ValueOrThrow("name");
- var trashId = obj.ValueOrThrow("trash_id");
- int? finalScore = null;
-
- if (obj.TryGetValue("trash_score", out var score))
- {
- finalScore = (int) score;
- }
-
- // Remove any properties starting with "trash_". Those are metadata that are not meant for Radarr itself Radarr
- // supposedly drops this anyway, but I prefer it to be removed. ToList() is important here since removing the
- // property itself modifies the collection, and we don't want the collection to get modified while still looping
- // over it.
- foreach (var trashProperty in obj.Properties().Where(x => Regex.IsMatch(x.Name, @"^trash_")).ToList())
- {
- trashProperty.Remove();
- }
-
- return new CustomFormatData(name, trashId, finalScore, obj);
- }
-}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/ICustomFormatUpdater.cs b/src/TrashLib/Services/Radarr/CustomFormat/ICustomFormatUpdater.cs
deleted file mode 100644
index 98d477ef..00000000
--- a/src/TrashLib/Services/Radarr/CustomFormat/ICustomFormatUpdater.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using TrashLib.Services.Radarr.Config;
-
-namespace TrashLib.Services.Radarr.CustomFormat;
-
-public interface ICustomFormatUpdater
-{
- Task Process(bool isPreview, RadarrConfiguration config);
-}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs b/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs
deleted file mode 100644
index 44ac7925..00000000
--- a/src/TrashLib/Services/Radarr/CustomFormat/Processors/PersistenceSteps/IJsonTransactionStep.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Newtonsoft.Json.Linq;
-using TrashLib.Services.Radarr.CustomFormat.Models;
-using TrashLib.Services.Radarr.CustomFormat.Models.Cache;
-
-namespace TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
-
-public interface IJsonTransactionStep
-{
- CustomFormatTransactionData Transactions { get; }
-
- void Process(IEnumerable guideCfs,
- IReadOnlyCollection radarrCfs);
-
- void RecordDeletions(IEnumerable deletedCfsInCache, IEnumerable radarrCfs);
-}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/IRadarrGuideDataLister.cs b/src/TrashLib/Services/Radarr/IRadarrGuideDataLister.cs
similarity index 67%
rename from src/TrashLib/Services/Radarr/CustomFormat/IRadarrGuideDataLister.cs
rename to src/TrashLib/Services/Radarr/IRadarrGuideDataLister.cs
index 8262c7a7..14ab7b11 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/IRadarrGuideDataLister.cs
+++ b/src/TrashLib/Services/Radarr/IRadarrGuideDataLister.cs
@@ -1,4 +1,4 @@
-namespace TrashLib.Services.Radarr.CustomFormat;
+namespace TrashLib.Services.Radarr;
public interface IRadarrGuideDataLister
{
diff --git a/src/TrashLib/Services/Radarr/IRadarrGuideService.cs b/src/TrashLib/Services/Radarr/IRadarrGuideService.cs
new file mode 100644
index 00000000..625a621f
--- /dev/null
+++ b/src/TrashLib/Services/Radarr/IRadarrGuideService.cs
@@ -0,0 +1,9 @@
+using TrashLib.Services.Common;
+using TrashLib.Services.Radarr.QualityDefinition;
+
+namespace TrashLib.Services.Radarr;
+
+public interface IRadarrGuideService : IGuideService
+{
+ ICollection GetQualities();
+}
diff --git a/src/TrashLib/Services/Radarr/LocalRepoRadarrGuideService.cs b/src/TrashLib/Services/Radarr/LocalRepoRadarrGuideService.cs
new file mode 100644
index 00000000..c731cd28
--- /dev/null
+++ b/src/TrashLib/Services/Radarr/LocalRepoRadarrGuideService.cs
@@ -0,0 +1,31 @@
+using Serilog;
+using TrashLib.Repo;
+using TrashLib.Services.Common.QualityDefinition;
+using TrashLib.Services.CustomFormat.Guide;
+using TrashLib.Services.CustomFormat.Models;
+using TrashLib.Services.Radarr.QualityDefinition;
+
+namespace TrashLib.Services.Radarr;
+
+public class LocalRepoRadarrGuideService : IRadarrGuideService
+{
+ private readonly IRepoPathsFactory _pathsFactory;
+ private readonly ICustomFormatLoader _cfLoader;
+ private readonly QualityGuideParser _parser;
+
+ public LocalRepoRadarrGuideService(IRepoPathsFactory pathsFactory, ILogger log, ICustomFormatLoader cfLoader)
+ {
+ _pathsFactory = pathsFactory;
+ _cfLoader = cfLoader;
+ _parser = new QualityGuideParser(log);
+ }
+
+ public ICollection GetQualities()
+ => _parser.GetQualities(_pathsFactory.Create().RadarrQualityPaths);
+
+ public ICollection GetCustomFormatData()
+ {
+ var paths = _pathsFactory.Create();
+ return _cfLoader.LoadAllCustomFormatsAtPaths(paths.RadarrCustomFormatPaths);
+ }
+}
diff --git a/src/TrashLib/Services/Radarr/QualityDefinition/RadarrQualityDefinitionUpdater.cs b/src/TrashLib/Services/Radarr/QualityDefinition/RadarrQualityDefinitionUpdater.cs
index 22fdc6ce..8f8adfc3 100644
--- a/src/TrashLib/Services/Radarr/QualityDefinition/RadarrQualityDefinitionUpdater.cs
+++ b/src/TrashLib/Services/Radarr/QualityDefinition/RadarrQualityDefinitionUpdater.cs
@@ -2,7 +2,6 @@ using CliFx.Infrastructure;
using Common.Extensions;
using Serilog;
using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
using TrashLib.Services.Radarr.QualityDefinition.Api;
using TrashLib.Services.Radarr.QualityDefinition.Api.Objects;
diff --git a/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs b/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs
index 8e429c38..50554127 100644
--- a/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs
+++ b/src/TrashLib/Services/Radarr/RadarrAutofacModule.cs
@@ -1,13 +1,5 @@
using Autofac;
-using Autofac.Extras.AggregateService;
-using TrashLib.Config.Services;
using TrashLib.Services.Radarr.Config;
-using TrashLib.Services.Radarr.CustomFormat;
-using TrashLib.Services.Radarr.CustomFormat.Api;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
-using TrashLib.Services.Radarr.CustomFormat.Processors;
-using TrashLib.Services.Radarr.CustomFormat.Processors.GuideSteps;
-using TrashLib.Services.Radarr.CustomFormat.Processors.PersistenceSteps;
using TrashLib.Services.Radarr.QualityDefinition;
using TrashLib.Services.Radarr.QualityDefinition.Api;
@@ -17,38 +9,11 @@ public class RadarrAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
- // Services
builder.RegisterType().As();
- builder.RegisterType().As();
- builder.RegisterType().As();
-
- // Configuration
+ builder.RegisterType().As();
builder.RegisterType().As();
- builder.RegisterType().As();
-
- // Quality Definition Support
builder.RegisterType().As();
-
- // Custom Format Support
- builder.RegisterType().As();
builder.RegisterType().As();
- builder.RegisterType().As();
builder.RegisterType().As();
-
- // Guide Processor
-
- // todo: register as singleton to avoid parsing guide multiple times when using 2 or more instances in config
- builder.RegisterType().As();
- builder.RegisterAggregateService();
- builder.RegisterType().As();
- builder.RegisterType().As();
- builder.RegisterType().As();
-
- // Persistence Processor
- builder.RegisterType().As();
- builder.RegisterAggregateService();
- builder.RegisterType().As();
- builder.RegisterType().As();
- builder.RegisterType().As();
}
}
diff --git a/src/TrashLib/Services/Radarr/CustomFormat/RadarrGuideDataLister.cs b/src/TrashLib/Services/Radarr/RadarrGuideDataLister.cs
similarity index 51%
rename from src/TrashLib/Services/Radarr/CustomFormat/RadarrGuideDataLister.cs
rename to src/TrashLib/Services/Radarr/RadarrGuideDataLister.cs
index 43fb3408..236a718c 100644
--- a/src/TrashLib/Services/Radarr/CustomFormat/RadarrGuideDataLister.cs
+++ b/src/TrashLib/Services/Radarr/RadarrGuideDataLister.cs
@@ -1,36 +1,28 @@
using CliFx.Infrastructure;
using JetBrains.Annotations;
using MoreLinq;
-using TrashLib.Services.Radarr.CustomFormat.Guide;
+using TrashLib.Services.Common;
-namespace TrashLib.Services.Radarr.CustomFormat;
+namespace TrashLib.Services.Radarr;
[UsedImplicitly]
public class RadarrGuideDataLister : IRadarrGuideDataLister
{
private readonly IConsole _console;
private readonly IRadarrGuideService _guide;
+ private readonly IGuideDataLister _guideLister;
- public RadarrGuideDataLister(IConsole console, IRadarrGuideService guide)
+ public RadarrGuideDataLister(
+ IConsole console,
+ IRadarrGuideService guide,
+ IGuideDataLister guideLister)
{
_console = console;
_guide = guide;
+ _guideLister = guideLister;
}
- public void ListCustomFormats()
- {
- _console.Output.WriteLine("\nList of Custom Formats in the TRaSH Guides:\n");
-
- var profilesFromGuide = _guide.GetCustomFormatData();
- foreach (var profile in profilesFromGuide)
- {
- _console.Output.WriteLine($" - {profile.TrashId} # {profile.Name}");
- }
-
- _console.Output.WriteLine(
- "\nThe above Custom Formats are in YAML format and ready to be copied & pasted " +
- "under the `trash_ids:` property.");
- }
+ public void ListCustomFormats() => _guideLister.ListCustomFormats(_guide.GetCustomFormatData());
public void ListQualities()
{
diff --git a/src/TrashLib/Services/Sonarr/ISonarrGuideDataLister.cs b/src/TrashLib/Services/Sonarr/ISonarrGuideDataLister.cs
index 94c04c21..747604f3 100644
--- a/src/TrashLib/Services/Sonarr/ISonarrGuideDataLister.cs
+++ b/src/TrashLib/Services/Sonarr/ISonarrGuideDataLister.cs
@@ -5,4 +5,5 @@ public interface ISonarrGuideDataLister
void ListReleaseProfiles();
void ListTerms(string releaseProfileId);
void ListQualities();
+ void ListCustomFormats();
}
diff --git a/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs b/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs
index 48c72b00..fd3ed526 100644
--- a/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs
+++ b/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs
@@ -1,8 +1,9 @@
+using TrashLib.Services.Common;
using TrashLib.Services.Sonarr.QualityDefinition;
namespace TrashLib.Services.Sonarr.ReleaseProfile.Guide;
-public interface ISonarrGuideService
+public interface ISonarrGuideService : IGuideService
{
IReadOnlyCollection GetReleaseProfileData();
ReleaseProfileData? GetUnfilteredProfileById(string trashId);
diff --git a/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/LocalRepoSonarrGuideService.cs b/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/LocalRepoSonarrGuideService.cs
index 61e345ed..075090ed 100644
--- a/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/LocalRepoSonarrGuideService.cs
+++ b/src/TrashLib/Services/Sonarr/ReleaseProfile/Guide/LocalRepoSonarrGuideService.cs
@@ -5,6 +5,8 @@ using Newtonsoft.Json;
using Serilog;
using TrashLib.Repo;
using TrashLib.Services.Common.QualityDefinition;
+using TrashLib.Services.CustomFormat.Guide;
+using TrashLib.Services.CustomFormat.Models;
using TrashLib.Services.Sonarr.QualityDefinition;
using TrashLib.Services.Sonarr.ReleaseProfile.Filters;
@@ -12,26 +14,37 @@ namespace TrashLib.Services.Sonarr.ReleaseProfile.Guide;
public class LocalRepoSonarrGuideService : ISonarrGuideService
{
- private readonly IRepoPathsFactory _pathFactory;
+ private readonly IRepoPathsFactory _pathsFactory;
private readonly ILogger _log;
+ private readonly ICustomFormatLoader _cfLoader;
private readonly Lazy> _data;
private readonly QualityGuideParser _parser;
- public LocalRepoSonarrGuideService(IRepoPathsFactory pathFactory, ILogger log)
+ public LocalRepoSonarrGuideService(
+ IRepoPathsFactory pathsFactory,
+ ILogger log,
+ ICustomFormatLoader cfLoader)
{
- _pathFactory = pathFactory;
+ _pathsFactory = pathsFactory;
_log = log;
+ _cfLoader = cfLoader;
_data = new Lazy>(GetReleaseProfileDataImpl);
_parser = new QualityGuideParser(log);
}
public ICollection GetQualities()
- => _parser.GetQualities(_pathFactory.Create().SonarrQualityPaths);
+ => _parser.GetQualities(_pathsFactory.Create().SonarrQualityPaths);
+
+ public ICollection GetCustomFormatData()
+ {
+ var paths = _pathsFactory.Create();
+ return _cfLoader.LoadAllCustomFormatsAtPaths(paths.SonarrCustomFormatPaths);
+ }
private IEnumerable GetReleaseProfileDataImpl()
{
var converter = new TermDataConverter();
- var paths = _pathFactory.Create();
+ var paths = _pathsFactory.Create();
var tasks = paths.SonarrReleaseProfilePaths
.SelectMany(x => x.GetFiles("*.json"))
.Select(x => LoadAndParseFile(x, converter));
diff --git a/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs b/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs
index 4099974d..12299376 100644
--- a/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs
+++ b/src/TrashLib/Services/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs
@@ -206,9 +206,13 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater
$"required version of {_compatibility.MinimumVersion} to use this program");
}
- if (capabilities.SupportsCustomFormats && config.ReleaseProfiles.Any())
+ switch (capabilities.SupportsCustomFormats)
{
- throw new VersionException("Sonarr v4 does not support Release Profiles. Please use Sonarr v3 instead.");
+ case true when config.ReleaseProfiles.Any():
+ throw new VersionException("Sonarr v4 does not support Release Profiles. Please use Sonarr v3 instead.");
+
+ case false when config.CustomFormats.Any():
+ throw new VersionException("Sonarr v3 does not support Custom Formats. Please use Sonarr v4 instead.");
}
}
diff --git a/src/TrashLib/Services/Sonarr/SonarrGuideDataLister.cs b/src/TrashLib/Services/Sonarr/SonarrGuideDataLister.cs
index 64e11146..2417e621 100644
--- a/src/TrashLib/Services/Sonarr/SonarrGuideDataLister.cs
+++ b/src/TrashLib/Services/Sonarr/SonarrGuideDataLister.cs
@@ -3,6 +3,7 @@ using CliFx.Infrastructure;
using JetBrains.Annotations;
using MoreLinq;
using Serilog;
+using TrashLib.Services.Common;
using TrashLib.Services.Sonarr.ReleaseProfile;
using TrashLib.Services.Sonarr.ReleaseProfile.Guide;
@@ -14,14 +15,22 @@ public class SonarrGuideDataLister : ISonarrGuideDataLister
private readonly IConsole _console;
private readonly ISonarrGuideService _guide;
private readonly ILogger _log;
+ private readonly IGuideDataLister _guideLister;
- public SonarrGuideDataLister(IConsole console, ISonarrGuideService guide, ILogger log)
+ public SonarrGuideDataLister(
+ IConsole console,
+ ISonarrGuideService guide,
+ ILogger log,
+ IGuideDataLister guideLister)
{
_console = console;
_guide = guide;
_log = log;
+ _guideLister = guideLister;
}
+ public void ListCustomFormats() => _guideLister.ListCustomFormats(_guide.GetCustomFormatData());
+
public void ListReleaseProfiles()
{
_console.Output.WriteLine("\nList of Release Profiles in the TRaSH Guides:\n");