fix(radarr): quality definition now sets unlimited

For max and preferred values
recyclarr
Robert Dailey 3 years ago
parent 41fdd3b174
commit 1ace0fb13d

@ -0,0 +1,193 @@
using FluentAssertions;
using NUnit.Framework;
using Trash.Radarr.QualityDefinition;
namespace Trash.Tests.Radarr.QualityDefinition
{
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class RadarrQualityDataTest
{
private static readonly object[] ToleranceTestValues =
{
new object[] {-RadarrQualityData.Tolerance - 0.01m, true},
new object[] {-RadarrQualityData.Tolerance, false},
new object[] {-RadarrQualityData.Tolerance / 2, false},
new object[] {RadarrQualityData.Tolerance / 2, false},
new object[] {RadarrQualityData.Tolerance, false},
new object[] {RadarrQualityData.Tolerance + 0.01m, true}
};
[TestCaseSource(nameof(ToleranceTestValues))]
public void PreferredOutsideTolerance_WithVariousTolerance_ReturnsExpectedResult(decimal offset,
bool expectedResult)
{
const decimal testVal = 100;
var data = new RadarrQualityData {Preferred = testVal};
data.PreferredOutsideTolerance(testVal + offset)
.Should().Be(expectedResult);
}
[TestCaseSource(nameof(ToleranceTestValues))]
public void MaxOutsideTolerance_WithVariousTolerance_ReturnsExpectedResult(decimal offset, bool expectedResult)
{
const decimal testVal = 100;
var data = new RadarrQualityData {Max = testVal};
data.MaxOutsideTolerance(testVal + offset)
.Should().Be(expectedResult);
}
[TestCaseSource(nameof(ToleranceTestValues))]
public void MinOutsideTolerance_WithVariousTolerance_ReturnsExpectedResult(decimal offset, bool expectedResult)
{
const decimal testVal = 0;
var data = new RadarrQualityData {Min = testVal};
data.MinOutsideTolerance(testVal + offset)
.Should().Be(expectedResult);
}
private static readonly object[] InterpolatedPreferredTestParams =
{
new[]
{
400m,
1.0m,
RadarrQualityData.PreferredUnlimitedThreshold
},
new[]
{
RadarrQualityData.PreferredUnlimitedThreshold,
1.0m,
RadarrQualityData.PreferredUnlimitedThreshold
},
new[]
{
RadarrQualityData.PreferredUnlimitedThreshold - 1m,
1.0m,
RadarrQualityData.PreferredUnlimitedThreshold - 1m
},
new[]
{
10m,
0m,
0m
},
new[]
{
100m,
0.5m,
50m
}
};
[TestCaseSource(nameof(InterpolatedPreferredTestParams))]
public void InterpolatedPreferred_VariousValues_ExpectedResults(decimal max, decimal ratio,
decimal expectedResult)
{
var data = new RadarrQualityData {Min = 0, Max = max};
data.InterpolatedPreferred(ratio).Should().Be(expectedResult);
}
[Test]
public void AnnotatedMax_OutsideThreshold_EqualsSameValueWithUnlimited()
{
const decimal testVal = RadarrQualityData.MaxUnlimitedThreshold;
var data = new RadarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal} (Unlimited)");
}
[Test]
public void AnnotatedMax_WithinThreshold_EqualsSameStringValue()
{
const decimal testVal = RadarrQualityData.MaxUnlimitedThreshold - 1;
var data = new RadarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal}");
}
[Test]
public void AnnotatedMin_NoThreshold_EqualsSameValue()
{
const decimal testVal = 10m;
var data = new RadarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal}");
}
[Test]
public void AnnotatedPreferred_OutsideThreshold_EqualsSameValueWithUnlimited()
{
const decimal testVal = RadarrQualityData.PreferredUnlimitedThreshold;
var data = new RadarrQualityData {Preferred = testVal};
data.AnnotatedPreferred.Should().Be($"{testVal} (Unlimited)");
}
[Test]
public void AnnotatedPreferred_WithinThreshold_EqualsSameStringValue()
{
const decimal testVal = RadarrQualityData.PreferredUnlimitedThreshold - 1;
var data = new RadarrQualityData {Preferred = testVal};
data.AnnotatedPreferred.Should().Be($"{testVal}");
}
[Test]
public void Max_AboveThreshold_EqualsSameValue()
{
const decimal testVal = RadarrQualityData.MaxUnlimitedThreshold + 1;
var data = new RadarrQualityData {Max = testVal};
data.Max.Should().Be(testVal);
}
[Test]
public void MaxForApi_AboveThreshold_EqualsNull()
{
const decimal testVal = RadarrQualityData.MaxUnlimitedThreshold + 1;
var data = new RadarrQualityData {Max = testVal};
data.MaxForApi.Should().Be(null);
}
[Test]
public void MaxForApi_HighestWithinThreshold_EqualsSameValue()
{
const decimal testVal = RadarrQualityData.MaxUnlimitedThreshold - 0.1m;
var data = new RadarrQualityData {Max = testVal};
data.MaxForApi.Should().Be(testVal).And.Be(data.Max);
}
[Test]
public void MaxForApi_LowestWithinThreshold_EqualsSameValue()
{
var data = new RadarrQualityData {Max = 0};
data.MaxForApi.Should().Be(0);
}
[Test]
public void Preferred_AboveThreshold_EqualsSameValue()
{
const decimal testVal = RadarrQualityData.PreferredUnlimitedThreshold + 1;
var data = new RadarrQualityData {Preferred = testVal};
data.Preferred.Should().Be(testVal);
}
[Test]
public void PreferredForApi_AboveThreshold_EqualsNull()
{
const decimal testVal = RadarrQualityData.PreferredUnlimitedThreshold + 1;
var data = new RadarrQualityData {Preferred = testVal};
data.PreferredForApi.Should().Be(null);
}
[Test]
public void PreferredForApi_HighestWithinThreshold_EqualsSameValue()
{
const decimal testVal = RadarrQualityData.PreferredUnlimitedThreshold - 0.1m;
var data = new RadarrQualityData {Preferred = testVal};
data.PreferredForApi.Should().Be(testVal).And.Be(data.Preferred);
}
[Test]
public void PreferredForApi_LowestWithinThreshold_EqualsSameValue()
{
var data = new RadarrQualityData {Preferred = 0};
data.PreferredForApi.Should().Be(0);
}
}
}

