From efc4455d929b26971fac6ce4a745badd1bfa7e15 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Mon, 25 Apr 2022 17:44:09 -0500 Subject: [PATCH] feat(sonarr): New --list-terms command line option New `--list-terms` command line option which can be used get a list of terms for a release profile. These lists of terms can be used to include or exclude specific optionals, for example. --- CHANGELOG.md | 2 + src/Trash/Command/SonarrCommand.cs | 23 ++++++++ src/TrashLib/Sonarr/IReleaseProfileLister.cs | 1 + .../Guide/ISonarrGuideService.cs | 1 + .../LocalRepoReleaseProfileJsonParser.cs | 17 +++++- src/TrashLib/Sonarr/ReleaseProfileLister.cs | 59 ++++++++++++++++++- 6 files changed, 100 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc40e5d7..2e7275c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ JSON files][sonarrjson]. This breaks existing `trash.yml` and manual changes *ar - Sonarr: New `--list-release-profiles` command line option which can be used to quickly and conveniently get a list of release profiles (and their Trash IDs) so you know what to add in your YAML config under `release_profiles`. +- Sonarr: New `--list-terms` command line option which can be used get a list of terms for a release + profile. These lists of terms can be used to include or exclude specific optionals, for example. [#17]: https://github.com/rcdailey/trash-updater/issues/17 [Upgrade Guide]: https://github.com/rcdailey/trash-updater/wiki/Upgrade-Guide diff --git a/src/Trash/Command/SonarrCommand.cs b/src/Trash/Command/SonarrCommand.cs index 93c3e273..5a372ba5 100644 --- a/src/Trash/Command/SonarrCommand.cs +++ b/src/Trash/Command/SonarrCommand.cs @@ -1,4 +1,5 @@ using CliFx.Attributes; +using CliFx.Exceptions; using Flurl.Http; using JetBrains.Annotations; using Serilog; @@ -27,6 +28,13 @@ public class SonarrCommand : ServiceCommand "List available release profiles from the guide in YAML format.")] public bool ListReleaseProfiles { get; [UsedImplicitly] set; } = false; + // The default value is "empty" because I need to know when the user specifies the option but no value with it. + // Discussed here: https://github.com/Tyrrrz/CliFx/discussions/128#discussioncomment-2647015 + [CommandOption("list-terms", Description = + "For the given Release Profile Trash ID, list terms in it that can be filtered in YAML format. " + + "Note that not every release profile has terms that may be filtered.")] + public string? ListTerms { get; [UsedImplicitly] set; } = "empty"; + public SonarrCommand( ILogger log, LoggingLevelSwitch loggingLevelSwitch, @@ -60,6 +68,21 @@ public class SonarrCommand : ServiceCommand return; } + if (ListTerms != "empty") + { + if (!string.IsNullOrEmpty(ListTerms)) + { + _lister.ListTerms(ListTerms); + } + else + { + throw new CommandException( + "The --list-terms option was specified without a Release Profile Trash ID specified"); + } + + return; + } + foreach (var config in _configLoader.LoadMany(Config, "sonarr")) { _log.Information("Processing server {Url}", config.BaseUrl); diff --git a/src/TrashLib/Sonarr/IReleaseProfileLister.cs b/src/TrashLib/Sonarr/IReleaseProfileLister.cs index f3065bef..11dd3688 100644 --- a/src/TrashLib/Sonarr/IReleaseProfileLister.cs +++ b/src/TrashLib/Sonarr/IReleaseProfileLister.cs @@ -3,4 +3,5 @@ namespace TrashLib.Sonarr; public interface IReleaseProfileLister { void ListReleaseProfiles(); + void ListTerms(string releaseProfileId); } diff --git a/src/TrashLib/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs b/src/TrashLib/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs index 3b0aab72..eacc9187 100644 --- a/src/TrashLib/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs +++ b/src/TrashLib/Sonarr/ReleaseProfile/Guide/ISonarrGuideService.cs @@ -3,4 +3,5 @@ public interface ISonarrGuideService { IReadOnlyCollection GetReleaseProfileData(); + ReleaseProfileData? GetUnfilteredProfileById(string trashId); } diff --git a/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs b/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs index df3f9b9e..391fb3ef 100644 --- a/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs +++ b/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs @@ -1,4 +1,5 @@ using System.IO.Abstractions; +using Common.Extensions; using Common.FluentValidation; using MoreLinq; using Newtonsoft.Json; @@ -10,14 +11,16 @@ public class LocalRepoReleaseProfileJsonParser : ISonarrGuideService { private readonly IFileSystem _fileSystem; private readonly IResourcePaths _paths; + private readonly Lazy> _data; public LocalRepoReleaseProfileJsonParser(IFileSystem fileSystem, IResourcePaths paths) { _fileSystem = fileSystem; _paths = paths; + _data = new Lazy>(GetReleaseProfileDataImpl); } - public IReadOnlyCollection GetReleaseProfileData() + private IEnumerable GetReleaseProfileDataImpl() { var converter = new TermDataConverter(); var jsonDir = Path.Combine(_paths.RepoPath, "docs/json/sonarr"); @@ -29,7 +32,17 @@ public class LocalRepoReleaseProfileJsonParser : ISonarrGuideService }); return Task.WhenAll(tasks).Result - .Choose(x => x is not null ? (true, x) : default) // Make non-nullable type + .Choose(x => x is not null ? (true, x) : default); // Make non-nullable type + } + + public ReleaseProfileData? GetUnfilteredProfileById(string trashId) + { + return _data.Value.FirstOrDefault(x => x.TrashId.EqualsIgnoreCase(trashId)); + } + + public IReadOnlyCollection GetReleaseProfileData() + { + return _data.Value .IsValid(new ReleaseProfileDataValidator()) .ToList(); } diff --git a/src/TrashLib/Sonarr/ReleaseProfileLister.cs b/src/TrashLib/Sonarr/ReleaseProfileLister.cs index 1439006c..ab2ec05d 100644 --- a/src/TrashLib/Sonarr/ReleaseProfileLister.cs +++ b/src/TrashLib/Sonarr/ReleaseProfileLister.cs @@ -1,5 +1,8 @@ +using System.Text; using CliFx.Infrastructure; using JetBrains.Annotations; +using Serilog; +using TrashLib.Sonarr.ReleaseProfile; using TrashLib.Sonarr.ReleaseProfile.Guide; namespace TrashLib.Sonarr; @@ -9,11 +12,13 @@ public class ReleaseProfileLister : IReleaseProfileLister { private readonly IConsole _console; private readonly ISonarrGuideService _guide; + private readonly ILogger _log; - public ReleaseProfileLister(IConsole console, ISonarrGuideService guide) + public ReleaseProfileLister(IConsole console, ISonarrGuideService guide, ILogger log) { _console = console; _guide = guide; + _log = log; } public void ListReleaseProfiles() @@ -29,4 +34,56 @@ public class ReleaseProfileLister : IReleaseProfileLister _console.Output.WriteLine( "\nThe above Release Profiles are in YAML format and ready to be copied & pasted under the `trash_ids:` property."); } + + public void ListTerms(string releaseProfileId) + { + _console.Output.WriteLine(); + + var profile = _guide.GetUnfilteredProfileById(releaseProfileId); + if (profile is null) + { + _log.Error("No release profile found with that Trash ID"); + return; + } + + var validator = new ReleaseProfileDataValidator(); + if (!validator.Validate(profile).IsValid) + { + _console.Output.WriteLine("This release profile has no terms that can be filtered. " + + "Terms must have Trash IDs assigned in order to be filtered."); + return; + } + + _console.Output.WriteLine($"List of Terms for the '{profile.Name}' Release Profile that may be filtered:\n"); + + PrintTerms(profile.Required, "Required"); + PrintTerms(profile.Ignored, "Ignored"); + PrintTerms(profile.Preferred.SelectMany(x => x.Terms), "Preferred"); + + _console.Output.WriteLine( + "The above Term Filters are in YAML format and ready to be copied & pasted under the `include:` or `exclude:` filter properties."); + } + + private void PrintTerms(IEnumerable terms, string category) + { + var filteredTerms = terms.Where(x => x.TrashId.Any()).ToList(); + if (!filteredTerms.Any()) + { + return; + } + + _console.Output.WriteLine($"{category} Terms:\n"); + foreach (var term in filteredTerms) + { + var line = new StringBuilder($" - {term.TrashId}"); + if (term.Name.Any()) + { + line.Append($" # {term.Name}"); + } + + _console.Output.WriteLine(line); + } + + _console.Output.WriteLine(); + } }