diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c7df12..37843e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Media Naming: Sync file naming configuration even if `rename` is not set to `true`. - Quality Profiles: Validation check added for quality groups with less than 2 qualities. +- Quality Profiles: Fix "Groups must contain multiple qualities" sync error. ## [6.0.0] - 2023-09-29 diff --git a/src/Recyclarr.Cli/Pipelines/QualityProfile/QualityItemOrganizer.cs b/src/Recyclarr.Cli/Pipelines/QualityProfile/QualityItemOrganizer.cs index 755c7723..74601531 100644 --- a/src/Recyclarr.Cli/Pipelines/QualityProfile/QualityItemOrganizer.cs +++ b/src/Recyclarr.Cli/Pipelines/QualityProfile/QualityItemOrganizer.cs @@ -96,6 +96,9 @@ public class QualityItemOrganizer .Select(y => y with {Allowed = false}) .ToList() }) + // Find item groups that have less than 2 nested qualities remaining in them. Those get flattened out. + // If Count == 0, that gets handled by the `Where()` below. + .Select(x => x.Items.Count == 1 ? x.Items.First() : x) .Where(x => x is not {Quality: null, Items.Count: 0}); } diff --git a/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/QualityItemOrganizerTest.cs b/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/QualityItemOrganizerTest.cs index 43e8b8aa..bd995337 100644 --- a/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/QualityItemOrganizerTest.cs +++ b/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/QualityItemOrganizerTest.cs @@ -64,9 +64,9 @@ public class QualityItemOrganizerTest NewQp.QualityDto(3, "three", true), NewQp.QualityDto(6, "six", false), NewQp.QualityDto(7, "seven", true), - NewQp.GroupDto(1002, "group3", true, + NewQp.GroupDto(1001, "group3", true, NewQp.QualityDto(8, "eight", true)), - NewQp.GroupDto(1003, "group4", false, + NewQp.GroupDto(1002, "group4", false, NewQp.QualityDto(9, "nine", false), NewQp.QualityDto(10, "ten", false)), NewQp.GroupDto(50, "group5", true, @@ -74,8 +74,7 @@ public class QualityItemOrganizerTest // ------ NOT IN CONFIG ------ NewQp.QualityDto(2, "two", false), NewQp.QualityDto(4, "four", false), - NewQp.GroupDto(1001, "group1", false, - NewQp.QualityDto(5, "five", false)) + NewQp.QualityDto(5, "five", false) } }); } @@ -98,16 +97,15 @@ public class QualityItemOrganizerTest // ------ NOT IN CONFIG ------ NewQp.QualityDto(2, "two", false), NewQp.QualityDto(4, "four", false), - NewQp.GroupDto(1001, "group1", false, - NewQp.QualityDto(5, "five", false)), + NewQp.QualityDto(5, "five", false), // ------ IN CONFIG ------ NewQp.QualityDto(1, "one", true), NewQp.QualityDto(3, "three", true), NewQp.QualityDto(6, "six", false), NewQp.QualityDto(7, "seven", true), - NewQp.GroupDto(1002, "group3", true, + NewQp.GroupDto(1001, "group3", true, NewQp.QualityDto(8, "eight", true)), - NewQp.GroupDto(1003, "group4", false, + NewQp.GroupDto(1002, "group4", false, NewQp.QualityDto(9, "nine", false), NewQp.QualityDto(10, "ten", false)), NewQp.GroupDto(50, "group5", true, @@ -115,4 +113,98 @@ public class QualityItemOrganizerTest } }); } + + [Test] + public void Remove_empty_group() + { + var config = new QualityProfileConfig + { + Qualities = new[] + { + NewQp.QualityConfig("one") + } + }; + + var dto = new QualityProfileDto + { + Items = new[] + { + NewQp.GroupDto(1001, "group1", true, + NewQp.QualityDto(1, "one", true)) + } + }; + + var sut = new QualityItemOrganizer(); + var result = sut.OrganizeItems(dto, config); + + result.Items.Should().BeEquivalentTo(new[] + { + NewQp.QualityDto(1, "one", true) + }); + } + + [Test] + public void Flatten_group_with_one_remaining_item() + { + var config = new QualityProfileConfig + { + Qualities = new[] + { + NewQp.QualityConfig("one") + } + }; + + var dto = new QualityProfileDto + { + Items = new[] + { + NewQp.GroupDto(1001, "group1", true, + NewQp.QualityDto(1, "one", true), + NewQp.QualityDto(2, "two", true)) + } + }; + + var sut = new QualityItemOrganizer(); + var result = sut.OrganizeItems(dto, config); + + result.Items.Should().BeEquivalentTo(new[] + { + NewQp.QualityDto(1, "one", true), + NewQp.QualityDto(2, "two", false) + }); + } + + [Test] + public void Do_not_flatten_group_with_two_remaining_items() + { + var config = new QualityProfileConfig + { + Qualities = new[] + { + NewQp.QualityConfig("one") + } + }; + + var dto = new QualityProfileDto + { + Items = new[] + { + NewQp.GroupDto(1001, "group1", true, + NewQp.QualityDto(1, "one", true), + NewQp.QualityDto(2, "two", true), + NewQp.QualityDto(3, "three", true)) + } + }; + + var sut = new QualityItemOrganizer(); + var result = sut.OrganizeItems(dto, config); + + result.Items.Should().BeEquivalentTo(new[] + { + NewQp.QualityDto(1, "one", true), + NewQp.GroupDto(1001, "group1", false, + NewQp.QualityDto(2, "two", false), + NewQp.QualityDto(3, "three", false)) + }); + } }