diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f97f821..1d5009cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ changes you may need to make. ### Added - Added Naming Sync (Media Management) for Sonarr v3, Sonarr v4, and Radarr (#179). +- A `list naming` command to show Sonarr and Radarr naming formats available from the guide. ### Changed diff --git a/src/Recyclarr.Cli/Console/CliSetup.cs b/src/Recyclarr.Cli/Console/CliSetup.cs index a8199827..2207dadf 100644 --- a/src/Recyclarr.Cli/Console/CliSetup.cs +++ b/src/Recyclarr.Cli/Console/CliSetup.cs @@ -20,6 +20,7 @@ public static class CliSetup list.AddCommand("custom-formats"); list.AddCommand("release-profiles"); list.AddCommand("qualities"); + list.AddCommand("naming"); }); cli.AddBranch("config", config => diff --git a/src/Recyclarr.Cli/Console/Commands/ListMediaNamingCommand.cs b/src/Recyclarr.Cli/Console/Commands/ListMediaNamingCommand.cs new file mode 100644 index 00000000..e7120a0d --- /dev/null +++ b/src/Recyclarr.Cli/Console/Commands/ListMediaNamingCommand.cs @@ -0,0 +1,41 @@ +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using JetBrains.Annotations; +using Recyclarr.Cli.Console.Helpers; +using Recyclarr.Cli.Pipelines.MediaNaming; +using Recyclarr.Common; +using Recyclarr.Repo; +using Spectre.Console.Cli; + +namespace Recyclarr.Cli.Console.Commands; + +[UsedImplicitly] +[Description("List media naming formats in the guide for a particular service.")] +public class ListMediaNamingCommand : AsyncCommand +{ + private readonly MediaNamingDataLister _lister; + private readonly IMultiRepoUpdater _repoUpdater; + + [UsedImplicitly] + [SuppressMessage("Design", "CA1034:Nested types should not be visible")] + public class CliSettings : BaseCommandSettings + { + [CommandArgument(0, "")] + [EnumDescription("The service type to obtain information about.")] + [UsedImplicitly(ImplicitUseKindFlags.Assign)] + public SupportedServices Service { get; init; } + } + + public ListMediaNamingCommand(MediaNamingDataLister lister, IMultiRepoUpdater repoUpdater) + { + _lister = lister; + _repoUpdater = repoUpdater; + } + + public override async Task ExecuteAsync(CommandContext context, CliSettings settings) + { + await _repoUpdater.UpdateAllRepositories(settings.CancellationToken); + _lister.ListNaming(settings.Service); + return 0; + } +} diff --git a/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingAutofacModule.cs b/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingAutofacModule.cs index 2c5aa761..5bafea61 100644 --- a/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingAutofacModule.cs +++ b/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingAutofacModule.cs @@ -9,6 +9,7 @@ public class MediaNamingAutofacModule : Module protected override void Load(ContainerBuilder builder) { base.Load(builder); + builder.RegisterType(); builder.RegisterAggregateService(); builder.RegisterType(); diff --git a/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingDataLister.cs b/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingDataLister.cs new file mode 100644 index 00000000..2095d1bb --- /dev/null +++ b/src/Recyclarr.Cli/Pipelines/MediaNaming/MediaNamingDataLister.cs @@ -0,0 +1,96 @@ +using System.Diagnostics.CodeAnalysis; +using Recyclarr.Common; +using Recyclarr.TrashGuide.MediaNaming; +using Spectre.Console; +using Spectre.Console.Rendering; + +namespace Recyclarr.Cli.Pipelines.MediaNaming; + +public class MediaNamingDataLister +{ + private readonly IAnsiConsole _console; + private readonly IMediaNamingGuideService _guide; + + public MediaNamingDataLister( + IAnsiConsole console, + IMediaNamingGuideService guide) + { + _console = console; + _guide = guide; + } + + public void ListNaming(SupportedServices serviceType) + { + switch (serviceType) + { + case SupportedServices.Radarr: + ListRadarrNaming(_guide.GetRadarrNamingData()); + break; + + case SupportedServices.Sonarr: + ListSonarrNaming(_guide.GetSonarrNamingData()); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(serviceType), serviceType, null); + } + } + + private void ListRadarrNaming(RadarrMediaNamingData guideData) + { + _console.MarkupLine("Media Naming Formats [red](Preview)[/]"); + + _console.WriteLine(); + _console.Write(DictionaryToTable("Movie Folder Format", guideData.Folder)); + _console.WriteLine(); + _console.Write(DictionaryToTable("Standard Movie Format", guideData.File)); + } + + private void ListSonarrNaming(SonarrMediaNamingData guideData) + { + _console.MarkupLine("Media Naming Formats [red](Preview)[/]"); + + _console.WriteLine(); + _console.Write(DictionaryToTable("Season Folder Format", guideData.Season)); + _console.WriteLine(); + _console.Write(DictionaryToTable("Series Folder Format", guideData.Series)); + _console.WriteLine(); + _console.Write(DictionaryToTable("Standard Episode Format", guideData.Episodes.Standard)); + _console.WriteLine(); + _console.Write(DictionaryToTable("Daily Episode Format", guideData.Episodes.Daily)); + _console.WriteLine(); + _console.Write(DictionaryToTable("Anime Episode Format", guideData.Episodes.Anime)); + } + + private static IRenderable DictionaryToTable(string title, IReadOnlyDictionary formats) + { + var table = new Table() + .AddColumns("Key", "Format"); + + var alternatingColors = new[] {"white", "paleturquoise4"}; + var colorIndex = 0; + + foreach (var (key, value) in formats) + { + var color = alternatingColors[colorIndex]; + table.AddRow( + $"[{color}]{Markup.Escape(TransformKey(key))}[/]", + $"[{color}]{Markup.Escape(value)}[/]"); + colorIndex = 1 - colorIndex; + } + + return new Rows(Markup.FromInterpolated($"[orange3]{title}[/]"), table); + } + + [SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")] + private static string TransformKey(string key) + { + var split = key.Split(':'); + if (split.Length > 1) + { + return $"{split[0]} (v{split[1]})"; + } + + return key; + } +}