using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; using ShellProgressBar; using View_by_Distance.Rename.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Rename; public class Rename { private readonly AppSettings _AppSettings; private readonly string _WorkingDirectory; private readonly IsEnvironment _IsEnvironment; private readonly Configuration _Configuration; private readonly IConfigurationRoot _ConfigurationRoot; private readonly Property.Models.Configuration _PropertyConfiguration; public Rename(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { if (isSilent) { } if (console is null) { } _AppSettings = appSettings; _IsEnvironment = isEnvironment; long ticks = DateTime.Now.Ticks; _WorkingDirectory = workingDirectory; _ConfigurationRoot = configurationRoot; ILogger? log = Log.ForContext(); Dictionary>> fileSizeToCollection = new(); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); _PropertyConfiguration = propertyConfiguration; _Configuration = configuration; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; propertyConfiguration.Update(); string? comparePathRoot = Path.GetDirectoryName(appSettings.ComparePathsFile); if (comparePathRoot is null || comparePathRoot == propertyConfiguration.RootDirectory) throw new Exception("Nested isn't allowed!"); log.Information(propertyConfiguration.RootDirectory); Verify(); string json = File.ReadAllText(appSettings.ComparePathsFile); MatchNginx[]? matchNginxCollection = System.Text.Json.JsonSerializer.Deserialize(json); if (matchNginxCollection is null) throw new NullReferenceException(nameof(matchNginxCollection)); if (matchNginxCollection.Length == 0 && matchNginxCollection[0].ConvertedPath.Contains("~~~")) MoveMatches(matchNginxCollection[0]); else if (matchNginxCollection.All(l => l.Name.StartsWith("#")) || matchNginxCollection.All(l => l.Name.StartsWith(" #")) || matchNginxCollection.All(l => l.Name.StartsWith("=20")) || matchNginxCollection.All(l => l.Name.StartsWith("#20"))) Rename2000(matchNginxCollection); else if (matchNginxCollection.Any()) { List lines = RenameFilesInDirectories(log, options, matchNginxCollection); File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines); if (comparePathRoot != Path.GetPathRoot(matchNginxCollection[0].ConvertedPath)) _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(comparePathRoot); } } private void Verify() { if (_AppSettings is null) { } if (_IsEnvironment is null) { } if (_Configuration is null) { } if (_ConfigurationRoot is null) { } if (_WorkingDirectory is null) { } } private static void MoveMatches(MatchNginx matchNginx) { string moveDirectory; string checkDirectory; string compareDirectory = "D:/"; int length = matchNginx.ConvertedPath.Length; string[] directories = Directory.GetDirectories(matchNginx.ConvertedPath, "*", SearchOption.TopDirectoryOnly); foreach (string directory in directories) { if (!string.IsNullOrEmpty(directory)) continue; checkDirectory = string.Concat(compareDirectory, directory[length..]); if (!Directory.Exists(checkDirectory)) continue; moveDirectory = string.Concat(compareDirectory[..^1], directory[length..]); Directory.Move(checkDirectory, moveDirectory); } } private static List<(FileHolder, string)> GetRenameUndoToDoCollection(ProgressBar progressBar, string[] files) { List<(FileHolder, string)> results = new(); string[] lines; string fileName; FileHolder fileHolder; foreach (string file in files) { progressBar.Tick(); fileName = Path.GetFileName(file); if (!fileName.EndsWith(".id")) continue; lines = File.ReadAllLines(file); if (lines.Length < 2) continue; fileHolder = new(lines[0]); results.Add(new(fileHolder, lines[1])); } return results; } private List<(FileHolder, string)> GetToDoCollection(ProgressBar progressBar, string[] files) { List<(FileHolder, string)> results = new(); int? id; string? message; string checkFile; TimeSpan timeSpan; DateTime? dateTime; DateTime?[] dateTimes; FileHolder fileHolder; bool isIgnoreExtension; string checkFileExtension; DateTime? minimumDateTime; const string jpg = ".jpg"; const string jpeg = ".jpeg"; bool isValidImageFormatExtension; bool nameWithoutExtensionIsIdFormat; IReadOnlyList directories; foreach (string file in files) { progressBar.Tick(); fileHolder = new(file); if (file.EndsWith(".jpg.del")) { checkFile = file[..^4]; if (File.Exists(checkFile)) continue; results.Add(new(fileHolder, checkFile)); continue; } if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryName is null) continue; if (files.Contains($"{fileHolder.FullName}.id")) continue; isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileHolder); if (!isIgnoreExtension && isValidImageFormatExtension) { if (fileHolder.ExtensionLowered == jpeg) { if (File.Exists($"{fileHolder.FullName}.id")) { checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.id"); if (File.Exists(checkFile)) continue; results.Add(new(new($"{fileHolder.FullName}.id"), checkFile)); } checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}"); if (File.Exists(checkFile)) continue; results.Add(new(fileHolder, checkFile)); } if (nameWithoutExtensionIsIdFormat) continue; } (dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension); minimumDateTime = dateTimes.Min(); if (minimumDateTime is null || !isIgnoreExtension && isValidImageFormatExtension) { dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder); if (dateTime is null || minimumDateTime is null) timeSpan = new TimeSpan(0); else timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTime.Value.Ticks)); } else { if (!int.TryParse(Path.GetFileName(fileHolder.DirectoryName)[..4], out int year)) year = minimumDateTime.Value.Year; if (_Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) continue; try { directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); } catch (Exception) { continue; } dateTime = Metadata.Models.Stateless.Methods.IMetadata.GetMinimumDateTime(dateTimes, year, directories); timeSpan = new TimeSpan(int.MaxValue); } if (dateTime is not null && string.IsNullOrEmpty(_AppSettings.CopyTo) && timeSpan.TotalMinutes > _AppSettings.MaxMinutesDelta) { checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; checkFile = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Value:yyyy-MM-dd}.{dateTime.Value.Ticks}.{fileHolder.Length}{checkFileExtension}"); if (checkFile == fileHolder.FullName) continue; results.Add(new(fileHolder, checkFile)); continue; } if (id is null) continue; checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; checkFile = Path.Combine(fileHolder.DirectoryName, $"{id.Value}{checkFileExtension}"); if (checkFile == fileHolder.FullName) continue; if (File.Exists(checkFile)) { checkFile = string.Concat(checkFile, ".del"); if (File.Exists(checkFile)) continue; } results.Add(new(fileHolder, checkFile)); } return results; } private static void Rename2000(MatchNginx[] matchNginxCollection) { string name; string check; string? directoryName; foreach (MatchNginx matchNginx in matchNginxCollection) { name = matchNginx.Name.Trim(); if (name.Length < 1 || (!name.StartsWith("zzz =20") && !name.StartsWith("=20") && !name.StartsWith("#20"))) continue; directoryName = Path.GetDirectoryName(matchNginx.ConvertedPath); if (directoryName is null) continue; if (name.StartsWith("=20") || name.StartsWith("#20")) check = Path.Combine(directoryName, name[1..]); else check = Path.Combine(directoryName, $"zzz {name[5..]}"); if (Directory.Exists(check) || File.Exists(check)) continue; if (!Directory.Exists(matchNginx.ConvertedPath)) File.Move(matchNginx.ConvertedPath, check); else Directory.Move(matchNginx.ConvertedPath, check); } } private static List GetAllFiles(MatchNginx[] matchNginxCollection) { List allFiles = new(); string[] files; string directoryName; ReadOnlySpan span; foreach (MatchNginx matchNginx in matchNginxCollection) { if (matchNginx.ConvertedPath.Length < 6) continue; directoryName = Path.GetFileName(matchNginx.ConvertedPath); if (matchNginx.ConvertedPath.Contains("!---")) span = "0"; else span = matchNginx.ConvertedPath.AsSpan(matchNginx.ConvertedPath.Length - 5, 3); if (directoryName.Length == 1 && int.TryParse(span, out int age)) continue; if (File.Exists(matchNginx.ConvertedPath)) continue; files = Directory.GetFiles(matchNginx.ConvertedPath, "*", SearchOption.AllDirectories); if (files.All(l => l.EndsWith(".id"))) { foreach (string file in files) File.Delete(file); continue; } allFiles.AddRange(files); } return allFiles; } private static void CreateDirectories(List directories) { foreach (string directory in directories) { if (Directory.Exists(directory)) continue; _ = Directory.CreateDirectory(directory); } } private List CopyInstead(ILogger log, List<(FileHolder, string)> verifiedToDoCollection) { List results = new(); string copyTo; string? directory; ConsoleKey? consoleKey = null; List distinctDirectories = new(); List<(FileHolder, string)> copyCollection = new(); foreach ((FileHolder fileHolder, string to) in verifiedToDoCollection) { copyTo = $"{_AppSettings.CopyTo}{to[1..]}"; directory = Path.GetDirectoryName(copyTo); if (directory is null) continue; copyCollection.Add(new(fileHolder, copyTo)); if (distinctDirectories.Contains(directory)) continue; distinctDirectories.Add(directory); } CreateDirectories(distinctDirectories); log.Information($"Ready to Copy {verifiedToDoCollection.Count} file(s)?"); for (int y = 0; y < int.MaxValue; y++) { log.Information("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files"); consoleKey = System.Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } log.Information(". . ."); if (consoleKey is null || consoleKey.Value != ConsoleKey.Y) log.Information("Nothing Copied!"); else { foreach ((FileHolder fileHolder, string to) in verifiedToDoCollection) { results.Add(fileHolder.NameWithoutExtension); File.Copy(fileHolder.FullName, to); } log.Information("Done Copying"); } return results; } private static List Move(ILogger log, List<(FileHolder, string)> verifiedToDoCollection) { List results = new(); ConsoleKey? consoleKey = null; log.Information($"Ready to Move {verifiedToDoCollection.Count} file(s)?"); for (int y = 0; y < int.MaxValue; y++) { log.Information("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files"); consoleKey = System.Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } log.Information(". . ."); if (consoleKey is null || consoleKey.Value != ConsoleKey.Y) log.Information("Nothing moved!"); else { foreach ((FileHolder fileHolder, string to) in verifiedToDoCollection) { results.Add(fileHolder.NameWithoutExtension); File.Move(fileHolder.FullName, to); File.WriteAllText($"{to}.id", $"{to}{Environment.NewLine}{fileHolder.FullName}"); } log.Information("Done Moving"); } return results; } private List RenameFilesInDirectories(ILogger log, ProgressBarOptions options, MatchNginx[] matchNginxCollection) { List results = new(); string[] files; string message; int distinctCount; ProgressBar progressBar; List distinctCollection = new(); List<(FileHolder, string)> toDoCollection; List<(FileHolder, string)> verifiedToDoCollection; List allFiles = GetAllFiles(matchNginxCollection); for (int i = 1; i < 3; i++) { message = $"{i}) Renaming files"; if (_AppSettings.RenameUndo && i == 1) continue; files = i == 2 ? allFiles.ToArray() : (from l in allFiles where l.Contains("Rename") select l).ToArray(); progressBar = new(files.Length, message, options); if (!files.Any()) continue; distinctCollection.Clear(); if (!_AppSettings.RenameUndo) toDoCollection = GetToDoCollection(progressBar, files); else toDoCollection = GetRenameUndoToDoCollection(progressBar, files); foreach ((FileHolder fileHolder, string to) in toDoCollection) { if (distinctCollection.Contains(to)) continue; distinctCollection.Add(to); } distinctCount = distinctCollection.Count; if (toDoCollection.Count != distinctCount) continue; verifiedToDoCollection = new(); foreach ((FileHolder fileHolder, string to) in toDoCollection) { if (File.Exists(to)) continue; verifiedToDoCollection.Add(new(fileHolder, to)); } if (!verifiedToDoCollection.Any()) continue; if (string.IsNullOrEmpty(_AppSettings.CopyTo)) results.AddRange(Move(log, toDoCollection)); else results.AddRange(CopyInstead(log, toDoCollection)); progressBar.Dispose(); } return results; } }