Instead of organizing logic using service, such as Sonarr or Radarr, organize it using function. So now logic is broken up by Custom Format, Release Profile, and Quality Size.pull/201/head
parent
7dec45a07a
commit
bcc65857df
@ -0,0 +1,10 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Repo;
|
||||||
|
|
||||||
|
public interface IRepoMetadataBuilder
|
||||||
|
{
|
||||||
|
RepoMetadata GetMetadata();
|
||||||
|
IReadOnlyList<IDirectoryInfo> ToDirectoryInfoList(IEnumerable<string> listOfDirectories);
|
||||||
|
IDirectoryInfo DocsDirectory { get; }
|
||||||
|
}
|
@ -1,14 +0,0 @@
|
|||||||
using System.IO.Abstractions;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Repo;
|
|
||||||
|
|
||||||
public interface IRepoPaths
|
|
||||||
{
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> RadarrCustomFormatPaths { get; }
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrReleaseProfilePaths { get; }
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrQualityPaths { get; }
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> RadarrQualityPaths { get; }
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrCustomFormatPaths { get; }
|
|
||||||
IFileInfo RadarrCollectionOfCustomFormats { get; }
|
|
||||||
IFileInfo SonarrCollectionOfCustomFormats { get; }
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace Recyclarr.TrashLib.Repo;
|
|
||||||
|
|
||||||
public interface IRepoPathsFactory
|
|
||||||
{
|
|
||||||
IRepoPaths Create();
|
|
||||||
RepoMetadata Metadata { get; }
|
|
||||||
}
|
|
@ -1,21 +1,25 @@
|
|||||||
namespace Recyclarr.TrashLib.Repo;
|
namespace Recyclarr.TrashLib.Repo;
|
||||||
|
|
||||||
public record RadarrMetadata(
|
public record RadarrMetadata
|
||||||
IReadOnlyCollection<string> CustomFormats,
|
{
|
||||||
IReadOnlyCollection<string> Qualities
|
public IReadOnlyCollection<string> CustomFormats { get; init; } = Array.Empty<string>();
|
||||||
);
|
public IReadOnlyCollection<string> Qualities { get; init; } = Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
public record SonarrMetadata(
|
public record SonarrMetadata
|
||||||
IReadOnlyCollection<string> ReleaseProfiles,
|
{
|
||||||
IReadOnlyCollection<string> Qualities,
|
public IReadOnlyCollection<string> ReleaseProfiles { get; init; } = Array.Empty<string>();
|
||||||
IReadOnlyCollection<string> CustomFormats
|
public IReadOnlyCollection<string> Qualities { get; init; } = Array.Empty<string>();
|
||||||
);
|
public IReadOnlyCollection<string> CustomFormats { get; init; } = Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
public record JsonPaths(
|
public record JsonPaths
|
||||||
RadarrMetadata Radarr,
|
{
|
||||||
SonarrMetadata Sonarr
|
public RadarrMetadata Radarr { get; init; } = new();
|
||||||
);
|
public SonarrMetadata Sonarr { get; init; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
public record RepoMetadata(
|
public record RepoMetadata
|
||||||
JsonPaths JsonPaths
|
{
|
||||||
);
|
public JsonPaths JsonPaths { get; init; } = new();
|
||||||
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
using Recyclarr.TrashLib.Startup;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Repo;
|
||||||
|
|
||||||
|
public class RepoMetadataBuilder : IRepoMetadataBuilder
|
||||||
|
{
|
||||||
|
private readonly IAppPaths _paths;
|
||||||
|
private readonly Lazy<RepoMetadata> _metadata;
|
||||||
|
|
||||||
|
public RepoMetadataBuilder(
|
||||||
|
IRepoMetadataParser parser,
|
||||||
|
IAppPaths paths)
|
||||||
|
{
|
||||||
|
_paths = paths;
|
||||||
|
_metadata = new Lazy<RepoMetadata>(parser.Deserialize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<IDirectoryInfo> ToDirectoryInfoList(IEnumerable<string> listOfDirectories)
|
||||||
|
{
|
||||||
|
return listOfDirectories.Select(x => _paths.RepoDirectory.SubDirectory(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDirectoryInfo DocsDirectory => _paths.RepoDirectory.SubDirectory("docs");
|
||||||
|
|
||||||
|
public RepoMetadata GetMetadata()
|
||||||
|
{
|
||||||
|
return _metadata.Value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
using System.IO.Abstractions;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Repo;
|
|
||||||
|
|
||||||
public record RepoPaths(
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> RadarrCustomFormatPaths,
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrReleaseProfilePaths,
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> RadarrQualityPaths,
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrQualityPaths,
|
|
||||||
IReadOnlyCollection<IDirectoryInfo> SonarrCustomFormatPaths,
|
|
||||||
IFileInfo RadarrCollectionOfCustomFormats,
|
|
||||||
IFileInfo SonarrCollectionOfCustomFormats
|
|
||||||
) : IRepoPaths;
|
|
@ -1,40 +0,0 @@
|
|||||||
using System.IO.Abstractions;
|
|
||||||
using Recyclarr.TrashLib.Startup;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Repo;
|
|
||||||
|
|
||||||
public class RepoPathsFactory : IRepoPathsFactory
|
|
||||||
{
|
|
||||||
private readonly IAppPaths _paths;
|
|
||||||
private readonly Lazy<RepoMetadata> _metadata;
|
|
||||||
|
|
||||||
public RepoMetadata Metadata => _metadata.Value;
|
|
||||||
|
|
||||||
public RepoPathsFactory(IRepoMetadataParser parser, IAppPaths paths)
|
|
||||||
{
|
|
||||||
_paths = paths;
|
|
||||||
_metadata = new Lazy<RepoMetadata>(parser.Deserialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<IDirectoryInfo> ToDirectoryInfoList(IEnumerable<string> listOfDirectories)
|
|
||||||
{
|
|
||||||
return listOfDirectories
|
|
||||||
.Select(x => _paths.RepoDirectory.SubDirectory(x))
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRepoPaths Create()
|
|
||||||
{
|
|
||||||
var docs = _paths.RepoDirectory.SubDirectory("docs");
|
|
||||||
var metadata = _metadata.Value;
|
|
||||||
return new RepoPaths(
|
|
||||||
ToDirectoryInfoList(metadata.JsonPaths.Radarr.CustomFormats),
|
|
||||||
ToDirectoryInfoList(metadata.JsonPaths.Sonarr.ReleaseProfiles),
|
|
||||||
ToDirectoryInfoList(metadata.JsonPaths.Radarr.Qualities),
|
|
||||||
ToDirectoryInfoList(metadata.JsonPaths.Sonarr.Qualities),
|
|
||||||
ToDirectoryInfoList(metadata.JsonPaths.Sonarr.CustomFormats),
|
|
||||||
docs.SubDirectory("Radarr").File("Radarr-collection-of-custom-formats.md"),
|
|
||||||
docs.SubDirectory("Sonarr").File("sonarr-collection-of-custom-formats.md")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
using MoreLinq;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
using Spectre.Console;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
public class GuideDataLister : IGuideDataLister
|
|
||||||
{
|
|
||||||
private readonly IAnsiConsole _console;
|
|
||||||
|
|
||||||
public GuideDataLister(IAnsiConsole console)
|
|
||||||
{
|
|
||||||
_console = console;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ListCustomFormats(IEnumerable<CustomFormatData> customFormats)
|
|
||||||
{
|
|
||||||
_console.WriteLine("\nList of Custom Formats in the TRaSH Guides:");
|
|
||||||
|
|
||||||
var categories = customFormats
|
|
||||||
.OrderBy(x => x.Name)
|
|
||||||
.ToLookup(x => x.Category)
|
|
||||||
.OrderBy(x => x.Key);
|
|
||||||
|
|
||||||
foreach (var cat in categories)
|
|
||||||
{
|
|
||||||
var title = cat.Key is not null ? $"{cat.Key}" : "[No Category]";
|
|
||||||
_console.WriteLine($"\n # {title}");
|
|
||||||
|
|
||||||
foreach (var cf in cat)
|
|
||||||
{
|
|
||||||
_console.WriteLine($" - {cf.TrashId} # {cf.Name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_console.WriteLine(
|
|
||||||
"\nThe above Custom Formats are in YAML format and ready to be copied & pasted " +
|
|
||||||
"under the `trash_ids:` property.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ListQualities(IEnumerable<QualitySizeData> qualityData)
|
|
||||||
{
|
|
||||||
_console.WriteLine("\nList of Quality Definition types in the TRaSH Guides:\n");
|
|
||||||
|
|
||||||
qualityData
|
|
||||||
.Select(x => x.Type)
|
|
||||||
.ForEach(x => _console.WriteLine($" - {x}"));
|
|
||||||
|
|
||||||
_console.WriteLine(
|
|
||||||
"\nThe above quality definition types can be used with the `quality_definition:` property in your " +
|
|
||||||
"recyclarr.yml file.");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
using Autofac;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
public class GuideServicesAutofacModule : Module
|
|
||||||
{
|
|
||||||
protected override void Load(ContainerBuilder builder)
|
|
||||||
{
|
|
||||||
base.Load(builder);
|
|
||||||
builder.RegisterType<GuideDataLister>().As<IGuideDataLister>();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
public interface IGuideDataLister
|
|
||||||
{
|
|
||||||
void ListCustomFormats(IEnumerable<CustomFormatData> customFormats);
|
|
||||||
void ListQualities(IEnumerable<QualitySizeData> qualityData);
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
public interface IGuideService
|
|
||||||
{
|
|
||||||
ICollection<CustomFormatData> GetCustomFormatData();
|
|
||||||
ICollection<QualitySizeData> GetQualities();
|
|
||||||
}
|
|
@ -0,0 +1,41 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
||||||
|
|
||||||
|
public class CustomFormatDataLister
|
||||||
|
{
|
||||||
|
private readonly IAnsiConsole _console;
|
||||||
|
private readonly ICustomFormatGuideService _guide;
|
||||||
|
|
||||||
|
public CustomFormatDataLister(IAnsiConsole console, ICustomFormatGuideService guide)
|
||||||
|
{
|
||||||
|
_console = console;
|
||||||
|
_guide = guide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ListCustomFormats(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
_console.WriteLine("\nList of Custom Formats in the TRaSH Guides:");
|
||||||
|
|
||||||
|
var categories = _guide.GetCustomFormatData(serviceType)
|
||||||
|
.OrderBy(x => x.Name)
|
||||||
|
.ToLookup(x => x.Category)
|
||||||
|
.OrderBy(x => x.Key);
|
||||||
|
|
||||||
|
foreach (var cat in categories)
|
||||||
|
{
|
||||||
|
var title = cat.Key is not null ? $"{cat.Key}" : "[No Category]";
|
||||||
|
_console.WriteLine($"\n # {title}");
|
||||||
|
|
||||||
|
foreach (var cf in cat)
|
||||||
|
{
|
||||||
|
_console.WriteLine($" - {cf.TrashId} # {cf.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_console.WriteLine(
|
||||||
|
"\nThe above Custom Formats are in YAML format and ready to be copied & pasted " +
|
||||||
|
"under the `trash_ids:` property.");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
using Recyclarr.TrashLib.Repo;
|
||||||
|
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
||||||
|
|
||||||
|
public class CustomFormatGuideService : ICustomFormatGuideService
|
||||||
|
{
|
||||||
|
private readonly IRepoMetadataBuilder _metadataBuilder;
|
||||||
|
private readonly ICustomFormatLoader _cfLoader;
|
||||||
|
|
||||||
|
public CustomFormatGuideService(
|
||||||
|
IRepoMetadataBuilder metadataBuilder,
|
||||||
|
ICustomFormatLoader cfLoader)
|
||||||
|
{
|
||||||
|
_metadataBuilder = metadataBuilder;
|
||||||
|
_cfLoader = cfLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomFormatPaths CreatePaths(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
var metadata = _metadataBuilder.GetMetadata();
|
||||||
|
return serviceType switch
|
||||||
|
{
|
||||||
|
SupportedServices.Radarr => new CustomFormatPaths(
|
||||||
|
_metadataBuilder.ToDirectoryInfoList(metadata.JsonPaths.Radarr.CustomFormats),
|
||||||
|
_metadataBuilder.DocsDirectory.SubDirectory("Radarr").File("Radarr-collection-of-custom-formats.md")
|
||||||
|
),
|
||||||
|
SupportedServices.Sonarr => new CustomFormatPaths(
|
||||||
|
_metadataBuilder.ToDirectoryInfoList(metadata.JsonPaths.Sonarr.CustomFormats),
|
||||||
|
_metadataBuilder.DocsDirectory.SubDirectory("Sonarr").File("sonarr-collection-of-custom-formats.md")
|
||||||
|
),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(serviceType), serviceType, null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<CustomFormatData> GetCustomFormatData(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
var paths = CreatePaths(serviceType);
|
||||||
|
|
||||||
|
return _cfLoader.LoadAllCustomFormatsAtPaths(
|
||||||
|
paths.CustomFormatDirectories,
|
||||||
|
paths.CollectionOfCustomFormatsMarkdown);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
||||||
|
|
||||||
|
internal record CustomFormatPaths(
|
||||||
|
IReadOnlyList<IDirectoryInfo> CustomFormatDirectories,
|
||||||
|
IFileInfo CollectionOfCustomFormatsMarkdown
|
||||||
|
);
|
@ -0,0 +1,9 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
||||||
|
|
||||||
|
public interface ICustomFormatGuideService
|
||||||
|
{
|
||||||
|
ICollection<CustomFormatData> GetCustomFormatData(SupportedServices serviceType);
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
using Recyclarr.TrashLib.Config.Services;
|
using Recyclarr.TrashLib.Config.Services;
|
||||||
using Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.CustomFormat;
|
namespace Recyclarr.TrashLib.Services.CustomFormat;
|
||||||
|
|
||||||
public interface ICustomFormatUpdater
|
public interface ICustomFormatUpdater
|
||||||
{
|
{
|
||||||
Task Process(bool isPreview, IEnumerable<CustomFormatConfig> configs, IGuideService guideService);
|
Task Process(bool isPreview, IEnumerable<CustomFormatConfig> configs, SupportedServices serviceType);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.QualitySize.Guide;
|
||||||
|
|
||||||
|
public interface IQualityGuideService
|
||||||
|
{
|
||||||
|
IReadOnlyList<QualitySizeData> GetQualitySizeData(SupportedServices serviceType);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
using Recyclarr.TrashLib.Repo;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.QualitySize.Guide;
|
||||||
|
|
||||||
|
public class QualityGuideService : IQualityGuideService
|
||||||
|
{
|
||||||
|
private readonly IRepoMetadataBuilder _metadataBuilder;
|
||||||
|
private readonly QualitySizeGuideParser _parser;
|
||||||
|
|
||||||
|
public QualityGuideService(
|
||||||
|
IRepoMetadataBuilder metadataBuilder,
|
||||||
|
QualitySizeGuideParser parser)
|
||||||
|
{
|
||||||
|
_metadataBuilder = metadataBuilder;
|
||||||
|
_parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QualitySizePaths CreatePaths(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
var metadata = _metadataBuilder.GetMetadata();
|
||||||
|
return serviceType switch
|
||||||
|
{
|
||||||
|
SupportedServices.Radarr => new QualitySizePaths(
|
||||||
|
_metadataBuilder.ToDirectoryInfoList(metadata.JsonPaths.Radarr.Qualities)
|
||||||
|
),
|
||||||
|
SupportedServices.Sonarr => new QualitySizePaths(
|
||||||
|
_metadataBuilder.ToDirectoryInfoList(metadata.JsonPaths.Sonarr.Qualities)
|
||||||
|
),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(serviceType), serviceType, null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<QualitySizeData> GetQualitySizeData(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
var paths = CreatePaths(serviceType);
|
||||||
|
return _parser.GetQualities(paths.QualitySizeDirectories);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
using MoreLinq;
|
||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.QualitySize.Guide;
|
||||||
|
|
||||||
|
public class QualitySizeDataLister
|
||||||
|
{
|
||||||
|
private readonly IAnsiConsole _console;
|
||||||
|
private readonly IQualityGuideService _guide;
|
||||||
|
|
||||||
|
public QualitySizeDataLister(
|
||||||
|
IAnsiConsole console,
|
||||||
|
IQualityGuideService guide)
|
||||||
|
{
|
||||||
|
_console = console;
|
||||||
|
_guide = guide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ListQualities(SupportedServices serviceType)
|
||||||
|
{
|
||||||
|
_console.WriteLine("\nList of Quality Definition types in the TRaSH Guides:\n");
|
||||||
|
|
||||||
|
_guide.GetQualitySizeData(serviceType)
|
||||||
|
.Select(x => x.Type)
|
||||||
|
.ForEach(x => _console.WriteLine($" - {x}"));
|
||||||
|
|
||||||
|
_console.WriteLine(
|
||||||
|
"\nThe above quality definition types can be used with the `quality_definition:` property in your " +
|
||||||
|
"recyclarr.yml file.");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.QualitySize.Guide;
|
||||||
|
|
||||||
|
internal record QualitySizePaths(
|
||||||
|
IReadOnlyCollection<IDirectoryInfo> QualitySizeDirectories
|
||||||
|
);
|
@ -1,9 +1,9 @@
|
|||||||
|
using Recyclarr.TrashLib.Config;
|
||||||
using Recyclarr.TrashLib.Config.Services;
|
using Recyclarr.TrashLib.Config.Services;
|
||||||
using Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.QualitySize;
|
namespace Recyclarr.TrashLib.Services.QualitySize;
|
||||||
|
|
||||||
public interface IQualitySizeUpdater
|
public interface IQualitySizeUpdater
|
||||||
{
|
{
|
||||||
Task Process(bool isPreview, QualityDefinitionConfig config, IGuideService guideService);
|
Task Process(bool isPreview, QualityDefinitionConfig config, SupportedServices serviceType);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
using Autofac;
|
||||||
|
using Recyclarr.TrashLib.Services.QualitySize.Api;
|
||||||
|
using Recyclarr.TrashLib.Services.QualitySize.Guide;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.QualitySize;
|
||||||
|
|
||||||
|
public class QualitySizeAutofacModule : Module
|
||||||
|
{
|
||||||
|
protected override void Load(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
builder.RegisterType<QualityDefinitionService>().As<IQualityDefinitionService>();
|
||||||
|
builder.RegisterType<QualitySizeUpdater>().As<IQualitySizeUpdater>();
|
||||||
|
builder.RegisterType<QualityGuideService>().As<IQualityGuideService>();
|
||||||
|
builder.RegisterType<QualitySizeGuideParser>();
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
namespace Recyclarr.TrashLib.Services.Radarr;
|
|
||||||
|
|
||||||
public interface IRadarrGuideDataLister
|
|
||||||
{
|
|
||||||
void ListCustomFormats();
|
|
||||||
void ListQualities();
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Repo;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize.Guide;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Radarr;
|
|
||||||
|
|
||||||
public class LocalRepoRadarrGuideService : RadarrGuideService
|
|
||||||
{
|
|
||||||
private readonly IRepoPathsFactory _pathsFactory;
|
|
||||||
private readonly ICustomFormatLoader _cfLoader;
|
|
||||||
private readonly QualitySizeGuideParser<QualitySizeData> _parser;
|
|
||||||
|
|
||||||
public LocalRepoRadarrGuideService(IRepoPathsFactory pathsFactory, ILogger log, ICustomFormatLoader cfLoader)
|
|
||||||
{
|
|
||||||
_pathsFactory = pathsFactory;
|
|
||||||
_cfLoader = cfLoader;
|
|
||||||
_parser = new QualitySizeGuideParser<QualitySizeData>(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICollection<QualitySizeData> GetQualities()
|
|
||||||
{
|
|
||||||
return _parser.GetQualities(_pathsFactory.Create().RadarrQualityPaths);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICollection<CustomFormatData> GetCustomFormatData()
|
|
||||||
{
|
|
||||||
var paths = _pathsFactory.Create();
|
|
||||||
return _cfLoader.LoadAllCustomFormatsAtPaths(
|
|
||||||
paths.RadarrCustomFormatPaths,
|
|
||||||
paths.RadarrCollectionOfCustomFormats);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
using JetBrains.Annotations;
|
|
||||||
using Recyclarr.TrashLib.Services.Common;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Radarr;
|
|
||||||
|
|
||||||
[UsedImplicitly]
|
|
||||||
public class RadarrGuideDataLister : IRadarrGuideDataLister
|
|
||||||
{
|
|
||||||
private readonly RadarrGuideService _guide;
|
|
||||||
private readonly IGuideDataLister _guideLister;
|
|
||||||
|
|
||||||
public RadarrGuideDataLister(
|
|
||||||
RadarrGuideService guide,
|
|
||||||
IGuideDataLister guideLister)
|
|
||||||
{
|
|
||||||
_guide = guide;
|
|
||||||
_guideLister = guideLister;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ListCustomFormats()
|
|
||||||
{
|
|
||||||
_guideLister.ListCustomFormats(_guide.GetCustomFormatData());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ListQualities()
|
|
||||||
{
|
|
||||||
_guideLister.ListQualities(_guide.GetQualities());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Services.Common;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Radarr;
|
|
||||||
|
|
||||||
public abstract class RadarrGuideService : IGuideService
|
|
||||||
{
|
|
||||||
public abstract ICollection<CustomFormatData> GetCustomFormatData();
|
|
||||||
public abstract ICollection<QualitySizeData> GetQualities();
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Api.Objects;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api;
|
||||||
|
|
||||||
public interface IReleaseProfileApiService
|
public interface IReleaseProfileApiService
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Api.Objects;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api;
|
||||||
|
|
||||||
public interface ISonarrReleaseProfileCompatibilityHandler
|
public interface ISonarrReleaseProfileCompatibilityHandler
|
||||||
{
|
{
|
@ -1,8 +1,8 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Api.Objects;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api.Mappings;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api.Mappings;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class SonarrApiObjectMappingProfile : Profile
|
public class SonarrApiObjectMappingProfile : Profile
|
@ -1,7 +1,7 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api.Objects;
|
||||||
|
|
||||||
[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
|
[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
|
||||||
public class SonarrPreferredTerm
|
public class SonarrPreferredTerm
|
@ -1,9 +1,9 @@
|
|||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Recyclarr.TrashLib.Http;
|
using Recyclarr.TrashLib.Http;
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Api.Objects;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api;
|
||||||
|
|
||||||
public class ReleaseProfileApiService : IReleaseProfileApiService
|
public class ReleaseProfileApiService : IReleaseProfileApiService
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api.Schemas;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Api.Schemas;
|
||||||
|
|
||||||
public static class SonarrReleaseProfileSchema
|
public static class SonarrReleaseProfileSchema
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public interface IReleaseProfileFilter
|
public interface IReleaseProfileFilter
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public interface IReleaseProfileFilterPipeline
|
public interface IReleaseProfileFilterPipeline
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class IncludeExcludeFilter : IReleaseProfileFilter
|
public class IncludeExcludeFilter : IReleaseProfileFilter
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class ReleaseProfileDataFilterer
|
public class ReleaseProfileDataFilterer
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using Recyclarr.Common.FluentValidation;
|
using Recyclarr.Common.FluentValidation;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class ReleaseProfileDataValidationFilterer
|
public class ReleaseProfileDataValidationFilterer
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class ReleaseProfileFilterPipeline : IReleaseProfileFilterPipeline
|
public class ReleaseProfileFilterPipeline : IReleaseProfileFilterPipeline
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class StrictNegativeScoresFilter : IReleaseProfileFilter
|
public class StrictNegativeScoresFilter : IReleaseProfileFilter
|
||||||
{
|
{
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Guide;
|
||||||
|
|
||||||
|
public interface IReleaseProfileGuideService
|
||||||
|
{
|
||||||
|
IReadOnlyList<ReleaseProfileData> GetReleaseProfileData();
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
using MoreLinq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Recyclarr.Common;
|
||||||
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Guide;
|
||||||
|
|
||||||
|
public class ReleaseProfileGuideParser
|
||||||
|
{
|
||||||
|
private readonly ILogger _log;
|
||||||
|
|
||||||
|
public ReleaseProfileGuideParser(ILogger log)
|
||||||
|
{
|
||||||
|
_log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ReleaseProfileData?> LoadAndParseFile(IFileInfo file, params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var stream = file.OpenText();
|
||||||
|
var json = await stream.ReadToEndAsync();
|
||||||
|
return JsonConvert.DeserializeObject<ReleaseProfileData>(json, converters);
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
HandleJsonException(e, file);
|
||||||
|
}
|
||||||
|
catch (AggregateException ae) when (ae.InnerException is JsonException e)
|
||||||
|
{
|
||||||
|
HandleJsonException(e, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleJsonException(JsonException exception, IFileInfo file)
|
||||||
|
{
|
||||||
|
_log.Warning(exception,
|
||||||
|
"Failed to parse Sonarr JSON file (This likely indicates a bug that should be " +
|
||||||
|
"reported in the TRaSH repo): {File}", file.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ReleaseProfileData> GetReleaseProfileData(IEnumerable<IDirectoryInfo> paths)
|
||||||
|
{
|
||||||
|
var converter = new TermDataConverter();
|
||||||
|
var tasks = JsonUtils.GetJsonFilesInDirectories(paths, _log)
|
||||||
|
.Select(x => LoadAndParseFile(x, converter));
|
||||||
|
|
||||||
|
var data = Task.WhenAll(tasks).Result
|
||||||
|
// Make non-nullable type and filter out null values
|
||||||
|
.Choose(x => x is not null ? (true, x) : default);
|
||||||
|
|
||||||
|
var validator = new ReleaseProfileDataValidationFilterer(_log);
|
||||||
|
return validator.FilterProfiles(data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using Recyclarr.TrashLib.Repo;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Guide;
|
||||||
|
|
||||||
|
public class ReleaseProfileGuideService : IReleaseProfileGuideService
|
||||||
|
{
|
||||||
|
private readonly IRepoMetadataBuilder _metadataBuilder;
|
||||||
|
private readonly ReleaseProfileGuideParser _parser;
|
||||||
|
|
||||||
|
public ReleaseProfileGuideService(
|
||||||
|
IRepoMetadataBuilder metadataBuilder,
|
||||||
|
ReleaseProfileGuideParser parser)
|
||||||
|
{
|
||||||
|
_metadataBuilder = metadataBuilder;
|
||||||
|
_parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReleaseProfilePaths GetPaths()
|
||||||
|
{
|
||||||
|
var metadata = _metadataBuilder.GetMetadata();
|
||||||
|
return new ReleaseProfilePaths(
|
||||||
|
_metadataBuilder.ToDirectoryInfoList(metadata.JsonPaths.Sonarr.ReleaseProfiles)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<ReleaseProfileData> GetReleaseProfileData()
|
||||||
|
{
|
||||||
|
var paths = GetPaths();
|
||||||
|
return _parser.GetReleaseProfileData(paths.ReleaseProfileDirectories).ToList();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
using System.IO.Abstractions;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile.Guide;
|
||||||
|
|
||||||
|
public record ReleaseProfilePaths(
|
||||||
|
IReadOnlyList<IDirectoryInfo> ReleaseProfileDirectories
|
||||||
|
);
|
@ -1,6 +1,6 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
using Recyclarr.TrashLib.Services.Sonarr.Config;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile;
|
||||||
|
|
||||||
public interface IReleaseProfileUpdater
|
public interface IReleaseProfileUpdater
|
||||||
{
|
{
|
@ -0,0 +1,31 @@
|
|||||||
|
using Autofac;
|
||||||
|
using Autofac.Extras.Ordering;
|
||||||
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Api;
|
||||||
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Filters;
|
||||||
|
using Recyclarr.TrashLib.Services.ReleaseProfile.Guide;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile;
|
||||||
|
|
||||||
|
public class ReleaseProfileAutofacModule : Module
|
||||||
|
{
|
||||||
|
protected override void Load(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
base.Load(builder);
|
||||||
|
|
||||||
|
builder.RegisterType<ReleaseProfileApiService>().As<IReleaseProfileApiService>();
|
||||||
|
|
||||||
|
builder.RegisterType<ReleaseProfileUpdater>().As<IReleaseProfileUpdater>();
|
||||||
|
builder.RegisterType<SonarrReleaseProfileCompatibilityHandler>()
|
||||||
|
.As<ISonarrReleaseProfileCompatibilityHandler>();
|
||||||
|
builder.RegisterType<ReleaseProfileFilterPipeline>().As<IReleaseProfileFilterPipeline>();
|
||||||
|
builder.RegisterType<ReleaseProfileGuideParser>();
|
||||||
|
builder.RegisterType<ReleaseProfileGuideService>().As<IReleaseProfileGuideService>();
|
||||||
|
|
||||||
|
// Release Profile Filters (ORDER MATTERS!)
|
||||||
|
builder.RegisterTypes(
|
||||||
|
typeof(IncludeExcludeFilter),
|
||||||
|
typeof(StrictNegativeScoresFilter))
|
||||||
|
.As<IReleaseProfileFilter>()
|
||||||
|
.OrderByRegistration();
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile;
|
||||||
|
|
||||||
internal class TermDataValidator : AbstractValidator<TermData>
|
internal class TermDataValidator : AbstractValidator<TermData>
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile;
|
||||||
|
|
||||||
public class ScopedState<T>
|
public class ScopedState<T>
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
namespace Recyclarr.TrashLib.Services.ReleaseProfile;
|
||||||
|
|
||||||
internal class TermDataConverter : JsonConverter
|
internal class TermDataConverter : JsonConverter
|
||||||
{
|
{
|
@ -1,13 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
|
||||||
|
|
||||||
public interface ISonarrApi
|
|
||||||
{
|
|
||||||
Task<IList<SonarrTag>> GetTags();
|
|
||||||
Task<SonarrTag> CreateTag(string tag);
|
|
||||||
Task<IReadOnlyCollection<SonarrQualityDefinitionItem>> GetQualityDefinition();
|
|
||||||
|
|
||||||
Task<IList<SonarrQualityDefinitionItem>> UpdateQualityDefinition(
|
|
||||||
IReadOnlyCollection<SonarrQualityDefinitionItem> newQuality);
|
|
||||||
}
|
|
@ -0,0 +1,9 @@
|
|||||||
|
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
||||||
|
|
||||||
|
public interface ISonarrTagApiService
|
||||||
|
{
|
||||||
|
Task<IList<SonarrTag>> GetTags();
|
||||||
|
Task<SonarrTag> CreateTag(string tag);
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
using JetBrains.Annotations;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
|
||||||
|
|
||||||
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
|
|
||||||
public class SonarrQualityItem
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Name { get; set; } = "";
|
|
||||||
public string Source { get; set; } = "";
|
|
||||||
public int Resolution { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
|
|
||||||
public class SonarrQualityDefinitionItem
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public SonarrQualityItem? Quality { get; set; }
|
|
||||||
public string Title { get; set; } = "";
|
|
||||||
public int Weight { get; set; }
|
|
||||||
public decimal MinSize { get; set; }
|
|
||||||
public decimal? MaxSize { get; set; }
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
using Flurl.Http;
|
|
||||||
using Recyclarr.TrashLib.Http;
|
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
|
||||||
|
|
||||||
public class SonarrApi : ISonarrApi
|
|
||||||
{
|
|
||||||
private readonly IServiceRequestBuilder _service;
|
|
||||||
|
|
||||||
public SonarrApi(IServiceRequestBuilder service)
|
|
||||||
{
|
|
||||||
_service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IList<SonarrTag>> GetTags()
|
|
||||||
{
|
|
||||||
return await _service.Request("tag")
|
|
||||||
.GetJsonAsync<List<SonarrTag>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SonarrTag> CreateTag(string tag)
|
|
||||||
{
|
|
||||||
return await _service.Request("tag")
|
|
||||||
.PostJsonAsync(new {label = tag})
|
|
||||||
.ReceiveJson<SonarrTag>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IReadOnlyCollection<SonarrQualityDefinitionItem>> GetQualityDefinition()
|
|
||||||
{
|
|
||||||
return await _service.Request("qualitydefinition")
|
|
||||||
.GetJsonAsync<List<SonarrQualityDefinitionItem>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IList<SonarrQualityDefinitionItem>> UpdateQualityDefinition(
|
|
||||||
IReadOnlyCollection<SonarrQualityDefinitionItem> newQuality)
|
|
||||||
{
|
|
||||||
return await _service.Request("qualityDefinition", "update")
|
|
||||||
.PutJsonAsync(newQuality)
|
|
||||||
.ReceiveJson<List<SonarrQualityDefinitionItem>>();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
using Flurl.Http;
|
||||||
|
using Recyclarr.TrashLib.Http;
|
||||||
|
using Recyclarr.TrashLib.Services.Sonarr.Api.Objects;
|
||||||
|
|
||||||
|
namespace Recyclarr.TrashLib.Services.Sonarr.Api;
|
||||||
|
|
||||||
|
public class SonarrTagApiService : ISonarrTagApiService
|
||||||
|
{
|
||||||
|
private readonly IServiceRequestBuilder _service;
|
||||||
|
|
||||||
|
public SonarrTagApiService(IServiceRequestBuilder service)
|
||||||
|
{
|
||||||
|
_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IList<SonarrTag>> GetTags()
|
||||||
|
{
|
||||||
|
return await _service.Request("tag")
|
||||||
|
.GetJsonAsync<List<SonarrTag>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SonarrTag> CreateTag(string tag)
|
||||||
|
{
|
||||||
|
return await _service.Request("tag")
|
||||||
|
.PostJsonAsync(new {label = tag})
|
||||||
|
.ReceiveJson<SonarrTag>();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
namespace Recyclarr.TrashLib.Services.Sonarr;
|
|
||||||
|
|
||||||
public interface ISonarrGuideDataLister
|
|
||||||
{
|
|
||||||
void ListReleaseProfiles();
|
|
||||||
void ListTerms(string releaseProfileId);
|
|
||||||
void ListQualities();
|
|
||||||
void ListCustomFormats();
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
using System.IO.Abstractions;
|
|
||||||
using MoreLinq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Recyclarr.Common;
|
|
||||||
using Recyclarr.Common.Extensions;
|
|
||||||
using Recyclarr.TrashLib.Repo;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Guide;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize.Guide;
|
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile.Filters;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr;
|
|
||||||
|
|
||||||
public class LocalRepoSonarrGuideService : SonarrGuideService
|
|
||||||
{
|
|
||||||
private readonly IRepoPathsFactory _pathsFactory;
|
|
||||||
private readonly ILogger _log;
|
|
||||||
private readonly ICustomFormatLoader _cfLoader;
|
|
||||||
private readonly Lazy<IEnumerable<ReleaseProfileData>> _data;
|
|
||||||
private readonly QualitySizeGuideParser<QualitySizeData> _parser;
|
|
||||||
|
|
||||||
public LocalRepoSonarrGuideService(
|
|
||||||
IRepoPathsFactory pathsFactory,
|
|
||||||
ILogger log,
|
|
||||||
ICustomFormatLoader cfLoader)
|
|
||||||
{
|
|
||||||
_pathsFactory = pathsFactory;
|
|
||||||
_log = log;
|
|
||||||
_cfLoader = cfLoader;
|
|
||||||
_data = new Lazy<IEnumerable<ReleaseProfileData>>(GetReleaseProfileDataImpl);
|
|
||||||
_parser = new QualitySizeGuideParser<QualitySizeData>(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICollection<QualitySizeData> GetQualities()
|
|
||||||
{
|
|
||||||
return _parser.GetQualities(_pathsFactory.Create().SonarrQualityPaths);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICollection<CustomFormatData> GetCustomFormatData()
|
|
||||||
{
|
|
||||||
var paths = _pathsFactory.Create();
|
|
||||||
return _cfLoader.LoadAllCustomFormatsAtPaths(
|
|
||||||
paths.SonarrCustomFormatPaths,
|
|
||||||
paths.SonarrCollectionOfCustomFormats);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<ReleaseProfileData> GetReleaseProfileDataImpl()
|
|
||||||
{
|
|
||||||
var converter = new TermDataConverter();
|
|
||||||
var paths = _pathsFactory.Create();
|
|
||||||
var tasks = JsonUtils.GetJsonFilesInDirectories(paths.SonarrReleaseProfilePaths, _log)
|
|
||||||
.Select(x => LoadAndParseFile(x, converter));
|
|
||||||
|
|
||||||
var data = Task.WhenAll(tasks).Result
|
|
||||||
// Make non-nullable type and filter out null values
|
|
||||||
.Choose(x => x is not null ? (true, x) : default);
|
|
||||||
|
|
||||||
var validator = new ReleaseProfileDataValidationFilterer(_log);
|
|
||||||
return validator.FilterProfiles(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<ReleaseProfileData?> LoadAndParseFile(IFileInfo file, params JsonConverter[] converters)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var stream = file.OpenText();
|
|
||||||
var json = await stream.ReadToEndAsync();
|
|
||||||
return JsonConvert.DeserializeObject<ReleaseProfileData>(json, converters);
|
|
||||||
}
|
|
||||||
catch (JsonException e)
|
|
||||||
{
|
|
||||||
HandleJsonException(e, file);
|
|
||||||
}
|
|
||||||
catch (AggregateException ae) when (ae.InnerException is JsonException e)
|
|
||||||
{
|
|
||||||
HandleJsonException(e, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleJsonException(JsonException exception, IFileInfo file)
|
|
||||||
{
|
|
||||||
_log.Warning(exception,
|
|
||||||
"Failed to parse Sonarr JSON file (This likely indicates a bug that should be " +
|
|
||||||
"reported in the TRaSH repo): {File}", file.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ReleaseProfileData? GetUnfilteredProfileById(string trashId)
|
|
||||||
{
|
|
||||||
return _data.Value.FirstOrDefault(x => x.TrashId.EqualsIgnoreCase(trashId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IReadOnlyCollection<ReleaseProfileData> GetReleaseProfileData()
|
|
||||||
{
|
|
||||||
return _data.Value.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
using Recyclarr.TrashLib.Services.Common;
|
|
||||||
using Recyclarr.TrashLib.Services.CustomFormat.Models;
|
|
||||||
using Recyclarr.TrashLib.Services.QualitySize;
|
|
||||||
using Recyclarr.TrashLib.Services.Sonarr.ReleaseProfile;
|
|
||||||
|
|
||||||
namespace Recyclarr.TrashLib.Services.Sonarr;
|
|
||||||
|
|
||||||
public abstract class SonarrGuideService : IGuideService
|
|
||||||
{
|
|
||||||
public abstract IReadOnlyCollection<ReleaseProfileData> GetReleaseProfileData();
|
|
||||||
public abstract ReleaseProfileData? GetUnfilteredProfileById(string trashId);
|
|
||||||
public abstract ICollection<CustomFormatData> GetCustomFormatData();
|
|
||||||
public abstract ICollection<QualitySizeData> GetQualities();
|
|
||||||
}
|
|
Loading…
Reference in new issue