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 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(isEnvironment.AppSettingsFileName); configurationRoot = configurationBuilder.Build(); appSettings = Models.Binder.AppSettings.Get(configurationRoot); 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 }; Load += new EventHandler(Form1_Load); Controls.Add(_ProgressBar); 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; _ProgressBar.Step = 1; bool isIgnoreExtension; _ProgressBar.Value = 0; DateTime? minimumDateTime; _ProgressBar.Visible = true; bool isValidImageFormatExtension; string? extraLargeBitmapThumbnail; string[] files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly); _ProgressBar.Maximum = files.Length; foreach (string file in files) { _ProgressBar.PerformStep(); fileHolder = new(file); _Lines.Add(fileHolder.NameWithoutExtension); isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); isIgnoreExtension = isValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); 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 (!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; dateTime = IProperty.GetDateTimeFromName(fileHolder); if (dateTime is not null && fileHolder.Name.Contains(dateTime.Value.ToString("yy"))) continue; (minimumDateTime, id, message) = IProperty.Get(fileHolder); if (id is null) continue; if (minimumDateTime is not null && fileHolder.Name.Contains(minimumDateTime.Value.ToString("yy"))) continue; if (dateTime is not null && minimumDateTime is not null && minimumDateTime.Value != dateTime.Value) continue; if (extraLargeBitmapThumbnail is not null) { File.Delete(fileHolder.FullName); fileHolder = new(file); if (fileHolder.DirectoryName is null) continue; } checkFile = Path.Combine(fileHolder.DirectoryName, $"{id.Value}{fileHolder.ExtensionLowered}"); if (File.Exists(checkFile)) continue; File.Move(fileHolder.FullName, checkFile); } _ProgressBar.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; FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding; _ProgressBar.Maximum = files.Length; foreach (string file in files) { _ProgressBar.PerformStep(); json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(file); 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; for (int i = 1; i < 3; i++) { foreach (string directory in directories) { 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(); } 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); } } 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; } }