@ -86,8 +86,13 @@ namespace Trash.Command
// This is important. If any DTOs are missing members, say, if Radarr or Sonarr adds one in a future
// version, this needs to fail to indicate that a software change is required. Otherwise, we lose
// state between when we request settings, and re-apply them again with a few properties modified.
MissingMemberHandling = MissingMemberHandling.Error
MissingMemberHandling = MissingMemberHandling.Error,
// This makes sure that null properties, such as maxSize and preferredSize in Radarr
// Quality Definitions, do not get written out to JSON request bodies.
NullValueHandling = NullValueHandling.Ignore
};
settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings);
});
}

@ -20,7 +20,7 @@ namespace Trash.Radarr.Api.Objects
public string Title { get; set; } = "";
public int Weight { get; set; }
public decimal MinSize { get; set; }
public decimal MaxSize { get; set; }
public decimal PreferredSize { get; set; }
public decimal? MaxSize { get; set; }
public decimal? PreferredSize { get; set; }
}
}

@ -1,10 +1,52 @@
namespace Trash.Radarr.QualityDefinition
using System;
using System.Globalization;
using System.Text;
namespace Trash.Radarr.QualityDefinition
{
public class RadarrQualityData
{
public const decimal Tolerance = 0.1m;
public const decimal MaxUnlimitedThreshold = 400;
public const decimal PreferredUnlimitedThreshold = 395;
public string Name { get; set; } = "";
public decimal Min { get; set; }
public decimal Max { get; set; }
public decimal Preferred { get; set; }
public decimal? MaxForApi => Max < MaxUnlimitedThreshold ? Max : null;
public decimal MinForApi => Min;
public decimal? PreferredForApi => Preferred < PreferredUnlimitedThreshold ? Preferred : null;
public string AnnotatedMin => Min.ToString(CultureInfo.InvariantCulture);
public string AnnotatedMax => AnnotatedValue(Max, MaxUnlimitedThreshold);
public string AnnotatedPreferred => AnnotatedValue(Preferred, PreferredUnlimitedThreshold);
public decimal InterpolatedPreferred(decimal ratio)
{
var cappedMax = Math.Min(Max, PreferredUnlimitedThreshold);
return Math.Round(Min + (cappedMax - Min) * ratio, 1);
}
private static string AnnotatedValue(decimal value, decimal threshold)
{
var builder = new StringBuilder(value.ToString(CultureInfo.InvariantCulture));
if (value >= threshold)
{
builder.Append(" (Unlimited)");
}
return builder.ToString();
}
public bool MinOutsideTolerance(decimal other) =>
Math.Abs(other - Min) > Tolerance;
public bool MaxOutsideTolerance(decimal? other) =>
Math.Abs((other ?? MaxUnlimitedThreshold) - Max) > Tolerance;
public bool PreferredOutsideTolerance(decimal? other) =>
Math.Abs((other ?? PreferredUnlimitedThreshold) - Preferred) > Tolerance;
}
}

