fix(sonarr): quality definition unlimited support

Also added some code sharing between Radarr and Sonarr for this stuff,
since they are largely similar (Radarr has preferred size but the rest
is the same).
recyclarr
Robert Dailey 4 years ago
parent f25d2620b5
commit 3d3c6f327d

@ -1,6 +1,7 @@
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using Trash.Radarr.QualityDefinition; using Trash.Radarr.QualityDefinition;
using Trash.Sonarr.QualityDefinition;
namespace Trash.Tests.Radarr.QualityDefinition namespace Trash.Tests.Radarr.QualityDefinition
{ {
@ -10,12 +11,12 @@ namespace Trash.Tests.Radarr.QualityDefinition
{ {
private static readonly object[] ToleranceTestValues = private static readonly object[] ToleranceTestValues =
{ {
new object[] {-RadarrQualityData.Tolerance - 0.01m, true}, new object[] {-SonarrQualityData.Tolerance - 0.01m, true},
new object[] {-RadarrQualityData.Tolerance, false}, new object[] {-SonarrQualityData.Tolerance, false},
new object[] {-RadarrQualityData.Tolerance / 2, false}, new object[] {-SonarrQualityData.Tolerance / 2, false},
new object[] {RadarrQualityData.Tolerance / 2, false}, new object[] {SonarrQualityData.Tolerance / 2, false},
new object[] {RadarrQualityData.Tolerance, false}, new object[] {SonarrQualityData.Tolerance, false},
new object[] {RadarrQualityData.Tolerance + 0.01m, true} new object[] {SonarrQualityData.Tolerance + 0.01m, true}
}; };
[TestCaseSource(nameof(ToleranceTestValues))] [TestCaseSource(nameof(ToleranceTestValues))]
@ -28,24 +29,6 @@ namespace Trash.Tests.Radarr.QualityDefinition
.Should().Be(expectedResult); .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 = private static readonly object[] InterpolatedPreferredTestParams =
{ {
new[] new[]
@ -88,30 +71,6 @@ namespace Trash.Tests.Radarr.QualityDefinition
data.InterpolatedPreferred(ratio).Should().Be(expectedResult); 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] [Test]
public void AnnotatedPreferred_OutsideThreshold_EqualsSameValueWithUnlimited() public void AnnotatedPreferred_OutsideThreshold_EqualsSameValueWithUnlimited()
{ {
@ -128,37 +87,6 @@ namespace Trash.Tests.Radarr.QualityDefinition
data.AnnotatedPreferred.Should().Be($"{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] [Test]
public void Preferred_AboveThreshold_EqualsSameValue() public void Preferred_AboveThreshold_EqualsSameValue()
{ {

@ -0,0 +1,94 @@
using FluentAssertions;
using NUnit.Framework;
using Trash.Sonarr.QualityDefinition;
namespace Trash.Tests.Sonarr.QualityDefinition
{
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class SonarrQualityDataTest
{
private static readonly object[] ToleranceTestValues =
{
new object[] {-SonarrQualityData.Tolerance - 0.01m, true},
new object[] {-SonarrQualityData.Tolerance, false},
new object[] {-SonarrQualityData.Tolerance / 2, false},
new object[] {SonarrQualityData.Tolerance / 2, false},
new object[] {SonarrQualityData.Tolerance, false},
new object[] {SonarrQualityData.Tolerance + 0.01m, true}
};
[TestCaseSource(nameof(ToleranceTestValues))]
public void MaxOutsideTolerance_WithVariousTolerance_ReturnsExpectedResult(decimal offset, bool expectedResult)
{
const decimal testVal = 100;
var data = new SonarrQualityData {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 SonarrQualityData {Min = testVal};
data.MinOutsideTolerance(testVal + offset)
.Should().Be(expectedResult);
}
[Test]
public void AnnotatedMax_OutsideThreshold_EqualsSameValueWithUnlimited()
{
const decimal testVal = SonarrQualityData.MaxUnlimitedThreshold;
var data = new SonarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal} (Unlimited)");
}
[Test]
public void AnnotatedMax_WithinThreshold_EqualsSameStringValue()
{
const decimal testVal = SonarrQualityData.MaxUnlimitedThreshold - 1;
var data = new SonarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal}");
}
[Test]
public void AnnotatedMin_NoThreshold_EqualsSameValue()
{
const decimal testVal = 10m;
var data = new SonarrQualityData {Max = testVal};
data.AnnotatedMax.Should().Be($"{testVal}");
}
[Test]
public void Max_AboveThreshold_EqualsSameValue()
{
const decimal testVal = SonarrQualityData.MaxUnlimitedThreshold + 1;
var data = new SonarrQualityData {Max = testVal};
data.Max.Should().Be(testVal);
}
[Test]
public void MaxForApi_AboveThreshold_EqualsNull()
{
const decimal testVal = SonarrQualityData.MaxUnlimitedThreshold + 1;
var data = new SonarrQualityData {Max = testVal};
data.MaxForApi.Should().Be(null);
}
[Test]
public void MaxForApi_HighestWithinThreshold_EqualsSameValue()
{
const decimal testVal = SonarrQualityData.MaxUnlimitedThreshold - 0.1m;
var data = new SonarrQualityData {Max = testVal};
data.MaxForApi.Should().Be(testVal).And.Be(data.Max);
}
[Test]
public void MaxForApi_LowestWithinThreshold_EqualsSameValue()
{
var data = new SonarrQualityData {Max = 0};
data.MaxForApi.Should().Be(0);
}
}
}

@ -1,26 +1,14 @@
using System; using System;
using System.Globalization; using Trash.Sonarr.QualityDefinition;
using System.Text;
namespace Trash.Radarr.QualityDefinition namespace Trash.Radarr.QualityDefinition
{ {
public class RadarrQualityData public class RadarrQualityData : SonarrQualityData
{ {
public const decimal Tolerance = 0.1m;
public const decimal MaxUnlimitedThreshold = 400;
public const decimal PreferredUnlimitedThreshold = 395; 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 Preferred { get; set; }
public decimal? MaxForApi => Max < MaxUnlimitedThreshold ? Max : null;
public decimal MinForApi => Min;
public decimal? PreferredForApi => Preferred < PreferredUnlimitedThreshold ? Preferred : null; 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 string AnnotatedPreferred => AnnotatedValue(Preferred, PreferredUnlimitedThreshold);
public decimal InterpolatedPreferred(decimal ratio) public decimal InterpolatedPreferred(decimal ratio)
@ -29,23 +17,6 @@ namespace Trash.Radarr.QualityDefinition
return Math.Round(Min + (cappedMax - Min) * ratio, 1); 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) => public bool PreferredOutsideTolerance(decimal? other) =>
Math.Abs((other ?? PreferredUnlimitedThreshold) - Preferred) > Tolerance; Math.Abs((other ?? PreferredUnlimitedThreshold) - Preferred) > Tolerance;
} }

@ -19,6 +19,6 @@ namespace Trash.Sonarr.Api.Objects
public string Title { get; set; } = ""; public string Title { get; set; } = "";
public int Weight { get; set; } public int Weight { get; set; }
public decimal MinSize { get; set; } public decimal MinSize { get; set; }
public decimal MaxSize { get; set; } public decimal? MaxSize { get; set; }
} }
} }

@ -1,9 +1,39 @@
namespace Trash.Sonarr.QualityDefinition using System;
using System.Globalization;
using System.Text;
namespace Trash.Sonarr.QualityDefinition
{ {
public class SonarrQualityData public class SonarrQualityData
{ {
public const decimal Tolerance = 0.1m;
public const decimal MaxUnlimitedThreshold = 400;
public string Name { get; set; } = ""; public string Name { get; set; } = "";
public decimal Min { get; set; } public decimal Min { get; set; }
public decimal Max { get; set; } public decimal Max { get; set; }
public decimal? MaxForApi => Max < MaxUnlimitedThreshold ? Max : null;
public decimal MinForApi => Min;
public string AnnotatedMin => Min.ToString(CultureInfo.InvariantCulture);
public string AnnotatedMax => AnnotatedValue(Max, MaxUnlimitedThreshold);
protected 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;
} }
} }

@ -68,13 +68,13 @@ namespace Trash.Sonarr.QualityDefinition
private static void PrintQualityPreview(IEnumerable<SonarrQualityData> quality) private static void PrintQualityPreview(IEnumerable<SonarrQualityData> quality)
{ {
Console.WriteLine(""); Console.WriteLine("");
const string format = "{0,-20} {1,-10} {2,-10}"; const string format = "{0,-20} {1,-10} {2,-15}";
Console.WriteLine(format, "Quality", "Min", "Max"); Console.WriteLine(format, "Quality", "Min", "Max");
Console.WriteLine(format, "-------", "---", "---"); Console.WriteLine(format, "-------", "---", "---");
foreach (var q in quality) foreach (var q in quality)
{ {
Console.WriteLine(format, q.Name, q.Min, q.Max); Console.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax);
} }
Console.WriteLine(""); Console.WriteLine("");
@ -116,13 +116,10 @@ namespace Trash.Sonarr.QualityDefinition
{ {
static bool QualityIsDifferent(SonarrQualityDefinitionItem a, SonarrQualityData b) static bool QualityIsDifferent(SonarrQualityDefinitionItem a, SonarrQualityData b)
{ {
const decimal tolerance = 0.1m; return b.MinOutsideTolerance(a.MinSize) ||
return b.MaxOutsideTolerance(a.MaxSize);
Math.Abs(a.MaxSize - b.Max) > tolerance ||
Math.Abs(a.MinSize - b.Min) > tolerance;
} }
// var newQuality = serverQuality.Where(q => guideQuality.Any(gq => gq.Name == q.Quality.Name));
var newQuality = new List<SonarrQualityDefinitionItem>(); var newQuality = new List<SonarrQualityDefinitionItem>();
foreach (var qualityData in guideQuality) foreach (var qualityData in guideQuality)
{ {
@ -139,12 +136,13 @@ namespace Trash.Sonarr.QualityDefinition
} }
// Not using the original list again, so it's OK to modify the definition reftype objects in-place. // Not using the original list again, so it's OK to modify the definition reftype objects in-place.
entry.MinSize = qualityData.Min; entry.MinSize = qualityData.MinForApi;
entry.MaxSize = qualityData.Max; entry.MaxSize = qualityData.MaxForApi;
newQuality.Add(entry); newQuality.Add(entry);
Log.Debug("Setting Quality [Name: {Name}] [Min: {Min}] [Max: {Max}]", Log.Debug("Setting Quality " +
entry.Quality?.Name, entry.MinSize, entry.MaxSize); "[Name: {Name}] [Source: {Source}] [Min: {Min}] [Max: {Max}]",
entry.Quality?.Name, entry.Quality?.Source, entry.MinSize, entry.MaxSize);
} }
await _api.UpdateQualityDefinition(newQuality); await _api.UpdateQualityDefinition(newQuality);

Loading…
Cancel
Save