You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
5.4 KiB
169 lines
5.4 KiB
using System.Diagnostics.CodeAnalysis;
|
|
using Recyclarr.Cli.Console;
|
|
using Recyclarr.Cli.Console.Settings;
|
|
using Recyclarr.Config;
|
|
using Recyclarr.Config.Models;
|
|
using Recyclarr.ServarrApi.CustomFormat;
|
|
using Recyclarr.TrashGuide.CustomFormat;
|
|
using Spectre.Console;
|
|
|
|
namespace Recyclarr.Cli.Processors.Delete;
|
|
|
|
public class DeleteCustomFormatsProcessor(
|
|
ILogger log,
|
|
IAnsiConsole console,
|
|
ICustomFormatApiService api,
|
|
IConfigurationRegistry configRegistry)
|
|
: IDeleteCustomFormatsProcessor
|
|
{
|
|
public async Task Process(IDeleteCustomFormatSettings settings)
|
|
{
|
|
var config = GetTargetConfig(settings);
|
|
|
|
var cfs = await ObtainCustomFormats(config);
|
|
|
|
if (!settings.All)
|
|
{
|
|
if (settings.CustomFormatNames.Count == 0)
|
|
{
|
|
throw new CommandException("Custom format names must be specified if the `--all` option is not used.");
|
|
}
|
|
|
|
cfs = ProcessManuallySpecifiedFormats(settings, cfs);
|
|
}
|
|
|
|
if (!cfs.Any())
|
|
{
|
|
console.MarkupLine("[yellow]Done[/]: No custom formats found or specified to delete.");
|
|
return;
|
|
}
|
|
|
|
PrintPreview(cfs);
|
|
|
|
if (settings.Preview)
|
|
{
|
|
console.MarkupLine("This is a preview! [u]No actual deletions will be performed.[/]");
|
|
return;
|
|
}
|
|
|
|
if (!settings.Force &&
|
|
!console.Confirm("\nAre you sure you want to [bold red]permanently delete[/] the above custom formats?"))
|
|
{
|
|
console.WriteLine("Aborted!");
|
|
return;
|
|
}
|
|
|
|
await DeleteCustomFormats(cfs, config);
|
|
}
|
|
|
|
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
|
private async Task DeleteCustomFormats(ICollection<CustomFormatData> cfs, IServiceConfiguration config)
|
|
{
|
|
await console.Progress().StartAsync(async ctx =>
|
|
{
|
|
var task = ctx.AddTask("Deleting Custom Formats").MaxValue(cfs.Count);
|
|
|
|
var options = new ParallelOptions {MaxDegreeOfParallelism = 8};
|
|
await Parallel.ForEachAsync(cfs, options, async (cf, token) =>
|
|
{
|
|
try
|
|
{
|
|
await api.DeleteCustomFormat(config, cf.Id, token);
|
|
log.Debug("Deleted {Name}", cf.Name);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
log.Debug(e, "Failed to delete CF");
|
|
console.WriteLine($"Failed to delete CF: {cf.Name}");
|
|
}
|
|
|
|
task.Increment(1);
|
|
});
|
|
});
|
|
}
|
|
|
|
private async Task<IList<CustomFormatData>> ObtainCustomFormats(IServiceConfiguration config)
|
|
{
|
|
IList<CustomFormatData> cfs = new List<CustomFormatData>();
|
|
|
|
await console.Status().StartAsync("Obtaining custom formats...", async _ =>
|
|
{
|
|
cfs = await api.GetCustomFormats(config);
|
|
});
|
|
|
|
return cfs;
|
|
}
|
|
|
|
private IList<CustomFormatData> ProcessManuallySpecifiedFormats(
|
|
IDeleteCustomFormatSettings settings,
|
|
IList<CustomFormatData> cfs)
|
|
{
|
|
ILookup<bool, (string Name, IEnumerable<CustomFormatData> Cfs)> result = settings.CustomFormatNames
|
|
.GroupJoin(cfs,
|
|
x => x,
|
|
x => x.Name,
|
|
(x, y) => (Name: x, Cf: y),
|
|
StringComparer.InvariantCultureIgnoreCase)
|
|
.ToLookup(x => x.Cf.Any());
|
|
|
|
// 'false' means there were no CFs matched to this CF name
|
|
if (result[false].Any())
|
|
{
|
|
var cfNames = result[false].Select(x => x.Name).ToList();
|
|
log.Debug("Unmatched CFs: {Names}", cfNames);
|
|
foreach (var name in cfNames)
|
|
{
|
|
console.MarkupLineInterpolated($"[yellow]Warning[/]: Unmatched CF Name: [teal]{name}[/]");
|
|
}
|
|
}
|
|
|
|
// 'true' represents CFs that match names provided in user-input (if provided)
|
|
cfs = result[true].SelectMany(x => x.Cfs).ToList();
|
|
return cfs;
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "CoVariantArrayConversion")]
|
|
private void PrintPreview(ICollection<CustomFormatData> cfs)
|
|
{
|
|
console.MarkupLine("The following custom formats will be [bold red]DELETED[/]:");
|
|
console.WriteLine();
|
|
|
|
var cfNames = cfs
|
|
.Select(x => x.Name)
|
|
.Order(StringComparer.InvariantCultureIgnoreCase)
|
|
.Chunk(Math.Max(15, cfs.Count / 3)) // Minimum row size is 15 for the table
|
|
.ToList();
|
|
|
|
var grid = new Grid().AddColumns(cfNames.Count);
|
|
|
|
foreach (var rowItems in cfNames.Transpose())
|
|
{
|
|
grid.AddRow(rowItems
|
|
.Select(x => Markup.FromInterpolated($"[bold white]{x}[/]"))
|
|
.ToArray());
|
|
}
|
|
|
|
console.Write(grid);
|
|
console.WriteLine();
|
|
}
|
|
|
|
private IServiceConfiguration GetTargetConfig(IDeleteCustomFormatSettings settings)
|
|
{
|
|
var configs = configRegistry.FindAndLoadConfigs(new ConfigFilterCriteria
|
|
{
|
|
Instances = new[] {settings.InstanceName}
|
|
});
|
|
|
|
switch (configs.Count)
|
|
{
|
|
case 0:
|
|
throw new ArgumentException($"No configuration found with name: {settings.InstanceName}");
|
|
|
|
case > 1:
|
|
throw new ArgumentException($"More than one instance found with this name: {settings.InstanceName}");
|
|
}
|
|
|
|
return configs.Single();
|
|
}
|
|
}
|