diff --git a/Delete-By-Distinct/Delete-By-Distinct.csproj b/Delete-By-Distinct/Delete-By-Distinct.csproj index 2a4f794..fd543e2 100644 --- a/Delete-By-Distinct/Delete-By-Distinct.csproj +++ b/Delete-By-Distinct/Delete-By-Distinct.csproj @@ -1,4 +1,4 @@ - + enable 10.0 @@ -6,7 +6,8 @@ Exe win-x64 net7.0 - + 0589ecff-b296-48be-a3f7-7bf27f453975 + Phares.View.by.Distance.Delete.By.Distinct false diff --git a/Delete-By-Distinct/DeleteByDistinct.cs b/Delete-By-Distinct/DeleteByDistinct.cs index 8f6b8d1..6492e72 100644 --- a/Delete-By-Distinct/DeleteByDistinct.cs +++ b/Delete-By-Distinct/DeleteByDistinct.cs @@ -19,25 +19,24 @@ public class DeleteByDistinct { } long ticks = DateTime.Now.Ticks; ILogger? log = Log.ForContext(); - Dictionary>> fileSizeToCollection = new(); + Dictionary> longToCollection = new(); Configuration configuration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; configuration.Update(); log.Information(configuration.RootDirectory); bool compareIsPopulatedAndNotTheSame = !string.IsNullOrEmpty(appSettings.CompareRootDirectory) && appSettings.CompareRootDirectory != configuration.RootDirectory; - Work(appSettings, ticks, log, configuration.RootDirectory, nameof(configuration.RootDirectory), options, fileSizeToCollection, logOnly: compareIsPopulatedAndNotTheSame); + Work(appSettings, ticks, log, configuration.RootDirectory, nameof(configuration.RootDirectory), options, longToCollection, logOnly: compareIsPopulatedAndNotTheSame); if (compareIsPopulatedAndNotTheSame) - Work(appSettings, ticks, log, appSettings.CompareRootDirectory, nameof(appSettings.CompareRootDirectory), options, fileSizeToCollection, logOnly: false); + Work(appSettings, ticks, log, appSettings.CompareRootDirectory, nameof(appSettings.CompareRootDirectory), options, longToCollection, logOnly: false); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(appSettings.CompareRootDirectory); } - private static void Work(AppSettings appSettings, long ticks, ILogger log, string directory, string variable, ProgressBarOptions options, Dictionary>> fileSizeToCollection, bool logOnly) + private static void Work(AppSettings appSettings, long ticks, ILogger log, string directory, string variable, ProgressBarOptions options, Dictionary> longToCollection, bool logOnly) { + long check; string message; - long checkTicks; - long checkLength; + string logFile; string checkName; - string deleteLog; int totalSeconds; FileInfo fileInfo; ProgressBar progressBar; @@ -45,7 +44,8 @@ public class DeleteByDistinct ConsoleKey? consoleKey = null; List deletedFiles = new(); List deletedDirectories = new(); - Dictionary>? fileTicksToNames; + Dictionary> longToCollectionB = new(); + List<(string Source, string Destination)> renameFiles = new(); log.Information($"Gathering {appSettings.SearchPattern} files from <{directory}>"); (string directory, string[] files)[] leftCollection = Shared.Models.Stateless.Methods.IFileHolder.GetFiles(directory, appSettings.SearchPattern).ToArray(); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); @@ -56,33 +56,33 @@ public class DeleteByDistinct progressBar.Tick(); foreach (string file in files) { - if (file.EndsWith(".id") || file.Contains("Rename")) + if (file.EndsWith(".id") || file.Contains("Rename") || file.EndsWith(".lsv")) continue; fileInfo = new(file); - if (fileInfo.Length < 100) - continue; - if (appSettings.RecycleOption) - checkLength = 1; - else - checkLength = fileInfo.Length; - if (!fileSizeToCollection.TryGetValue(checkLength, out fileTicksToNames)) + if (appSettings.SizeForLong) { - fileSizeToCollection.Add(checkLength, new()); - if (!fileSizeToCollection.TryGetValue(checkLength, out fileTicksToNames)) - throw new Exception(); + if (fileInfo.Length < 100) + continue; + check = fileInfo.Length; } - if (appSettings.RecycleOption) - checkTicks = 1; - else - checkTicks = new DateTime(ticks).Ticks; - if (!fileTicksToNames.TryGetValue(checkTicks, out fileNames)) + else if (appSettings.TicksForLong) { - fileTicksToNames.Add(checkTicks, new()); - if (!fileTicksToNames.TryGetValue(checkTicks, out fileNames)) + if (fileInfo.LastWriteTime.Hour == 0 && fileInfo.LastWriteTime.Minute == 0 && fileInfo.LastWriteTime.Second == 0) + continue; + check = fileInfo.LastWriteTime.Ticks; + } + else + throw new Exception(); + if (!longToCollection.TryGetValue(check, out fileNames)) + { + longToCollection.Add(check, new()); + if (!longToCollection.TryGetValue(check, out fileNames)) throw new Exception(); } checkName = fileInfo.Name.ToLower().Replace(".jpeg", ".jpg"); - if (fileNames.Contains(checkName)) + if (!logOnly && appSettings.RenameToMatch && fileNames.Count == 1 && fileInfo.DirectoryName is not null && fileInfo.Name != fileNames.First()) + renameFiles.Add((fileInfo.FullName, Path.Combine(fileInfo.DirectoryName, fileNames.First()))); + else if (fileNames.Contains(checkName)) deletedFiles.Add(file); else fileNames.Add(checkName); @@ -90,12 +90,12 @@ public class DeleteByDistinct } progressBar.Dispose(); log.Information(". . ."); - deleteLog = $"{ticks}-{variable}-Files.lsv"; + logFile = $"{ticks}-{variable}-Files-A.lsv"; if (!logOnly) - File.WriteAllLines(Path.Combine(directory, deleteLog), deletedFiles); + File.WriteAllLines(Path.Combine(directory, logFile), deletedFiles); if (deletedFiles.Any() && !logOnly) { - log.Information($"Ready to delete {deletedFiles.Count} from {variable} {appSettings.SearchPattern} file(s)? See <{deleteLog}>"); + log.Information($"Ready to delete {deletedFiles.Count} from {variable} {appSettings.SearchPattern} file(s)? See <{logFile}>"); for (int y = 0; y < int.MaxValue; y++) { log.Information("Press \"Y\" key to delete file(s), \"N\" key to log file(s) or close console to not delete files"); @@ -127,16 +127,40 @@ public class DeleteByDistinct for (int i = 1; i < 5; i++) { progressBar.Tick(); - List check = new(); - Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(directory, check); - if (!check.Any()) + List collection = new(); + Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(directory, collection); + if (!collection.Any()) break; - deletedDirectories.AddRange(check); + deletedDirectories.AddRange(collection); } progressBar.Dispose(); log.Information(". . ."); - deleteLog = $"{ticks + 1}-{variable}-Directories.lsv"; - File.WriteAllLines(Path.Combine(directory, deleteLog), deletedDirectories.Distinct()); + logFile = $"{ticks + 1}-{variable}-Directories.lsv"; + File.WriteAllLines(Path.Combine(directory, logFile), deletedDirectories.Distinct()); + } + } + logFile = $"{ticks}-{variable}-Files-B.lsv"; + if (!logOnly) + File.WriteAllLines(Path.Combine(directory, logFile), renameFiles.Select(l => l.Source)); + if (renameFiles.Any() && !logOnly) + { + log.Information($"Ready to rename to match {renameFiles.Count} from {variable} {appSettings.SearchPattern} file(s)? See <{logFile}>"); + for (int y = 0; y < int.MaxValue; y++) + { + log.Information("Press \"Y\" key to rename to match file(s), \"N\" key to log file(s) or close console to not rename to match files"); + consoleKey = Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + log.Information(". . ."); + if (consoleKey is not null && consoleKey.Value == ConsoleKey.Y) + { + foreach ((string source, string destination) in renameFiles) + { + try + { File.Move(source, destination); } + catch (Exception) { } + } } } } diff --git a/Delete-By-Distinct/Models/AppSettings.cs b/Delete-By-Distinct/Models/AppSettings.cs index c8550be..af77c53 100644 --- a/Delete-By-Distinct/Models/AppSettings.cs +++ b/Delete-By-Distinct/Models/AppSettings.cs @@ -1,37 +1,19 @@ using System.Text.Json; -using System.Text.Json.Serialization; namespace View_by_Distance.Delete.By.Distinct.Models; -public class AppSettings +public record AppSettings(string Company, + string CompareRootDirectory, + int MaxDegreeOfParallelism, + string OutputExtension, + bool RecycleOption, + bool RenameToMatch, + string SearchPattern, + bool SizeForLong, + bool TicksForLong, + string WorkingDirectoryName) { - public string Company { init; get; } - public string CompareRootDirectory { init; get; } - public int MaxDegreeOfParallelism { init; get; } - public string OutputExtension { init; get; } - public bool RecycleOption { init; get; } - public string SearchPattern { init; get; } - public string WorkingDirectoryName { init; get; } - - [JsonConstructor] - public AppSettings(string company, - string compareRootDirectory, - int maxDegreeOfParallelism, - string outputExtension, - bool recycleOption, - string searchPattern, - string workingDirectoryName) - { - Company = company; - CompareRootDirectory = compareRootDirectory; - MaxDegreeOfParallelism = maxDegreeOfParallelism; - OutputExtension = outputExtension; - RecycleOption = recycleOption; - SearchPattern = searchPattern; - WorkingDirectoryName = workingDirectoryName; - } - public override string ToString() { string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); diff --git a/Delete-By-Distinct/Models/Binder/AppSettings.cs b/Delete-By-Distinct/Models/Binder/AppSettings.cs index 79f515a..2594f68 100644 --- a/Delete-By-Distinct/Models/Binder/AppSettings.cs +++ b/Delete-By-Distinct/Models/Binder/AppSettings.cs @@ -13,7 +13,10 @@ public class AppSettings public int? MaxDegreeOfParallelism { get; set; } public string OutputExtension { get; set; } public bool? RecycleOption { get; set; } + public bool? RenameToMatch { get; set; } public string SearchPattern { get; set; } + public bool? SizeForLong { get; set; } + public bool? TicksForLong { get; set; } public string WorkingDirectoryName { get; set; } #nullable restore @@ -31,13 +34,24 @@ public class AppSettings throw new NullReferenceException(nameof(appSettings.MaxDegreeOfParallelism)); if (appSettings?.RecycleOption is null) throw new NullReferenceException(nameof(appSettings.RecycleOption)); + if (appSettings?.RenameToMatch is null) + throw new NullReferenceException(nameof(appSettings.RenameToMatch)); + if (appSettings?.SizeForLong is null) + throw new NullReferenceException(nameof(appSettings.SizeForLong)); + if (appSettings?.TicksForLong is null) + throw new NullReferenceException(nameof(appSettings.TicksForLong)); + if (appSettings.TicksForLong.Value == appSettings.SizeForLong.Value) + throw new Exception("Check appSettings file!"); result = new( appSettings.Company, appSettings.CompareRootDirectory, appSettings.MaxDegreeOfParallelism.Value, appSettings.OutputExtension, appSettings.RecycleOption.Value, + appSettings.RenameToMatch.Value, appSettings.SearchPattern, + appSettings.SizeForLong.Value, + appSettings.TicksForLong.Value, appSettings.WorkingDirectoryName ); return result; diff --git a/Delete-By-Distinct/appsettings.Development.json b/Delete-By-Distinct/appsettings.Development.json index 0bc8aa5..7865dac 100644 --- a/Delete-By-Distinct/appsettings.Development.json +++ b/Delete-By-Distinct/appsettings.Development.json @@ -1,25 +1,14 @@ { - "CompareRootDirectory": "D:/2) Images B/Not-Copy-Copy-1e85c0ba", "Logging": { "LogLevel": { "Log4netProvider": "Debug" } }, - "MaxDegreeOfParallelism": 6, - "RecycleOption": true, - "SearchPattern": "*.*", "Serilog": { "MinimumLevel": "Debug" }, "Windows": { "Configuration": { - "xRootDirectory": "D:/2) Images B/Corrupt", - "xxRootDirectory": "D:/2) Images B/Not-Copy-Copy-1e85c0ba", - "RootDirectory": "D:/1) Images A/Images-1e85c0ba", - "xxxxRootDirectory": "E:/3) Videos A/Device Videos 2_0_0_3 - Current", - "xxxxxRootDirectory": "E:/4) Videos B/Device Videos 2_0_0_3 - Current - Ignore", - "xxxxxxRootDirectory": "C:/1) Images A/Images-1e85c0ba", - "xxxxxxxRootDirectory": "C:/2) Images B/Not-Copy-Copy-1e85c0ba", "VerifyToSeason": [] } } diff --git a/Delete-By-Distinct/appsettings.json b/Delete-By-Distinct/appsettings.json index 72c9971..eebe64a 100644 --- a/Delete-By-Distinct/appsettings.json +++ b/Delete-By-Distinct/appsettings.json @@ -12,7 +12,10 @@ }, "MaxDegreeOfParallelism": 6, "RecycleOption": false, + "RenameToMatch": false, + "SizeForLong": true, "SearchPattern": "*.jpg", + "TicksForLong": false, "Serilog": { "Using": [ "Serilog.Sinks.Console",