diff --git a/Distance/Models/_E_Distance.cs b/Distance/Models/_E_Distance.cs index dc337c8..d9809e8 100644 --- a/Distance/Models/_E_Distance.cs +++ b/Distance/Models/_E_Distance.cs @@ -79,7 +79,7 @@ public partial class E_Distance : IDistance return results; } - private static List GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers) + private static ReadOnlyCollection GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers) { List faceDistanceEncodings = new(); foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) @@ -88,7 +88,7 @@ public partial class E_Distance : IDistance continue; faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); } - return faceDistanceEncodings; + return new(faceDistanceEncodings); } private List<(Face Face, double? Length)> GetValues(MappingFromItem mappingFromItem, List intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding) @@ -102,7 +102,7 @@ public partial class E_Distance : IDistance int faceDistanceContainersLength = faceDistanceContainers.Length; if (faceDistanceContainersLength != intersectFaces.Count) throw new NotSupportedException(); - List faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers); + ReadOnlyCollection faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers); if (faceDistanceEncodings.Count != intersectFaces.Count) throw new NotSupportedException(); List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); @@ -315,7 +315,7 @@ public partial class E_Distance : IDistance _DuplicateMappedFaceFiles.Clear(); } - public List GetMissingFaceDistanceContainer(int maxDegreeOfParallelism, long ticks, string dFacesCollectionDirectory, Dictionary>> missingIdThenWholePercentagesToPersonContainers) + public ReadOnlyCollection GetMissingFaceDistanceContainer(int maxDegreeOfParallelism, long ticks, string dFacesCollectionDirectory, ReadOnlyDictionary>> missingIdThenWholePercentagesToPersonContainers) { List results = new(); string[] files; @@ -365,7 +365,7 @@ public partial class E_Distance : IDistance results.Add(faceDistanceContainer); } }); - return results; + return new(results); } public static void SaveFaceDistances(Property.Models.Configuration configuration, SortingContainer[] sortingContainers) @@ -380,7 +380,7 @@ public partial class E_Distance : IDistance File.WriteAllLines(eDistanceContentFileName, results); } - public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, List distinctFilteredFaces) + public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, ReadOnlyCollection distinctFilteredFaces) { List faces = new(); foreach (Face face in distinctFilteredFaces) @@ -443,7 +443,7 @@ public partial class E_Distance : IDistance return results; } - private static List GetSortingCollection(Map.Models.MapLogic mapLogic, List faceDistanceEncodings, int i, FaceDistance faceDistanceEncoding) + private static List GetSortingCollection(Map.Models.MapLogic mapLogic, ReadOnlyCollection faceDistanceEncodings, int i, FaceDistance faceDistanceEncoding) { List results; List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); @@ -451,9 +451,9 @@ public partial class E_Distance : IDistance return results; } - public static FaceDistanceContainer[] GetFaceDistanceContainers(List distinctFilteredFaces) + public static ReadOnlyCollection GetFaceDistanceContainers(ReadOnlyCollection distinctFilteredFaces) { - FaceDistanceContainer[] results; + ReadOnlyCollection results; FaceDistance faceDistance; FaceDistanceContainer faceDistanceContainer; List collection = new(); @@ -467,11 +467,11 @@ public partial class E_Distance : IDistance faceDistanceContainer = new(face, faceDistance); collection.Add(faceDistanceContainer); } - results = collection.ToArray(); + results = new(collection.ToArray()); return results; } - public static List GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers, List missingFaceDistanceContainers) + public static ReadOnlyCollection GetFaceDistanceEncodings(ReadOnlyCollection faceDistanceContainers, ReadOnlyCollection missingFaceDistanceContainers) { List faceDistanceEncodings = new(); foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) @@ -486,10 +486,10 @@ public partial class E_Distance : IDistance continue; faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); } - return faceDistanceEncodings; + return new(faceDistanceEncodings); } - public static FaceDistanceContainer[] FilteredFaceDistanceContainers(Map.Models.MapLogic mapLogic, FaceDistanceContainer[] faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits) + public static FaceDistanceContainer[] FilteredFaceDistanceContainers(Map.Models.MapLogic mapLogic, ReadOnlyCollection faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits) { List results = new(); foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) @@ -517,7 +517,7 @@ public partial class E_Distance : IDistance return results.ToArray(); } - public static SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration mapConfiguration, long ticks, Map.Models.MapLogic mapLogic, IDistanceLimits distanceLimits, List faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers) + public static SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration mapConfiguration, long ticks, Map.Models.MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers) { SortingContainer[] results; List collection = new(); @@ -569,7 +569,7 @@ public partial class E_Distance : IDistance } if (faceDistanceEncoding is null) throw new Exception(); - faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); + faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncoding); if (faceDistanceLengths.Count != files.Count) throw new Exception(); for (int i = 0; i < files.Count; i++) @@ -586,7 +586,7 @@ public partial class E_Distance : IDistance } if (faceDistanceEncoding is null) throw new Exception(); - faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); + faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncoding); if (faceDistanceLengths.Count != files.Count) throw new Exception(); for (int i = 0; i < files.Count; i++) diff --git a/FaceRecognitionDotNet/FaceRecognition.cs b/FaceRecognitionDotNet/FaceRecognition.cs index 46687ad..6569a70 100644 --- a/FaceRecognitionDotNet/FaceRecognition.cs +++ b/FaceRecognitionDotNet/FaceRecognition.cs @@ -1,5 +1,6 @@ using DlibDotNet; using DlibDotNet.Dnn; +using System.Collections.ObjectModel; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; @@ -409,7 +410,7 @@ public class FaceRecognition : DisposableObject return null; } - public static List FaceDistances(List faceDistances, FaceDistance faceDistanceToCompare) + public static List FaceDistances(ReadOnlyCollection faceDistances, FaceDistance faceDistanceToCompare) { List results = new(); if (faceDistances is null) diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 41643cd..b7959b1 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -77,9 +77,6 @@ public partial class DlibDotNet _PropertyRootExistedBefore = !Directory.Exists(propertyRoot); string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(propertyConfiguration.RootDirectory); _ArgZeroIsConfigurationRootDirectory = propertyConfiguration.RootDirectory == argZero; - if (!Directory.Exists(argZero)) - _ = Directory.CreateDirectory(argZero); - Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(argZero, ticks); if (!Directory.Exists(argZero)) _ = Directory.CreateDirectory(argZero); _Log.Information(configuration.ModelDirectory); @@ -359,7 +356,6 @@ public partial class DlibDotNet Mapping result; bool? isUsed; int? eyeα = null; - int notMapped = 0; bool? isFocusPerson; bool? eyeReview = null; bool? inSkipCollection; @@ -391,7 +387,7 @@ public partial class DlibDotNet mappingFromFilter = new(isFocusModel, isFocusPerson, isFocusRelativePath, isIgnoreRelativePath, inSkipCollection, isUsed); } result = new(mappingFromItem, mappingFromFilter, mappingFromLocation, mappingFromPhotoPrismCollection: null); - notMapped += mapLogic.UpdateMappingFromPerson(locationContainersFiles, wholePercentagesToPersonContainers, result); + int notMapped = mapLogic.UpdateMappingFromPerson(locationContainersFiles, wholePercentagesToPersonContainers, result); return (result, notMapped); } @@ -557,9 +553,8 @@ public partial class DlibDotNet { if (_Log is null) throw new NullReferenceException(nameof(_Log)); - int notMapped = 0; + int result = 0; int exceptionsCount = 0; - bool exceptions = false; bool ignoreXMatches = _JLinkResolvedDirectories.Count > 0; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; DateTime[] containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); @@ -573,37 +568,35 @@ public partial class DlibDotNet { try { - notMapped = FullParallelForWork(propertyLogic, - metadata, - mapLogic, - outputResolution, - outputResolutionHasNumber, - cResultsFullGroupDirectory, - dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, - sourceDirectoryChanges, - fileNameToCollection, - container, - index: i, - filteredItems[i], - containerDateTimes, - isFocusRelativePath, - isIgnoreRelativePath, - facePartsCollectionDirectory); + result += FullParallelForWork(propertyLogic, + metadata, + mapLogic, + outputResolution, + outputResolutionHasNumber, + cResultsFullGroupDirectory, + dResultsFullGroupDirectory, + d2ResultsFullGroupDirectory, + sourceDirectoryChanges, + fileNameToCollection, + container, + index: i, + filteredItems[i], + containerDateTimes, + isFocusRelativePath, + isIgnoreRelativePath, + facePartsCollectionDirectory); if (i == 0 || sourceDirectoryChanges.Count > 0) progressBar.Tick(); } catch (Exception ex) { - if (!exceptions) - exceptions = true; exceptionsCount++; _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, ex.Message, Environment.NewLine, ex.StackTrace), ex); if (exceptionsCount == filteredItems.Length) throw new Exception(string.Concat("All in [", container.SourceDirectory, "] failed!")); } }); - return (notMapped, exceptions); + return (result, exceptionsCount > 0); } private static void WriteTab(string checkDirectory, List<(string Id, string Line)> metadataIdLines, string fileName) @@ -693,11 +686,10 @@ public partial class DlibDotNet return new(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); } - private int FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, MapLogic mapLogic) + private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, MapLogic mapLogic) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); - int result = 0; int total; int notMapped; string message; @@ -705,6 +697,7 @@ public partial class DlibDotNet int totalSeconds; Container container; Item[] filteredItems; + int totalNotMapped = 0; bool outputResolutionHasNumber; bool anyNullOrNoIsUniqueFileName; string cResultsFullGroupDirectory; @@ -737,7 +730,7 @@ public partial class DlibDotNet sourceDirectoryChanges.Clear(); anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - message = $"{i + 1:000} [{filteredItems.Length:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}"; + message = $"{i + 1:000} [{filteredItems.Length:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <{container.SourceDirectory}> - total not mapped {totalNotMapped:000000}"; propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, container.SourceDirectory, anyNullOrNoIsUniqueFileName); if (outputResolutionHasNumber) _Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory); @@ -755,7 +748,7 @@ public partial class DlibDotNet container, filteredItems, message); - result += notMapped; + totalNotMapped += notMapped; if (exceptions) { _Exceptions.Add(container.SourceDirectory); @@ -773,11 +766,15 @@ public partial class DlibDotNet } total += container.Items.Count; } + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + message = $"### [###] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <> - total not mapped {totalNotMapped:000000}"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(1, message, options); + progressBar.Tick(); } - return result; } - private void SaveFaceDistances(long ticks, MapLogic mapLogic, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Dictionary> idToWholePercentagesToMapping, List faceDistanceEncodings, FaceDistanceContainer[] faceDistanceContainers) + private void SaveFaceDistances(long ticks, MapLogic mapLogic, ReadOnlyCollection mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary> idToWholePercentagesToMapping, ReadOnlyCollection faceDistanceEncodings, ReadOnlyCollection faceDistanceContainers) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -812,50 +809,44 @@ public partial class DlibDotNet E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); if (filteredFaceDistanceContainers.Length > 0) { - int updated = mapLogic.UpdateFromSortingContainers(_Configuration.SaveIndividually, distanceLimits, sortingContainers); + int updated = mapLogic.UpdateFromSortingContainers(_Configuration.SaveIndividually, idToWholePercentagesToMapping, distanceLimits, sortingContainers); List saveContainers = mapLogic.GetSaveContainers(_Configuration.SaveIndividually, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToWholePercentagesToMapping, useFiltersCounter, sortingContainers.Length > 0); - mapLogic.SaveContainers(_Configuration.SaveIndividually, filteredFaceDistanceContainers.Length, updated, saveContainers); + mapLogic.SaveContainers(_Configuration.SaveIndividually, updated, saveContainers); } } } - private void SaveFaceDistances(long ticks, MapLogic mapLogic, List distinctFilteredFaces, Mapping[] mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, string dFacesCollectionDirectory, Dictionary> idToWholePercentagesToMapping) + private void SaveFaceDistances(long ticks, MapLogic mapLogic, ReadOnlyCollection distinctFilteredFaces, ReadOnlyCollection mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, string dFacesCollectionDirectory, ReadOnlyDictionary> idToWholePercentagesToMapping) { E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); - FaceDistanceContainer[] faceDistanceContainers = E_Distance.GetFaceDistanceContainers(distinctFilteredFaces); - Dictionary>> missingIdThenWholePercentagesToPersonContainers = mapLogic.GetMissing(idToWholePercentagesToMapping); - List missingFaceDistanceContainers = _Distance.GetMissingFaceDistanceContainer(_AppSettings.MaxDegreeOfParallelism, ticks, dFacesCollectionDirectory, missingIdThenWholePercentagesToPersonContainers); - List faceDistanceEncodings = E_Distance.GetFaceDistanceEncodings(faceDistanceContainers, missingFaceDistanceContainers); - if (faceDistanceContainers.Length > 0) + ReadOnlyCollection faceDistanceContainers = E_Distance.GetFaceDistanceContainers(distinctFilteredFaces); + ReadOnlyDictionary>> missingIdThenWholePercentagesToPersonContainers = mapLogic.GetMissing(idToWholePercentagesToMapping); + ReadOnlyCollection missingFaceDistanceContainers = _Distance.GetMissingFaceDistanceContainer(_AppSettings.MaxDegreeOfParallelism, ticks, dFacesCollectionDirectory, missingIdThenWholePercentagesToPersonContainers); + ReadOnlyCollection faceDistanceEncodings = E_Distance.GetFaceDistanceEncodings(faceDistanceContainers, missingFaceDistanceContainers); + if (faceDistanceContainers.Count > 0) SaveFaceDistances(ticks, mapLogic, mappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, faceDistanceEncodings, faceDistanceContainers); } - private void MapLogic(long ticks, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, Dictionary> personKeyToIds, List distinctFilteredFaces, Mapping[] distinctFilteredMappingCollection, int totalNotMapped) + private void MapLogic(long ticks, ReadOnlyCollection containers, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection distinctFilteredFaces, ReadOnlyCollection distinctFilteredMappingCollection) { string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, "[()]"); string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultCollection, _Configuration.PropertyConfiguration.ResultAllInOne); - if (distinctFilteredMappingCollection.Length > 0) + if (distinctFilteredMappingCollection.Count > 0) { Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, ticks); if (Directory.Exists(d2FacePartsContentCollectionDirectory)) Shared.Models.Stateless.Methods.IPath.MakeHiddenIfAllItemsAreHidden(d2FacePartsContentCollectionDirectory); } if (Directory.Exists(fPhotoPrismContentDirectory)) - F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, ticks, distinctFilteredFaces, mapLogic); + F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, ticks, distinctFilteredFaces, mapLogic); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctFilteredMappingCollection); - if (!string.IsNullOrEmpty(_Configuration.PersonCharacters)) - { - if (_Configuration.PersonCharactersCopyCount > 0) - mapLogic.CopyAtLeastOneMappedFiles(_Configuration.PersonCharactersCopyCount, dFacesContentDirectory, a2PeopleSingletonDirectory, distinctFilteredMappingCollection); - mapLogic.SavePersonKeyToCount(dFacesContentDirectory, a2PeopleSingletonDirectory, distinctFilteredMappingCollection); - } - Dictionary> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctFilteredMappingCollection); + ReadOnlyDictionary> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctFilteredMappingCollection); mapLogic.CopyManualFiles(dFacesContentDirectory, idToWholePercentagesToMapping); if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctFilteredMappingCollection, idToWholePercentagesToMapping, totalNotMapped); + mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctFilteredMappingCollection, idToWholePercentagesToMapping); if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) SaveFaceDistances(ticks, mapLogic, distinctFilteredFaces, distinctFilteredMappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, dFacesCollectionDirectory, idToWholePercentagesToMapping); } @@ -906,12 +897,12 @@ public partial class DlibDotNet return result; } - private Mapping[] GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, int totalNotMapped, bool distinctItems) + private ReadOnlyCollection GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, bool distinctItems) { - Mapping[] results; + ReadOnlyCollection results; int count = 0; + int notMapped; Mapping mapping; - int notMapped = 0; bool anyValidFaces; string focusRelativePath; bool? isFocusRelativePath; @@ -952,28 +943,23 @@ public partial class DlibDotNet continue; anyValidFaces = true; mappingCollection.Add(face.Mapping); + if (face.Mapping.MappingFromPerson is null || face.Mapping.MappingFromPerson.LocationContainersFiles.Count == 0) + continue; + if (_Configuration.LocationContainerDistanceTolerance is null) + Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(propertyConfiguration, face.Mapping.MappingFromItem, face.Mapping.MappingFromPerson); } if (!anyValidFaces) { (mapping, notMapped) = GetMapping(mapLogic, locationContainersFiles, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem); mappingCollection.Add(mapping); - if (mapping.MappingFromPerson is null || mapping.MappingFromPerson.LocationContainersFiles.Count == 0) - continue; - if (_Configuration.LocationContainerDistanceTolerance is null) - Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(propertyConfiguration, mapping.MappingFromItem, mapping.MappingFromPerson); } } } - results = (from l in mappingCollection orderby l.MappingFromItem.Id select l).ToArray(); - if (notMapped != totalNotMapped) - { - if (notMapped != totalNotMapped) - { } - } + results = new((from l in mappingCollection orderby l.MappingFromItem.Id select l).ToArray()); return results; } - private static void Verify(string eDistanceContentDirectory, List distinctFilteredItems) + private static void Verify(string eDistanceContentDirectory, ReadOnlyCollection distinctFilteredItems) { #if VerifyItem bool found; @@ -1062,14 +1048,17 @@ public partial class DlibDotNet } } - private static bool GetRunToDoCollectionFirst(long ticks, string rootDirectory, FileSystemInfo fileSystemInfo) + private bool GetRunToDoCollectionFirst(long ticks) { bool result = false; string[] directories; string seasonDirectory; DirectoryInfo directoryInfo; DateTime dateTime = new(ticks); + string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; + string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); (int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); + FileSystemInfo fileSystemInfo = new DirectoryInfo(eDistanceContentDirectory); string[] checkDirectories = new string[] { Path.Combine(rootDirectory, "Ancestry"), @@ -1079,9 +1068,10 @@ public partial class DlibDotNet }; foreach (string checkDirectory in checkDirectories) { - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}"); + if (checkDirectory == rootDirectory) + seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName}"); + else + seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}"); if (!Directory.Exists(seasonDirectory)) _ = Directory.CreateDirectory(seasonDirectory); if (result) @@ -1124,13 +1114,15 @@ public partial class DlibDotNet const string directorySearchFilter = "*"; Dictionary> personKeyToIds; bool configurationOutputResolutionsHas = false; + bool runToDoCollectionFirst = GetRunToDoCollectionFirst(ticks); Dictionary> fileNameToCollection; (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks); a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton); - bool runToDoCollectionFirst = GetRunToDoCollectionFirst(ticks, _Configuration.PropertyConfiguration.RootDirectory, new DirectoryInfo(eDistanceContentDirectory)); + _ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, $"({ticks})")); if (runToDoCollectionFirst) mapLogic = null; else @@ -1209,8 +1201,8 @@ public partial class DlibDotNet B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); - int totalNotMapped = FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, mapLogic); - List distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, containers, distinctItems: true, filterItems: true); + FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, mapLogic); + ReadOnlyCollection distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, new(containers), distinctItems: true, filterItems: true); if (_Configuration.LookForAbandoned) { foreach (string outputResolution in _Configuration.OutputResolutions) @@ -1221,10 +1213,13 @@ public partial class DlibDotNet } _Distance.Clear(); Verify(eDistanceContentDirectory, distinctFilteredItems); - List distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); - Mapping[] distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, totalNotMapped, distinctItems: true); - string json = JsonSerializer.Serialize(distinctFilteredMappingCollection); - File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); + ReadOnlyCollection distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); + ReadOnlyCollection distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true); + if (runToDoCollectionFirst) + { + string json = JsonSerializer.Serialize(distinctFilteredMappingCollection); + File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); + } foreach (string outputResolution in _Configuration.OutputResolutions) { if (_PropertyRootExistedBefore) @@ -1233,15 +1228,15 @@ public partial class DlibDotNet if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection); if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any() && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, personContainers, a2PeopleContentDirectory, personKeyToIds, distinctFilteredMappingCollection, totalNotMapped); + mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, personContainers, a2PeopleContentDirectory, personKeyToIds, distinctFilteredMappingCollection); (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); if (_ArgZeroIsConfigurationRootDirectory && _Configuration.SaveResizedSubfiles && outputResolution == _Configuration.OutputResolutions[0] && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Exceptions.Count == 0) - MapLogic(ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogic, outputResolution, personKeyToIds, distinctFilteredFaces, distinctFilteredMappingCollection, totalNotMapped); - if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && distinctFilteredMappingCollection.Length > 0) + MapLogic(ticks, new(containers), dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogic, outputResolution, new(personKeyToIds), distinctFilteredFaces, distinctFilteredMappingCollection); + if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && distinctFilteredMappingCollection.Count > 0) _Random.Random(_Configuration.PropertyConfiguration, outputResolution, personKeyToIds, distinctFilteredMappingCollection); if (_IsEnvironment.Development) continue; diff --git a/Instance/Models/ReadOnlyCollection.cs b/Instance/Models/ReadOnlyCollection.cs new file mode 100644 index 0000000..e69de29 diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index ef03684..9b64837 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Text.Json; namespace View_by_Distance.Instance.Models; @@ -25,7 +26,7 @@ internal class F_Random return result; } - private static Dictionary> Get(Dictionary> personKeyToIds, Shared.Models.Mapping[] mappingCollection, string dateFormat) + private static Dictionary> Get(Dictionary> personKeyToIds, ReadOnlyCollection mappingCollection, string dateFormat) { Dictionary> results = new(); string key; @@ -58,7 +59,7 @@ internal class F_Random return results; } - internal void Random(Property.Models.Configuration configuration, string outputResolution, Dictionary> personKeyToIds, Shared.Models.Mapping[] mappingCollection) + internal void Random(Property.Models.Configuration configuration, string outputResolution, Dictionary> personKeyToIds, ReadOnlyCollection mappingCollection) { string key; string json; diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 126dfa1..cd8f7b4 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -58,6 +58,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic ReadOnlyDictionary> readOnlyPersonKeyToPersonContainerCollection; Stateless.MapLogic.SetSkipCollections(configuration, personContainers, a2PeopleSingletonDirectory, skipCollection, skipNotSkipCollection); List records = Stateless.MapLogic.SetPersonCollectionsAndGetRecords(configuration, ticks, personContainers, eDistanceContentDirectory); + ReadOnlyCollection<(Stateless.MapLogic.PersonKeyFormattedIdThenWholePercentages, PersonContainer)> readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer; locationContainers.AddRange(Stateless.MapLogic.GetLocationContainers(distance, maxDegreeOfParallelism, configuration, ticks, personContainers, eDistanceContentDirectory, skipCollection, records)); int lossCount = records.Count - locationContainers.Count; ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection = Stateless.MapLogic.GetPersonKeyFormattedIdThenWholePercentages(configuration, ticks, records); @@ -84,16 +85,18 @@ public class MapLogic : Shared.Models.Methods.IMapLogic readOnlyPersonKeyToCount = new(personKeyToCount); readOnlyPersonKeyFormattedToPersonContainer = new(personKeyFormattedToPersonContainer); readOnlyPersonKeyToPersonContainerCollection = new(personKeyToPersonContainerCollection); - if (possiblyNewPersonDisplayDirectoryNamesAndPersonContainer.Count > 0) - Stateless.MapLogic.PossiblyRebuildPersonContainers(configuration, - a2PeopleSingletonDirectory, - possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); + readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new(possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } Stateless.MapLogic.SetPersonKeyToPersonContainer(configuration, personContainers, readOnlyPersonKeyToCount, personKeyToPersonContainer, readOnlyPersonKeyToPersonContainerCollection); + Stateless.MapLogic.PossiblyRebuildPersonContainers(configuration, + ticks, + a2PeopleSingletonDirectory, + readOnlyPersonKeyToCount, + readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer); idThenWholePercentagesToPersonContainers = Stateless.MapLogic.GetIdThenWholePercentagesToPersonContainers(configuration, readOnlyPersonKeyFormattedToPersonContainer, personKeyFormattedIdThenWholePercentagesCollection); @@ -190,18 +193,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (mapping.MappingFromLocation is null) continue; - if (wholePercentagesToPersonContainers is not null) + if (wholePercentagesToPersonContainers is null) { if (mapping.MappingFromFilter.InSkipCollection is not null && mapping.MappingFromFilter.InSkipCollection.Value) continue; result += 1; continue; } - if (wholePercentagesToPersonContainers is null) - { - result += 1; - continue; - } if (!wholePercentagesToPersonContainers.TryGetValue(mapping.MappingFromLocation.WholePercentages, out personContainers)) { if (mapping.MappingFromFilter.InSkipCollection is not null && mapping.MappingFromFilter.InSkipCollection.Value) @@ -229,7 +227,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - public void SaveContainers(bool saveIndividually, int totalNotMapped, int? updated, List saveContainers) + public void SaveContainers(bool saveIndividually, int? updated, List saveContainers) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -242,9 +240,9 @@ public class MapLogic : Shared.Models.Methods.IMapLogic int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); string message; if (updated is null) - message = $") {saveContainers.Count:000} save(s) - {totalNotMapped} Total not Mapped - {totalSeconds} total second(s)"; + message = $") {saveContainers.Count:000} save(s) - {totalSeconds} total second(s)"; else - message = $") {saveContainers.Count:000} save(s) - {totalNotMapped} Total not Mapped - {updated} Updated - {totalSeconds} total second(s)"; + message = $") {saveContainers.Count:000} save(s) - {updated} Updated - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; foreach (string directory in directories) { @@ -323,7 +321,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } foreach (SaveContainer saveContainer in saveContainers) { - if (string.IsNullOrEmpty(saveContainer.ShortcutFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.ShortcutFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) continue; try { @@ -366,11 +364,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - private string? GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem) + private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem) { - string? result = null; + long? ticks = null; const int zero = 0; string mappingSegmentB; + string? directory = null; string personKeyFormatted; PersonBirthday personBirthday; PersonContainer personContainer; @@ -380,25 +379,26 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0) continue; personBirthday = personContainer.Birthdays[zero]; + ticks = personBirthday.Value.Ticks; mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, mappingFromItem); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); if (!saveIndividually || segmentC is null) - result = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mappingSegmentB); + directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mappingSegmentB); else - result = Path.Combine(_EDistanceContentTicksDirectory, by, segmentC.PadLeft(padLeft, '0'), personKeyFormatted, mappingSegmentB); + directory = Path.Combine(_EDistanceContentTicksDirectory, by, segmentC.PadLeft(padLeft, '0'), personKeyFormatted, mappingSegmentB); _NotMappedPersonContainers.RemoveAt(i); break; } - return result; + return (ticks, directory); } - private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Mapping[] mappingCollection, Dictionary> idToWholePercentagesToMapping, Dictionary> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny) + private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyCollection mappingCollection, ReadOnlyDictionary> idToWholePercentagesToMapping, ReadOnlyDictionary> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); List results = new(); string by; - long ticks; + long? ticks; List? ids; long personKey; bool isByMapping; @@ -417,7 +417,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic SaveContainer? saveContainer; FileHolder facePartsFileHolder; FileHolder hiddenFaceFileHolder; - Dictionary? wholePercentagesToMapping; + ReadOnlyDictionary? wholePercentagesToMapping; int padLeft = _Configuration.FaceDistancePermyriad.ToString().Length; string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); foreach (Mapping mapping in mappingCollection) @@ -448,9 +448,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic continue; if (distinct.Contains(mapping.SortingContainer.Sorting.Id)) continue; - ticks = DateTime.Now.Ticks; - directory = GetDirectory(_Configuration, saveIndividually, padLeft, mapping.SegmentC, by, mapping.MappingFromItem); - if (string.IsNullOrEmpty(directory)) + (ticks, directory) = GetDirectory(_Configuration, saveIndividually, padLeft, mapping.SegmentC, by, mapping.MappingFromItem); + if (ticks is null || string.IsNullOrEmpty(directory)) continue; personDirectory = Path.Combine(directory, $"X]{ticks}"); if (saveIndividually) @@ -496,9 +495,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (!idToWholePercentagesToMapping.TryGetValue(mapping.SortingContainer.Sorting.Id, out wholePercentagesToMapping)) continue; - if (!wholePercentagesToMapping.ContainsKey(mapping.SortingContainer.Sorting.WholePercentages)) + if (!wholePercentagesToMapping.TryGetValue(mapping.SortingContainer.Sorting.WholePercentages, out keyMapping)) continue; - keyMapping = wholePercentagesToMapping[mapping.SortingContainer.Sorting.WholePercentages]; if (keyMapping.MappingFromLocation is null) continue; if (saveIndividually && keyMapping.MappingFromLocation.WholePercentages == mapping.MappingFromLocation.WholePercentages) @@ -520,9 +518,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectory(_PropertyConfiguration, d2FacePartsContentDirectory, mapping.MappingFromItem); facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}")); (saveContainer, SaveContainer? extraSaveContainer) = Stateless.MapLogic.GetContainers(_Configuration.FacesFileNameExtension, _Configuration.FacePartsFileNameExtension, directory, faceFileHolder, facePartsFileHolder, mapping); - if (extraSaveContainer is null) - continue; - results.Add(extraSaveContainer); + if (extraSaveContainer is not null) + results.Add(extraSaveContainer); } else { @@ -532,6 +529,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic 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 (!isByMapping && mapping.By is not null && mapping.MappingFromPerson?.LocationContainersFiles.Count > 0 && IPerson.IsDefaultName(mapping.MappingFromPerson)) + results.Add(new(Path.GetDirectoryName(personDirectory) ?? personDirectory, mapping.MappingFromPerson.LocationContainersFiles[0])); } } results.Add(saveContainer); @@ -557,18 +556,18 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public List GetSaveContainers(bool saveIndividually, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Mapping[] mappingCollection, Dictionary> idToWholePercentagesToMapping, int? useFiltersCounter, bool sortingContainersAny) + public List GetSaveContainers(bool saveIndividually, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyCollection mappingCollection, ReadOnlyDictionary> idToWholePercentagesToMapping, int? useFiltersCounter, bool sortingContainersAny) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); List results; bool saveMapped = false; - Dictionary> personKeyToIds = new(); + ReadOnlyDictionary> personKeyToIds = new(new Dictionary>()); results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, saveIndividually, sortingContainersAny); return results; } - public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, Dictionary> idToWholePercentagesToMapping, int totalNotMapped) + public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection mappingCollection, ReadOnlyDictionary> idToWholePercentagesToMapping) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -578,7 +577,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic bool saveIndividually = false; string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping)); List saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, mappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, saveIndividually: false); - SaveContainers(saveIndividually, totalNotMapped, updated, saveContainers); + SaveContainers(saveIndividually, updated, saveContainers); if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory)) Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory); } @@ -627,7 +626,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public int UpdateFromSortingContainers(bool saveIndividually, Shared.Models.Methods.IDistanceLimits distanceLimits, SortingContainer[] sortingContainers) + public int UpdateFromSortingContainers(bool saveIndividually, ReadOnlyDictionary> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, SortingContainer[] sortingContainers) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -638,19 +637,21 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } int result = 0; string key; + Mapping? mapping; const int zero = 0; string mappingSegmentB; string personKeyFormatted; PersonBirthday personBirthday; - List wholePercentagesCollectionForA; - List wholePercentagesCollectionForB; + List? wholePercentagesCollectionForA; + List? wholePercentagesCollectionForB; Dictionary keyToCount = new(); Dictionary keyToSegmentC = new(); ReadOnlyCollection? personContainers; + ReadOnlyDictionary? wholePercentagesToMapping; Dictionary> idToWholePercentagesCollectionForA = new(); Dictionary> idToWholePercentagesCollectionForB = new(); - ReadOnlyDictionary>? wholePercentagesToPersonContainers; int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); + ReadOnlyDictionary>? wholePercentagesToPersonContainers; string message = $") {sortingContainers.Length:000} Update From Sorting Container(s) - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using ProgressBar progressBar = new(sortingContainers.Length, message, options); @@ -659,12 +660,18 @@ public class MapLogic : Shared.Models.Methods.IMapLogic progressBar.Tick(); if (sortingContainer.Mapping?.MappingFromLocation is null) throw new NotSupportedException(); - if (!idToWholePercentagesCollectionForA.ContainsKey(sortingContainer.Mapping.MappingFromItem.Id)) + if (!idToWholePercentagesCollectionForA.TryGetValue(sortingContainer.Mapping.MappingFromItem.Id, out wholePercentagesCollectionForA)) + { idToWholePercentagesCollectionForA.Add(sortingContainer.Mapping.MappingFromItem.Id, new()); - wholePercentagesCollectionForA = idToWholePercentagesCollectionForA[sortingContainer.Mapping.MappingFromItem.Id]; - if (!idToWholePercentagesCollectionForB.ContainsKey(sortingContainer.Mapping.MappingFromItem.Id)) + if (!idToWholePercentagesCollectionForA.TryGetValue(sortingContainer.Mapping.MappingFromItem.Id, out wholePercentagesCollectionForA)) + throw new Exception(); + } + if (!idToWholePercentagesCollectionForB.TryGetValue(sortingContainer.Mapping.MappingFromItem.Id, out wholePercentagesCollectionForB)) + { idToWholePercentagesCollectionForB.Add(sortingContainer.Mapping.MappingFromItem.Id, new()); - wholePercentagesCollectionForB = idToWholePercentagesCollectionForB[sortingContainer.Mapping.MappingFromItem.Id]; + if (!idToWholePercentagesCollectionForB.TryGetValue(sortingContainer.Mapping.MappingFromItem.Id, out wholePercentagesCollectionForB)) + throw new Exception(); + } if (!_IdThenWholePercentagesToPersonContainers.TryGetValue(sortingContainer.Sorting.Id, out wholePercentagesToPersonContainers) || !wholePercentagesToPersonContainers.TryGetValue(sortingContainer.Sorting.WholePercentages, out personContainers)) { if (!_Configuration.SaveSortingWithoutPerson) @@ -699,7 +706,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic keyToCount[key] = 0; keyToSegmentC[key] = sortingContainer.Sorting.DistancePermyriad.ToString(); } - sortingContainer.Mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, personContainer.DisplayDirectoryName, personBirthday, mappingSegmentB, keyToSegmentC[key], sortingContainer); + if (!idToWholePercentagesToMapping.TryGetValue(sortingContainer.Sorting.Id, out wholePercentagesToMapping)) + continue; + if (!wholePercentagesToMapping.TryGetValue(sortingContainer.Sorting.WholePercentages, out mapping)) + continue; + if (mapping.MappingFromPerson is null) + continue; + sortingContainer.Mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, personContainer.DisplayDirectoryName, personBirthday, mappingSegmentB, keyToSegmentC[key], sortingContainer, mapping.MappingFromPerson.LocationContainersFiles); wholePercentagesCollectionForB.Add(sortingContainer.Mapping.MappingFromLocation.WholePercentages); result += 1; break; @@ -709,13 +722,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - public void CopyManualFiles(string dFacesContentDirectory, Dictionary> idToWholePercentagesToMapping) + public void CopyManualFiles(string dFacesContentDirectory, ReadOnlyDictionary> idToWholePercentagesToMapping) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); int? id; - Mapping mapping; string faceFile; + Mapping? mapping; string checkFile; string directory; FileInfo fileInfo; @@ -732,7 +745,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic PersonBirthday personBirthday; string? personDisplayDirectory; WindowsShortcut windowsShortcut; - Dictionary? wholePercentagesToMapping; + ReadOnlyDictionary? wholePercentagesToMapping; string by = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy); ReadOnlyDictionary>? wholePercentagesToPeronContainerCollection; string successful = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Successful"; @@ -759,9 +772,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personDirectory = Path.Combine(directory, personKeyToPersonContainer.Value.DisplayDirectoryName, "lnk"); if (!idToWholePercentagesToMapping.TryGetValue(id.Value, out wholePercentagesToMapping)) continue; - if (!wholePercentagesToMapping.ContainsKey(wholePercentages.Value)) + if (!wholePercentagesToMapping.TryGetValue(wholePercentages.Value, out mapping)) continue; - mapping = wholePercentagesToMapping[wholePercentages.Value]; if (mapping.MappingFromLocation is null) continue; if (string.IsNullOrEmpty(personDisplayDirectory)) @@ -808,139 +820,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - private List GetDirectories(string a2PeopleSingletonDirectory, Mapping[] mappingCollection) - { - if (_Configuration is null) - throw new NullReferenceException(nameof(_Configuration)); - List results = new(); - int count; - long personKey; - string directory; - string? directoryName; - PersonContainer? personContainer; - foreach (Mapping mapping in mappingCollection) - { - if (mapping.MappingFromLocation is null || mapping.MappingFromPerson is null) - continue; - if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting) - continue; - if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB)) - throw new NotSupportedException(); - if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName)) - throw new NotSupportedException(); - personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks; - if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists) - continue; - directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); - if (directoryName is null) - throw new NotSupportedException(); - if (!_PersonKeyToCount.TryGetValue(personKey, out count)) - continue; - if (!_PersonKeyToPersonContainer.TryGetValue(personKey, out personContainer)) - continue; - if (personContainer.PersonDirectory is null || !_Configuration.PersonCharacters.Contains(personContainer.PersonDirectory.Char)) - continue; - directory = Path.Combine(a2PeopleSingletonDirectory, personContainer.PersonDirectory.Char.ToString(), personContainer.PersonDirectory.Group, personContainer.DisplayDirectoryName, count.ToString("0000")); - if (results.Contains(directory)) - continue; - results.Add(directory); - } - return results; - } - - public void SavePersonKeyToCount(string dFacesContentDirectory, string a2PeopleSingletonDirectory, Mapping[] mappingCollection) - { - List directories = GetDirectories(a2PeopleSingletonDirectory, mappingCollection); - string directoryName; - string? personNameDirectory; - DateTime dateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day).AddDays(1); - foreach (string directory in directories) - { - if (Directory.Exists(directory)) - continue; - _ = Directory.CreateDirectory(directory); - directoryName = Path.GetFileName(directory); - personNameDirectory = Path.GetDirectoryName(directory); - if (string.IsNullOrEmpty(personNameDirectory)) - continue; - if (!int.TryParse(directoryName, out int count)) - continue; - Directory.SetLastWriteTime(personNameDirectory, dateTime.AddMinutes(count)); - } - } - - public void CopyAtLeastOneMappedFiles(int personCharactersCopyCount, string dFacesContentDirectory, string a2PeopleSingletonDirectory, Mapping[] mappingCollection) - { - if (_Configuration is null) - throw new NullReferenceException(nameof(_Configuration)); - string year; - long personKey; - string fileName; - string faceFile; - string directory; - string faceFileName; - string facesDirectory; - string? directoryName; - PersonContainer? personContainer; - Dictionary personKeyToCount = new(); - bool usePersonCharactersCopyCount = personCharactersCopyCount != int.MaxValue; - string delete = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Delete"; - foreach (Mapping mapping in mappingCollection) - { - directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); - if (directoryName is null) - throw new NotSupportedException(); - if (mapping.MappingFromLocation is null || mapping.MappingFromPerson is null) - continue; - if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists) - continue; - if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting) - continue; - if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB)) - throw new NotSupportedException(); - if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName)) - throw new NotSupportedException(); - facesDirectory = Stateless.MapLogic.GetFacesDirectory(_PropertyConfiguration, dFacesContentDirectory, mapping.MappingFromItem); - faceFileName = $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"; - faceFile = Path.Combine(facesDirectory, faceFileName); - personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks; - if (usePersonCharactersCopyCount) - { - if (!personKeyToCount.ContainsKey(personKey)) - personKeyToCount.Add(personKey, 0); - if (personKeyToCount[personKey] > personCharactersCopyCount) - continue; - } - if (!_PersonKeyToPersonContainer.TryGetValue(personKey, out personContainer)) - continue; - if (personContainer.PersonDirectory is null || !_Configuration.PersonCharacters.Contains(personContainer.PersonDirectory.Char)) - continue; - if (personContainer.DisplayDirectoryAllFiles.Any(l => l.EndsWith(faceFileName))) - continue; - if (!File.Exists(faceFile)) - continue; - directory = Path.Combine(a2PeopleSingletonDirectory, personContainer.PersonDirectory.Char.ToString(), personContainer.PersonDirectory.Group, personContainer.DisplayDirectoryName); - if (usePersonCharactersCopyCount) - { - if (!Directory.Exists(directory)) - continue; - } - else - { - year = mapping.MappingFromItem.IsWrongYear is null || mapping.MappingFromItem.IsWrongYear.Value ? "0000" : mapping.MappingFromItem.MinimumDateTime.ToString("yyyy"); - directory = Path.Combine(directory, delete, year); - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - } - fileName = Path.Combine(directory, faceFileName); - if (File.Exists(fileName)) - continue; - if (usePersonCharactersCopyCount) - personKeyToCount[personKey] += 1; - File.Copy(faceFile, fileName); - } - } - private (string, PersonBirthday?) GetPersonBirthday(string[] directoryNames) { if (_Configuration is null) @@ -1037,7 +916,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - private (int, FileHolder, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection personContainers, Mapping[] mappingCollection, Dictionary> personKeyToIds) + private (int, FileHolder, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection personContainers, ReadOnlyCollection mappingCollection, Dictionary> personKeyToIds) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1098,7 +977,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection personContainers, string a2PeopleContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, int totalNotMapped) + public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection personContainers, string a2PeopleContentDirectory, Dictionary> personKeyToIds, ReadOnlyCollection mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1113,10 +992,10 @@ public class MapLogic : Shared.Models.Methods.IMapLogic saveContainer = new(imageFileHolder, checkFile, directory); saveContainers.Add(saveContainer); } - SaveContainers(saveIndividually, totalNotMapped, null, saveContainers); + SaveContainers(saveIndividually, null, saveContainers); } - private List GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection) + private List GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, Dictionary> personKeyToIds, ReadOnlyCollection mappingCollection) { List results = new(); if (_Configuration is null) @@ -1163,7 +1042,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directory = Path.Combine($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); - if (IPerson.IsDefaultName(_Configuration.MappingDefaultName, mapping.MappingFromPerson.DisplayDirectoryName)) + if (IPerson.IsDefaultName(mapping.MappingFromPerson)) continue; directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); @@ -1172,7 +1051,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection) + public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, Dictionary> personKeyToIds, ReadOnlyCollection mappingCollection) { string hiddenFile; WindowsShortcut windowsShortcut; @@ -1211,7 +1090,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - private (List<(string, DateTime[])>, List) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(Dictionary> personKeyToIds, string dFacesContentDirectory, List filteredItems, Mapping[] mappingCollection) + private (List<(string, DateTime[])>, List) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyDictionary> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection filteredItems, ReadOnlyCollection mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1302,14 +1181,14 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return new(directoriesAndDateTimes, collection); } - public void SaveShortcutsForOutputResolutionsDuringMapLogic(Container[] containers, Dictionary> personKeyToIds, string dFacesContentDirectory, Mapping[] mappingCollection) + public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection containers, ReadOnlyDictionary> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); WindowsShortcut windowsShortcut; List<(string, DateTime[])> directoriesAndDateTimes; List collection; - List filteredItems = IContainer.GetItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true); + ReadOnlyCollection filteredItems = IContainer.GetItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true); (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, filteredItems, mappingCollection); string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); foreach (string directory in directories) @@ -1344,7 +1223,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - public Dictionary>> GetMissing(Dictionary> idToWholePercentagesToMapping) + public ReadOnlyDictionary>> GetMissing(ReadOnlyDictionary> idToWholePercentagesToMapping) { Dictionary>> results = new(); foreach (KeyValuePair>> idToCollection in _IdThenWholePercentagesToPersonContainers) @@ -1353,7 +1232,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic continue; results.Add(idToCollection.Key, idToCollection.Value); } - return results; + return new(results); } public ReadOnlyDictionary>? GetWholePercentagesToPersonContainers(int? id) @@ -1376,7 +1255,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers)) { - if (!ignoreXMatches || personContainers.All(l => l.ApproximateYears is null && l.DisplayDirectoryName.First() != 'X')) + if (!ignoreXMatches || personContainers.All(l => IPerson.IsDefaultName(l))) result = true; } } diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 5b847bf..1b0f9b1 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -168,7 +168,7 @@ internal abstract class MapLogic if (files.Length != 4) continue; collection = files.Select(l => new FileInfo(l)).ToArray(); - isDefault = alphaDirectoryName.First() == 'X' && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); + isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); if (isDefault) facesFileNames = (from l in collection where l.Extension == configuration.FacesFileNameExtension select l.FullName).ToArray(); else @@ -321,7 +321,7 @@ internal abstract class MapLogic { directoryNumber++; personDisplayDirectoryName = Path.GetFileName(personNameDirectory); - isDefault = personDisplayDirectoryName.First() == 'X' && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); + isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); if (isDefault && personDisplayDirectoryName.Length == 1) { if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) @@ -726,8 +726,10 @@ internal abstract class MapLogic } } - internal static void PossiblyRebuildPersonContainers(Configuration configuration, string? a2PeopleSingletonDirectory, List<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) + internal static void PossiblyRebuildPersonContainers(Configuration configuration, long ticks, string? a2PeopleSingletonDirectory, ReadOnlyDictionary readOnlyPersonKeyToCount, ReadOnlyCollection<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) { + int count; + long personKey; bool[] matches; string fileName; string checkFile; @@ -737,6 +739,7 @@ internal abstract class MapLogic List distinct = new(); PersonBirthday personBirthday; string personDisplayDirectory; + DateTime dateTime = new(ticks); string personKeyFormattedDirectory; foreach ((PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages, PersonContainer personContainer) in possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) { @@ -745,13 +748,8 @@ internal abstract class MapLogic if (a2PeopleSingletonDirectory is null || personContainer.Key is null || personContainer.Birthdays is null || personContainer.PersonDirectory is null || personContainer.Birthdays.Length == 0) continue; fileName = $"{Path.GetFileName(personKeyFormattedIdThenWholePercentages.MappedFaceFile)}{configuration.FacesHiddenFileNameExtension}"; - matches = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(fileName) select true).ToArray(); - if (matches.Length > 0) - continue; - matches = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(configuration.FacesHiddenFileNameExtension) select true).ToArray(); - if (matches.Length > 0) - continue; personBirthday = personContainer.Birthdays[zero]; + personKey = personBirthday.Value.Ticks; personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); personDisplayDirectory = Path.Combine(a2PeopleSingletonDirectory, personContainer.PersonDirectory.Char.ToString(), personContainer.PersonDirectory.Group, personContainer.DisplayDirectoryName); personKeyFormattedDirectory = Path.GetFullPath(Path.Combine(personDisplayDirectory, personKeyFormatted)); @@ -760,6 +758,15 @@ internal abstract class MapLogic throw new NotSupportedException(); if (!Directory.Exists(personKeyFormattedDirectory)) _ = Directory.CreateDirectory(personKeyFormattedDirectory); + _ = readOnlyPersonKeyToCount.TryGetValue(personKey, out count); + _ = Directory.CreateDirectory(Path.Combine(personDisplayDirectory, count.ToString("0000"))); + Directory.SetLastWriteTime(personDisplayDirectory, dateTime.AddMinutes(count)); + matches = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(fileName) select true).ToArray(); + if (matches.Length > 0) + continue; + matches = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(configuration.FacesHiddenFileNameExtension) select true).ToArray(); + if (matches.Length > 0) + continue; if (!File.Exists(personKeyFormattedIdThenWholePercentages.MappedFaceFile)) continue; checkFile = Path.Combine(personKeyFormattedDirectory, $"{Path.GetFileName(personKeyFormattedIdThenWholePercentages.MappedFaceFile)}{configuration.FacesHiddenFileNameExtension}"); @@ -790,6 +797,8 @@ internal abstract class MapLogic DateTime dateTime = DateTime.Now; for (int i = 1; i < 5; i++) _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); + if (!Directory.Exists(eDistanceContentDirectory)) + _ = Directory.CreateDirectory(eDistanceContentDirectory); string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string ticksDirectory in ticksDirectories) { @@ -1227,7 +1236,7 @@ internal abstract class MapLogic return results; } - internal static Mapping[] GetSelectedMappingCollection(List faces) + internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection faces) { Mapping[] results; IEnumerable collection = from l in faces orderby l.Mapping?.MappingFromItem.Id select l.Mapping; @@ -1235,7 +1244,7 @@ internal abstract class MapLogic return results; } - internal static List GetFaces(List items) + internal static ReadOnlyCollection GetFaces(ReadOnlyCollection items) { List results = new(); foreach (Item item in items) @@ -1249,18 +1258,26 @@ internal abstract class MapLogic results.Add(face); } } - return results; + return new(results); } - internal static Mapping[] GetSelectedMappingCollection(List items) + internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection items) { Mapping[] results; - List faces = GetFaces(items); + ReadOnlyCollection faces = GetFaces(items); results = GetSelectedMappingCollection(faces); return results; } - internal static Dictionary> GetIdToWholePercentagesToFace(Mapping[] mappingCollection) + private static ReadOnlyDictionary> GetReadOnly(Dictionary> keyValuePairs) + { + Dictionary> results = new(); + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return new(results); + } + + internal static ReadOnlyDictionary> GetIdToWholePercentagesToFace(ReadOnlyCollection mappingCollection) { Dictionary> results = new(); Dictionary? keyValuePairs; @@ -1278,7 +1295,7 @@ internal abstract class MapLogic continue; keyValuePairs.Add(mapping.MappingFromLocation.WholePercentages, mapping); } - return results; + return GetReadOnly(results); } private static string? TryToFind(char[] personCharacters, string a2PeopleSingletonDirectory, List<(string Directory, string DirectoryName, string DirectoryNameSplitFirst)> a2PeopleSingletonDirectories, string file, string path) diff --git a/Map/Models/Stateless/Methods/IMapLogic.cs b/Map/Models/Stateless/Methods/IMapLogic.cs index 8ed8acc..56bb680 100644 --- a/Map/Models/Stateless/Methods/IMapLogic.cs +++ b/Map/Models/Stateless/Methods/IMapLogic.cs @@ -1,3 +1,5 @@ +using System.Collections.ObjectModel; + namespace View_by_Distance.Map.Models.Stateless.Methods; public interface IMapLogic @@ -8,24 +10,24 @@ public interface IMapLogic static Dictionary> GetIdToPersonKeys(Dictionary> personKeyToIds) => MapLogic.GetIdToPersonKeys(personKeyToIds); - List TestStatic_GetFaces(List items) => + ReadOnlyCollection TestStatic_GetFaces(ReadOnlyCollection items) => GetFaces(items); - static List GetFaces(List items) => + static ReadOnlyCollection GetFaces(ReadOnlyCollection items) => MapLogic.GetFaces(items); - Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(List items) => + Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection items) => GetSelectedMappingCollection(items); - static Shared.Models.Mapping[] GetSelectedMappingCollection(List items) => + static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection items) => MapLogic.GetSelectedMappingCollection(items); - Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(List faces) => + Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection faces) => GetSelectedMappingCollection(faces); - static Shared.Models.Mapping[] GetSelectedMappingCollection(List faces) => + static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection faces) => MapLogic.GetSelectedMappingCollection(faces); - Dictionary> TestStatic_GetIdToWholePercentagesToFace(Shared.Models.Mapping[] mappingCollection) => + ReadOnlyDictionary> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection mappingCollection) => GetIdToWholePercentagesToFace(mappingCollection); - static Dictionary> GetIdToWholePercentagesToFace(Shared.Models.Mapping[] mappingCollection) => + static ReadOnlyDictionary> GetIdToWholePercentagesToFace(ReadOnlyCollection mappingCollection) => MapLogic.GetIdToWholePercentagesToFace(mappingCollection); List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) => diff --git a/PhotoPrism/Models/_F_PhotoPrism.cs b/PhotoPrism/Models/_F_PhotoPrism.cs index 1328c0d..16695e0 100644 --- a/PhotoPrism/Models/_F_PhotoPrism.cs +++ b/PhotoPrism/Models/_F_PhotoPrism.cs @@ -141,7 +141,7 @@ public class F_PhotoPrism return results; } - private static void PopulateSubjects(string mappingDefaultName, string personBirthdayFormat, List subjects, StringBuilder stringBuilder, ReadOnlyCollection personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection) + private static void PopulateSubjects(string personBirthdayFormat, List subjects, StringBuilder stringBuilder, ReadOnlyCollection personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection) { long? personKey; const int zero = 0; @@ -153,7 +153,7 @@ public class F_PhotoPrism { if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0) continue; - if (IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName)) + if (IPerson.IsDefaultName(personContainer)) continue; personBirthday = personContainer.Birthdays[zero]; personKey = personBirthday.Value.Ticks; @@ -169,7 +169,7 @@ public class F_PhotoPrism } } - public static void WriteMatches(string fPhotoPrismContentDirectory, string mappingDefaultName, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, List distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic) + public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, ReadOnlyCollection distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic) { string file; string text; @@ -224,7 +224,7 @@ public class F_PhotoPrism if (collection.Count == 0) continue; sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray(); - PopulateSubjects(mappingDefaultName, personBirthdayFormat, subjects, stringBuilder, personContainers, sortedCollection); + PopulateSubjects(personBirthdayFormat, subjects, stringBuilder, personContainers, sortedCollection); } if (subjects.Count > 0) { diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index e9dc39c..39d9d64 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -57,12 +57,11 @@ public class Mapping : Properties.IMapping _MappingFromPerson = new(approximateYears, displayDirectoryName, locationContainersFiles, personBirthday, segmentB); } - public void UpdateMappingFromPerson(int? approximateYears, string displayDirectoryName, PersonBirthday personBirthday, string segmentB, string segmentC, SortingContainer sortingContainer) + public void UpdateMappingFromPerson(int? approximateYears, string displayDirectoryName, PersonBirthday personBirthday, string segmentB, string segmentC, SortingContainer sortingContainer, ReadOnlyCollection locationContainersFiles) { _SegmentC = segmentC; _By = Stateless.IMapLogic.Sorting; _SortingContainer = sortingContainer; - ReadOnlyCollection locationContainersFiles = new(Array.Empty()); _MappingFromPerson = new(approximateYears, displayDirectoryName, locationContainersFiles, personBirthday, segmentB); } diff --git a/Shared/Models/SaveContainer.cs b/Shared/Models/SaveContainer.cs index 84be9ae..eff3e08 100644 --- a/Shared/Models/SaveContainer.cs +++ b/Shared/Models/SaveContainer.cs @@ -32,6 +32,10 @@ public class SaveContainer this(string.Empty, directory, null, null, null, false, null, string.Empty) { } + public SaveContainer(string directory, string locationContainersFile) : + this(string.Empty, directory, null, null, null, false, new(locationContainersFile), Path.Combine(directory, $"{Path.GetFileName(locationContainersFile)}.lnk")) + { } + public SaveContainer(string directory, FileHolder? faceFileHolder, FileHolder? resizedFileHolder, string shortcutFile) : this(string.Empty, directory, faceFileHolder, null, null, true, resizedFileHolder, shortcutFile) { } diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs index 299cb82..c358675 100644 --- a/Shared/Models/Stateless/Methods/Container.cs +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Text.Json; namespace View_by_Distance.Shared.Models.Stateless.Methods; @@ -250,7 +251,7 @@ internal abstract class Container return results; } - internal static List GetItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container[] containers, bool distinctItems, bool filterItems) + internal static ReadOnlyCollection GetItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection containers, bool distinctItems, bool filterItems) { List results = new(); List distinct = new(); @@ -280,7 +281,7 @@ internal abstract class Container results.Add(item); } } - return results; + return new(results); } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IContainer.cs b/Shared/Models/Stateless/Methods/IContainer.cs index 1e5fa79..da6ffe3 100644 --- a/Shared/Models/Stateless/Methods/IContainer.cs +++ b/Shared/Models/Stateless/Methods/IContainer.cs @@ -1,3 +1,5 @@ +using System.Collections.ObjectModel; + namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IContainer @@ -43,9 +45,9 @@ public interface IContainer static List GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, Models.Container[] containers) => Container.GetFilteredDistinctIds(propertyConfiguration, containers); - List TestStatic_GetItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container[] containers, bool distinctItems, bool filterItems) => + ReadOnlyCollection TestStatic_GetItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection containers, bool distinctItems, bool filterItems) => GetItems(propertyConfiguration, containers, distinctItems, filterItems); - static List GetItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container[] containers, bool distinctItems, bool filterItems) => + static ReadOnlyCollection GetItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection containers, bool distinctItems, bool filterItems) => Container.GetItems(propertyConfiguration, containers, distinctItems, filterItems); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPerson.cs b/Shared/Models/Stateless/Methods/IPerson.cs index f6b80e6..c99f9f3 100644 --- a/Shared/Models/Stateless/Methods/IPerson.cs +++ b/Shared/Models/Stateless/Methods/IPerson.cs @@ -37,9 +37,19 @@ public interface IPerson hour == 17 ? "Dead-Male-No" : throw new NotImplementedException(personDisplayDirectoryName); - bool TestStatic_IsDefaultName(string mappingDefaultName, string personDisplayDirectoryName) => - IsDefaultName(mappingDefaultName, personDisplayDirectoryName); - static bool IsDefaultName(string mappingDefaultName, string personDisplayDirectoryName) => - personDisplayDirectoryName == mappingDefaultName || (personDisplayDirectoryName.Length > 1 && personDisplayDirectoryName[0] == 'X' && personDisplayDirectoryName[1] == ']'); + bool TestStatic_IsDefaultName(string personDisplayDirectoryName) => + IsDefaultName(personDisplayDirectoryName); + static bool IsDefaultName(string personDisplayDirectoryName) => + personDisplayDirectoryName.Length > 1 && personDisplayDirectoryName[0] == 'X' && personDisplayDirectoryName[1] == ']'; + + bool TestStatic_IsDefaultName(Models.PersonContainer personContainer) => + IsDefaultName(personContainer); + static bool IsDefaultName(Models.PersonContainer personContainer) => + personContainer.ApproximateYears is null || IsDefaultName(personContainer.DisplayDirectoryName); + + bool TestStatic_IsDefaultName(MappingFromPerson mappingFromPerson) => + IsDefaultName(mappingFromPerson); + static bool IsDefaultName(MappingFromPerson mappingFromPerson) => + mappingFromPerson.ApproximateYears is null || IsDefaultName(mappingFromPerson.DisplayDirectoryName); } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 5156828..7a946b6 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -263,7 +263,7 @@ public class UnitTestFace collection = faceRecognition.GetCollection(image, locations: new(), includeFaceEncoding: true, includeFaceParts: true); Assert.IsTrue(collection.Count == 1); List faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList(); - List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]); + List faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncodings[0]); Assert.IsTrue(faceDistanceLengths.Count == 1); Assert.IsNotNull(sourceFileName); NonThrowTryCatch();