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.Cli/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhase.cs

133 lines
4.9 KiB

using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models;
using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
public class QualityProfileConfigPhase(ILogger log, ProcessedCustomFormatCache cache)
: IConfigPipelinePhase<QualityProfilePipelineContext>
{
public Task Execute(QualityProfilePipelineContext context, IServiceConfiguration config)
{
// 1. For each group of CFs that has a quality profile specified
// 2. For each quality profile score config in that CF group
// 3. For each CF in the group above, match it to a Guide CF object and pair it with the quality profile config
var profileAndCfs = config.CustomFormats
.SelectMany(x => x.QualityProfiles
.Select(y => (Profile: y, x.TrashIds)))
.SelectMany(x => x.TrashIds
.Select(cache.LookupByTrashId)
.NotNull()
.Select(y => (x.Profile, Cf: y)));
var allProfiles = config.QualityProfiles
.Select(x => new ProcessedQualityProfileData {Profile = x})
.ToDictionary(x => x.Profile.Name, x => x, StringComparer.InvariantCultureIgnoreCase);
foreach (var (profile, cf) in profileAndCfs)
{
if (!allProfiles.TryGetValue(profile.Name, out var profileCfs))
{
log.Debug("Implicitly adding quality profile config for {ProfileName}", profile.Name);
// If the user did not specify a quality profile in their config, we still create the QP object
// for consistency (at the very least for the name).
allProfiles[profile.Name] = profileCfs =
new ProcessedQualityProfileData
{
Profile = new QualityProfileConfig {Name = profile.Name},
// The user must explicitly specify a profile in the top-level `quality_profiles` section of
// their config, otherwise we do not implicitly create them in the service.
ShouldCreate = false
};
}
AddCustomFormatScoreData(profileCfs, profile, cf);
}
var profilesToReturn = allProfiles.Values.ToList();
PrintDiagnostics(profilesToReturn);
context.ConfigOutput = profilesToReturn;
return Task.CompletedTask;
}
private void PrintDiagnostics(IEnumerable<ProcessedQualityProfileData> profiles)
{
var scoreless = profiles
.SelectMany(x => x.ScorelessCfs)
.Select(x => (x.Name, x.TrashId))
.ToList();
if (scoreless.Count == 0)
{
return;
}
foreach (var (name, trashId) in scoreless)
{
log.Debug("CF has no score in the guide or config YAML: {Name} ({TrashId})", name, trashId);
}
}
private void AddCustomFormatScoreData(
ProcessedQualityProfileData profile,
QualityProfileScoreConfig scoreConfig,
CustomFormatData cf)
{
var existingScoreData = profile.CfScores;
var scoreToUse = DetermineScore(profile.Profile, scoreConfig, cf);
if (scoreToUse is null)
{
profile.ScorelessCfs.Add(cf);
return;
}
var existingScore = existingScoreData.FirstOrDefault(x => x.TrashId.EqualsIgnoreCase(cf.TrashId));
if (existingScore is not null)
{
if (existingScore.Score != scoreToUse)
{
log.Warning(
"Custom format {Name} ({TrashId}) is duplicated in quality profile {ProfileName} with a score " +
"of {NewScore}, which is different from the original score of {OriginalScore}",
cf.Name, cf.TrashId, scoreConfig.Name, scoreToUse, existingScore.Score);
}
else
{
log.Debug("Skipping duplicate score for {Name} ({TrashId})", cf.Name, cf.TrashId);
}
return;
}
existingScoreData.Add(new ProcessedQualityProfileScore(cf.TrashId, cf.Name, cf.Id, scoreToUse.Value));
}
private int? DetermineScore(
QualityProfileConfig profile,
QualityProfileScoreConfig scoreConfig,
CustomFormatData cf)
{
if (scoreConfig.Score is not null)
{
return scoreConfig.Score;
}
if (profile.ScoreSet is not null)
{
if (cf.TrashScores.TryGetValue(profile.ScoreSet, out var scoreFromSet))
{
return scoreFromSet;
}
log.Debug("CF {CfName} has no Score Set with name '{ScoreSetName}'", cf.Name, profile.ScoreSet);
}
return cf.DefaultScore;
}
}