diff --git a/.vscode/settings.json b/.vscode/settings.json index 76213b0..bfdac37 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,5 +40,6 @@ "files.exclude": { "**/.git": false }, - "coverage-gutters.coverageBaseDir": "./.vscode/ReportGenerator/Cobertura/*" + "coverage-gutters.coverageBaseDir": "./.vscode/ReportGenerator/Cobertura/*", + "extensions.ignoreRecommendations": true } \ No newline at end of file diff --git a/Distance/Models/MapLogicSupport.cs b/Distance/Models/MapLogicSupport.cs index 6f9bb2e..467f5e2 100644 --- a/Distance/Models/MapLogicSupport.cs +++ b/Distance/Models/MapLogicSupport.cs @@ -1,9 +1,7 @@ using ShellProgressBar; -using System.Text.Json; using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Map.Models; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Distance.Models; @@ -15,19 +13,38 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport private int _Distance; private int _Confidence; - private readonly int _FaceConfidencePercent; - private readonly int _FaceDistancePermyriad; - private readonly int[] _RangeDaysDeltaTolerance; - private readonly int[] _RangeFaceAreaPermilleTolerance; + private readonly double _FaceAreaPermille; + private readonly double _RangeDaysDeltaTolerance; + private readonly double _FaceConfidencePercent; + private readonly double _FaceDistancePermyriad; private readonly int _SortingMaximumPerFaceShouldBeHigh; + private readonly bool _RangeDaysDeltaTargetLessThenUpper; - public MapLogicSupport(int faceConfidencePercent, int faceDistancePermyriad, int[] rangeDaysDeltaTolerance, int[] rangeFaceAreaPermilleTolerance, int sortingMaximumPerFaceShouldBeHigh) + public MapLogicSupport(int faceConfidencePercent, + int faceDistancePermyriad, + int[] rangeDaysDeltaTolerance, + double[] rangeDistanceTolerance, + int[] rangeFaceAreaPermilleTolerance, + double[] rangeFaceConfidence, + int sortingMaximumPerFaceShouldBeHigh, + int? useFiltersCounter = null) { - _FaceConfidencePercent = faceConfidencePercent; - _FaceDistancePermyriad = faceDistancePermyriad; - _RangeDaysDeltaTolerance = rangeDaysDeltaTolerance; - _RangeFaceAreaPermilleTolerance = rangeFaceAreaPermilleTolerance; _SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + _RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2]; + if (useFiltersCounter is null) + { + _FaceAreaPermille = rangeFaceAreaPermilleTolerance[1]; + _RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1]; + _FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1]; + _FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1]; + } + else + { + _RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[1]; + _FaceConfidencePercent = faceConfidencePercent * ((rangeFaceConfidence[2] - rangeFaceConfidence[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceConfidence[1]; + _FaceAreaPermille = ((rangeFaceAreaPermilleTolerance[2] - rangeFaceAreaPermilleTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceAreaPermilleTolerance[1]; + _FaceDistancePermyriad = faceDistancePermyriad * ((rangeDistanceTolerance[2] - rangeDistanceTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDistanceTolerance[1]; + } } public static void SaveFaceDistances(Property.Models.Configuration configuration, SortingContainer[] sortingContainers) @@ -42,118 +59,33 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport File.WriteAllLines(eDistanceContentFileName, results); } - private List GetSortingContainers(Configuration mapConfiguration, Face face, FaceDistance faceDistanceEncoding, List sortingCollection, int? useFiltersCounter) + private List GetSortingContainers(Configuration mapConfiguration, Face face, FaceDistance faceDistanceEncoding, List sortingCollection) { List results = new(); SortingContainer sortingContainer; Sorting[] collection = Shared.Models.Stateless.Methods.ISorting.Sort(sortingCollection); - double a; - double b; - double c; - double d; - double faceAreaPermille; - double faceConfidencePercent; - double faceDistancePermyriad; - double rangeDaysDeltaTolerance; - if (useFiltersCounter is null) - { - a = 1f; - b = 1f; - c = 1f; - d = 1f; - } - else if (useFiltersCounter.Value < 5) - { - a = 1.25f; - b = 0.8f; - c = a; - d = b; - } - else if (useFiltersCounter.Value < 9) - { - a = 1.5f; - b = 0.667f; - c = a; - d = b; - } - else if (useFiltersCounter.Value < 13) - { - a = 1.75f; - b = 0.571f; - c = a; - d = b; - } - else - { - a = 2f; - b = 0.5f; - c = a; - d = b; - } - if (useFiltersCounter is null) - { - rangeDaysDeltaTolerance = _RangeDaysDeltaTolerance[1]; - faceDistancePermyriad = _FaceDistancePermyriad; - faceConfidencePercent = _FaceConfidencePercent; - faceAreaPermille = _RangeFaceAreaPermilleTolerance[1]; - } - else if (useFiltersCounter.Value is 1 or 5 or 9 or 13) - { - rangeDaysDeltaTolerance = _RangeDaysDeltaTolerance[1] * a; - faceDistancePermyriad = _FaceDistancePermyriad * c; - faceConfidencePercent = _FaceConfidencePercent * d; - faceAreaPermille = _RangeFaceAreaPermilleTolerance[1] * d; - } - else if (useFiltersCounter.Value is 2 or 6 or 10 or 14) - { - rangeDaysDeltaTolerance = _RangeDaysDeltaTolerance[1] * c; - faceDistancePermyriad = _FaceDistancePermyriad * a; - faceConfidencePercent = _FaceConfidencePercent * d; - faceAreaPermille = _RangeFaceAreaPermilleTolerance[1] * d; - } - else if (useFiltersCounter.Value is 3 or 7 or 11 or 15) - { - rangeDaysDeltaTolerance = _RangeDaysDeltaTolerance[1] * c; - faceDistancePermyriad = _FaceDistancePermyriad * c; - faceConfidencePercent = _FaceConfidencePercent * b; - faceAreaPermille = _RangeFaceAreaPermilleTolerance[1] * d; - } - else if (useFiltersCounter.Value is 4 or 8 or 12 or 16) - { - rangeDaysDeltaTolerance = _RangeDaysDeltaTolerance[1] * c; - faceDistancePermyriad = _FaceDistancePermyriad * c; - faceConfidencePercent = _FaceConfidencePercent * d; - faceAreaPermille = _RangeFaceAreaPermilleTolerance[1] * b; - } - else - { - rangeDaysDeltaTolerance = int.MaxValue; - faceDistancePermyriad = int.MaxValue; - faceAreaPermille = 0; - faceConfidencePercent = 0; - } foreach (Sorting sorting in collection) { - if (face.Mapping is null || faceDistanceEncoding.NormalizedRectangle is null) + if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.NormalizedRectangle is null) throw new NotSupportedException(); if (!mapConfiguration.SaveSortingWithoutPerson && face.Mapping.MappingFromPerson is null) continue; - if (sorting.DaysDelta > rangeDaysDeltaTolerance) + if (sorting.DaysDelta > _RangeDaysDeltaTolerance) { _Days += 1; continue; } - if (sorting.DistancePermyriad > faceDistancePermyriad) + if (sorting.DistancePermyriad > _FaceDistancePermyriad) { _Distance += 1; continue; } - if (face.Mapping.MappingFromLocation.ConfidencePercent < faceConfidencePercent) + if (face.Mapping.MappingFromLocation.ConfidencePercent < _FaceConfidencePercent) { _Confidence += 1; continue; } - if (face.Mapping.MappingFromLocation.AreaPermille < faceAreaPermille) + if (face.Mapping.MappingFromLocation.AreaPermille < _FaceAreaPermille) { _Area += 1; continue; @@ -182,7 +114,7 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport List collection = new(); foreach (Face face in distinctFilteredFaces) { - if (face.Mapping is null) + if (face.Mapping?.MappingFromLocation is null) throw new NotSupportedException(); if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) continue; @@ -212,7 +144,7 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport return faceDistanceEncodings; } - public SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Configuration mapConfiguration, long ticks, MapLogic mapLogic, List distinctFilteredFaces, List missingFaceDistanceContainers, int? useFiltersCounter) + public SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Configuration mapConfiguration, long ticks, MapLogic mapLogic, List distinctFilteredFaces, List missingFaceDistanceContainers) { SortingContainer[] results; List collection = new(); @@ -235,7 +167,7 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport List sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, i, faceDistanceEncoding); if (!sortingCollection.Any()) return; - List sortingContainers = GetSortingContainers(mapConfiguration, face, faceDistanceEncoding, sortingCollection, useFiltersCounter); + List sortingContainers = GetSortingContainers(mapConfiguration, face, faceDistanceEncoding, sortingCollection); if (sortingContainers.Any()) { lock (collection) @@ -246,7 +178,7 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport results = Array.Empty(); else { - if (_RangeDaysDeltaTolerance[1] > _RangeDaysDeltaTolerance[2]) + if (_RangeDaysDeltaTargetLessThenUpper) results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(collection); else results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(collection); @@ -272,7 +204,7 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport _ = Parallel.For(0, distinctFilteredFaces.Count, parallelOptions, (i, state) => { Face face = distinctFilteredFaces[i]; - if (face.FaceEncoding is null || face.Mapping is null) + if (face.FaceEncoding is null || face.Mapping?.MappingFromLocation is null) throw new NotSupportedException(); if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) return; @@ -284,62 +216,14 @@ public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport }); } - void Shared.Models.Methods.IMapLogicSupport.SavePossiblyNewPersonContainers(IPropertyConfiguration propertyConfiguration, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, string? a2PeopleSingletonDirectory, Dictionary personKeyToPersonContainer, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) - { - string json; - string[] files; - string checkFile; - string[] segments; - const int zero = 0; - char personCharacter; - string personKeyFormatted; - string personDisplayDirectory; - PersonBirthday personBirthday; - string personDisplayDirectoryName; - string checkPersonDisplayDirectory; - string checkPersonKeyFormattedDirectory; - JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; - foreach ((string[] personDisplayDirectoryNames, PersonContainer personContainer) in possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) - { - if (a2PeopleSingletonDirectory is null || personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) - continue; - personBirthday = personContainer.Birthdays[zero]; - personDisplayDirectoryName = personDisplayDirectoryNames[^1]; - personDisplayDirectory = Path.Combine(personDisplayDirectoryNames); - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); - segments = personDisplayDirectoryName.Split(personCharacters); - if (segments.Length != 2) - personCharacter = '_'; - else - personCharacter = personDisplayDirectoryName[segments[zero].Length]; - checkPersonDisplayDirectory = Path.Combine(a2PeopleSingletonDirectory, personCharacter.ToString(), personDisplayDirectoryName); - checkPersonKeyFormattedDirectory = Path.Combine(checkPersonDisplayDirectory, personKeyFormatted); - if (Directory.Exists(checkPersonKeyFormattedDirectory)) - continue; - _ = Directory.CreateDirectory(checkPersonKeyFormattedDirectory); - checkFile = Path.Combine(checkPersonKeyFormattedDirectory, $"{personKeyFormatted}.json"); - json = JsonSerializer.Serialize(personContainer.Person, jsonSerializerOptions); - _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); - if (!Directory.Exists(personDisplayDirectory)) - continue; - files = Directory.GetFiles(personDisplayDirectory, $"*{facesFileNameExtension}", SearchOption.TopDirectoryOnly); - foreach (string file in files) - { - checkFile = Path.Combine(checkPersonDisplayDirectory, Path.GetFileName(file)); - if (File.Exists(checkFile)) - continue; - File.Copy(files[0], checkFile); - break; - } - } - } - public static Dictionary> GetIdToNormalizedRectangleToFace(Mapping[] mappingCollection) { Dictionary> results = new(); Dictionary? keyValuePairs; foreach (Mapping mapping in mappingCollection) { + if (mapping.MappingFromLocation is null) + continue; if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs)) { results.Add(mapping.MappingFromItem.Id, new()); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index cfb9531..67694f2 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -598,7 +598,7 @@ public partial class DlibDotNet DateTime[] containerDateTimes; string deterministicHashCodeKey; MappingFromItem mappingFromItem; - MappingFromLocation mappingFromLocation; + MappingFromLocation? mappingFromLocation; List? mappingFromPhotoPrismCollection; foreach (Container container in containers) { @@ -618,12 +618,15 @@ public partial class DlibDotNet foreach (Shared.Models.Face face in item.Faces) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) - continue; - confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_Configuration.FaceConfidencePercent, _Configuration.RangeFaceConfidence, face.Location.Confidence); - faceAreaPermille = Shared.Models.Stateless.Methods.IMapping.GetAreaPermille(_Configuration.FaceAreaPermille, face.Location, face.OutputResolution); - normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - mappingFromLocation = new(faceAreaPermille, confidencePercent, deterministicHashCodeKey, normalizedRectangle); + mappingFromLocation = null; + else + { + confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_Configuration.FaceConfidencePercent, _Configuration.RangeFaceConfidence, face.Location.Confidence); + faceAreaPermille = Shared.Models.Stateless.Methods.IMapping.GetAreaPermille(_Configuration.FaceAreaPermille, face.Location, face.OutputResolution); + normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); + mappingFromLocation = new(faceAreaPermille, confidencePercent, deterministicHashCodeKey, normalizedRectangle); + } if (!fileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection)) mappingFromPhotoPrismCollection = null; mapping = new(mappingFromItem, mappingFromLocation, mappingFromPhotoPrismCollection); @@ -695,7 +698,7 @@ public partial class DlibDotNet return items; } - private void MapLogic(string argZero, long ticks, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string fPhotoPrismContentDirectory, MapLogicSupport mapLogicSupport, MapLogic mapLogic, string outputResolution, Dictionary> personKeyToIds, List distinctFilteredFaces, Mapping[] mappingCollection, int totalNotMapped) + 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) { int? useFiltersCounter = null; SortingContainer[] sortingContainers; @@ -708,7 +711,7 @@ public partial class DlibDotNet if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) { List filteredItems = GetItems(argZero, containers); - mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, filteredItems, mappingCollection); + mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, filteredItems, mappingCollection); } if (_Configuration.PersonCharactersCopyCount > 0 && !string.IsNullOrEmpty(_Configuration.PersonCharacters)) mapLogic.CopyAtLeastOneMappedFiles(dFacesContentDirectory, a2PeopleSingletonDirectory, mappingCollection); @@ -717,16 +720,19 @@ public partial class DlibDotNet mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, personKeyToIds, mappingCollection, idToNormalizedRectangleToMapping, totalNotMapped); if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) { + MapLogicSupport mapLogicSupport; MapLogicSupport.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); List distinctFurtherFilteredFaces = mapLogic.GetFurtherFilterBySkipCollection(distinctFilteredFaces); Dictionary> missingIdThenNormalizedRectangleToPersonContainers = mapLogic.GetMissing(idToNormalizedRectangleToMapping); List missingFaceDistanceContainers = _Distance.GetMissingFaceDistanceContainer(_AppSettings.MaxDegreeOfParallelism, ticks, dFacesCollectionDirectory, missingIdThenNormalizedRectangleToPersonContainers); - sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers, useFiltersCounter); + mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh); + sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers); if (!sortingContainers.Any()) { for (useFiltersCounter = 1; useFiltersCounter < 17; useFiltersCounter++) { - sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers, useFiltersCounter); + mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh, useFiltersCounter); + sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers); if (sortingContainers.Any()) break; } @@ -734,7 +740,7 @@ public partial class DlibDotNet MapLogicSupport.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); if (totalNotMapped > 0) { - int updated = mapLogic.UpdateFromSortingContainers(sortingContainers); + int updated = mapLogic.UpdateFromSortingContainers(mapLogicSupport, sortingContainers); List saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, useFiltersCounter, sortingContainers.Any()); mapLogic.SaveContainers(totalNotMapped, updated, saveContainers); } @@ -1043,14 +1049,13 @@ public partial class DlibDotNet propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); } containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); - MapLogicSupport mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.SortingMaximumPerFaceShouldBeHigh); - MapLogic? mapLogic = _Configuration.DistanceMoveUnableToMatch ? null : new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport); + MapLogic? mapLogic = _Configuration.DistanceMoveUnableToMatch ? null : new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory); personKeyToIds = mapLogic is null ? new() : mapLogic.GetPersonKeyToIds(); fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); Dictionary>> idToLocationContainers = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, eDistanceContentDirectory, fileNameToCollection, idToLocationContainers); _Distance.Clear(); - mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport); + mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory); SetMapping(fileNameToCollection, argZero, containers); if (!personKeyToIds.Any()) personKeyToIds = mapLogic.GetPersonKeyToIds(); @@ -1076,7 +1081,7 @@ public partial class DlibDotNet && outputResolution == _Configuration.OutputResolutions[0] && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Exceptions.Count == 0) - MapLogic(argZero, ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogicSupport, mapLogic, outputResolution, personKeyToIds, distinctFilteredFaces, mappingCollection, totalNotMapped); + MapLogic(argZero, ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogic, outputResolution, personKeyToIds, distinctFilteredFaces, mappingCollection, totalNotMapped); if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Any() && mappingCollection.Any()) _Random.Random(_Configuration.PropertyConfiguration, outputResolution, personKeyToIds, mappingCollection); if (_IsEnvironment.Development) diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 001dbd7..ac2412e 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -55,15 +55,15 @@ public class Configuration public bool PropertiesChangedForMetadata { init; get; } public bool PropertiesChangedForResize { init; get; } public int[] RangeDaysDeltaTolerance { init; get; } + public double[] RangeDistanceTolerance { init; get; } public int[] RangeFaceAreaPermilleTolerance { init; get; } public double[] RangeFaceConfidence { init; get; } - public double[] RangeDistanceTolerance { init; get; } public bool Reverse { init; get; } public string[] SaveFaceDistancesForOutputResolutions { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; } + public string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions { init; get; } public bool SaveFullYearOfRandomFiles { init; get; } public string[] SaveMappedForOutputResolutions { init; get; } - public string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions { init; get; } public string[] SaveRandomForOutputResolutions { init; get; } public bool SaveResizedSubfiles { init; get; } public string[] SaveShortcutsForOutputResolutions { init; get; } diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 5c16513..99c6847 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -25,14 +25,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic private readonly int _MaxDegreeOfParallelism; private readonly Configuration? _Configuration; private readonly string _EDistanceContentTicksDirectory; - private readonly Shared.Models.Methods.IMapLogicSupport? _MapLogicSupport; private readonly Shared.Models.Properties.IPropertyConfiguration _PropertyConfiguration; - public MapLogic(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, long ticks, PersonContainer[] personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, Shared.Models.Methods.IMapLogicSupport? mapLogicSupport) + public MapLogic(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, long ticks, PersonContainer[] personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) { _Ticks = ticks; _Configuration = configuration; - _MapLogicSupport = mapLogicSupport; _Log = Serilog.Log.ForContext(); _PropertyConfiguration = propertyConfiguration; _MaxDegreeOfParallelism = maxDegreeOfParallelism; @@ -60,16 +58,14 @@ public class MapLogic : Shared.Models.Methods.IMapLogic _ = Directory.CreateDirectory(eDistanceContentDirectory); if (!Directory.Exists(eDistanceContentTicksDirectory)) _ = Directory.CreateDirectory(eDistanceContentTicksDirectory); - if (configuration is not null && mapLogicSupport is not null) + if (configuration is not null) { List personContainerCollection = new(personContainers); - Stateless.MapLogic.Set(propertyConfiguration, - configuration, + Stateless.MapLogic.Set(configuration, ticks, personContainerCollection, a2PeopleSingletonDirectory, eDistanceContentDirectory, - mapLogicSupport, personKeyToPersonContainer, notMappedPersonContainers, skipCollection, @@ -185,6 +181,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic Dictionary? normalizedRectangleToPersonContainers; foreach (Mapping mapping in mappingCollection) { + if (mapping.MappingFromLocation is null) + continue; if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(mapping.MappingFromItem.Id, out normalizedRectangleToPersonContainers)) { if (_SkipCollection.TryGetValue(mapping.MappingFromItem.Id, out normalizedRectangles) && normalizedRectangles.Contains(mapping.MappingFromLocation.NormalizedRectangle)) @@ -335,7 +333,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic SaveContainer? result; string shortcutFile = string.Empty; string? facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); - if (facesDirectory is null) + if (facesDirectory is null || mapping.MappingFromLocation is null) result = null; else { @@ -446,6 +444,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); foreach (Mapping mapping in mappingCollection) { + if (mapping.MappingFromLocation is null) + continue; directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); if (directoryName is null) throw new NotSupportedException(); @@ -462,7 +462,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (sortingContainersAny) continue; - mapping.UpdateMappingFromUnknownPerson(new(mapping, new(mapping))); + mapping.UpdateMappingFromUnknownPerson(new(mapping, new(mapping, mapping.MappingFromLocation))); if (mapping.SortingContainer is null) continue; } @@ -626,13 +626,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public int UpdateFromSortingContainers(SortingContainer[] sortingContainers) + public int UpdateFromSortingContainers(Shared.Models.Methods.IMapLogicSupport mapLogicSupport, SortingContainer[] sortingContainers) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); - if (_MapLogicSupport is not null) + if (mapLogicSupport is not null) { - string counts = _MapLogicSupport.GetCounts(); + string counts = mapLogicSupport.GetCounts(); _ = Directory.CreateDirectory(Path.Combine(_EDistanceContentTicksDirectory, counts)); } int result = 0; @@ -656,7 +656,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic foreach (SortingContainer sortingContainer in sortingContainers) { progressBar.Tick(); - if (sortingContainer.Mapping is null) + if (sortingContainer.Mapping?.MappingFromLocation is null) throw new NotSupportedException(); if (!idToNormalizedRectangleCollectionForA.ContainsKey(sortingContainer.Mapping.MappingFromItem.Id)) idToNormalizedRectangleCollectionForA.Add(sortingContainer.Mapping.MappingFromItem.Id, new()); @@ -761,6 +761,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (!normalizedRectangleToMapping.ContainsKey(normalizedRectangle.Value)) continue; mapping = normalizedRectangleToMapping[normalizedRectangle.Value]; + if (mapping.MappingFromLocation is null) + continue; if (string.IsNullOrEmpty(personDisplayDirectory)) throw new NotSupportedException(); directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); @@ -822,7 +824,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); if (directoryName is null) throw new NotSupportedException(); - if (mapping.MappingFromPerson is null) + if (mapping.MappingFromLocation is null || mapping.MappingFromPerson is null) continue; if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists) continue; @@ -903,8 +905,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); - if (_MapLogicSupport is null) - throw new NullReferenceException(nameof(_MapLogicSupport)); List results = new(); string[] files; string checkDirectory; @@ -979,7 +979,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NotSupportedException(); if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting) continue; - if (mapping.MappingFromPerson?.ApproximateYears is null) + if (mapping.MappingFromPerson?.ApproximateYears is null || mapping.MappingFromLocation is null) continue; if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB)) throw new NotSupportedException(); @@ -1097,7 +1097,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic Dictionary> idToPersonKeys = Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); foreach (Mapping mapping in mappingCollection) { - if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null || mapping.MappingFromPerson is null) + if (mapping.MappingFromLocation is null || mapping.MappingFromItem.ImageFileHolder.DirectoryName is null || mapping.MappingFromPerson is null) continue; if (!idToLocationContainers.TryGetValue(mapping.MappingFromItem.Id, out locationContainers) || !locationContainers.Any()) directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(mapping.MappingFromItem.ResizedFileHolder.FullName); @@ -1112,9 +1112,9 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (!string.IsNullOrEmpty(model) && !string.IsNullOrEmpty(model.Trim())) { model = Regex.Replace(model, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"); - directory = Path.Combine(eDistanceContentDirectory, "Model Shortcuts", model, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); + directory = Path.Combine($"{eDistanceContentDirectory}---", "Model Shortcuts", model, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: false)); } if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys)) continue; @@ -1122,12 +1122,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (!personKeys.Contains(mapping.MappingFromPerson.PersonBirthday.Value.Ticks)) continue; personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday); - directory = Path.Combine(eDistanceContentDirectory, "Person Key Shortcuts", personKeyFormatted, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); + directory = Path.Combine($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); - directory = Path.Combine(eDistanceContentDirectory, "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: false)); + directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: false)); } return results; } @@ -1151,9 +1151,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic hiddenFile = $"{s.FileName}.lvs"; if (File.Exists(hiddenFile)) continue; - File.WriteAllLines(hiddenFile, new string[] { s.FullName, s.Description }); - File.SetAttributes(hiddenFile, FileAttributes.Hidden); - File.SetLastWriteTime(hiddenFile, s.DateTime); + if (s.Description is not null) + { + File.WriteAllLines(hiddenFile, new string[] { s.FullName, s.Description }); + File.SetAttributes(hiddenFile, FileAttributes.Hidden); + File.SetLastWriteTime(hiddenFile, s.DateTime); + } if (File.Exists(s.FileName)) continue; try @@ -1168,15 +1171,17 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - private (List<(string, DateTime[])>, List) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(Dictionary> personKeyToIds, List filteredItems, Mapping[] mappingCollection) + private (List<(string, DateTime[])>, List) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(Dictionary> personKeyToIds, string dFacesContentDirectory, List filteredItems, Mapping[] mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); long personKey; string fileName; + string fullName; string directory; string? directoryName; string personDirectory; + string? facesDirectory; string personKeyFormatted; List distinct = new(); List collection = new(); @@ -1185,9 +1190,11 @@ public class MapLogic : Shared.Models.Methods.IMapLogic { if (item.ResizedFileHolder is null) continue; + if (item.Faces.Any(l => l.FaceEncoding is not null)) + continue; foreach (Face face in item.Faces) { - if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null) + if (face.Mapping is null) continue; directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath); if (directoryName is null) @@ -1197,7 +1204,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directory = Path.Combine(item.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne); personDirectory = Path.Combine(directory, "No Faces"); fileName = Path.Combine(personDirectory, $"{item.ResizedFileHolder.Name}.lnk"); - collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, item.ImageFileHolder.LastWriteTime.Value, fileName, face.Mapping.MappingFromItem.Id.ToString())); + collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, item.ImageFileHolder.LastWriteTime.Value, fileName, face.Mapping.MappingFromItem.Id.ToString(), MakeAllHidden: false)); if (face.Mapping.MappingFromItem.ContainerDateTimes.Any() && !distinct.Contains(item.ResizedFileHolder.DirectoryName)) { distinct.Add(item.ResizedFileHolder.DirectoryName); @@ -1222,7 +1229,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne); 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)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); + facesDirectory = 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}"); + fileName = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ResizedFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}.lnk"); + collection.Add(new(fullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true)); } else { @@ -1243,20 +1256,20 @@ public class MapLogic : Shared.Models.Methods.IMapLogic else personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{personKeyToIds[personKey].Count} Face(s)"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); - collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); } } return new(directoriesAndDateTimes, collection); } - public void SaveShortcutsForOutputResolutionsDuringMapLogic(Dictionary> personKeyToIds, List filteredItems, Mapping[] mappingCollection) + public void SaveShortcutsForOutputResolutionsDuringMapLogic(Dictionary> personKeyToIds, string dFacesContentDirectory, List filteredItems, Mapping[] mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); WindowsShortcut windowsShortcut; List<(string, DateTime[])> directoriesAndDateTimes; List collection; - (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, filteredItems, mappingCollection); + (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, filteredItems, mappingCollection); string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); foreach (string directory in directories) { @@ -1274,6 +1287,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic windowsShortcut = new() { Path = s.FullName, Description = s.Description }; windowsShortcut.Save(s.FileName); windowsShortcut.Dispose(); + if (s.MakeAllHidden) + File.SetAttributes(s.FileName, FileAttributes.Hidden); File.SetLastWriteTime(s.FileName, s.DateTime); } catch (Exception) @@ -1306,7 +1321,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic List? normalizedRectangles; foreach (Face face in distinctFilteredFaces) { - if (face.Mapping is null) + if (face.Mapping?.MappingFromLocation is null) continue; if (_SkipCollection.TryGetValue(face.Mapping.MappingFromItem.Id, out normalizedRectangles) && normalizedRectangles.Contains(face.Mapping.MappingFromLocation.NormalizedRectangle)) continue; diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index bb89d49..d76db7d 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -1,5 +1,6 @@ using Humanizer; using ShellProgressBar; +using System.Text.Json; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless.Methods; using WindowsShortcutFactory; @@ -503,7 +504,57 @@ internal abstract class MapLogic } } - internal static void Set(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, long ticks, List personContainers, string? a2PeopleContentDirectory, string eDistanceContentDirectory, Shared.Models.Methods.IMapLogicSupport mapLogicSupport, Dictionary personKeyToPersonContainer, List notMappedPersonContainers, Dictionary> skipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers) + static void SavePossiblyNewPersonContainers(string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, string? a2PeopleSingletonDirectory, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) + { + string json; + string[] files; + string checkFile; + string[] segments; + const int zero = 0; + char personCharacter; + string personKeyFormatted; + string personDisplayDirectory; + PersonBirthday personBirthday; + string personDisplayDirectoryName; + string checkPersonDisplayDirectory; + string checkPersonKeyFormattedDirectory; + JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; + foreach ((string[] personDisplayDirectoryNames, PersonContainer personContainer) in possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) + { + if (a2PeopleSingletonDirectory is null || personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) + continue; + personBirthday = personContainer.Birthdays[zero]; + personDisplayDirectoryName = personDisplayDirectoryNames[^1]; + personDisplayDirectory = Path.Combine(personDisplayDirectoryNames); + personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); + segments = personDisplayDirectoryName.Split(personCharacters); + if (segments.Length != 2) + personCharacter = '_'; + else + personCharacter = personDisplayDirectoryName[segments[zero].Length]; + checkPersonDisplayDirectory = Path.Combine(a2PeopleSingletonDirectory, personCharacter.ToString(), personDisplayDirectoryName); + checkPersonKeyFormattedDirectory = Path.Combine(checkPersonDisplayDirectory, personKeyFormatted); + if (Directory.Exists(checkPersonKeyFormattedDirectory)) + continue; + _ = Directory.CreateDirectory(checkPersonKeyFormattedDirectory); + checkFile = Path.Combine(checkPersonKeyFormattedDirectory, $"{personKeyFormatted}.json"); + json = JsonSerializer.Serialize(personContainer.Person, jsonSerializerOptions); + _ = IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + if (!Directory.Exists(personDisplayDirectory)) + continue; + files = Directory.GetFiles(personDisplayDirectory, $"*{facesFileNameExtension}", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + checkFile = Path.Combine(checkPersonDisplayDirectory, Path.GetFileName(file)); + if (File.Exists(checkFile)) + continue; + File.Copy(files[0], checkFile); + break; + } + } + } + + internal static void Set(Configuration? configuration, long ticks, List personContainers, string? a2PeopleContentDirectory, string eDistanceContentDirectory, Dictionary personKeyToPersonContainer, List notMappedPersonContainers, Dictionary> skipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers) { if (configuration is null) throw new NullReferenceException(nameof(configuration)); @@ -543,7 +594,7 @@ internal abstract class MapLogic notMappedPersonContainers.AddRange(GetNotMappedPersonContainers(configuration, personContainers, personKeys, personKeyCollection)); AppendToSkipCollection(skipCollection, idThenNormalizedRectangleToPersonContainers, incorrectIdThenNormalizedRectangleToPersonContainers); if (possiblyNewPersonDisplayDirectoryNamesAndPersonContainer.Any()) - mapLogicSupport.SavePossiblyNewPersonContainers(propertyConfiguration, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), configuration.FacesFileNameExtension, a2PeopleContentDirectory, personKeyToPersonContainer, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); + SavePossiblyNewPersonContainers(configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), configuration.FacesFileNameExtension, a2PeopleContentDirectory, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long minimumDateTimeTicks, bool? isWrongYear) @@ -587,6 +638,8 @@ internal abstract class MapLogic internal static SaveContainer GetDebugSaveContainer(string directory, SortingContainer sortingContainer, Mapping mapping) { SaveContainer result; + if (sortingContainer.Mapping.MappingFromLocation is null) + throw new NullReferenceException(nameof(sortingContainer.Mapping.MappingFromLocation)); FileHolder faceFileHolder = new($"C:/{sortingContainer.Sorting.Id}.{sortingContainer.Sorting.NormalizedRectangle}"); string shortcutFile = Path.Combine(directory, $"{sortingContainer.Mapping.MappingFromLocation.DeterministicHashCodeKey}{sortingContainer.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.debug.lnk"); result = new(directory, faceFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile); diff --git a/PhotoPrism/Models/_F_PhotoPrism.cs b/PhotoPrism/Models/_F_PhotoPrism.cs index 9981df3..8071bdb 100644 --- a/PhotoPrism/Models/_F_PhotoPrism.cs +++ b/PhotoPrism/Models/_F_PhotoPrism.cs @@ -109,7 +109,7 @@ public class F_PhotoPrism foreach (Face face in distinctFilteredFaces) { collection.Clear(); - normalizedRectangle = face.Mapping?.MappingFromLocation.NormalizedRectangle; + normalizedRectangle = face.Mapping?.MappingFromLocation?.NormalizedRectangle; if (normalizedRectangle is null) continue; if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null) diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index 5524d8f..e20dbcd 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -123,14 +123,14 @@ public class Mapping : Properties.IMapping protected SortingContainer? _SortingContainer; public int? By => _By; public MappingFromItem MappingFromItem { init; get; } - public MappingFromLocation MappingFromLocation { init; get; } + public MappingFromLocation? MappingFromLocation { init; get; } public List? MappingFromPhotoPrismCollection { init; get; } public MappingFromPerson? MappingFromPerson => _MappingFromPerson; public string? SegmentC => _SegmentC; public SortingContainer? SortingContainer => _SortingContainer; [JsonConstructor] - public Mapping(int? by, MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation, List? mappingFromPhotoPrismCollection, MappingFromPerson? mappingFromPerson, string? segmentC, SortingContainer? sortingContainer) + public Mapping(int? by, MappingFromItem mappingFromItem, MappingFromLocation? mappingFromLocation, List? mappingFromPhotoPrismCollection, MappingFromPerson? mappingFromPerson, string? segmentC, SortingContainer? sortingContainer) { _By = by; _SegmentC = segmentC; @@ -141,7 +141,7 @@ public class Mapping : Properties.IMapping _SortingContainer = sortingContainer; } - public Mapping(MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation, List? mappingFromPhotoPrismCollection) : + public Mapping(MappingFromItem mappingFromItem, MappingFromLocation? mappingFromLocation, List? mappingFromPhotoPrismCollection) : this(null, mappingFromItem, mappingFromLocation, mappingFromPhotoPrismCollection, null, null, null) { } diff --git a/Shared/Models/Methods/IMapLogicSupport.cs b/Shared/Models/Methods/IMapLogicSupport.cs index d8e1b1d..7620b41 100644 --- a/Shared/Models/Methods/IMapLogicSupport.cs +++ b/Shared/Models/Methods/IMapLogicSupport.cs @@ -4,6 +4,5 @@ public interface IMapLogicSupport { string GetCounts(); - void SavePossiblyNewPersonContainers(Properties.IPropertyConfiguration propertyConfiguration, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, string? a2PeopleContentDirectory, Dictionary personKeyToPersonContainer, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } \ No newline at end of file diff --git a/Shared/Models/Properties/IMapping.cs b/Shared/Models/Properties/IMapping.cs index 315f3c4..6adee17 100644 --- a/Shared/Models/Properties/IMapping.cs +++ b/Shared/Models/Properties/IMapping.cs @@ -47,7 +47,7 @@ public interface IMapping public int? By { get; } public string? SegmentC { get; } public MappingFromItem MappingFromItem { init; get; } - public MappingFromLocation MappingFromLocation { init; get; } + public MappingFromLocation? MappingFromLocation { init; get; } public List? MappingFromPhotoPrismCollection { init; get; } public MappingFromPerson? MappingFromPerson { get; } public SortingContainer? SortingContainer { get; } diff --git a/Shared/Models/SaveShortcutsForOutputResolutions.cs b/Shared/Models/SaveShortcutsForOutputResolutions.cs index a94f08a..0ffba5d 100644 --- a/Shared/Models/SaveShortcutsForOutputResolutions.cs +++ b/Shared/Models/SaveShortcutsForOutputResolutions.cs @@ -1,4 +1,4 @@ namespace View_by_Distance.Shared.Models; -public record SaveShortcutsForOutputResolutions(string FullName, string Directory, DateTime DateTime, string FileName, string Description) +public record SaveShortcutsForOutputResolutions(string FullName, string Directory, DateTime DateTime, string FileName, string? Description, bool MakeAllHidden) { } \ No newline at end of file diff --git a/Shared/Models/Sorting.cs b/Shared/Models/Sorting.cs index e0bfaa7..eb9e14c 100644 --- a/Shared/Models/Sorting.cs +++ b/Shared/Models/Sorting.cs @@ -22,8 +22,8 @@ public record class Sorting : Properties.ISorting Older = older; } - public Sorting(Mapping mapping) : - this(0, 0, mapping.MappingFromItem.Id, mapping.MappingFromLocation.NormalizedRectangle, false) + public Sorting(Mapping mapping, MappingFromLocation mappingFromLocation) : + this(0, 0, mapping.MappingFromItem.Id, mappingFromLocation.NormalizedRectangle, false) { } public override string ToString() diff --git a/Shared/Models/SortingContainer.cs b/Shared/Models/SortingContainer.cs index 834354e..e73687f 100644 --- a/Shared/Models/SortingContainer.cs +++ b/Shared/Models/SortingContainer.cs @@ -17,7 +17,7 @@ public record class SortingContainer : Properties.ISortingContainer public override string ToString() { - string result = string.Concat(Mapping.MappingFromItem.Id, '\t', Mapping.MappingFromLocation.NormalizedRectangle, '\t', Sorting.Id, '\t', Sorting.NormalizedRectangle, '\t', Sorting.Older, '\t', '\t', Sorting.DistancePermyriad, '\t', Sorting.DaysDelta); + string result = string.Concat(Mapping.MappingFromItem.Id, '\t', Mapping.MappingFromLocation?.NormalizedRectangle, '\t', Sorting.Id, '\t', Sorting.NormalizedRectangle, '\t', Sorting.Older, '\t', '\t', Sorting.DistancePermyriad, '\t', Sorting.DaysDelta); return result; }