feat: allow optional terms to be synced

New `filter` YAML config provided to enable this feature using
`include_optional` (true or false).
recyclarr
Robert Dailey 3 years ago
parent fc7c8bce30
commit b1abb2ca85

@ -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
[0.1.0]: https://github.com/rcdailey/trash-updater/releases/tag/v0.1.0

@ -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<string> {"ignored1"},
Required = new List<string> {"required1"},
Preferred = new Dictionary<int, List<string>>
{
{100, new List<string> {"preferred1"}}
},
Optional = new ProfileDataOptional
{
Ignored = new List<string> {"ignored2"},
Required = new List<string> {"required2"},
Preferred = new Dictionary<int, List<string>>
{
{200, new List<string> {"preferred2"}},
{100, new List<string> {"preferred3"}}
}
}
};
var filtered = new FilteredProfileData(profileData, config);
filtered.Should().BeEquivalentTo(new
{
Ignored = new List<string> {"ignored1", "ignored2"},
Required = new List<string> {"required1", "required2"},
Preferred = new Dictionary<int, List<string>>
{
{100, new List<string> {"preferred1", "preferred3"}},
{200, new List<string> {"preferred2"}}
}
});
}
[Test]
public void Filter_ExcludeOptional_HasNoOptionalItems()
{
var config = new ReleaseProfileConfig();
config.Filter.IncludeOptional = false;
var profileData = new ProfileData
{
Ignored = new List<string> {"ignored1"},
Required = new List<string> {"required1"},
Preferred = new Dictionary<int, List<string>>
{
{100, new List<string> {"preferred1"}}
},
Optional = new ProfileDataOptional
{
Ignored = new List<string> {"ignored2"},
Required = new List<string> {"required2"},
Preferred = new Dictionary<int, List<string>>
{
{200, new List<string> {"preferred2"}},
{100, new List<string> {"preferred3"}}
}
}
};
var filtered = new FilteredProfileData(profileData, config);
filtered.Should().BeEquivalentTo(new
{
Ignored = new List<string> {"ignored1"},
Required = new List<string> {"required1"},
Preferred = new Dictionary<int, List<string>>
{
{100, new List<string> {"preferred1"}}
}
});
}
}
}

@ -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<string> Required => _config.Filter.IncludeOptional
? _profileData.Required.Concat(_profileData.Optional.Required).ToList()
: _profileData.Required;
public List<string> Ignored => _config.Filter.IncludeOptional
? _profileData.Ignored.Concat(_profileData.Optional.Ignored).ToList()
: _profileData.Ignored;
public Dictionary<int, List<string>> Preferred => _config.Filter.IncludeOptional
? _profileData.Preferred
.Union(_profileData.Optional.Preferred)
.GroupBy(kvp => kvp.Key)
.ToDictionary(grp => grp.Key, grp => new List<string>(grp.SelectMany(l => l.Value)))
: _profileData.Preferred;
public bool? IncludePreferredWhenRenaming => _profileData.IncludePreferredWhenRenaming;
}
}

@ -56,12 +56,13 @@ namespace Trash.Sonarr.ReleaseProfile
return $"[Trash] {titleType} - {profileName}";
}
private static SonarrReleaseProfile? GetProfileToUpdate(List<SonarrReleaseProfile> profiles, string profileName)
private static SonarrReleaseProfile? GetProfileToUpdate(IEnumerable<SonarrReleaseProfile> 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<int> 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<int> 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<int> tagIds)
private async Task CreateNewProfile(string title, FilteredProfileData profile, List<int> tagIds)
{
var newProfile = new SonarrReleaseProfile
{
@ -101,7 +102,7 @@ namespace Trash.Sonarr.ReleaseProfile
}
private async Task ProcessReleaseProfiles(IDictionary<string, ProfileData> 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);

@ -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<string> Tags { get; init; } = new();
}
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
public class SonarrProfileFilterConfig
{
public bool IncludeOptional { get; set; }
// todo: Add Include & Exclude later (list of strings)
}
}

@ -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/

Loading…
Cancel
Save