diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index b6c272a..1bac4f3 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -40,7 +40,6 @@ public partial class DlibDotNet private readonly Models.Configuration _Configuration; private readonly bool _ArgZeroIsConfigurationRootDirectory; private readonly Map.Models.Configuration _MapConfiguration; - private readonly Dictionary> _FileNameToCollection; public DlibDotNet( List args, @@ -54,7 +53,6 @@ public partial class DlibDotNet string message; _Console = console; _AppSettings = appSettings; - _FileNameToCollection = new(); _IsEnvironment = isEnvironment; long ticks = DateTime.Now.Ticks; _Exceptions = new List(); @@ -209,7 +207,7 @@ public partial class DlibDotNet private void Verify(Models.Configuration configuration) { if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0])) - throw new NullReferenceException($"{nameof(configuration.OutputResolutions)} must be _FileNameToCollection valid outputResolution!"); + throw new NullReferenceException($"{nameof(configuration.OutputResolutions)} must be fileNameToCollection valid outputResolution!"); if ((from l in configuration.OutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) throw new Exception($"One or more {nameof(configuration.OutputResolutions)} are not in the ValidResolutions list!"); if ((from l in configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) @@ -253,13 +251,13 @@ public partial class DlibDotNet string[] segments = sourceDirectoryNames[0].Split(' '); century = segments[^1].Length == 4 ? segments[^1][..2] : null; if (segments.Length < 2 || century is null || (century != "18" && century != "19" && century != "20")) - throw new Exception("root subdirectory must have _FileNameToCollection year at the end or directory name needs to be added to the exclude list!"); + throw new Exception("root subdirectory must have fileNameToCollection year at the end or directory name needs to be added to the exclude list!"); } } } string[] resizeMatch = (from l in sourceDirectoryNames where configuration.ValidResolutions.Contains(l) select l).ToArray(); if (resizeMatch.Any()) - throw new Exception("Input directory should be the source and not _FileNameToCollection resized directory!"); + throw new Exception("Input directory should be the source and not fileNameToCollection resized directory!"); if (configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits) throw new Exception("Configuration has to match interface!"); if (configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor) @@ -287,7 +285,26 @@ public partial class DlibDotNet return result; } - private void FullParallelForWork(A_Property propertyLogic, Dictionary>> idToMappedFaceFilesWithCollection, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsDateGroupDirectory, string dResultsFullGroupDirectory, string eDistanceContentDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List> imageFaceCollections, Container container, int index, Item item, DateTime[] containerDateTimes) + private void FullParallelForWork( + A_Property propertyLogic, + Dictionary>> idToMappedFaceFilesWithCollection, + string outputResolution, + string bResultsFullGroupDirectory, + string cResultsFullGroupDirectory, + string dResultsDateGroupDirectory, + string dResultsFullGroupDirectory, + string eDistanceContentDirectory, + List> sourceDirectoryChanges, + List propertyFileHolderCollection, + List propertyCollection, + List>> metadataCollections, + List> resizeKeyValuePairs, + Dictionary> fileNameToCollection, + List> imageFaceCollections, + Container container, + int index, + Item item, + DateTime[] containerDateTimes) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -364,7 +381,7 @@ public partial class DlibDotNet collection = null; else _ = idToMappedFaceFilesWithCollection.TryGetValue(item.Property.Id.Value, out collection); - if (!_FileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection)) + if (!fileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection)) mappingFromPhotoPrismCollection = null; faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, collection, mappingFromPhotoPrismCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) @@ -410,6 +427,7 @@ public partial class DlibDotNet List propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, + Dictionary> fileNameToCollection, List> imageFaceCollections, Container container, Item[] filteredItems, @@ -453,6 +471,7 @@ public partial class DlibDotNet propertyCollection, metadataCollection, resizeKeyValuePairs, + fileNameToCollection, imageFaceCollections, container, index: i, @@ -627,7 +646,7 @@ public partial class DlibDotNet _Metadata.SetAngleBracketCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, container.SourceDirectory); } - private void FullDoWork(string argZero, string propertyRoot, long ticks, A_Property propertyLogic, int t, Container[] containers, string? a2PeopleContentDirectory, string eDistanceContentDirectory) + private void FullDoWork(string argZero, string propertyRoot, long ticks, A_Property propertyLogic, int t, Container[] containers, string eDistanceContentDirectory, Dictionary> fileNameToCollection, Dictionary>> idToMappedFaceFilesWithCollection) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -651,7 +670,6 @@ public partial class DlibDotNet int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; List nullablePropertyCollection = new(); List>> metadataCollection = new(); - Dictionary>> idToMappedFaceFilesWithCollection = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); foreach (string outputResolution in _Configuration.OutputResolutions) { @@ -696,6 +714,7 @@ public partial class DlibDotNet nullablePropertyCollection, metadataCollection, resizeKeyValuePairs, + fileNameToCollection, imageFaceCollections, container, filteredItems, @@ -801,8 +820,16 @@ public partial class DlibDotNet } if (renameCollection.Any()) { - foreach (string rename in renameCollection) - File.Move(rename, $"{rename}.abd"); + string checkFile; + foreach (string file in renameCollection) + { + if (!File.Exists(file)) + continue; + checkFile = $"{file}.abd"; + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + } throw new Exception($"Renamed {renameCollection.Count}(s) files!"); } } @@ -824,18 +851,26 @@ public partial class DlibDotNet } if (renameCollection.Any()) { - foreach (string rename in renameCollection) - File.Move(rename, $"{rename}.mvd"); + string checkFile; + foreach (string file in renameCollection) + { + if (!File.Exists(file)) + continue; + checkFile = $"{file}.mvd"; + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + } throw new Exception($"Renamed {renameCollection.Count}(s) files!"); } } - private List GetFilteredDistinctFaces(string argZero, Container[] containers) + private (List, List) GetFilteredDistinct(string argZero, Container[] containers) { - List results = new(); + List resultIds = new(); + List resultFaces = new(); Item[] filteredItems; bool isIgnoreRelativePath; - List distinct = new(); foreach (Container container in containers) { if (!container.Items.Any()) @@ -850,20 +885,20 @@ public partial class DlibDotNet { if (item.Property?.Id is null || item.ResizedFileHolder is null) continue; - if (distinct.Contains(item.Property.Id.Value)) + if (resultIds.Contains(item.Property.Id.Value)) continue; - distinct.Add(item.Property.Id.Value); + resultIds.Add(item.Property.Id.Value); if (isIgnoreRelativePath) continue; foreach (Shared.Models.Face face in item.Faces) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) continue; - results.Add(face); + resultFaces.Add(face); } } } - return results; + return new(resultIds, resultFaces); } private List GetItems(string argZero, Container[] containers) @@ -892,7 +927,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, List distinctFilteredFaces, Mapping[] mappingCollection, int totalNotMapped, Dictionary personKeyToCount) + 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) { int? useFiltersCounter = null; SortingContainer[] sortingContainers; @@ -905,13 +940,13 @@ public partial class DlibDotNet if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) { List filteredItems = GetItems(argZero, containers); - mapLogic.SaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount); + mapLogic.SaveShortcutsForOutputResolutions(personKeyToIds, filteredItems, mappingCollection); } if (_Configuration.PersonCharactersCopyCount > 0 && !string.IsNullOrEmpty(_Configuration.PersonCharacters)) mapLogic.CopyAtLeastOneMappedFiles(dFacesContentDirectory, a2PeopleSingletonDirectory, mappingCollection); mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping); if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, totalNotMapped); + mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, personKeyToIds, mappingCollection, idToNormalizedRectangleToMapping, totalNotMapped); if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) { MapLogicSupport.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); @@ -984,7 +1019,7 @@ public partial class DlibDotNet bool isValidImageFormatExtension; for (int y = 0; y < int.MaxValue; y++) { - _Log.Information("Enter _FileNameToCollection url for _FileNameToCollection image"); + _Log.Information("Enter fileNameToCollection url for fileNameToCollection image"); line = _Console.ReadLine(); if (string.IsNullOrEmpty(line)) break; @@ -1154,6 +1189,36 @@ public partial class DlibDotNet return results; } + private static void LookForAbandoned(Dictionary>> idToMappedFaceFilesWithCollection, List distinctFilteredIds) + { + List renameCollection = new(); + foreach (KeyValuePair>> idToCollection in idToMappedFaceFilesWithCollection) + { + if (distinctFilteredIds.Contains(idToCollection.Key)) + continue; + foreach (LocationContainer locationContainer in idToCollection.Value) + { + if (locationContainer.File.Contains('!')) + continue; + renameCollection.Add(locationContainer.File); + } + } + if (renameCollection.Any()) + { + string checkFile; + foreach (string file in renameCollection) + { + if (!File.Exists(file)) + continue; + checkFile = $"{file}.abd"; + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + } + throw new Exception($"Renamed {renameCollection.Count}(s) files!"); + } + } + private void Search(long ticks, string argZero, string propertyRoot) { int f; @@ -1169,6 +1234,8 @@ public partial class DlibDotNet string d2ResultsFullGroupDirectory; string fPhotoPrismContentDirectory; string fPhotoPrismSingletonDirectory; + Dictionary> personKeyToIds; + Dictionary> fileNameToCollection; string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string message = $") Building Container(s) - {totalSeconds} total second(s)"; @@ -1210,19 +1277,18 @@ public partial class DlibDotNet 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); - if (Directory.Exists(fPhotoPrismSingletonDirectory)) - { - Dictionary> fileNameToCollection = F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); - foreach (KeyValuePair> keyValuePair in fileNameToCollection) - _FileNameToCollection.Add(keyValuePair.Key, keyValuePair.Value); - } - FullDoWork(argZero, propertyRoot, ticks, propertyLogic, t, containers, a2PeopleContentDirectory, eDistanceContentDirectory); + personKeyToIds = mapLogic is null ? new() : mapLogic.GetPersonKeyToIds(); + fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); + Dictionary>> idToMappedFaceFilesWithCollection = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); + FullDoWork(argZero, propertyRoot, ticks, propertyLogic, t, containers, eDistanceContentDirectory, fileNameToCollection, idToMappedFaceFilesWithCollection); _Distance.Clear(); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport); - SetMapping(_FileNameToCollection, argZero, containers); - List distinctFilteredFaces = GetFilteredDistinctFaces(argZero, containers); + SetMapping(fileNameToCollection, argZero, containers); + if (!personKeyToIds.Any()) + personKeyToIds = mapLogic.GetPersonKeyToIds(); + (List distinctFilteredIds, List distinctFilteredFaces) = GetFilteredDistinct(argZero, containers); + LookForAbandoned(idToMappedFaceFilesWithCollection, distinctFilteredIds); Mapping[] mappingCollection = MapLogicSupport.GetSelectedMappingCollection(distinctFilteredFaces); - Dictionary personKeyToCount = mapLogic.GetPersonKeyToCount(mappingCollection); int totalNotMapped = mapLogic.UpdateMappingFromPerson(mappingCollection); if (a2PeopleContentDirectory is not null && false) mapLogic.CreateTree(ticks, a2PeopleContentDirectory); @@ -1230,17 +1296,19 @@ public partial class DlibDotNet { if (_PropertyRootExistedBefore || container is not null) break; - (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); + if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveShortcutsForOutputResolutions(a2PeopleContentDirectory, personKeyToIds, mappingCollection, totalNotMapped); if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, _PersonContainers, a2PeopleContentDirectory, mappingCollection, personKeyToCount, totalNotMapped); + mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, _PersonContainers, a2PeopleContentDirectory, personKeyToIds, mappingCollection, totalNotMapped); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); if (_ArgZeroIsConfigurationRootDirectory && _Configuration.SaveResizedSubfiles && outputResolution == _Configuration.OutputResolutions[0] && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Exceptions.Count == 0) - MapLogic(argZero, ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogicSupport, mapLogic, outputResolution, distinctFilteredFaces, mappingCollection, totalNotMapped, personKeyToCount); + MapLogic(argZero, ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, fPhotoPrismContentDirectory, mapLogicSupport, mapLogic, outputResolution, personKeyToIds, distinctFilteredFaces, mappingCollection, totalNotMapped); if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution)) - _Random.Random(_Configuration.PropertyConfiguration, mapLogic, outputResolution, mappingCollection); + _Random.Random(_Configuration.PropertyConfiguration, outputResolution, personKeyToIds, mappingCollection); if (_IsEnvironment.Development) continue; G2_Identify identify = new(_Configuration); diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index a003244..47795cf 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -43,14 +43,15 @@ internal class F_Random return result; } - private static Dictionary> Get(Map.Models.MapLogic mapLogic, Shared.Models.Mapping[] mappingCollection, string dateFormat) + private static Dictionary> Get(Dictionary> personKeyToIds, Shared.Models.Mapping[] mappingCollection, string dateFormat) { Dictionary> results = new(); string key; + long personKey; DateTime dateTime; List? personKeys; List? relativePaths; - Dictionary> idToPersonKeys = mapLogic.GetIdToPeronKeys(); + Dictionary> idToPersonKeys = Map.Models.Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); foreach (Shared.Models.Mapping mapping in mappingCollection) { if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null || mapping.MappingFromPerson is null) @@ -59,7 +60,8 @@ internal class F_Random continue; if (!personKeys.Contains(mapping.MappingFromPerson.PersonBirthday.Value.Ticks)) continue; - dateTime = new(mapping.MappingFromPerson.PersonBirthday.Value.Ticks); + personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks; + dateTime = new(personKey); key = dateTime.ToString(dateFormat); if (!results.TryGetValue(key, out relativePaths)) { @@ -72,7 +74,7 @@ internal class F_Random return results; } - internal void Random(Property.Models.Configuration configuration, Map.Models.MapLogic mapLogic, string outputResolution, Shared.Models.Mapping[] mappingCollection) + internal void Random(Property.Models.Configuration configuration, string outputResolution, Dictionary> personKeyToIds, Shared.Models.Mapping[] mappingCollection) { string key; string json; @@ -82,7 +84,7 @@ internal class F_Random string dateFormat = "MM-dd"; List relativePaths = new(); DateTime dateTime = new(2024, 1, 1); //Leap year - Dictionary> dayToRelativePaths = Get(mapLogic, mappingCollection, dateFormat); + Dictionary> dayToRelativePaths = Get(personKeyToIds, mappingCollection, dateFormat); string fRandomCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "[]"); string[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string file in files) diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index b176410..2d418d1 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -1,5 +1,6 @@ using Humanizer; using ShellProgressBar; +using System.Collections.ObjectModel; using System.Text.Json; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless.Methods; @@ -10,10 +11,10 @@ namespace View_by_Distance.Map.Models; public class MapLogic : Shared.Models.Methods.IMapLogic { - protected readonly Dictionary> _SkipCollection; protected readonly List _NotMappedPersonContainers; - protected readonly Dictionary _PersonKeyToPersonContainer; - protected readonly Dictionary> _IdThenNormalizedRectangleToPersonContainers; + protected readonly ReadOnlyDictionary> _SkipCollection; + protected readonly ReadOnlyDictionary _PersonKeyToPersonContainer; + protected readonly ReadOnlyDictionary> _IdThenNormalizedRectangleToPersonContainers; public Dictionary KeyValuePairs => throw new NotImplementedException(); public Dictionary IndicesFromNew => throw new NotImplementedException(); @@ -87,11 +88,11 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (collection is null) throw new NullReferenceException(nameof(collection)); } - _SkipCollection = skipCollection; - _PersonKeyToPersonContainer = personKeyToPersonContainer; + _SkipCollection = new(skipCollection); + _PersonKeyToPersonContainer = new(personKeyToPersonContainer); _EDistanceContentTicksDirectory = eDistanceContentTicksDirectory; - _IdThenNormalizedRectangleToPersonContainers = idThenNormalizedRectangleToPersonContainers; _NotMappedPersonContainers = notMappedPersonContainers.OrderByDescending(l => l.Key).ToList(); + _IdThenNormalizedRectangleToPersonContainers = new(idThenNormalizedRectangleToPersonContainers); } public override string ToString() @@ -131,36 +132,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - private static Dictionary> GetIdToPersonKeys(Dictionary> keyValuePairs) + public Dictionary> GetPersonKeyToIds() { - Dictionary> results = new(); - List? collection; - foreach (KeyValuePair> keyValuePair in keyValuePairs) - { - foreach (int id in keyValuePair.Value) - { - if (!results.TryGetValue(id, out collection)) - { - results.Add(id, new()); - if (!results.TryGetValue(id, out collection)) - throw new Exception(); - } - if (collection.Contains(keyValuePair.Key)) - continue; - collection.Add(keyValuePair.Key); - } - } - return results; - } - - public Dictionary> GetIdToPeronKeys() - { - Dictionary> results; - long key; + Dictionary> results = new(); + long personKey; const int zero = 0; List? collection; PersonBirthday personBirthday; - Dictionary> keyValuePairs = new(); foreach (KeyValuePair> idToCollection in _IdThenNormalizedRectangleToPersonContainers) { foreach (KeyValuePair normalizedRectangleToPersonContainers in idToCollection.Value) @@ -172,11 +150,11 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personBirthday = personContainer.Birthdays[zero]; if (IPersonBirthday.IsCounterPersonBirthday(personBirthday)) continue; - key = personBirthday.Value.Ticks; - if (!keyValuePairs.TryGetValue(key, out collection)) + personKey = personBirthday.Value.Ticks; + if (!results.TryGetValue(personKey, out collection)) { - keyValuePairs.Add(key, new()); - if (!keyValuePairs.TryGetValue(key, out collection)) + results.Add(personKey, new()); + if (!results.TryGetValue(personKey, out collection)) throw new Exception(); } if (collection.Contains(idToCollection.Key)) @@ -185,7 +163,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } } - results = GetIdToPersonKeys(keyValuePairs); return results; } @@ -236,36 +213,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - public Dictionary GetPersonKeyToCount(Mapping[] mappingCollection) - { - if (_Configuration is null) - throw new NullReferenceException(nameof(_Configuration)); - Dictionary results = new(); - long personKey; - const int zero = 0; - PersonBirthday personBirthday; - PersonContainer[]? personContainers; - Dictionary? normalizedRectangleToPersonContainers; - foreach (Mapping mapping in mappingCollection) - { - if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(mapping.MappingFromItem.Id, out normalizedRectangleToPersonContainers)) - continue; - if (!normalizedRectangleToPersonContainers.TryGetValue(mapping.MappingFromLocation.NormalizedRectangle, out personContainers)) - continue; - foreach (PersonContainer personContainer in personContainers) - { - if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) - continue; - personBirthday = personContainer.Birthdays[zero]; - personKey = personBirthday.Value.Ticks; - if (!results.ContainsKey(personKey)) - results.Add(personKey, 0); - results[personKey] += 1; - } - } - return results; - } - public void SaveContainers(int totalNotMapped, int? updated, List saveContainers) { if (_Configuration is null) @@ -472,12 +419,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return result; } - private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, Dictionary personKeyToCount, int? useFiltersCounter, bool saveMapped, bool sortingContainersAny) + private List GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, Dictionary> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool sortingContainersAny) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); List results = new(); string by; + List? ids; long personKey; bool isByMapping; bool isBySorting; @@ -546,9 +494,9 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, "lnk"); else personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName[..1], "lnk"); - if (isByMapping && personKeyToCount.TryGetValue(personKey, out int count)) + if (isByMapping && personKeyToIds.TryGetValue(personKey, out ids)) { - saveContainer = new(Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{count} Face(s)")); + saveContainer = new(Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{ids.Count} Face(s)")); results.Add(saveContainer); } } @@ -604,12 +552,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NullReferenceException(nameof(_Configuration)); List results; bool saveMapped = false; - Dictionary personKeyToCount = new(); - results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, useFiltersCounter, saveMapped, sortingContainersAny); + Dictionary> personKeyToIds = new(); + results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny); return results; } - public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, Dictionary personKeyToCount, int totalNotMapped) + public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, Dictionary> idToNormalizedRectangleToMapping, int totalNotMapped) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -617,7 +565,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic bool saveMapped = true; int? useFiltersCounter = null; string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping)); - List saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, useFiltersCounter, saveMapped, sortingContainersAny: true); + List saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true); SaveContainers(totalNotMapped, updated, saveContainers); if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory)) Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory); @@ -952,7 +900,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return new(personKeyFormatted, personBirthday); } - private List GetPersonKeyFormattedCollection(string[] jLinks, string a2PeopleContentDirectory, PersonContainer[] personContainers, Dictionary personKeyToCount) + private List GetPersonKeyFormattedCollection(string[] jLinks, string a2PeopleContentDirectory, PersonContainer[] personContainers, Dictionary> personKeyToIds) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -991,10 +939,10 @@ public class MapLogic : Shared.Models.Methods.IMapLogic (personKeyFormatted, personBirthday) = GetPersonBirthday(windowsShortcut.Path); if (personBirthday is null) throw new NotSupportedException(fileNameWithoutExtension); - if (!personKeyToCount.ContainsKey(personBirthday.Value.Ticks)) + if (!personKeyToIds.ContainsKey(personBirthday.Value.Ticks)) collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension))); else - collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{personKeyToCount[personBirthday.Value.Ticks]} Face(s)"))); + collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{personKeyToIds[personBirthday.Value.Ticks].Count} Face(s)"))); foreach ((long personKey, string displayDirectoryName) in collection) { matches = (from l in personContainers where l.Key == personKey && l.ApproximateYears.HasValue select l).ToArray(); @@ -1012,7 +960,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - private (int, FileHolder, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, PersonContainer[] personContainers, Mapping[] mappingCollection, Dictionary personKeyToCount) + private (int, FileHolder, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, PersonContainer[] personContainers, Mapping[] mappingCollection, Dictionary> personKeyToIds) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1023,7 +971,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic string personDirectory; string personKeyFormatted; bool usePersonKeyAndDeterministicHashCodeKey = false; - List personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleContentDirectory, personContainers, personKeyToCount); + List personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleContentDirectory, personContainers, personKeyToIds); List<(int Id, FileHolder ImageFileHolder, int ApproximateYears, string PersonKeyFormatted, string CheckFile, string Directory, string PersonDirectory)> collection = new(); foreach (Mapping mapping in mappingCollection) { @@ -1112,7 +1060,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic } } - public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, PersonContainer[] personContainers, string a2PeopleContentDirectory, Mapping[] mappingCollection, Dictionary personKeyToCount, int totalNotMapped) + public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, PersonContainer[] personContainers, string a2PeopleContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, int totalNotMapped) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1120,7 +1068,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic List distinctCollection = new(); List saveContainers = new(); BeforeSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory); - (int, FileHolder, int, string, string, string, string)[] collection = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, mappingCollection, personKeyToCount); + (int, FileHolder, int, string, string, string, string)[] collection = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, mappingCollection, personKeyToIds); foreach ((int id, FileHolder imageFileHolder, int approximateYears, string personKeyFormatted, string directory, string personDirectory, string checkFile) in collection) { if (distinctCollection.Contains(id)) @@ -1134,7 +1082,64 @@ public class MapLogic : Shared.Models.Methods.IMapLogic SaveContainers(totalNotMapped, null, saveContainers); } - private (List<(string, DateTime[])>, List<(string, string, string, string)>) GetCollectionForSaveShortcutsForOutputResolutions(List filteredItems, Mapping[] mappingCollection, Dictionary personKeyToCount) + public void SaveShortcutsForOutputResolutions(string a2PeopleContentDirectory, Dictionary> personKeyToIds, Mapping[] mappingCollection, int totalNotMapped) + { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); + long personKey; + string fileName; + string directory; + string hiddenFile; + string personDirectory; + List? personKeys; + string personKeyFormatted; + WindowsShortcut windowsShortcut; + List collection = new(); + Dictionary> idToPersonKeys = Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); + foreach (Mapping mapping in mappingCollection) + { + if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null || mapping.MappingFromPerson is null) + continue; + if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys)) + continue; + personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks; + if (!personKeys.Contains(mapping.MappingFromPerson.PersonBirthday.Value.Ticks)) + continue; + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday); + directory = Path.Combine(a2PeopleContentDirectory, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted); + personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName[..1], Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName)); + fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + } + string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); + foreach (string d in directories) + { + if (string.IsNullOrEmpty(d)) + continue; + if (!Directory.Exists(d)) + _ = Directory.CreateDirectory(d); + } + foreach (SaveShortcutsForOutputResolutions s in collection) + { + hiddenFile = $"{s.FileName}.lvs"; + 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 + { + windowsShortcut = new() { Path = s.FullName, Description = s.Description }; + windowsShortcut.Save(s.FileName); + windowsShortcut.Dispose(); + File.SetLastWriteTime(s.FileName, s.DateTime); + } + catch (Exception) + { } + } + } + + private (List<(string, DateTime[])>, List) GetCollectionForSaveShortcutsForOutputResolutions(Dictionary> personKeyToIds, List filteredItems, Mapping[] mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -1145,7 +1150,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic string personDirectory; string personKeyFormatted; List distinct = new(); - List<(string, string, string, string)> collection = new(); + List collection = new(); List<(string, DateTime[])> directoriesAndDateTimes = new(); foreach (Item item in filteredItems) { @@ -1158,12 +1163,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath); if (directoryName is null) throw new NotSupportedException(); - if (item.ResizedFileHolder?.DirectoryName is null || !item.ResizedFileHolder.Exists) + if (item.ResizedFileHolder?.DirectoryName is null || !item.ResizedFileHolder.Exists || item.ImageFileHolder.LastWriteTime is null) continue; 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, fileName, face.Mapping.MappingFromItem.Id.ToString())); + collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, item.ImageFileHolder.LastWriteTime.Value, fileName, face.Mapping.MappingFromItem.Id.ToString())); if (face.Mapping.MappingFromItem.ContainerDateTimes.Any() && !distinct.Contains(item.ResizedFileHolder.DirectoryName)) { distinct.Add(item.ResizedFileHolder.DirectoryName); @@ -1188,7 +1193,7 @@ 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, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); } else { @@ -1204,25 +1209,25 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes)); } directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted); - if (!personKeyToCount.ContainsKey(personKey)) + if (!personKeyToIds.ContainsKey(personKey)) personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName); else - personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{personKeyToCount[personKey]} Face(s)"); + 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, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey)); } } return new(directoriesAndDateTimes, collection); } - public void SaveShortcutsForOutputResolutions(List filteredItems, Mapping[] mappingCollection, Dictionary personKeyToCount) + public void SaveShortcutsForOutputResolutions(Dictionary> personKeyToIds, List filteredItems, Mapping[] mappingCollection) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); WindowsShortcut windowsShortcut; List<(string, DateTime[])> directoriesAndDateTimes; - List<(string, string Directory, string, string)> collection; - (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount); + List collection; + (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutions(personKeyToIds, filteredItems, mappingCollection); string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); foreach (string directory in directories) { @@ -1231,14 +1236,14 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (!Directory.Exists(directory)) _ = Directory.CreateDirectory(directory); } - foreach ((string fullName, string directory, string fileName, string description) in collection) + foreach (SaveShortcutsForOutputResolutions saveShortcutsForOutputResolutions in collection) { - if (File.Exists(fileName)) + if (File.Exists(saveShortcutsForOutputResolutions.FileName)) continue; try { - windowsShortcut = new() { Path = fullName, Description = description }; - windowsShortcut.Save(fileName); + windowsShortcut = new() { Path = saveShortcutsForOutputResolutions.FullName, Description = saveShortcutsForOutputResolutions.Description }; + windowsShortcut.Save(saveShortcutsForOutputResolutions.FileName); windowsShortcut.Dispose(); } catch (Exception) diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index e21b40d..8b5e51d 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -680,4 +680,26 @@ internal abstract class MapLogic return results; } + internal static Dictionary> GetIdToPersonKeys(Dictionary> personKeyToIds) + { + Dictionary> results = new(); + List? collection; + foreach (KeyValuePair> keyValuePair in personKeyToIds) + { + foreach (int id in keyValuePair.Value) + { + if (!results.TryGetValue(id, out collection)) + { + results.Add(id, new()); + if (!results.TryGetValue(id, out collection)) + throw new Exception(); + } + if (collection.Contains(keyValuePair.Key)) + continue; + collection.Add(keyValuePair.Key); + } + } + return results; + } + } \ No newline at end of file diff --git a/Map/Models/Stateless/Methods/IMapLogic.cs b/Map/Models/Stateless/Methods/IMapLogic.cs index 5fabff3..dd15a90 100644 --- a/Map/Models/Stateless/Methods/IMapLogic.cs +++ b/Map/Models/Stateless/Methods/IMapLogic.cs @@ -1,7 +1,12 @@ namespace View_by_Distance.Map.Models.Stateless.Methods; public interface IMapLogic -{ // ... +{ + + Dictionary> TestStatic_GetIdToPersonKeys(Dictionary> personKeyToIds) => + GetIdToPersonKeys(personKeyToIds); + static Dictionary> GetIdToPersonKeys(Dictionary> personKeyToIds) => + MapLogic.GetIdToPersonKeys(personKeyToIds); List<(long, string)> TestStatic_GetDisplayDirectoryAllFiles(Shared.Models.PersonContainer[] personContainers) => GetDisplayDirectoryAllFiles(personContainers); diff --git a/Rename/Rename.cs b/Rename/Rename.cs index da627d9..f579d0c 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -36,7 +36,7 @@ public class Rename _PropertyConfiguration = propertyConfiguration; _Configuration = configuration; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - propertyConfiguration.Update(); + propertyConfiguration.Update(); string? comparePathRoot = Path.GetDirectoryName(appSettings.ComparePathsFile); if (comparePathRoot is null || comparePathRoot == propertyConfiguration.RootDirectory) throw new Exception("Nested isn't allowed!"); @@ -244,14 +244,16 @@ public class Rename { List results = new(); string[] files; + string message; int distinctCount; - string message = "Renaming files"; + ProgressBar progressBar; List<(FileHolder, string)> renameCollection; List allFiles = GetAllFiles(matchNginxCollection); - using ProgressBar progressBar = new(matchNginxCollection.Length * 2, message, options); for (int i = 1; i < 3; i++) { + message = $"{i}) Renaming files"; files = i == 2 ? allFiles.ToArray() : (from l in allFiles where l.Contains("Rename") select l).ToArray(); + progressBar = new(files.Length, message, options); (renameCollection, distinctCount) = RenameFilesInDirectory(progressBar, files); foreach ((FileHolder fileHolder, string to) in renameCollection) { @@ -263,6 +265,7 @@ public class Rename File.Move(fileHolder.FullName, to); File.WriteAllText($"{to}.id", $"{to}{Environment.NewLine}{fileHolder.FullName}"); } + progressBar.Dispose(); } return results; } diff --git a/Shared/Models/SaveShortcutsForOutputResolutions.cs b/Shared/Models/SaveShortcutsForOutputResolutions.cs new file mode 100644 index 0000000..a94f08a --- /dev/null +++ b/Shared/Models/SaveShortcutsForOutputResolutions.cs @@ -0,0 +1,4 @@ +namespace View_by_Distance.Shared.Models; + +public record SaveShortcutsForOutputResolutions(string FullName, string Directory, DateTime DateTime, string FileName, string Description) +{ } \ No newline at end of file