diff --git a/FaceParts/Models/_D2_FaceParts.cs b/FaceParts/Models/_D2_FaceParts.cs index 1fc982c..74215c6 100644 --- a/FaceParts/Models/_D2_FaceParts.cs +++ b/FaceParts/Models/_D2_FaceParts.cs @@ -286,32 +286,20 @@ public class D2_FaceParts private void SaveFaceLandmarkImage(MappingFromItem mappingFromItem, List<(Shared.Models.Face, FileInfo?, string, bool)> faceCollection, string fileName) { - int x; - int y; Pen pen; - const int pointSize = 2; using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName); using Graphics graphic = Graphics.FromImage(image); foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.FaceParts is null || !face.FaceParts.Any()) continue; + pen = face.Mapping?.MappingFromPerson is null ? Pens.Red : Pens.GreenYellow; try { foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts) { - foreach (FacePoint facePoint in facePoints) - { - pen = face.Mapping?.MappingFromPerson is null ? Pens.Red : Pens.GreenYellow; - graphic.DrawEllipse(pen, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2); - } - if (facePart == FacePart.Chin) - continue; - if (facePoints.Length < 3) - continue; - x = (int)(from l in facePoints select l.X).Average(); - y = (int)(from l in facePoints select l.Y).Average(); - graphic.DrawEllipse(Pens.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2); + for (int i = 0; i < facePoints.Length - 1; i++) + graphic.DrawLine(pen, new Point(facePoints[i].X, facePoints[i].Y), new Point(facePoints[i + 1].X, facePoints[i + 1].Y)); } } catch (Exception) { } @@ -321,13 +309,10 @@ public class D2_FaceParts #pragma warning restore CA1416 - public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection) + private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection) { + bool results = false; string checkFile; - bool hasNotMapped = false; - string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.ImageFileHolder.Name}{_FileNameExtension}"); - bool save = faceCollection.Any(l => l.Face.FaceEncoding is not null && l.Face.Location is not null && l.Face.OutputResolution is not null && l.Face.FaceParts is not null && l.Face.FaceParts.Any()); - FileInfo newFileInfo = new(fileName); foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) @@ -347,16 +332,28 @@ public class D2_FaceParts } else { - if (!hasNotMapped) - hasNotMapped = true; + if (!results) + results = true; if (!File.Exists(checkFile)) File.Copy(fileInfo.FullName, checkFile); } } } - if (save && !newFileInfo.Exists) + return results; + } + + public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection) + { + bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection); + string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.ImageFileHolder.Name}{_FileNameExtension}"); + bool save = faceCollection.Any(l => l.Face.FaceEncoding is not null && l.Face.Location is not null && l.Face.OutputResolution is not null && l.Face.FaceParts is not null && l.Face.FaceParts.Any()); + FileInfo fileInfo = new(fileName); + if (save && (!fileInfo.Exists || new TimeSpan(DateTime.Now.Ticks - fileInfo.LastWriteTime.Ticks).TotalDays > 10)) + { SaveFaceLandmarkImage(mappingFromItem, faceCollection, fileName); - if (!hasNotMapped && !newFileInfo.Attributes.HasFlag(FileAttributes.Hidden) && (newFileInfo.Exists || save)) + fileInfo.Refresh(); + } + if (!hasNotMapped && !fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && (fileInfo.Exists || save)) File.SetAttributes(fileName, FileAttributes.Hidden); } diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index b6bc11d..8555f69 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -362,7 +362,10 @@ public partial class DlibDotNet subFileTuples.Add(new Tuple(nameof(A_Property), new FileInfo(item.SourceDirectoryFileHolder.FullName).LastWriteTime)); bool nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(item.ImageFileHolder); if (nameWithoutExtensionIsIdFormat && item.ImageFileHolder.NameWithoutExtension != item.Property.Id.ToString()) + { _Log.Information($"Name without extension is Id format but doesn't match id <{item.ImageFileHolder.FullName}>"); + File.Move(item.ImageFileHolder.FullName, $"{item.ImageFileHolder.FullName}.rename"); + } } else { @@ -727,7 +730,7 @@ public partial class DlibDotNet return items; } - private void SaveFaceDistances(long ticks, MapLogic mapLogic, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, Dictionary> idToNormalizedRectangleToMapping, List faceDistanceEncodings, FaceDistanceContainer[] faceDistanceContainers) + private void SaveFaceDistances(long ticks, MapLogic mapLogic, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Dictionary> idToNormalizedRectangleToMapping, List faceDistanceEncodings, FaceDistanceContainer[] faceDistanceContainers) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -762,14 +765,15 @@ public partial class DlibDotNet E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); if (filteredFaceDistanceContainers.Length > 0) { + bool forIndividually = true; int updated = mapLogic.UpdateFromSortingContainers(distanceLimits, sortingContainers); - List saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, useFiltersCounter, sortingContainers.Any()); + List saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToNormalizedRectangleToMapping, useFiltersCounter, forIndividually, sortingContainers.Any()); mapLogic.SaveContainers(filteredFaceDistanceContainers.Length, updated, saveContainers); } } } - private void SaveFaceDistances(long ticks, MapLogic mapLogic, List distinctFilteredFaces, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string dFacesCollectionDirectory, Dictionary> idToNormalizedRectangleToMapping) + private void SaveFaceDistances(long ticks, MapLogic mapLogic, List distinctFilteredFaces, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, string dFacesCollectionDirectory, Dictionary> idToNormalizedRectangleToMapping) { E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); FaceDistanceContainer[] faceDistanceContainers = E_Distance.GetFaceDistanceContainers(distinctFilteredFaces); @@ -777,7 +781,7 @@ public partial class DlibDotNet List missingFaceDistanceContainers = _Distance.GetMissingFaceDistanceContainer(_AppSettings.MaxDegreeOfParallelism, ticks, dFacesCollectionDirectory, missingIdThenNormalizedRectangleToPersonContainers); List faceDistanceEncodings = E_Distance.GetFaceDistanceEncodings(faceDistanceContainers, missingFaceDistanceContainers); if (faceDistanceContainers.Any()) - SaveFaceDistances(ticks, mapLogic, mappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, idToNormalizedRectangleToMapping, faceDistanceEncodings, faceDistanceContainers); + SaveFaceDistances(ticks, mapLogic, mappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToNormalizedRectangleToMapping, faceDistanceEncodings, faceDistanceContainers); } private void MapLogic(string argZero, long ticks, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, Dictionary> personKeyToIds, List distinctFilteredFaces, Mapping[] mappingCollection, int totalNotMapped) @@ -800,9 +804,9 @@ public partial class DlibDotNet mapLogic.CopyAtLeastOneMappedFiles(dFacesContentDirectory, a2PeopleSingletonDirectory, mappingCollection); mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping); if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, personKeyToIds, mappingCollection, idToNormalizedRectangleToMapping, totalNotMapped); + mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, mappingCollection, idToNormalizedRectangleToMapping, totalNotMapped); if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) - SaveFaceDistances(ticks, mapLogic, distinctFilteredFaces, mappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, dFacesCollectionDirectory, idToNormalizedRectangleToMapping); + SaveFaceDistances(ticks, mapLogic, distinctFilteredFaces, mappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, dFacesCollectionDirectory, idToNormalizedRectangleToMapping); } private string SaveUrlAndGetNewRootDirectory(Container container) @@ -956,9 +960,14 @@ public partial class DlibDotNet List> results = new(); collection.AddRange(Map.Models.Stateless.Methods.IMapLogic.GetDisplayDirectoryAllFiles(_Faces.FileNameExtension, _PersonContainers)); collection.AddRange(Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, _PersonContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory)); - for (int i = 0; i < collection.Count; i++) + for (int i = collection.Count - 1; i > -1; i--) { file = collection[i].File; + if (file.EndsWith(".old")) + { + collection.RemoveAt(i); + continue; + } if (!file.EndsWith(".dup") && !file.EndsWith(".unk") && !file.EndsWith(".abd")) continue; if (!File.Exists(file)) @@ -1044,6 +1053,12 @@ public partial class DlibDotNet Dictionary> fileNameToCollection; (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); + a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); + eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), "()"); + fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "()"); + fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "{}"); + propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); + MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _PersonContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string message = $") Building Container(s) - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; @@ -1056,36 +1071,26 @@ public partial class DlibDotNet (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory); progressBar.Tick(); } - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); - if (containers.Length != 1) - { - a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); - eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), "()"); - fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "()"); - fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "{}"); - } - else + if (containers.Length == 1) { string resultsGroupDirectory; a2PeopleContentDirectory = null; eDistanceContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "()"); fPhotoPrismContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "()"); fPhotoPrismSingletonDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "{}"); - string? newRootDirectory = SaveUrlAndGetNewRootDirectory(containers[0]); for (int i = 1; i < 10; i++) { resultsGroupDirectory = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, string.Empty, create: true); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(resultsGroupDirectory); } - argZero = newRootDirectory; - _Configuration.PropertyConfiguration.ChangeRootDirectory(newRootDirectory); + argZero = SaveUrlAndGetNewRootDirectory(containers[0]); + _Configuration.PropertyConfiguration.ChangeRootDirectory(argZero); (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); } B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); - MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _PersonContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); personKeyToIds = mapLogic.GetPersonKeyToIds(); if (!string.IsNullOrEmpty(_Configuration.GenealogicalDataCommunicationFile) && !string.IsNullOrEmpty(a2PeopleContentDirectory) && _GenealogicalDataCommunicationHeaderLines is not null && _GenealogicalDataCommunicationFooterLines is not null && _GenealogicalDataCommunicationHeaderLines.Any() && _GenealogicalDataCommunicationFooterLines.Any()) Shared.Models.Stateless.Methods.IGenealogicalDataCommunication.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GenealogicalDataCommunicationHeaderLines, _GenealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index ec44ebd..0b576b3 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -224,10 +224,15 @@ public class MapLogic : Shared.Models.Methods.IMapLogic using ProgressBar progressBar = new(saveContainers.Count, message, options); foreach (SaveContainer saveContainer in saveContainers) { + progressBar.Tick(); if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.FaceFileHolder is null) continue; - progressBar.Tick(); - if (!saveContainer.FaceFileHolder.Exists && saveContainer.ResizedFileHolder is not null && saveContainer.ResizedFileHolder.Exists) + if (saveContainer.FacePartsFileHolder is null && saveContainer.HiddenFaceFileHolder is null && saveContainer.ResizedFileHolder is null) + { + checkFile = saveContainer.CheckFile; + sourceFile = saveContainer.FaceFileHolder.FullName; + } + else if (!saveContainer.FaceFileHolder.Exists && saveContainer.ResizedFileHolder is not null && saveContainer.ResizedFileHolder.Exists) { checkFile = saveContainer.CheckFile; sourceFile = saveContainer.ResizedFileHolder.FullName; @@ -293,60 +298,44 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - private static string? GetFacesDirectory(string dFacesContentDirectory, MappingFromItem mappingFromItem) - { - string? result; - string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath); - if (directoryName is null) - result = null; - else - result = Path.Combine($"{dFacesContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension); - return result; - } - - private static string? GetFacePartsDirectory(string d2FacePartsContentDirectory, MappingFromItem mappingFromItem) - { - string? result; - string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath); - if (directoryName is null) - result = null; - else - result = Path.Combine($"{d2FacePartsContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension); - return result; - } - private SaveContainer? GetMatchSaveContainer(string dFacesContentDirectory, string d2FacePartsContentDirectory, string directory, Mapping mapping) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); SaveContainer? result; - string shortcutFile = string.Empty; - string? facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); - if (facesDirectory is null || mapping.MappingFromLocation is null) + if (mapping.MappingFromLocation is null) result = null; else { - FileHolder faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}")); - if (!faceFileHolder.Exists) + string checkFile; + string? facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + if (facesDirectory is null) result = null; else { - string? facePartsDirectory = GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem); - if (facePartsDirectory is null) + FileHolder faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}")); + if (!faceFileHolder.Exists) result = null; else { - string checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); - FileHolder hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}")); - FileHolder facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}")); - result = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile); + string shortcutFile = string.Empty; + string? facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem); + if (facePartsDirectory is null) + result = null; + else + { + checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); + FileHolder hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}")); + FileHolder facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}")); + result = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile); + } } } } return result; } - private static (string, bool, bool) Get(int? useFiltersCounter, bool sortingContainersAny, string forceSingleImageHumanized, Mapping mapping) + private static (string, bool, bool) Get(int? useFiltersCounter, bool forIndividually, bool sortingContainersAny, string forceSingleImageHumanized, Mapping mapping) { string by; bool isByMapping; @@ -362,7 +351,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping; isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting; if (isBySorting && mapping.MappingFromPerson is null) - by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person"; + by = forIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person"; else if (isBySorting && useFiltersCounter.HasValue) by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Modified Filters - {useFiltersCounter.Value}"; else @@ -370,7 +359,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic by = mapping.By.Value switch { Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping), - Shared.Models.Stateless.IMapLogic.Sorting => nameof(Shared.Models.Stateless.IMapLogic.Sorting), + Shared.Models.Stateless.IMapLogic.Sorting => forIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting), Shared.Models.Stateless.IMapLogic.ForceSingleImage => forceSingleImageHumanized, _ => throw new NotImplementedException() }; @@ -405,7 +394,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, Dictionary> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool sortingContainersAny) + private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, Dictionary> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool forIndividually, bool sortingContainersAny) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -418,6 +407,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic string checkFile; string directory; string shortcutFile; + Mapping? keyMapping; string? directoryName; string personDirectory; string? facesDirectory; @@ -428,6 +418,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic SaveContainer? saveContainer; FileHolder facePartsFileHolder; FileHolder hiddenFaceFileHolder; + string? facePartsContentCollectionFile; Dictionary? normalizedRectangleToMapping; string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); foreach (Mapping mapping in mappingCollection) @@ -439,7 +430,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NotSupportedException(); if (mapping.MappingFromFilter.InSkipCollection is not null && mapping.MappingFromFilter.InSkipCollection.Value) continue; - (by, isByMapping, isBySorting) = Get(useFiltersCounter, sortingContainersAny, forceSingleImageHumanized, mapping); + (by, isByMapping, isBySorting) = Get(useFiltersCounter, forIndividually, sortingContainersAny, forceSingleImageHumanized, mapping); if (isByMapping && !saveMapped) continue; if (mapping.MappingFromPerson is null) @@ -460,6 +451,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic continue; directory = GetDirectory(by, mapping.MappingFromItem, mapping.SortingContainer); personDirectory = Path.Combine(directory, $"Z]{DateTime.Now.Ticks}"); + if (forIndividually) + directory = Path.Combine(directory, mapping.MappingFromItem.Id.ToString()); distinct.Add(mapping.MappingFromItem.Id); distinct.Add(mapping.SortingContainer.Sorting.Id); } @@ -471,7 +464,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NotSupportedException(); personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks; personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday); - if (string.IsNullOrEmpty(mapping.SegmentC)) + if (forIndividually || string.IsNullOrEmpty(mapping.SegmentC)) directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mapping.MappingFromPerson.SegmentB); else directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mapping.MappingFromPerson.SegmentB, mapping.SegmentC); @@ -481,6 +474,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, "lnk"); else personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName[..1], "lnk"); + if (forIndividually) + directory = Path.Combine(directory, mapping.MappingFromItem.Id.ToString()); if (isByMapping && personKeyToIds.TryGetValue(personKey, out ids)) { saveContainer = new(Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{ids.Count} Face(s)")); @@ -489,7 +484,24 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } saveContainer = new(personDirectory); results.Add(saveContainer); - facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + if (!isBySorting || mapping.SortingContainer is null) + keyMapping = null; + else + { + if (!idToNormalizedRectangleToMapping.TryGetValue(mapping.SortingContainer.Sorting.Id, out normalizedRectangleToMapping)) + continue; + if (!normalizedRectangleToMapping.ContainsKey(mapping.SortingContainer.Sorting.NormalizedRectangle)) + continue; + keyMapping = normalizedRectangleToMapping[mapping.SortingContainer.Sorting.NormalizedRectangle]; + if (keyMapping.MappingFromLocation is null) + continue; + if (keyMapping.MappingFromLocation.NormalizedRectangle == mapping.MappingFromLocation.NormalizedRectangle) + { + saveContainer = new(Path.Combine(directory, "Maybe")); + results.Add(saveContainer); + } + } + facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); if (facesDirectory is null) continue; faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}")); @@ -502,47 +514,61 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } else { - facePartsDirectory = GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem); - if (facePartsDirectory is null) - continue; - checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); - // else - shortcutFile = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.lnk"); - hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}")); - facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}")); - saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile); + if (forIndividually) + { + facePartsContentCollectionFile = Stateless.MapLogic.GetFacePartsContentCollectionFile(_Configuration.FacePartsFileNameExtension, d2FacePartsContentCollectionDirectory, mapping.MappingFromItem); + if (facePartsContentCollectionFile is null) + continue; + (saveContainer, SaveContainer extraSaveContainer) = Stateless.MapLogic.GetContainers(_Configuration.FacesFileNameExtension, _Configuration.FacePartsFileNameExtension, directory, faceFileHolder, facePartsContentCollectionFile, mapping); + results.Add(extraSaveContainer); + } + else + { + facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem); + if (facePartsDirectory is null) + continue; + shortcutFile = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.lnk"); + checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); + hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}")); + saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile); + } } results.Add(saveContainer); - if (!isBySorting || mapping.SortingContainer is null) + if (!isBySorting || mapping.SortingContainer is null || keyMapping is null) continue; - if (!idToNormalizedRectangleToMapping.TryGetValue(mapping.SortingContainer.Sorting.Id, out normalizedRectangleToMapping)) - continue; - if (!normalizedRectangleToMapping.ContainsKey(mapping.SortingContainer.Sorting.NormalizedRectangle)) - continue; - if (isBySorting && mapping.MappingFromPerson is null) + if (!forIndividually && isBySorting && mapping.MappingFromPerson is null) { - saveContainer = GetMatchSaveContainer(dFacesContentDirectory, d2FacePartsContentDirectory, directory, normalizedRectangleToMapping[mapping.SortingContainer.Sorting.NormalizedRectangle]); + saveContainer = GetMatchSaveContainer(dFacesContentDirectory, d2FacePartsContentDirectory, directory, keyMapping); if (saveContainer is not null) results.Add(saveContainer); } - saveContainer = Stateless.MapLogic.GetDebugSaveContainer(directory, mapping.SortingContainer, normalizedRectangleToMapping[mapping.SortingContainer.Sorting.NormalizedRectangle]); + if (!forIndividually) + saveContainer = Stateless.MapLogic.GetDebugSaveContainer(directory, mapping.SortingContainer, keyMapping); + else + { + (saveContainer, SaveContainer? extraSaveContainer) = Stateless.MapLogic.GetContainers(_Configuration.FacesFileNameExtension, _Configuration.FacePartsFileNameExtension, dFacesContentDirectory, d2FacePartsContentCollectionDirectory, directory, mapping.SortingContainer, keyMapping); + if (saveContainer is null || extraSaveContainer is null) + continue; + results.Add(extraSaveContainer); + } results.Add(saveContainer); } return results; } - public List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, int? useFiltersCounter, bool sortingContainersAny) + public List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, int? useFiltersCounter, bool forIndividually, bool sortingContainersAny) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); List results; bool saveMapped = false; Dictionary> personKeyToIds = new(); - results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny); + results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, forIndividually, sortingContainersAny); return results; } - public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, int totalNotMapped) + public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, int totalNotMapped) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -550,7 +576,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic bool saveMapped = true; int? useFiltersCounter = null; string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping)); - List saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true); + List saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, forIndividually: false); SaveContainers(totalNotMapped, updated, saveContainers); if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory)) Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory); @@ -760,7 +786,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (string.IsNullOrEmpty(directoryName)) throw new NotSupportedException(); shortcutFile = Path.Combine(personDisplayDirectory, $"{personDisplayFileName}.lnk"); - facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); if (facesDirectory is null) continue; faceFileName = $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"; @@ -825,7 +851,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NotSupportedException(); if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName)) throw new NotSupportedException(); - facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); if (facesDirectory is null) continue; faceFileName = $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"; @@ -1234,7 +1260,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personDirectory = Path.Combine(directory, "Unknown"); fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); - facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); if (facesDirectory is null || mapping.MappingFromLocation is null) continue; fullName = Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"); diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 07324eb..ea2c3fc 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -98,7 +98,6 @@ internal abstract class MapLogic string personKeyFormatted; string ticksDirectoryName; string? personFirstInitial; - DirectoryInfo directoryInfo; bool isReservedDirectoryName; string[] personKeyDirectories; string[] personNameDirectories; @@ -115,21 +114,11 @@ internal abstract class MapLogic ticksDirectoryName = Path.GetFileName(ticksDirectory); if (ticksDirectoryName.Length < 3 || ticksDirectoryName[zero] != '(' || ticksDirectoryName[^1] != ')') continue; - if (!long.TryParse(ticksDirectoryName[1..^1], out long directoryTicks)) - { - if (!long.TryParse(ticksDirectoryName[1..^4], out directoryTicks)) - continue; - } - directoryInfo = new(ticksDirectory); - if (directoryInfo.CreationTime.Ticks != directoryTicks) - Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); - if (directoryInfo.LastWriteTime.Ticks != directoryTicks) - Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string personKeyDirectory in personKeyDirectories) { personKeyFormatted = Path.GetFileName(personKeyDirectory); - isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy)); + isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)); yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string yearDirectory in yearDirectories) { @@ -525,6 +514,40 @@ internal abstract class MapLogic } } + private static string[] UpdateDateVerifyAndGetTicksDirectories(string eDistanceContentDirectory) + { + const int zero = 0; + string ticksDirectoryName; + DirectoryInfo directoryInfo; + long? lastDirectoryTicks = null; + DateTime dateTime = DateTime.Now; + List<(string Directory, TimeSpan TimeSpan)> collection = new(); + string[] results = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string ticksDirectory in results) + { + ticksDirectoryName = Path.GetFileName(ticksDirectory); + if (ticksDirectoryName.Length < 3 || ticksDirectoryName[zero] != '(' || ticksDirectoryName[^1] != ')') + continue; + if (!long.TryParse(ticksDirectoryName[1..^1], out long directoryTicks)) + { + if (!long.TryParse(ticksDirectoryName[1..^4], out directoryTicks)) + throw new NotSupportedException(); + } + directoryInfo = new(ticksDirectory); + if (directoryInfo.CreationTime.Ticks != directoryTicks) + Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); + if (directoryInfo.LastWriteTime.Ticks != directoryTicks) + Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); + if (lastDirectoryTicks is not null && new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays > 1) + collection.Add((ticksDirectory, new TimeSpan(directoryTicks - lastDirectoryTicks.Value))); + lastDirectoryTicks = directoryTicks; + } + string[] compare = (from l in collection where l.TimeSpan.TotalDays < 4 select l.Directory).ToArray(); + if (compare.Any()) + throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); + return results; + } + internal static void Set(Configuration? configuration, long ticks, List personContainers, string? a2PeopleSingletonDirectory, string eDistanceContentDirectory, Dictionary personKeyToPersonContainer, List notMappedPersonContainers, Dictionary> skipCollection, Dictionary> skipNotSkipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers) { if (configuration is null) @@ -537,12 +560,12 @@ internal abstract class MapLogic Dictionary personKeyFormattedToNewestPersonKeyFormatted = new(); Dictionary personKeyFormattedToPersonContainer = new(); Dictionary> personKeyToPersonContainerCollection = new(); + string[] ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(eDistanceContentDirectory); List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedRectangleCollection = new(); List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new(); SetPersonCollections(configuration, personContainers, a2PeopleSingletonDirectory, personKeys, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, skipCollection, skipNotSkipCollection); personContainers.AddRange(GetNonSpecificPeopleCollection(configuration, ticks, personKeys)); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)"; List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, personKeyFormattedCollection, ticksDirectories, message); (int unableToMatchCount, int duplicateCount) = SetCollectionsAndGetUnableToConvertCount(configuration, ticks, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedIdThenNormalizedRectangleCollection, collection); @@ -604,6 +627,39 @@ internal abstract class MapLogic return result; } + internal static string? GetFacePartsContentCollectionFile(string extension, string d2FacePartsContentCollectionDirectory, MappingFromItem mappingFromItem) + { + string? result; + string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath); + if (directoryName is null) + result = null; + else + result = Path.Combine($"{d2FacePartsContentCollectionDirectory}{directoryName}", $"{mappingFromItem.ImageFileHolder.Name}{extension}"); + return result; + } + + internal static string? GetFacesDirectory(string dFacesContentDirectory, MappingFromItem mappingFromItem) + { + string? result; + string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath); + if (directoryName is null) + result = null; + else + result = Path.Combine($"{dFacesContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension); + return result; + } + + internal static string? GetFacePartsDirectory(string d2FacePartsContentDirectory, MappingFromItem mappingFromItem) + { + string? result; + string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath); + if (directoryName is null) + result = null; + else + result = Path.Combine($"{d2FacePartsContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension); + return result; + } + internal static SaveContainer GetDebugSaveContainer(string directory, SortingContainer sortingContainer, Mapping mapping) { SaveContainer result; @@ -615,6 +671,54 @@ internal abstract class MapLogic return result; } + internal static (SaveContainer?, SaveContainer?) GetContainers(string facesFileNameExtension, string facePartsFileNameExtension, string dFacesContentDirectory, string d2FacePartsContentCollectionDirectory, string directory, SortingContainer sortingContainer, Mapping mapping) + { + SaveContainer? result; + SaveContainer? saveContainer; + if (sortingContainer.Mapping.MappingFromLocation is null) + throw new NullReferenceException(nameof(sortingContainer.Mapping.MappingFromLocation)); + if (mapping.MappingFromLocation is null) + (result, saveContainer) = (null, null); + else + { + string? facePartsContentCollectionFile = GetFacePartsContentCollectionFile(facePartsFileNameExtension, d2FacePartsContentCollectionDirectory, mapping.MappingFromItem); + if (facePartsContentCollectionFile is null || !File.Exists(facePartsContentCollectionFile)) + result = null; + else + { + string checkFile = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}{facePartsFileNameExtension}"); + result = new(checkFile, directory, new(facePartsContentCollectionFile)); + } + string? facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); + if (facesDirectory is null) + saveContainer = null; + else + { + FileHolder faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}")); + if (!faceFileHolder.Exists) + saveContainer = null; + else + { + string checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}"); + saveContainer = new(checkFile, directory, faceFileHolder); + } + } + } + return (result, saveContainer); + } + + internal static (SaveContainer, SaveContainer) GetContainers(string facesFileNameExtension, string facePartsFileNameExtension, string directory, FileHolder faceFileHolder, string facePartsContentCollectionFile, Mapping mapping) + { + string checkFile; + SaveContainer result; + if (mapping.MappingFromLocation is null) + throw new NullReferenceException(nameof(mapping.MappingFromLocation)); + checkFile = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}{facePartsFileNameExtension}"); + result = new(checkFile, directory, new(facePartsContentCollectionFile)); + checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}"); + return (result, new(checkFile, directory, faceFileHolder)); + } + private static IEnumerable<(string, string)> GetCollection(string[] yearDirectories) { foreach (string l in yearDirectories) diff --git a/Rename/Rename.cs b/Rename/Rename.cs index 2d8d3b3..9514758 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -126,6 +126,7 @@ public class Rename string fileName; string? message; string checkFile; + string? directory; TimeSpan timeSpan; DateTime? dateTime; DateTime?[] dateTimes; @@ -143,6 +144,20 @@ public class Rename { progressBar.Tick(); fileHolder = new(file); + if (file.EndsWith(".rename")) + { + directory = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directory)) + continue; + checkFile = Path.Combine(directory, $"rename_{Path.GetFileName(file[..^7])}"); + if (File.Exists(checkFile)) + continue; + if (distinct.Contains(checkFile)) + continue; + distinct.Add(checkFile); + results.Add(new(fileHolder, checkFile)); + continue; + } if (file.EndsWith(".jpg.del")) { checkFile = file[..^4]; @@ -391,17 +406,20 @@ public class Rename List results = new(); string[] files; string message; + List allFiles; ProgressBar progressBar; List<(FileHolder, string)> toDoCollection; List<(FileHolder, string)> verifiedToDoCollection; - List allFiles = GetAllFiles(matchNginxCollection); + allFiles = GetAllFiles(matchNginxCollection); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; for (int i = 1; i < 3; i++) { + if (!allFiles.Any()) + continue; 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(); + files = i == 2 ? allFiles.ToArray() : (from l in allFiles where l.Contains("Rename", StringComparison.OrdinalIgnoreCase) select l).ToArray(); progressBar = new(files.Length, message, options); if (!files.Any()) continue; @@ -424,6 +442,7 @@ public class Rename results.AddRange(Move(log, toDoCollection)); else results.AddRange(CopyInstead(log, toDoCollection)); + allFiles = GetAllFiles(matchNginxCollection); progressBar.Dispose(); } return results; diff --git a/Shared/Models/Stateless/IMapLogic.cs b/Shared/Models/Stateless/IMapLogic.cs index 863d30d..7470743 100644 --- a/Shared/Models/Stateless/IMapLogic.cs +++ b/Shared/Models/Stateless/IMapLogic.cs @@ -5,6 +5,7 @@ public interface IMapLogic const int CopyNotMappedFaces = 5; const int ForceSingleImage = 3; + const int Individually = 6; const int ManualCopy = 4; const int Mapping = 1; const int Sigma = 3; diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index 4b19ef0..7ae900f 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -106,6 +106,8 @@ internal abstract partial class XDirectory FileInfo fileInfo = new(file); foreach (string possible in collection) { + if (possible == file) + continue; possibleFileInfo = new(possible); if (possibleFileInfo.LastWriteTime == fileInfo.LastWriteTime && possibleFileInfo.Length == fileInfo.Length) continue; @@ -115,7 +117,7 @@ internal abstract partial class XDirectory File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Min()); continue; } - throw new Exception(); + throw new Exception(Path.GetFileNameWithoutExtension(file)); } } diff --git a/Tests/UnitTestHardCoded.cs b/Tests/UnitTestHardCoded.cs index 6671329..46fadea 100644 --- a/Tests/UnitTestHardCoded.cs +++ b/Tests/UnitTestHardCoded.cs @@ -259,9 +259,11 @@ public partial class UnitTestHardCoded new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160708345114583/638160708345114583.ged"), new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160728606500015/638160728606500015.ged"), new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160738845419877/638160738845419877.ged"), + new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160743318283885/638160743318283885.ged"), new(false, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Ancestry-Porterfield/Porterfield Family Tree.ged"), new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160708345114583/638160708345114583-Export.ged"), new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160738845419877/638160738845419877-Export.ged"), + new(true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160743318283885/638160743318283885-Export.ged"), }; foreach ((bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles) { @@ -304,9 +306,11 @@ public partial class UnitTestHardCoded new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160708345114583/638160708345114583.ged.cln"), new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160728606500015/638160728606500015.ged.cln"), new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160738845419877/638160738845419877.ged.cln"), + new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160743318283885/638160743318283885.ged.cln"), new(false, false, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Ancestry-Porterfield/Porterfield Family Tree.ged.cln"), new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160708345114583/638160708345114583-Export.ged.cln"), new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160738845419877/638160738845419877-Export.ged.cln"), + new(true, true, "D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Code-638160743318283885/638160743318283885-Export.ged.cln"), }; foreach ((bool verify, bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles) { @@ -347,4 +351,366 @@ public partial class UnitTestHardCoded NonThrowTryCatch(); } + private string[] GetFamily() => new string[]{ + "UBertha Scott (Barry Scott) 10/2/1900-8/19/1993", + "MEarl Daniel Herman 1/5/1918-10/19/1962", + "FGlendola Koch 8/10/1919-5/16/1910", + "MLawrence Koch 5/14/1916-6/29/2003", + "MEarl Herman Jr. (Sonny Herman) 6/24/1937-12/05/2007", + "FBetty Herman 11/24/1941-11/25/2008", + "FCindy Hoylman 12/4/1958", + "MBill Hoylman 6/29/1959", + "MJoshua Hoylman 7/17/1978", + "FSasha Hoylman 1/21/1981", + "FLyla Hoylman 1/30/2000", + "MWilliam Hoylman 1/2/2006", + "MJon Hoylman 8/17/2007", + "FAmanda Westphal 3/14/1981", + "MMatthew Westphal 06/09/1981", + "MVincent Westphal 12/16/2009", + "MJim Herman 6/8/1960", + "MJames Parmenter 5/21/1973-7/15/1999", + "MChristopher Parmenter 11/5/1976", + "FAlexa Parmenter 10/07/2009", + "MMathew Parmenter 03/21/2004", + "MGreg Herman 4/12/1979", + "MChad Herman 1/2/1983", + "FPiper Marie 4/20/2002", + "MDale Herman 8/28/1962", + "FNancee Herman 3/25/1964", + "FSara Herman 3/2/1992", + "MNolan Herman 10/6/1995", + "MNathan Herman 5/22/1997", + "UNeven Herman 2/23/2000", + "MRodney Herman 4/29/1964", + "FTeresa Davies 08/17/1978", + "FNicole Mangold 9/14/1988", + "MTJ Mangold 1/3/1991", + "FBrook Lynn 11/20/2010", + "FTiffany Herman 3/25/1990", + "MAndrew Herman 5/25/2007", + "MCarson James 1/26/2012", + "FPenny Mews 6/21/1966", + "MThomas Arthur 2/22/1998", + "MDanny Herman 10/6/1941", + "MDan Herman 1/19/1963", + "MDaniel Lee Herman 11/10/1983", + "FDestini Marie Herman 4/21/1985", + "MDavid Earl Jensen (Timmy Jensen) 3/10/1964", + "MDarrin Hansen 6/1/1966", + "FTasha Hansen 12/10/1983", + "FCheri Lynch 1/19/1973", + "FHannah Marie 10/5/1996", + "FHolly Marie 1/25/1979", + "FEarline Wheeler 7/18/1944", + "MDewey Wheeler 9/3/1941", + "MMark Wheeler 8/19/1962", + "MMichael Shane Wheeler 1/31/1985", + "FCadence Lynn Wheeler 9/16/2003", + "FMacy Marie Wheeler 9/16/2003", + "FKarmin Herman 9/25/1963", + "MJon Herman 8/5/1959", + "FChelsea Marie Herman 1/1/1989", + "MMatthew Jon Herman 2/23/1992", + "FBonnie Sherwood 10/12/1965", + "MRandy Sherwood 7/9/1959", + "MAustin James Sherwood 12/20/1994", + "FStephanie Marie Sherwood 2/8/1999", + "FCelia Harken 5/12/1950", + "MLarry Harken 4/12/1949", + "FCelena Vesely 5/11/1976", + "MBen Vesely 9/5/1975", + "MSammual Edward Vesely 5/7/2006", + "MElijah John Vesely 1/25/2008", + "MGlen Herman 5/5/1952", + "FKathryn Melvina Holst 11/23/1920-03/08/2010", + "FDonna Owens 4/8/1942", + "MMike Owens 9/2/1935", + "FAngie Georgie 4/24/1960", + "MJohn Georgie 4/12/1965", + "FSarah Etheridge Georgie 11/28/1980", + "MHaiden Michael Kilpatrick 6/26/1998", + "FEmmalea Kathryn Georgie 8/17/2003", + "MJames Etheridge 8/25/1983", + "UShawnessy Etheridge 11/9/1995", + "FHaley Etheridge 5/7/1997", + "MDenise Engbroten 8/17/1962", + "FAshley Koffman 6/18/1982", + "MEric Koffman 6/28/1982", + "MEvan Koffman 7/21/1985", + "FHeather Shook 8/3/1978", + "MGage Shook 10/9/2000", + "FGrace LeAnn Shook 3/14/2002", + "FJanet Schwab 9/13/45-4/20/2007", + "MAlan Schwab 7/31/1964", + "MRandy Schwab 8/1/1967", + "FMadison Lee Schwab 12/6/1997", + "FMorgan Lynn Schwab 5/13/2000", + "FKristen Fralich 12/14/1971", + "MAaron Fralich 6/26/1966", + "FAbigail Kristine Fralich 3/8/1998", + "MDavid Dixon 11/6/1945", + "FMary Dixon 4/1/1949", + "MRon Dixon 9/22/1966", + "MRyan Dixon 6/30/1988", + "FMegan Dixon 4/30/1990", + "UTatum Dixon 4/30/1990", + "MJoshua David Dixon 10/5/1995", + "FKelly Norman Dixon 7/5/1967", + "FKaitlyn Dixon 10/16/2000", + "FPeggy Swails 9/22/1968", + "MJohn Swails 11/25/1968", + "MMariah Swails 2/10/1991", + "MJohnathan Drake 4/18/1994", + "FDawson Swails 8/18/1998", + "FMarisa Swails 9/7/1999", + "MRaymond Schwab 7/20/1947", + "FBonnie Schwab 1/15/1947", + "MScott Schwab 3/27/1966", + "FBonnie Schwab 1/15/1947", + "MAustin Scott Schwab 7/13/1991", + "MAndrew Paul Schwab 3/26/1995", + "FAddyson Grace Schwab 8/27/1999", + "MAaron Patrick Schwab 6/5/2001", + "FDebra Sottos 3/29/1969", + "MMike Sottos 8/4/1972-7/31/2006", + "MLogan Ray Nolin 3/23/1991", + "MSeth Michael Sottos 7/27/2000", + "FGrace Adelia Lou 9/29/2001", + "FClaire Marie Jeane 7/07/2003", + "FEmma Rose Jacquelin 4/04/2005", + "FRose Olivia Mae 1/6/2007", + "FTeresa Justice 4/16/1971", + "MKevin Justice 7/6/1967", + "MNoah Gale Justice 9/17/1998", + "MBenjamin Kevin Justice 1/18/2001", + "MKenny Schwab 7/28/1948", + "FBonnie Schwab 9/11/1947", + "FDiane Schwab 6/10/1966", + "FMary Anderegg 4/24/1970", + "MScott Anderegg 10/4/1967", + "FHanna Catherine Anderegg 1/31/2001", + "FMadison Alyse Anderegg 9/20/2003", + "FShelly Whittle 6/24/1972", + "MBrant Whittle 3/5/1971", + "FKendra Kay Whittle 8/31/1999", + "MDrake Thomas Whittle 7/16/1991", + "UKelesy Taylor Whittle 2/2/1995", + "FRoberta Garrett 11/7/1951", + "MCharley Garrett 6/2/1951", + "MTravis Barker 6/9/1970", + "FJulie Barker 3/1/1971", + "FKayla Barker 3/31/1991", + "UAlli Leighton Barker 3/10/1997", + "MGarrett Ambrose Barker 4/11/2000", + "MCharley Garrett Jr. 2/9/76-10/21/2000", + "MBlake Mitchell Garrett 8/21/1994", + "FMakenzie Faye Garrett 2/16/2000", + "MRobert Dean Rush 12/11/1950-3/20/1976", + "MDean Herman 12/25/1922-4/24/1908", + "FThelma Herman 6/9/1926-10/25/1909", + "FElizabeth Leach 8/12/1948", + "MGary Leach 6/24/1945", + "FStephen Herman 7/19/1951", + "FDiane Herman 8/31/1957", + "FMolly Elizabeth Herman 10/11/1983", + "MThaddeus Benjamin Herman 3/9/1986", + "MMaryam Safajoo Herman 2/7/1987", + "FGeorgia Marie Herman 10/4/1988", + "MTimothy Herman 2/22/1958", + "MJon Herman 8/5/1959", + "FKarmin Herman 9/25/1963", + "FChelsea Marie Herman 1/1/1989", + "MMatthew Jon Herman 2/23/1992", + "MBen Herman 5/27/1962", + "FSydney Herman 7/12/1992", + "FHaley Anderson Carlisle 6/24/1989", + "FJennifer Cedillo 12/31/1966", + "MDave Cedillo 7/17/1966", + "FLenore Pearson 3/2/1925", + "MChester Pearson 2/7/1925", + "FAmy Scofield 7/28/1950", + "MRick Scofield 7/9/1954", + "UTracey Eickstaedt 3/19/1971", + "MTroy Eickstaedt 4/11/1970", + "FHaley Morgan Eickstaedt 9/11/1994", + "MDominique Dawn Eickstaedt 4/10/1998", + "FAmber Dawn Scofield 10/9/1978", + "MDalton Rickie Wenzel 8/25/2000", + "MShane Scofield 6/19/1985", // Nope + "FAshley Scofield 7/13/1984", + "FKathy Pettus 1/28/1955", + "MEd Pettus 11/5/1951", + "MEddie Pettus 9/10/1982", + "MMichael Pettus 8/15/1987", + "FRuthMary Tibbetts 2/1/1929", + "MJames Tibbetts 7/24/1922-10/15/1981", + "MDave Tibbetts 11/12/1956", + "FGale Tibbetts 11/26/1958", // https://www.facebook.com/gale.tibbetts.18/photos // https://scontent-lax3-2.xx.fbcdn.net/v/t1.6435-9/92647697_1914827555328335_6217595516130164736_n.jpg?_nc_cat=107&ccb=1-7&_nc_sid=8bfeb9&_nc_ohc=CGu6LkY9MisAX__EerY&_nc_ht=scontent-lax3-2.xx&oh=00_AfD-o-blr_-6HXChsCosOq_n-iqWvmPzh_vmOFVnax1ntA&oe=64530587 + "FJessica Ann Tibbetts 9/8/1990", + "MJonathon Tibbetts 8/11/1994", + "FErin Tibbetts 7/15/1998", + "MElmer John Herman 1/6/1931-10/12/1977", + "FNorma Herman 6/5/1933", + "FLannie Bosveld 2/3/1954", + "MTom Bosveld 10/7/1949", + "MJeremy Bosveld 2/14/1973", + "UAmbjour Hazen 10/16/1991", + "UJordan Hazen 8/22/1991-12/23/2007", + "FKira Hazen 9/02/1993", + "MDevan Hazen 8/14/1999", + "MEthan Hazen 8/14/1999", + "FApril Hill 6/9/1980", + "MRandall Hill 1/16/1978", // https://www.facebook.com/randall.d.hill/about_contact_and_basic_info // https://www.facebook.com/photo.php?fbid=10154576010477639&set=pb.530957638.-2207520000.&type=3 // https://scontent-lax3-1.xx.fbcdn.net/v/t1.18169-9/16265790_10154576010477639_102119672782426718_n.jpg?_nc_cat=102&ccb=1-7&_nc_sid=174925&_nc_ohc=cWEECl9DMhoAX_qlUB-&_nc_ht=scontent-lax3-1.xx&oh=00_AfC4PZ-tytVowtRSu1AJtkxRkQb0_j0WSDk4MKquqs0img&oe=64531181 + "FBrenda Olson 8/27/1958", // https://www.facebook.com/barbara.olson.96/about_contact_and_basic_info + "MChris Olson 11/13/1951", + "FShilo Zeches 4/9/1980", + "FAddison Zeches 9/14/2003", + "FFrancis Zeches 6/2/2006", + "FBarbara Olson 12/25/1981", + "MAllan Olson 4/5/1977", + "MJacob Olson 12/1/1906", + "FJayden Olson 10/5/1909", + "FRachael Zeches 8/28/1983", + "MMarc Allan Zeches 6/9/2005", + "FCynthia Bott (Charlie Bott) 4/7/1964", + "FStephanie Martinez 3/13/1983", + "FIsidro Martinez (David Martinez) 1/6/1980", + "FNorma Herman 6/5/1933", + "UNayeli Teresa Herman 10/6/2001", + "FStephanie Herman Jr. 11/5/2003", + "MDavid Herman 6/29/2006", + "FKimberly Zoe 4/6/1984", + "MRobert Zoe Jr. 10/17/2005", + "MBlake Austin Zoe 3/20/2007", + "FSara 10/8/1988", + "FKeri Lee 3/30/1992", + "FMarcia Lamprecht 1/28/1933", + "MButch Darel Peirce 1/3/1936", + "MNorman Lamprecht 3/29/1930-3/26/2002", + "FJulie Arabzadeh 8/21/1950", + "FJeana Arabzadeh 3/20/1978", + "FJoyce Kamali 1/8/1952", + "MEarl Rodriguez 7/27/1919", + "FKai Kamali 9/6/1974", + "FLauren Lamprecht 12/4/1956", + "FLaura Lamprecht 5/22/1980", + "FLeland Lamprecht 4/6/1983", + "MNorman Herman 2/17/1935", + "FJan Herman 7/20/1930", + "FBonnie Glicco 9/19/1956", + "MCalvin Glicco 1/6/1954", + "FAnn Marie Glicco 4/25/1978", + "FJessica Glicco 11/14/1981", + "MThomas Glicco 10/11/2000", + "MGabriel Glicco 1/4/2004", + "FMackenzie Glicco 8/7/2007", + "MMark Herman 9/9/1957", + "MBrandt Moss 5/4/1996", + "MChristopher Herman 7/25/1979", + "FKari Herman 5/12/1982", + "MMyles McKissack 9/16/2008", + "MLogan McKissack 10/9/2011", + "MChris Woolery 3/11/1988", + "FAdalin Woolery 3/14/2011", + "MGerald Billy 3/31/1937-8/29/1982", + "FMary Ann Herman 6/2/1934", + "MMike Herman 8/27/1955", + "FCarolyn Hardin 1/4/1951", + "MMark Herman 2/7/1957", + "MKyle Herman 6/18/1989", + "MEric Herman 4/16/1993", + "MJoe Herman 1/14/1959", + "FLisa Herman 4/26/1962-3/2/2011", + "MBrett Herman 2/2/1989", + "FJill Elisabeth Herman 8/18/1997", + "MJeff Herman 4/14/1961", + "MKeith Herman 12/20/1941", + "FMary Ann Herman 5/10/1943", + "FCarol Herman 3/1/1943-9/30/1990", + "MBrian Herman 6/30/1965", + "FStuart Herman 12/22/1987", + "MTrevor Herman 1/10/1990", + "MCletus Barry 1/12/1922-4/30/1999", + "FAgnes Barry 10/20/1923", + "FJanet Barry 7/22/1947", + "MJack Herman 1/27/1905", + "FHelen Herman 8/22/1908-4/13/1997", + "FJoyce Waddell 05/13/1946", + "MDewey Lynn Waddell 9/10/1970", + "MJonathon G Waddell 9/27/1971", + }; + + [TestMethod] + public void TestMethodFamily() + { + int age; + char sex; + int hours; + bool alive; + string name; + long personKey; + string ageGroup; + string? directory; + bool verify = false; + string[] dateSegments; + DateTime parseDateTime; + PersonName? personName; + string[] spaceSegments; + string personKeyFormatted; + List lines = new(); + bool isDefaultName = false; + PersonBirthday personBirthday; + string[] family = GetFamily(); + DateTime dateTime = DateTime.Now; + string saveDirectory = $"D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/Norman-{dateTime.Ticks}"; + foreach (string familyMember in family) + { + sex = familyMember[0]; + if (sex is not 'U' and not 'F' and not 'M') + continue; + spaceSegments = familyMember[1..].Split(' '); + dateSegments = spaceSegments[^1].Split('-'); + name = string.Join(' ', spaceSegments[..^1]); + if (!DateTime.TryParse(dateSegments[0], out parseDateTime)) + continue; + personName = IPerson.GetPersonName(name); + if (personName is null) + continue; + personBirthday = new(parseDateTime); + if (dateSegments.Length == 1) + { + lines.Add($"{name}\t{sex}\t{personBirthday.Value:yyyy-MM-dd}\tnull"); + alive = true; + } + else + { + if (!DateTime.TryParse(dateSegments[1], out parseDateTime)) + continue; + alive = false; + lines.Add($"{name}\t{sex}\t{personBirthday.Value:yyyy-MM-dd}\t{parseDateTime:yyyy-MM-dd}"); + } + hours = IPersonBirthday.GetHour(alive, sex); + personKey = personBirthday.Value.AddHours(hours).Ticks; + personKeyFormatted = IPersonBirthday.GetFormatted(_PropertyConfiguration.PersonBirthdayFormat, personKey); + (age, _) = IAge.GetAge(dateTime.Ticks, personKey); + if (age < 25) + ageGroup = "1) Less-25"; + else if (age < 50) + ageGroup = "2) Less-50"; + else if (age < 100) + ageGroup = "3) Less-100"; + else if (age < 200) + ageGroup = "4) Less-200"; + else + ageGroup = "5) Else"; + directory = Path.Combine(saveDirectory, "Norman", ageGroup, $"{personName.First.Value} {personName.Last.Value}^{age}", personKeyFormatted); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + IGenealogicalDataCommunication.WriteFile(personKeyFormatted, personBirthday, personName, null, isDefaultName, directory, null, verify); + } + File.WriteAllLines(Path.Combine(saveDirectory, "tsv.txt"), lines); + NonThrowTryCatch(); + } + } \ No newline at end of file