You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
recyclarr/src/Recyclarr.TrashLib/Services/QualitySize/QualitySizeUpdater.cs

142 lines
5.0 KiB

using Recyclarr.Common.Extensions;
using Recyclarr.TrashLib.Config.Services;
using Recyclarr.TrashLib.Services.QualitySize.Api;
using Recyclarr.TrashLib.Services.QualitySize.Guide;
using Spectre.Console;
namespace Recyclarr.TrashLib.Services.QualitySize;
internal class QualitySizeUpdater : IQualitySizeUpdater
{
private readonly ILogger _log;
private readonly IQualityDefinitionService _api;
private readonly IAnsiConsole _console;
private readonly IQualityGuideService _guide;
public QualitySizeUpdater(
ILogger logger,
IQualityDefinitionService api,
IAnsiConsole console,
IQualityGuideService guide)
{
_log = logger;
_api = api;
_console = console;
_guide = guide;
}
public async Task Process(bool isPreview, IServiceConfiguration config)
{
var qualityDef = config.QualityDefinition;
if (qualityDef is null)
{
return;
}
var qualityDefinitions = _guide.GetQualitySizeData(config.ServiceType);
var selectedQuality = qualityDefinitions
.FirstOrDefault(x => x.Type.EqualsIgnoreCase(qualityDef.Type));
if (selectedQuality == null)
{
_log.Error("The specified quality definition type does not exist: {Type}", qualityDef.Type);
return;
}
_log.Information("Processing Quality Definition: {QualityDefinition}", qualityDef.Type);
if (qualityDef.PreferredRatio is not null)
{
_log.Information("Using an explicit preferred ratio which will override values from the guide");
// Fix an out of range ratio and warn the user
if (qualityDef.PreferredRatio is < 0 or > 1)
{
var clampedRatio = Math.Clamp(qualityDef.PreferredRatio.Value, 0, 1);
_log.Warning("Your `preferred_ratio` of {CurrentRatio} is out of range. " +
"It must be a decimal between 0.0 and 1.0. It has been clamped to {ClampedRatio}",
qualityDef.PreferredRatio, clampedRatio);
qualityDef.PreferredRatio = clampedRatio;
}
// Apply a calculated preferred size
foreach (var quality in selectedQuality.Qualities)
{
quality.Preferred = quality.InterpolatedPreferred(qualityDef.PreferredRatio.Value);
}
}
if (isPreview)
{
PrintQualityPreview(selectedQuality.Qualities);
return;
}
await ProcessQualityDefinition(config, selectedQuality.Qualities);
}
private void PrintQualityPreview(IReadOnlyCollection<QualitySizeItem> qualitySizeItems)
{
var table = new Table();
table.Title("Quality Sizes [red](Preview)[/]");
table.AddColumn("[bold]Quality[/]");
table.AddColumn("[bold]Min[/]");
table.AddColumn("[bold]Max[/]");
table.AddColumn("[bold]Preferred[/]");
foreach (var q in qualitySizeItems)
{
var quality = $"[dodgerblue1]{q.Quality}[/]";
table.AddRow(quality, q.AnnotatedMin, q.AnnotatedMax, q.AnnotatedPreferred);
}
_console.WriteLine();
_console.Write(table);
}
private static bool QualityIsDifferent(ServiceQualityDefinitionItem a, QualitySizeItem b)
{
return b.IsMinDifferent(a.MinSize) || b.IsMaxDifferent(a.MaxSize) ||
a.PreferredSize is not null && b.IsPreferredDifferent(a.PreferredSize);
}
private async Task ProcessQualityDefinition(
IServiceConfiguration config,
IReadOnlyCollection<QualitySizeItem> guideQuality)
{
var serverQuality = await _api.GetQualityDefinition(config);
var newQuality = new List<ServiceQualityDefinitionItem>();
foreach (var qualityData in guideQuality)
{
var serverEntry = serverQuality.FirstOrDefault(q => q.Quality?.Name == qualityData.Quality);
if (serverEntry == null)
{
_log.Warning("Server lacks quality definition for {Quality}; it will be skipped", qualityData.Quality);
continue;
}
if (!QualityIsDifferent(serverEntry, qualityData))
{
continue;
}
// Not using the original list again, so it's OK to modify the definition ref type objects in-place.
serverEntry.MinSize = qualityData.MinForApi;
serverEntry.MaxSize = qualityData.MaxForApi;
serverEntry.PreferredSize = qualityData.PreferredForApi;
newQuality.Add(serverEntry);
_log.Debug("Setting Quality " +
"[Name: {Name}] [Source: {Source}] [Min: {Min}] [Max: {Max}] [Preferred: {Preferred}]",
serverEntry.Quality?.Name, serverEntry.Quality?.Source, serverEntry.MinSize, serverEntry.MaxSize,
serverEntry.PreferredSize);
}
await _api.UpdateQualityDefinition(config, newQuality);
_log.Information("Number of updated qualities: {Count}", newQuality.Count);
}
}