using Microsoft.Extensions.Configuration; using Microsoft.WindowsAPICodePack.Shell; using Phares.Shared; using Serilog; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Text.Json; using View_by_Distance.Drag_Drop.Models; using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless.Methods; namespace View_by_Distance.Drag_Drop; public partial class Form : System.Windows.Forms.Form { private readonly ILogger _Logger; private readonly TextBox _TextBox; private readonly List _Lines; private readonly AppSettings _AppSettings; private readonly ProgressBar _ProgressBar; private readonly string _WorkingDirectory; private readonly Configuration _Configuration; private readonly IsEnvironment _IsEnvironment; private readonly ProgressBar _InnerProgressBar; private readonly Dictionary _IdToItem; private readonly string _ResizeFileNameExtension; private readonly IConfigurationRoot _ConfigurationRoot; private readonly Property.Models.Configuration _PropertyConfiguration; public Form() { InitializeComponent(); _Lines = new(); ILogger logger; AppSettings appSettings; string workingDirectory; Configuration configuration; IsEnvironment isEnvironment; _IdToItem = new(); IConfigurationRoot configurationRoot; LoggerConfiguration loggerConfiguration = new(); Property.Models.Configuration propertyConfiguration; Assembly assembly = Assembly.GetExecutingAssembly(); bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() .AddEnvironmentVariables() .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); configurationRoot = configurationBuilder.Build(); appSettings = Models.Binder.AppSettings.Get(configurationRoot); if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) throw new Exception("Working directory name must have parentDirectory value!"); workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext
(); propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); (_, _, string resizeFileNameExtension) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; _Configuration = configuration; _IsEnvironment = isEnvironment; _WorkingDirectory = workingDirectory; _ConfigurationRoot = configurationRoot; _PropertyConfiguration = propertyConfiguration; _ResizeFileNameExtension = resizeFileNameExtension; _TextBox = new() { Location = new(5, 5), Dock = DockStyle.Top }; _ProgressBar = new() { Location = new(5, 5), Dock = DockStyle.Top, Visible = false }; _InnerProgressBar = new() { Location = new(5, 5), Dock = DockStyle.Top, Visible = false }; Load += new EventHandler(Form1_Load); Controls.Add(_ProgressBar); Controls.Add(_InnerProgressBar); Controls.Add(_TextBox); } void Form1_Load(object? sender, EventArgs e) { try { AllowDrop = true; DragDrop += new DragEventHandler(Form1_DragDrop); DragEnter += new DragEventHandler(Form1_DragEnter); _TextBox.LostFocus += new EventHandler(TextBox_LostFocus); } catch (Exception) { throw; } } void TextBox_LostFocus(object? sender, EventArgs e) { try { if (_TextBox.Text == "ps") throw new NotImplementedException(); } catch (Exception) { throw; } } void Form1_DragEnter(object? sender, DragEventArgs e) { try { if (e.Data is not null && e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; } catch (Exception) { throw; } } void LoadData() { Container[] containers; Property.Models.A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _ResizeFileNameExtension, _Configuration.Reverse); (_, _, _, containers) = Property.Models.Stateless.Container.GetContainers(_Configuration.PropertyConfiguration, propertyLogic); List collection = Program.GetItemCollection(_Configuration, containers); foreach (Item item in collection) { if (item.Property?.Id is null) continue; if (_IdToItem.ContainsKey(item.Property.Id.Value)) continue; _IdToItem.Add(item.Property.Id.Value, item); } if (_Logger is null) throw new NullReferenceException(nameof(_Logger)); _Logger.Debug((_AppSettings is null).ToString()); _Logger.Debug((_Configuration is null).ToString()); _Logger.Debug((_IsEnvironment is null).ToString()); _Logger.Debug((_WorkingDirectory is null).ToString()); _Logger.Debug((_ConfigurationRoot is null).ToString()); _Logger.Debug((_PropertyConfiguration is null).ToString()); } public static string? GetFaceEncoding(string file) { string? result; List results = new(); const string comment = "Comment: "; if (File.Exists(file)) { IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); foreach (MetadataExtractor.Directory directory in directories) { if (directory.Name != "PNG-tEXt") continue; foreach (MetadataExtractor.Tag tag in directory.Tags) { if (tag.Name != "Textual Data" || string.IsNullOrEmpty(tag.Description)) continue; if (!tag.Description.StartsWith(comment)) continue; results.Add(tag.Description); } } } result = results.Any() ? results[0][comment.Length..] : null; return result; } private void RenameFilesInDirectory(string directory, string searchPattern) { int? id; string? message; string checkFile; DateTime? dateTime; FileHolder fileHolder; bool isIgnoreExtension; string checkFileExtension; DateTime? minimumDateTime; const string jpg = ".jpg"; _InnerProgressBar.Step = 1; _InnerProgressBar.Value = 0; const string jpeg = ".jpeg"; _InnerProgressBar.Visible = true; bool isValidImageFormatExtension; string? extraLargeBitmapThumbnail; string[] files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly); if (files.All(l => l.EndsWith(".id"))) { foreach (string file in files) File.Delete(file); } _InnerProgressBar.Maximum = files.Length; foreach (string file in files) { _InnerProgressBar.PerformStep(); fileHolder = new(file); _Lines.Add(fileHolder.NameWithoutExtension); if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryName is null) continue; if (files.Contains($"{fileHolder.FullName}.id")) continue; isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); if (IProperty.NameWithoutExtensionIsIdFormat(fileHolder)) { if (fileHolder.ExtensionLowered == jpeg) { if (File.Exists($"{fileHolder.FullName}.id")) File.Move($"{fileHolder.FullName}.id", Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.id")); File.Move(fileHolder.FullName, Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}")); } continue; } if (!isIgnoreExtension && isValidImageFormatExtension) extraLargeBitmapThumbnail = null; else { extraLargeBitmapThumbnail = SaveExtraLargeBitmapThumbnail(fileHolder); if (extraLargeBitmapThumbnail is null) continue; fileHolder = new(extraLargeBitmapThumbnail); isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); if (isIgnoreExtension || !isValidImageFormatExtension) continue; } if (fileHolder.DirectoryName is null) continue; (minimumDateTime, id, message) = IProperty.Get(fileHolder); if (id is null) continue; dateTime = IProperty.GetDateTimeFromName(fileHolder); if (dateTime is not null && minimumDateTime is not null && new TimeSpan(Math.Abs(minimumDateTime.Value.Ticks - dateTime.Value.Ticks)).TotalMinutes > 2) { checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; checkFile = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Value:yyyy-MM-dd}.{dateTime.Value.Ticks}{checkFileExtension}"); if (checkFile == fileHolder.FullName || File.Exists(checkFile)) continue; File.Move(fileHolder.FullName, checkFile); File.WriteAllText($"{checkFile}.id", $"{id.Value}{Environment.NewLine}{fileHolder.Name}"); continue; } if (extraLargeBitmapThumbnail is not null) { File.Delete(fileHolder.FullName); fileHolder = new(file); if (fileHolder.DirectoryName is null) continue; } checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; checkFile = Path.Combine(fileHolder.DirectoryName, $"{id.Value}{checkFileExtension}"); if (checkFile == fileHolder.FullName || File.Exists(checkFile)) continue; File.Move(fileHolder.FullName, checkFile); File.WriteAllText($"{checkFile}.id", $"{id.Value}{Environment.NewLine}{fileHolder.Name}"); } _InnerProgressBar.Visible = false; } private string? SaveExtraLargeBitmapThumbnail(FileHolder fileHolder) { string? result; ShellFile shellFile = ShellFile.FromFilePath(fileHolder.FullName); if (shellFile is null || shellFile.Thumbnail is null || shellFile.Thumbnail.ExtraLargeBitmap.Clone() is not Bitmap bitmap || bitmap.Width == 0) result = null; else { result = $"{fileHolder.FullName}{_ResizeFileNameExtension}"; bitmap.Save(result); bitmap.Dispose(); shellFile.Dispose(); } return result; } private List<(string, FaceDistance)> GetFileAndFaceDistanceCollection(string[] files) { // int? id; string? json; // string? message; // DateTime? dateTime; // FileHolder fileHolder; // bool isIgnoreExtension; // DateTime? minimumDateTime; FaceDistance faceDistance; // bool isValidImageFormatExtension; List<(string, FaceDistance)> collection = new(); Shared.Models.FaceEncoding? modelsFaceEncoding; IReadOnlyList directories; FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding; _ProgressBar.Maximum = files.Length; foreach (string file in files) { _ProgressBar.PerformStep(); directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(directories); if (json is null) break; modelsFaceEncoding = JsonSerializer.Deserialize(json); if (modelsFaceEncoding is null) throw new NotSupportedException(); faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding); faceDistance = new(faceRecognitionDotNetFaceEncoding); collection.Add(new(file, faceDistance)); // fileHolder = new(file); // _Lines.Add(fileHolder.NameWithoutExtension); // isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); // isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); // if (isIgnoreExtension || !isValidImageFormatExtension) // continue; // if (fileHolder.CreationTime is null || fileHolder.Name.Contains(fileHolder.CreationTime.Value.ToString("yy"))) // continue; // if (fileHolder.LastWriteTime is null || fileHolder.Name.Contains(fileHolder.LastWriteTime.Value.ToString("yy"))) // continue; // if (fileHolder.NameWithoutExtension.Length == 1 || fileHolder.NameWithoutExtension[1..].All(l => char.IsNumber(l))) // continue; // if (fileHolder.DirectoryName is null) // continue; // dateTime = IProperty.GetDateTimeFromName(fileHolder); // if (dateTime is not null && fileHolder.Name.Contains(dateTime.Value.ToString("yy"))) // continue; // (minimumDateTime, id, message) = IProperty.Get(fileHolder); // if (minimumDateTime is null || id is null) // continue; // if (fileHolder.Name.Contains(minimumDateTime.Value.ToString("yy"))) // continue; // if (dateTime is not null && minimumDateTime.Value != dateTime.Value) // continue; } return collection; } private static List<(string File, double? Sum)> GetFileAndSum(List<(string File, FaceDistance FaceDistance)> collection) { List<(string File, double? Sum)> results = new(); List lengths = new(); List faceDistanceLengths; int take = (int)(collection.Count * .3333); List faceDistances = collection.Select(l => l.FaceDistance).ToList(); foreach ((string file, FaceDistance faceDistance) in collection) { lengths.Clear(); faceDistanceLengths = FaceRecognition.FaceDistances(faceDistances, faceDistance); if (faceDistanceLengths.Count != faceDistances.Count) throw new NotSupportedException(); lengths.AddRange(from l in faceDistanceLengths orderby l.Length is not null, l.Length select l.Length); results.Add(new(file, lengths.Take(take).Sum())); } return results; } private void ChangeDate(string directory, DateTime dateTime, string searchPattern) { string[] files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly); _ProgressBar.Step = 1; _ProgressBar.Value = 0; _ProgressBar.Visible = true; List<(string File, double? Sum)> results; List<(string File, FaceDistance FaceDistance)> collection = GetFileAndFaceDistanceCollection(files); _ProgressBar.Maximum = files.Length; if (collection.Count != files.Length) results = new(); else results = GetFileAndSum(collection); if (results.Count == files.Length) { foreach ((string file, double? sum) in results) { if (sum is null) continue; File.SetCreationTime(file, dateTime.AddSeconds(sum.Value)); } } if (results.Count == files.Length) { } } private List GetBirthDates(string directory) { List results = new(); string[] directoryNames = IPath.GetDirectoryNames(directory); foreach (string directoryName in directoryNames) { if (directoryName.Length != _Configuration.PersonBirthdayFormat.Length) continue; if (!DateTime.TryParseExact(directoryName, _Configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) continue; results.Add(dateTime); } return results; } private void RenameFilesInDirectories(List directories) { string directoryName; ReadOnlySpan span; _ProgressBar.Step = 1; _ProgressBar.Visible = true; _ProgressBar.Maximum = directories.Count; for (int i = 1; i < 3; i++) { _ProgressBar.Value = 0; foreach (string directory in directories) { _ProgressBar.PerformStep(); if (directory.Length < 6) continue; directoryName = Path.GetFileName(directory); if (directory.Contains("!---")) span = "0"; else span = directory.AsSpan(directory.Length - 5, 3); if (directoryName.Length != 1 || !int.TryParse(span, out int age)) { if (i == 1) RenameFilesInDirectory(directory, "*Rename*"); else if (i == 2) RenameFilesInDirectory(directory, "*"); else continue; } else { if (i == 1) { List birthDates = GetBirthDates(directory); if (birthDates.Count != 1) continue; ChangeDate(directory, birthDates[0].AddYears(age), "*"); } else continue; } } } File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", _Lines); _Lines.Clear(); _ProgressBar.Visible = false; } void Form1_DragDrop(object? sender, DragEventArgs e) { try { if (e.Data is null || e.Data.GetData(DataFormats.FileDrop) is not string[] paths) _TextBox.Text = string.Empty; else { List directories = GetDirectoriesOrDoDragDrop(paths); if (directories.Any()) { RenameFilesInDirectories(directories); string? parentDirectory = Path.GetDirectoryName(directories[0]); if (parentDirectory is not null && parentDirectory != Path.GetPathRoot(directories[0])) _ = IPath.DeleteEmptyDirectories(parentDirectory); } } } catch (Exception) { throw; } } private List GetDirectoriesOrDoDragDrop(string[] paths) { List results = new(); string name; string[] segments; foreach (string path in paths) { name = Path.GetFileNameWithoutExtension(path); Text = name; segments = name.Split('.'); if (Directory.Exists(path)) { results.Add(path); results.AddRange(Directory.GetDirectories(path, "*", SearchOption.AllDirectories)); } else { if (!_IdToItem.Any()) LoadData(); if (int.TryParse(segments[0], out int id) && _IdToItem.TryGetValue(id, out Item? item)) { Text = item.ImageFileHolder.Name; _TextBox.Text = item.ImageFileHolder.FullName; if (item.ImageFileHolder.DirectoryName is not null) _Logger.Information(item.ImageFileHolder.DirectoryName); if (!string.IsNullOrEmpty(item.ImageFileHolder.DirectoryName)) _ = Process.Start("explorer.exe", string.Concat("\"", item.ImageFileHolder.DirectoryName, "\"")); } } } return results; } }