using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; using Newtonsoft.Json; using RedundancyFinder; using Spectre.Console; using Spectre.Console.Cli; namespace RedundancyFinderCLI { internal sealed class DeleteCommand : Command { public sealed class Settings : CommandSettings { [Description("Paths to Keep.")] [DefaultValue(new string[] { "H:\\" })] [CommandArgument(1, "[path]")] public string[]? FoldersToKeep { get; init; } [Description("Path to analyze.")] [DefaultValue("redundancies.json")] [CommandArgument(0, "[path]")] public string? Path { get; init; } [Description("File extensions to search for. Comma separated.")] [CommandOption("-e|--extensions")] [DefaultValue(".jpg,.webp,.raw,.pdf,.xsl,.xslx,.doc,.docx,.txt,.jpeg,.mov,.mp4,.mp3,.wav,.bmp,.gif,.png,.cu,.mid,.msb,.mov,.avi,.wmv,.flv,.m4v,.bak,.cpr,.xml,.psd")] public string? Extensions { get; init; } [Description("Show all information.")] [CommandOption("-v|--verbose")] [DefaultValue(false)] public bool Verbose { get; init; } } public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) { WriteLine($"[yellow]Analyzing {settings.Path}[/]"); var redundancies = JsonConvert.DeserializeObject>(File.ReadAllText(settings.Path)); var pathsToDelete = new List(); foreach (var redundancy in redundancies.Values) { var pathToKeep = redundancy.Paths.FirstOrDefault(x => settings.FoldersToKeep.Any(y => x.StartsWith(y))); if (pathToKeep != default) { foreach (var path in redundancy.Paths) { if (path != pathToKeep) { pathsToDelete.Add(path); } } } else if(settings.Verbose) { if (redundancy.Paths.Count > 0) { WriteLine($"[blue]Skipping [/]'{redundancy.Paths.FirstOrDefault()}'[blue]. No paths to keep![/]"); } else { WriteLine($"[yellow]Skipping [/]'{redundancy.Hash}'[/].[blue] No paths![/]"); } } } foreach (var path in pathsToDelete) { AnsiConsole.WriteLine(path); } if (pathsToDelete.Count == 0) { WriteLine("[yellow]Nothing to delete![/]"); return 0; } var confirmation = AnsiConsole.Prompt( new TextPrompt("Delete all of the above?") .AddChoice(true) .AddChoice(false) .DefaultValue(true) .WithConverter(choice => choice ? "y" : "n")); if (confirmation) { foreach (var path in pathsToDelete) { try { File.Delete(path); } catch (Exception e) { WriteLine($"[red]Error deleting file: [/]'{path}'\nMessage:\n{e.Message}"); } WriteLine($"[yellow]Deleted file: [/]'{path}'"); } } return 0; } private void WriteLine(string v) { string now = Markup.Escape($"[{DateTime.Now.ToString("HH:mm:ss")}]"); AnsiConsole.MarkupLine($"[gray]{now}[/] {v}"); } private static string GetSizeFormat(ulong totalSize) { string sizeUnit = "B"; double size = totalSize; while (size > 1024) { size /= 1024d; sizeUnit = sizeUnit switch { "B" => "KB", "KB" => "MB", "MB" => "GB", "GB" => "TB", _ => sizeUnit }; } string sizeFormat = $"{size:.00} {sizeUnit}"; return sizeFormat; } } }