diff --git a/CHANGELOG.md b/CHANGELOG.md index a756c88f..964fa1bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- New filter configuration for Sonarr release profiles that (for now) allows you to include optional + terms. Look for `filter` in the [Configuration Reference] for more details. + +[Configuration Reference]: https://github.com/rcdailey/trash-updater/wiki/Configuration-Reference + ## [1.2.0] - 2021-04-19 ### Added @@ -49,4 +56,4 @@ See the [Python Migration Guide][py-mig] for details on how to update your YAML [1.2.0]: https://github.com/rcdailey/trash-updater/compare/v1.1.0...v1.2.0 [1.1.0]: https://github.com/rcdailey/trash-updater/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/rcdailey/trash-updater/compare/v0.1.0...v1.0.0 -[0.1.0]: https://github.com/rcdailey/trash-updater/releases/tag/v0.1.0 \ No newline at end of file +[0.1.0]: https://github.com/rcdailey/trash-updater/releases/tag/v0.1.0 diff --git a/src/Trash.Tests/Sonarr/ReleaseProfile/FilteredProfileDataTest.cs b/src/Trash.Tests/Sonarr/ReleaseProfile/FilteredProfileDataTest.cs new file mode 100644 index 00000000..684299ac --- /dev/null +++ b/src/Trash.Tests/Sonarr/ReleaseProfile/FilteredProfileDataTest.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using FluentAssertions; +using NUnit.Framework; +using Trash.Sonarr; +using Trash.Sonarr.ReleaseProfile; + +namespace Trash.Tests.Sonarr.ReleaseProfile +{ + [TestFixture] + [Parallelizable(ParallelScope.All)] + public class FilteredProfileDataTest + { + [Test] + public void Filter_IncludeOptional_HasAllOptionalItems() + { + var config = new ReleaseProfileConfig(); + config.Filter.IncludeOptional = true; + + var profileData = new ProfileData + { + Ignored = new List {"ignored1"}, + Required = new List {"required1"}, + Preferred = new Dictionary> + { + {100, new List {"preferred1"}} + }, + Optional = new ProfileDataOptional + { + Ignored = new List {"ignored2"}, + Required = new List {"required2"}, + Preferred = new Dictionary> + { + {200, new List {"preferred2"}}, + {100, new List {"preferred3"}} + } + } + }; + + var filtered = new FilteredProfileData(profileData, config); + + filtered.Should().BeEquivalentTo(new + { + Ignored = new List {"ignored1", "ignored2"}, + Required = new List {"required1", "required2"}, + Preferred = new Dictionary> + { + {100, new List {"preferred1", "preferred3"}}, + {200, new List {"preferred2"}} + } + }); + } + + [Test] + public void Filter_ExcludeOptional_HasNoOptionalItems() + { + var config = new ReleaseProfileConfig(); + config.Filter.IncludeOptional = false; + + var profileData = new ProfileData + { + Ignored = new List {"ignored1"}, + Required = new List {"required1"}, + Preferred = new Dictionary> + { + {100, new List {"preferred1"}} + }, + Optional = new ProfileDataOptional + { + Ignored = new List {"ignored2"}, + Required = new List {"required2"}, + Preferred = new Dictionary> + { + {200, new List {"preferred2"}}, + {100, new List {"preferred3"}} + } + } + }; + + var filtered = new FilteredProfileData(profileData, config); + + filtered.Should().BeEquivalentTo(new + { + Ignored = new List {"ignored1"}, + Required = new List {"required1"}, + Preferred = new Dictionary> + { + {100, new List {"preferred1"}} + } + }); + } + } +} diff --git a/src/Trash/Sonarr/ReleaseProfile/FilteredProfileData.cs b/src/Trash/Sonarr/ReleaseProfile/FilteredProfileData.cs new file mode 100644 index 00000000..51e951f6 --- /dev/null +++ b/src/Trash/Sonarr/ReleaseProfile/FilteredProfileData.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Trash.Sonarr.ReleaseProfile +{ + public class FilteredProfileData + { + private readonly ReleaseProfileConfig _config; + private readonly ProfileData _profileData; + + public FilteredProfileData(ProfileData profileData, ReleaseProfileConfig config) + { + _profileData = profileData; + _config = config; + } + + public List Required => _config.Filter.IncludeOptional + ? _profileData.Required.Concat(_profileData.Optional.Required).ToList() + : _profileData.Required; + + public List Ignored => _config.Filter.IncludeOptional + ? _profileData.Ignored.Concat(_profileData.Optional.Ignored).ToList() + : _profileData.Ignored; + + public Dictionary> Preferred => _config.Filter.IncludeOptional + ? _profileData.Preferred + .Union(_profileData.Optional.Preferred) + .GroupBy(kvp => kvp.Key) + .ToDictionary(grp => grp.Key, grp => new List(grp.SelectMany(l => l.Value))) + : _profileData.Preferred; + + public bool? IncludePreferredWhenRenaming => _profileData.IncludePreferredWhenRenaming; + } +} diff --git a/src/Trash/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs b/src/Trash/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs index 5f4ad086..b401b25c 100644 --- a/src/Trash/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs +++ b/src/Trash/Sonarr/ReleaseProfile/ReleaseProfileUpdater.cs @@ -56,12 +56,13 @@ namespace Trash.Sonarr.ReleaseProfile return $"[Trash] {titleType} - {profileName}"; } - private static SonarrReleaseProfile? GetProfileToUpdate(List profiles, string profileName) + private static SonarrReleaseProfile? GetProfileToUpdate(IEnumerable profiles, + string profileName) { return profiles.FirstOrDefault(p => p.Name == profileName); } - private static void SetupProfileRequestObject(SonarrReleaseProfile profileToUpdate, ProfileData profile, + private static void SetupProfileRequestObject(SonarrReleaseProfile profileToUpdate, FilteredProfileData profile, List tagIds) { profileToUpdate.Preferred = profile.Preferred @@ -80,7 +81,7 @@ namespace Trash.Sonarr.ReleaseProfile profileToUpdate.Tags = tagIds; } - private async Task UpdateExistingProfile(SonarrReleaseProfile profileToUpdate, ProfileData profile, + private async Task UpdateExistingProfile(SonarrReleaseProfile profileToUpdate, FilteredProfileData profile, List tagIds) { Log.Debug("Update existing profile with id {ProfileId}", profileToUpdate.Id); @@ -88,7 +89,7 @@ namespace Trash.Sonarr.ReleaseProfile await _api.UpdateReleaseProfile(profileToUpdate); } - private async Task CreateNewProfile(string title, ProfileData profile, List tagIds) + private async Task CreateNewProfile(string title, FilteredProfileData profile, List tagIds) { var newProfile = new SonarrReleaseProfile { @@ -101,7 +102,7 @@ namespace Trash.Sonarr.ReleaseProfile } private async Task ProcessReleaseProfiles(IDictionary profiles, - ReleaseProfileConfig profile) + ReleaseProfileConfig config) { await DoVersionEnforcement(); @@ -109,11 +110,11 @@ namespace Trash.Sonarr.ReleaseProfile // If tags were provided, ensure they exist. Tags that do not exist are added first, so that we // may specify them with the release profile request payload. - if (profile.Tags.Count > 0) + if (config.Tags.Count > 0) { var sonarrTags = await _api.GetTags(); - await CreateMissingTags(sonarrTags, profile.Tags); - tagIds = sonarrTags.Where(t => profile.Tags.Any(ct => ct.EqualsIgnoreCase(t.Label))) + await CreateMissingTags(sonarrTags, config.Tags); + tagIds = sonarrTags.Where(t => config.Tags.Any(ct => ct.EqualsIgnoreCase(t.Label))) .Select(t => t.Id) .ToList(); } @@ -125,17 +126,18 @@ namespace Trash.Sonarr.ReleaseProfile foreach (var (name, profileData) in profiles) { - var title = BuildProfileTitle(profile.Type, name); + var filteredProfileData = new FilteredProfileData(profileData, config); + var title = BuildProfileTitle(config.Type, name); var profileToUpdate = GetProfileToUpdate(existingProfiles, title); if (profileToUpdate != null) { Log.Information("Update existing profile: {ProfileName}", title); - await UpdateExistingProfile(profileToUpdate, profileData, tagIds); + await UpdateExistingProfile(profileToUpdate, filteredProfileData, tagIds); } else { Log.Information("Create new profile: {ProfileName}", title); - await CreateNewProfile(title, profileData, tagIds); + await CreateNewProfile(title, filteredProfileData, tagIds); } } } @@ -146,9 +148,13 @@ namespace Trash.Sonarr.ReleaseProfile { Log.Information("Processing Release Profile: {ProfileName}", profile.Type); var markdown = await _parser.GetMarkdownData(profile.Type); - var profiles = Utils.FilterProfiles(_parser.ParseMarkdown(profile, markdown)); + if (profile.Filter.IncludeOptional) + { + Log.Information("Configuration is set to allow optional terms to be synchronized"); + } + if (args.Preview) { Utils.PrintTermsAndScores(profiles); diff --git a/src/Trash/Sonarr/SonarrConfiguration.cs b/src/Trash/Sonarr/SonarrConfiguration.cs index 75e9bff9..db68f22a 100644 --- a/src/Trash/Sonarr/SonarrConfiguration.cs +++ b/src/Trash/Sonarr/SonarrConfiguration.cs @@ -26,6 +26,14 @@ namespace Trash.Sonarr { public ReleaseProfileType Type { get; init; } public bool StrictNegativeScores { get; init; } + public SonarrProfileFilterConfig Filter { get; init; } = new(); public List Tags { get; init; } = new(); } + + [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] + public class SonarrProfileFilterConfig + { + public bool IncludeOptional { get; set; } + // todo: Add Include & Exclude later (list of strings) + } } diff --git a/wiki/Configuration-Reference.md b/wiki/Configuration-Reference.md index ff9ba764..0cc42823 100644 --- a/wiki/Configuration-Reference.md +++ b/wiki/Configuration-Reference.md @@ -37,6 +37,8 @@ sonarr: - anime - type: series strict_negative_scores: false + filter: + include_optional: true tags: - tv ``` @@ -81,6 +83,11 @@ sonarr: release profile (if present) are removed and replaced with only the tags in this list. If no tags are specified, no tags will be set on the release profile. + - `filter` (Optional): Defines various ways that release profile terms from the guide are + synchronized with Sonarr. Any combination of the below properties may be specified here: + - `include_optional`: Set to `true` to include terms marked "Optional" in the guide. By default, + optional terms are *not* synchronized to Sonarr. The default is `false`. + [sonarr_quality]: https://trash-guides.info/Sonarr/V3/Sonarr-Quality-Settings-File-Size/ [sonarr_profile_anime]: https://trash-guides.info/Sonarr/V3/Sonarr-Release-Profile-RegEx-Anime/ [sonarr_profile_series]: https://trash-guides.info/Sonarr/V3/Sonarr-Release-Profile-RegEx/