@ -26,13 +26,13 @@ namespace Trash.Radarr.QualityDefinition
private static void PrintQualityPreview(IEnumerable<RadarrQualityData> quality)
{
Console.WriteLine("");
const string format = "{0,-20} {1,-10} {2,-10} {3,-10}";
const string format = "{0,-20} {1,-10} {2,-15} {3,-15}";
Console.WriteLine(format, "Quality", "Min", "Max", "Preferred");
Console.WriteLine(format, "-------", "---", "---", "---------");
foreach (var q in quality)
{
Console.WriteLine(format, q.Name, q.Min, q.Max, q.Preferred);
Console.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax, q.AnnotatedPreferred);
}
Console.WriteLine("");
@ -59,8 +59,7 @@ namespace Trash.Radarr.QualityDefinition
// Apply a calculated preferred size
foreach (var quality in selectedQuality)
{
quality.Preferred =
Math.Round(quality.Min + (quality.Max - quality.Min) * config.QualityDefinition.PreferredRatio, 1);
quality.Preferred = quality.InterpolatedPreferred(config.QualityDefinition.PreferredRatio);
}
if (args.Preview)
@ -83,11 +82,9 @@ namespace Trash.Radarr.QualityDefinition
{
static bool QualityIsDifferent(RadarrQualityDefinitionItem a, RadarrQualityData b)
{
const decimal tolerance = 0.1m;
return
Math.Abs(a.MaxSize - b.Max) > tolerance ||
Math.Abs(a.MinSize - b.Min) > tolerance ||
Math.Abs(a.PreferredSize - b.Preferred) > tolerance;
return b.MinOutsideTolerance(a.MinSize) ||
b.MaxOutsideTolerance(a.MaxSize) ||
b.PreferredOutsideTolerance(a.PreferredSize);
}
var newQuality = new List<RadarrQualityDefinitionItem>();
@ -106,9 +103,9 @@ namespace Trash.Radarr.QualityDefinition
}
// Not using the original list again, so it's OK to modify the definition reftype objects in-place.
entry.MinSize = qualityData.Min;
entry.MaxSize = qualityData.Max;
entry.PreferredSize = qualityData.Preferred;
entry.MinSize = qualityData.MinForApi;
entry.MaxSize = qualityData.MaxForApi;
entry.PreferredSize = qualityData.PreferredForApi;
newQuality.Add(entry);
Log.Debug("Setting Quality " +

Loading…
Cancel
Save