diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index e947edd..9f3cc19 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -160,39 +160,6 @@ public partial class DlibDotNet _Log.Information("First run completed. Run again if wanted"); } - private long LogDelta(long ticks, string? methodName) - { - long result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; - _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); - result = DateTime.Now.Ticks; - return result; - } - - private long LogDeltaInSeconds(long ticks, string methodName) - { - long result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - double delta = new TimeSpan(DateTime.Now.Ticks - ticks).Seconds; - _Log.Debug($"{methodName} took {Math.Floor(delta)} seconds(s)"); - result = DateTime.Now.Ticks; - return result; - } - - private long LogDeltaInMinutes(long ticks, string methodName) - { - long result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - double delta = new TimeSpan(DateTime.Now.Ticks - ticks).Minutes; - _Log.Debug($"{methodName} took {Math.Floor(delta)} minutes(s)"); - result = DateTime.Now.Ticks; - return result; - } - private static void Verify(Models.Configuration configuration) { if (configuration.RangeDaysDeltaTolerance.Length != 3) @@ -260,32 +227,507 @@ public partial class DlibDotNet throw new Exception("Configuration has to match interface!"); } - private static Map.Models.Configuration Get(Models.Configuration configuration, string facesFileNameExtension, string facesHiddenFileNameExtension, string facePartsFileNameExtension) + private void Search(long ticks, ReadOnlyCollection personContainers, string argZero, string propertyRoot) { - Map.Models.Configuration result = new( - configuration.DeletePossibleDuplicates, - configuration.DistanceMoveUnableToMatch, - configuration.DistanceRenameToMatch, - configuration.FaceConfidencePercent, - configuration.FaceDistancePermyriad, - configuration.LocationContainerDistanceTolerance, - configuration.LocationDigits, - configuration.MappingDefaultName, - configuration.PersonBirthdayFirstYear, - configuration.PersonBirthdayFormat, - configuration.PersonCharacters.ToArray(), - configuration.RangeDaysDeltaTolerance, - configuration.RangeDistanceTolerance, - configuration.SaveSortingWithoutPerson, - configuration.SkipNotSkipDirectories, - configuration.SortingMaximumPerKey, - configuration.SortingMinimumToUseSigma, - facesFileNameExtension, - facesHiddenFileNameExtension, - facePartsFileNameExtension); + int t; + string message; + MapLogic? mapLogic; + Container[] containers; + A_Property propertyLogic; + string eDistanceContentDirectory; + string? a2PeopleContentDirectory; + string aResultsFullGroupDirectory; + string bResultsFullGroupDirectory; + string cResultsFullGroupDirectory; + string fPhotoPrismContentDirectory; + const string fileSearchFilter = "*"; + string fPhotoPrismSingletonDirectory; + bool filesCollectionCountIsOne = false; + List? filesCollection = null; + const string directorySearchFilter = "*"; + string? filesCollectionRootDirectory = null; + bool configurationOutputResolutionsHas = false; + ReadOnlyDictionary> personKeyToIds; + bool runToDoCollectionFirst = GetRunToDoCollectionFirst(ticks); + Dictionary> fileNameToCollection; + (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks); + a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); + eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); + string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton); + _ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, $"({ticks})")); + if (runToDoCollectionFirst) + mapLogic = null; + else + mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); + foreach (string outputResolution in _Configuration.OutputResolutions) + { + if (outputResolution.Any(l => char.IsNumber(l))) + continue; + configurationOutputResolutionsHas = true; + if (!runToDoCollectionFirst) + break; + (filesCollectionRootDirectory, filesCollection) = GetFilesCollectionThenCopyOrMove(ticks, fileSearchFilter, directorySearchFilter, options, outputResolution); + filesCollectionCountIsOne = filesCollection.Count == 1; + break; + } + fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultSingleton); + propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); + if (filesCollectionCountIsOne) + { + if (filesCollection is null) + throw new NullReferenceException(nameof(filesCollection)); + string resultsGroupDirectory; + a2PeopleContentDirectory = null; + eDistanceContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismSingletonDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultSingleton); + for (int i = 1; i < 10; i++) + { + resultsGroupDirectory = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, string.Empty, create: true); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(resultsGroupDirectory); + } + argZero = SaveUrlAndGetNewRootDirectory(filesCollection.First()); + _Configuration.PropertyConfiguration.ChangeRootDirectory(argZero); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); + propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); + propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); + } + if (configurationOutputResolutionsHas) + { + int count; + foreach (string outputResolution in _Configuration.OutputResolutions) + { + if (outputResolution.Any(l => char.IsNumber(l))) + continue; + (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); + filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultAllInOne); + filesCollection = IDirectory.GetFilesCollection(filesCollectionRootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage: true); + count = filesCollection.Select(l => l.Length).Sum(); + break; + } + } + if (filesCollectionRootDirectory is null || filesCollection is null) + throw new NullReferenceException(nameof(filesCollection)); + message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + using (ProgressBar progressBar = new(2, message, options)) + { + progressBar.Tick(); + string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton); + if (!Directory.Exists(aPropertySingletonDirectory)) + _ = Directory.CreateDirectory(aPropertySingletonDirectory); + (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, filesCollection); + progressBar.Tick(); + } + fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); + B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); + mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); + FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, mapLogic); + ReadOnlyCollection distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, new(containers), distinctItems: true, filterItems: true); + if (_Configuration.LookForAbandoned) + { + string dResultsFullGroupDirectory; + string d2ResultsFullGroupDirectory; + foreach (string outputResolution in _Configuration.OutputResolutions) + { + (cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); + mapLogic.LookForAbandoned(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, containers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); + } + } + _Distance.Clear(); + ReadOnlyCollection distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); + ReadOnlyCollection distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true); + if (runToDoCollectionFirst) + { + string json = JsonSerializer.Serialize(distinctFilteredMappingCollection); + File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); + } + foreach (string outputResolution in _Configuration.OutputResolutions) + { + if (_PropertyRootExistedBefore) + break; + personKeyToIds = mapLogic.GetPersonKeyToIds(); + if (_Configuration.SavePropertyShortcutsForOutputResolutions.Contains(outputResolution)) + SavePropertyShortcutsForOutputResolutions(eDistanceContentDirectory, distinctFilteredItems); + if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection); + if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any() && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, personContainers, a2PeopleContentDirectory, personKeyToIds, distinctFilteredMappingCollection); + if (_ArgZeroIsConfigurationRootDirectory + && _Configuration.SaveResizedSubfiles + && outputResolution == _Configuration.OutputResolutions[0] + && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) + && _Exceptions.Count == 0) + MapLogic(ticks, new(containers), fPhotoPrismContentDirectory, mapLogic, outputResolution, new(personKeyToIds), distinctFilteredFaces, distinctFilteredMappingCollection); + if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && distinctFilteredMappingCollection.Count > 0) + _Random.Random(_Configuration.PropertyConfiguration, _Configuration.RadomUseBirthdayMinimum, _Configuration.ValidKeyWordsToIgnoreInRandom, outputResolution, personKeyToIds, distinctFilteredMappingCollection); + if (_IsEnvironment.Development) + continue; + if (!_IsEnvironment.Development) + { + string dResultsFullGroupDirectory; + string c2ResultsFullGroupDirectory; + string d2ResultsFullGroupDirectory; + (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultCollection)); + } + } + } + + private bool GetRunToDoCollectionFirst(long ticks) + { + bool result = false; + string[] directories; + string seasonDirectory; + DirectoryInfo directoryInfo; + DateTime dateTime = new(ticks); + string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; + string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); + (int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); + FileSystemInfo fileSystemInfo = new DirectoryInfo(eDistanceContentDirectory); + string[] checkDirectories = new string[] + { + Path.Combine(rootDirectory, "Ancestry"), + Path.Combine(rootDirectory, "Facebook"), + Path.Combine(rootDirectory, "LinkedIn"), + rootDirectory, + }; + foreach (string checkDirectory in checkDirectories) + { + if (checkDirectory == rootDirectory) + seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName}"); + else + seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}"); + if (!Directory.Exists(seasonDirectory)) + _ = Directory.CreateDirectory(seasonDirectory); + if (result) + continue; + directories = Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + directoryInfo = new(directory); + if (directoryInfo.LastWriteTime > fileSystemInfo.LastWriteTime) + { + result = true; + break; + } + } + } return result; } + private string SaveUrlAndGetNewRootDirectory(string[] files) + { + string result; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + if (files.Length == 0) + throw new NotSupportedException(); + string? sourceDirectory = Path.GetDirectoryName(files.First()); + if (string.IsNullOrEmpty(sourceDirectory)) + throw new NotSupportedException(); + Uri uri; + string? line; + string fileName; + Task task; + string relativePath; + FileHolder fileHolder; + string extensionLowered; + string sourceDirectoryFile; + HttpClient httpClient = new(); + bool isValidImageFormatExtension; + result = Path.GetDirectoryName(Path.GetDirectoryName(sourceDirectory)) ?? throw new NotSupportedException(); + int length = result.Length; + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Enter fileNameToCollection url for fileNameToCollection image"); + line = _Console.ReadLine(); + if (string.IsNullOrEmpty(line)) + break; + uri = new(line); + if (uri.HostNameType != UriHostNameType.Dns) + continue; + task = httpClient.GetByteArrayAsync(uri); + fileName = Path.GetFileName(uri.LocalPath); + sourceDirectoryFile = Path.Combine(sourceDirectory, fileName); + File.WriteAllBytes(sourceDirectoryFile, task.Result); + extensionLowered = Path.GetExtension(uri.LocalPath); + relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length, forceExtensionToLower: true); + isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(extensionLowered); + fileHolder = new(sourceDirectoryFile); + _ = new Item(fileHolder, relativePath, isValidImageFormatExtension); + // container.Items.Add(item); + } + _Log.Information(". . ."); + return result; + } + + private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, MapLogic mapLogic) + { + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + int total; + int notMapped; + string message; + bool exceptions; + int totalSeconds; + Container container; + Item[] filteredItems; + int totalNotMapped = 0; + bool outputResolutionHasNumber; + bool anyNullOrNoIsUniqueFileName; + string cResultsFullGroupDirectory; + string dResultsFullGroupDirectory; + string c2ResultsFullGroupDirectory; + string d2ResultsFullGroupDirectory; + int containersLength = containers.Length; + List> sourceDirectoryChanges = new(); + int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; + string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); + foreach (string outputResolution in _Configuration.OutputResolutions) + { + total = 0; + outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l)); + (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); + _Faces.Update(dResultsFullGroupDirectory); + _Resize.Update(cResultsFullGroupDirectory); + _FaceParts.Update(d2ResultsFullGroupDirectory); + _BlurHasher.Update(c2ResultsFullGroupDirectory); + for (int i = 0; i < containers.Length; i++) + { + container = containers[i]; + if (container.Items.Count == 0) + continue; + if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero)) + continue; + filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(_Configuration.PropertyConfiguration, container); + if (filteredItems.Length == 0) + continue; + sourceDirectoryChanges.Clear(); + anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName); + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + message = $"{i + 1:000} [{filteredItems.Length:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <{container.SourceDirectory}> - total not mapped {totalNotMapped:000000}"; + propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, container.SourceDirectory, anyNullOrNoIsUniqueFileName); + if (outputResolutionHasNumber) + _Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory); + (notMapped, exceptions) = FullParallelWork(maxDegreeOfParallelism, + propertyLogic, + metadata, + mapLogic, + outputResolution, + outputResolutionHasNumber, + cResultsFullGroupDirectory, + dResultsFullGroupDirectory, + d2ResultsFullGroupDirectory, + sourceDirectoryChanges, + fileNameToCollection, + container, + filteredItems, + message); + totalNotMapped += notMapped; + if (exceptions) + { + _Exceptions.Add(container.SourceDirectory); + continue; + } + if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Length > 0) + { + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue or close console"); + if (_Console.ReadKey() == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + total += container.Items.Count; + } + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + message = $"### [###] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <> - total not mapped {totalNotMapped:000000}"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(1, message, options); + progressBar.Tick(); + } + } + + private ReadOnlyCollection GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, bool distinctItems) + { + ReadOnlyCollection results; + int count = 0; + int notMapped; + Mapping mapping; + bool anyValidFaces; + string focusRelativePath; + bool? isFocusRelativePath; + List distinct = new(); + DateTime[] containerDateTimes; + IEnumerable filteredItems; + MappingFromItem mappingFromItem; + List mappingCollection = new(); + ReadOnlyCollection? locationContainersFiles = null; + foreach (Container container in containers) + { + if (container.Items.Count == 0) + continue; + filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(propertyConfiguration, container); + if (!filteredItems.Any()) + continue; + containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); + focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory)); + isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath); + foreach (Item item in filteredItems) + { + if (item.Property?.Id is null || item.ResizedFileHolder is null) + continue; + mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder); + if (distinctItems) + { + if (distinct.Contains(item.Property.Id.Value)) + continue; + distinct.Add(item.Property.Id.Value); + } + count++; + anyValidFaces = false; + foreach (Shared.Models.Face face in item.Faces) + { + if (face.Mapping is null) + continue; + anyValidFaces = true; + mappingCollection.Add(face.Mapping); + if (face.Mapping.MappingFromPerson is null || face.Mapping.MappingFromPerson.LocationContainersFiles.Count == 0) + continue; + if (_Configuration.LocationContainerDistanceTolerance is null) + Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(propertyConfiguration, face.Mapping.MappingFromItem, face.Mapping.MappingFromPerson); + } + if (!anyValidFaces) + { + (mapping, notMapped) = GetMapping(mapLogic, locationContainersFiles, item, isFocusRelativePath, mappingFromItem); + mappingCollection.Add(mapping); + } + } + } + results = new((from l in mappingCollection orderby l.MappingFromItem.Id select l).ToArray()); + return results; + } + + private static void SavePropertyShortcutsForOutputResolutions(string eDistanceContentDirectory, ReadOnlyCollection distinctFilteredItems) + { +#if VerifyItem + bool found; + List notFound = new(); + foreach (Item item in distinctFilteredItems) + { + found = false; + if (item.Property?.Id is null) + continue; + foreach (Mapping mapping in distinctFilteredMappingCollection) + { + if (mapping.MappingFromItem.Id != item.Property.Id.Value) + continue; + found = true; + break; + } + if (!found) + notFound.Add(item); + } + if (notFound.Count > 0) + throw new NotSupportedException(); +#endif + string model; + string fileName; + string directory; + bool? isWrongYear; + List dateTimes; + List distinct = new(); + WindowsShortcut windowsShortcut; + List<(string, string, string)> collection = new(); + foreach (Item item in distinctFilteredItems) + { + if (item.Property?.Id is null || item.ImageFileHolder.LastWriteTime is null) + continue; + if (item.IsNotUniqueAndNeedsReview is null || !item.IsNotUniqueAndNeedsReview.Value) + continue; + directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(item.IsNotUniqueAndNeedsReview)})", item.ImageFileHolder.NameWithoutExtension); + fileName = Path.Combine(directory, $"{item.ImageFileHolder.Length} {item.ImageFileHolder.LastWriteTime.Value.Ticks}.lnk"); + collection.Add((item.ImageFileHolder.FullName, directory, fileName)); + if (distinct.Contains(directory)) + continue; + distinct.Add(directory); + } + foreach (Item item in distinctFilteredItems) + { + if (item.Property?.Id is null || item.Property.DateTimeOriginal is null) + continue; + dateTimes = item.Property.GetDateTimes(); + (isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(item.ImageFileHolder, item.Property.DateTimeOriginal, dateTimes); + if (isWrongYear is null || !isWrongYear.Value) + continue; + // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " + model = string.IsNullOrEmpty(item.Property.Model) ? "Unknown" : Regex.Replace(item.Property.Model.Trim(), @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"); + directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(Item)})", item.Property.DateTimeOriginal.Value.Year.ToString(), model); + fileName = item.IsNotUniqueAndNeedsReview is not null && item.IsNotUniqueAndNeedsReview.Value ? Path.Combine(directory, $"{item.ImageFileHolder.Name} {item.ImageFileHolder.Length}.lnk") : Path.Combine(directory, $"{item.ImageFileHolder.Name}.lnk"); + collection.Add((item.ImageFileHolder.FullName, directory, fileName)); + if (distinct.Contains(directory)) + continue; + distinct.Add(directory); + } +#if Mapping + foreach (Mapping mapping in distinctFilteredMappingCollection) + { + if (mapping.MappingFromItem.IsWrongYear is null || !mapping.MappingFromItem.IsWrongYear.Value) + continue; + directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(Mapping)})", mapping.MappingFromItem.MinimumDateTime.Year.ToString()); + fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); + collection.Add((mapping.MappingFromItem.ResizedFileHolder.FullName, directory, fileName)); + if (distinct.Contains(directory)) + continue; + distinct.Add(directory); + } +#endif + foreach (string distinctDirectory in distinct) + { + if (!Directory.Exists(distinctDirectory)) + _ = Directory.CreateDirectory(distinctDirectory); + } + foreach ((string path, string checkDirectory, string checkFile) in collection) + { + if (File.Exists(checkFile)) + continue; + windowsShortcut = new() { Path = path }; + windowsShortcut.Save(checkFile); + windowsShortcut.Dispose(); + } + } + + private void MapLogic(long ticks, ReadOnlyCollection containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection distinctFilteredFaces, ReadOnlyCollection distinctFilteredMappingCollection) + { + (_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); + string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); + string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); + string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, "[()]"); + if (distinctFilteredMappingCollection.Count > 0) + { + Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, ticks); + if (Directory.Exists(d2FacePartsContentCollectionDirectory)) + Shared.Models.Stateless.Methods.IPath.MakeHiddenIfAllItemsAreHidden(d2FacePartsContentCollectionDirectory); + } + if (Directory.Exists(fPhotoPrismContentDirectory)) + F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, ticks, distinctFilteredFaces, mapLogic); + if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctFilteredMappingCollection); + ReadOnlyDictionary> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctFilteredMappingCollection); + if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctFilteredMappingCollection, idToWholePercentagesToMapping); + if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) + SaveFaceDistances(ticks, mapLogic, distinctFilteredFaces, distinctFilteredMappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping); + } + private bool? GetIsFocusModel(Shared.Models.Property? property) { bool? result; @@ -298,6 +740,39 @@ public partial class DlibDotNet return result; } + private void LogItemPropertyIsNull(Item item) + { + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + if (!item.SourceDirectoryFileHolder.Exists) + _Log.Information(string.Concat("NoJson <", item.ImageFileHolder.FullName, '>')); + else if (item.FileSizeChanged.HasValue && item.FileSizeChanged.Value) + _Log.Information(string.Concat("FileSizeChanged <", item.ImageFileHolder.FullName, '>')); + else if (item.LastWriteTimeChanged.HasValue && item.LastWriteTimeChanged.Value) + _Log.Information(string.Concat("LastWriteTimeChanged <", item.ImageFileHolder.FullName, '>')); + else if (item.Moved.HasValue && item.Moved.Value) + _Log.Information(string.Concat("Moved <", item.ImageFileHolder.FullName, '>')); + } + + private void LogNameWithoutExtensionIsIdFormatBut(Item item) + { + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + _Log.Information($"Name without extension is Id format but doesn't match id <{item.ImageFileHolder.FullName}>"); + File.Move(item.ImageFileHolder.FullName, $"{item.ImageFileHolder.FullName}.rename"); + } + + private long LogDelta(long ticks, string? methodName) + { + long result; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + private int GetNotMappedCountAndSetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, ReadOnlyCollection> locationContainers, MappingFromItem mappingFromItem, List? mappingFromPhotoPrismCollection, List faces) { int result; @@ -357,6 +832,32 @@ public partial class DlibDotNet return result; } + private static Map.Models.Configuration Get(Models.Configuration configuration, string facesFileNameExtension, string facesHiddenFileNameExtension, string facePartsFileNameExtension) + { + Map.Models.Configuration result = new( + configuration.DeletePossibleDuplicates, + configuration.DistanceMoveUnableToMatch, + configuration.DistanceRenameToMatch, + configuration.FaceConfidencePercent, + configuration.FaceDistancePermyriad, + configuration.LocationContainerDistanceTolerance, + configuration.LocationDigits, + configuration.MappingDefaultName, + configuration.PersonBirthdayFirstYear, + configuration.PersonBirthdayFormat, + configuration.PersonCharacters.ToArray(), + configuration.RangeDaysDeltaTolerance, + configuration.RangeDistanceTolerance, + configuration.SaveSortingWithoutPerson, + configuration.SkipNotSkipDirectories, + configuration.SortingMaximumPerKey, + configuration.SortingMinimumToUseSigma, + facesFileNameExtension, + facesHiddenFileNameExtension, + facePartsFileNameExtension); + return result; + } + private (Mapping, int) GetMapping(MapLogic mapLogic, ReadOnlyCollection? locationContainersFiles, Item item, bool? isFocusRelativePath, MappingFromItem mappingFromItem) { Mapping result; @@ -397,28 +898,6 @@ public partial class DlibDotNet return (result, notMapped); } - private void LogItemPropertyIsNull(Item item) - { - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - if (!item.SourceDirectoryFileHolder.Exists) - _Log.Information(string.Concat("NoJson <", item.ImageFileHolder.FullName, '>')); - else if (item.FileSizeChanged.HasValue && item.FileSizeChanged.Value) - _Log.Information(string.Concat("FileSizeChanged <", item.ImageFileHolder.FullName, '>')); - else if (item.LastWriteTimeChanged.HasValue && item.LastWriteTimeChanged.Value) - _Log.Information(string.Concat("LastWriteTimeChanged <", item.ImageFileHolder.FullName, '>')); - else if (item.Moved.HasValue && item.Moved.Value) - _Log.Information(string.Concat("Moved <", item.ImageFileHolder.FullName, '>')); - } - - private void LogNameWithoutExtensionIsIdFormatBut(Item item) - { - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - _Log.Information($"Name without extension is Id format but doesn't match id <{item.ImageFileHolder.FullName}>"); - File.Move(item.ImageFileHolder.FullName, $"{item.ImageFileHolder.FullName}.rename"); - } - private int FullParallelForWork(A_Property propertyLogic, B_Metadata metadata, MapLogic mapLogic, @@ -608,41 +1087,6 @@ public partial class DlibDotNet return (result, exceptionsCount > 0); } - private static void WriteTab(string checkDirectory, List<(string Id, string Line)> metadataIdLines, string fileName) - { - string text; - FileInfo fileInfo; - List duplicates = new(); - List metadataIds = new(); - fileInfo = new(Path.Combine(checkDirectory, "[()]", Path.ChangeExtension(fileName, "tsv"))); - if (fileInfo?.Directory is null) - throw new Exception(); - if (!fileInfo.Directory.Exists) - fileInfo.Directory.Create(); - foreach ((string Id, string Line) metadataIdLine in metadataIdLines) - { - if (metadataIds.Contains(metadataIdLine.Id)) - duplicates.Add(metadataIdLine.Id); - else - metadataIds.Add(metadataIdLine.Id); - } - for (int i = metadataIdLines.Count - 1; i > -1; i--) - { - if (duplicates.Contains(metadataIdLines[i].Id)) - metadataIdLines.RemoveAt(i); - } - if (metadataIdLines.Count > 0) - { - text = string.Join(Environment.NewLine, from l in metadataIdLines orderby l.Id select l.Line); - _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, text, updateDateWhenMatches: true, compareBeforeWrite: true); - } - else - { - if (fileInfo.Exists) - File.Delete(fileInfo.FullName); - } - } - private (string, string) GetResultsFullGroupDirectories() { string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( @@ -695,94 +1139,6 @@ public partial class DlibDotNet return new(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); } - private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, MapLogic mapLogic) - { - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - int total; - int notMapped; - string message; - bool exceptions; - int totalSeconds; - Container container; - Item[] filteredItems; - int totalNotMapped = 0; - bool outputResolutionHasNumber; - bool anyNullOrNoIsUniqueFileName; - string cResultsFullGroupDirectory; - string dResultsFullGroupDirectory; - string c2ResultsFullGroupDirectory; - string d2ResultsFullGroupDirectory; - int containersLength = containers.Length; - List> sourceDirectoryChanges = new(); - int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; - string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); - foreach (string outputResolution in _Configuration.OutputResolutions) - { - total = 0; - outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l)); - (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); - _Faces.Update(dResultsFullGroupDirectory); - _Resize.Update(cResultsFullGroupDirectory); - _FaceParts.Update(d2ResultsFullGroupDirectory); - _BlurHasher.Update(c2ResultsFullGroupDirectory); - for (int i = 0; i < containers.Length; i++) - { - container = containers[i]; - if (container.Items.Count == 0) - continue; - if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero)) - continue; - filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(_Configuration.PropertyConfiguration, container); - if (filteredItems.Length == 0) - continue; - sourceDirectoryChanges.Clear(); - anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName); - totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - message = $"{i + 1:000} [{filteredItems.Length:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <{container.SourceDirectory}> - total not mapped {totalNotMapped:000000}"; - propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, container.SourceDirectory, anyNullOrNoIsUniqueFileName); - if (outputResolutionHasNumber) - _Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory); - (notMapped, exceptions) = FullParallelWork(maxDegreeOfParallelism, - propertyLogic, - metadata, - mapLogic, - outputResolution, - outputResolutionHasNumber, - cResultsFullGroupDirectory, - dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, - sourceDirectoryChanges, - fileNameToCollection, - container, - filteredItems, - message); - totalNotMapped += notMapped; - if (exceptions) - { - _Exceptions.Add(container.SourceDirectory); - continue; - } - if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Length > 0) - { - for (int y = 0; y < int.MaxValue; y++) - { - _Log.Information("Press \"Y\" key when ready to continue or close console"); - if (_Console.ReadKey() == ConsoleKey.Y) - break; - } - _Log.Information(". . ."); - } - total += container.Items.Count; - } - totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - message = $"### [###] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - <> - total not mapped {totalNotMapped:000000}"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(1, message, options); - progressBar.Tick(); - } - } - private void SaveFaceDistances(long ticks, MapLogic mapLogic, ReadOnlyCollection mappingCollection, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary> idToWholePercentagesToMapping, ReadOnlyCollection faceDistanceEncodings, ReadOnlyCollection faceDistanceContainers) { if (_Log is null) @@ -842,266 +1198,6 @@ public partial class DlibDotNet } } - private void MapLogic(long ticks, ReadOnlyCollection containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection distinctFilteredFaces, ReadOnlyCollection distinctFilteredMappingCollection) - { - (_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); - string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); - string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, "[()]"); - if (distinctFilteredMappingCollection.Count > 0) - { - Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, ticks); - if (Directory.Exists(d2FacePartsContentCollectionDirectory)) - Shared.Models.Stateless.Methods.IPath.MakeHiddenIfAllItemsAreHidden(d2FacePartsContentCollectionDirectory); - } - if (Directory.Exists(fPhotoPrismContentDirectory)) - F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, ticks, distinctFilteredFaces, mapLogic); - if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctFilteredMappingCollection); - ReadOnlyDictionary> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctFilteredMappingCollection); - if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctFilteredMappingCollection, idToWholePercentagesToMapping); - if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) - SaveFaceDistances(ticks, mapLogic, distinctFilteredFaces, distinctFilteredMappingCollection, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping); - } - - private string SaveUrlAndGetNewRootDirectory(string[] files) - { - string result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - if (files.Length == 0) - throw new NotSupportedException(); - string? sourceDirectory = Path.GetDirectoryName(files.First()); - if (string.IsNullOrEmpty(sourceDirectory)) - throw new NotSupportedException(); - Uri uri; - string? line; - string fileName; - Task task; - string relativePath; - FileHolder fileHolder; - string extensionLowered; - string sourceDirectoryFile; - HttpClient httpClient = new(); - bool isValidImageFormatExtension; - result = Path.GetDirectoryName(Path.GetDirectoryName(sourceDirectory)) ?? throw new NotSupportedException(); - int length = result.Length; - for (int y = 0; y < int.MaxValue; y++) - { - _Log.Information("Enter fileNameToCollection url for fileNameToCollection image"); - line = _Console.ReadLine(); - if (string.IsNullOrEmpty(line)) - break; - uri = new(line); - if (uri.HostNameType != UriHostNameType.Dns) - continue; - task = httpClient.GetByteArrayAsync(uri); - fileName = Path.GetFileName(uri.LocalPath); - sourceDirectoryFile = Path.Combine(sourceDirectory, fileName); - File.WriteAllBytes(sourceDirectoryFile, task.Result); - extensionLowered = Path.GetExtension(uri.LocalPath); - relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length, forceExtensionToLower: true); - isValidImageFormatExtension = _Configuration.PropertyConfiguration.ValidImageFormatExtensions.Contains(extensionLowered); - fileHolder = new(sourceDirectoryFile); - _ = new Item(fileHolder, relativePath, isValidImageFormatExtension); - // container.Items.Add(item); - } - _Log.Information(". . ."); - return result; - } - - private ReadOnlyCollection GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, bool distinctItems) - { - ReadOnlyCollection results; - int count = 0; - int notMapped; - Mapping mapping; - bool anyValidFaces; - string focusRelativePath; - bool? isFocusRelativePath; - List distinct = new(); - DateTime[] containerDateTimes; - IEnumerable filteredItems; - MappingFromItem mappingFromItem; - List mappingCollection = new(); - ReadOnlyCollection? locationContainersFiles = null; - foreach (Container container in containers) - { - if (container.Items.Count == 0) - continue; - filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(propertyConfiguration, container); - if (!filteredItems.Any()) - continue; - containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); - focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory)); - isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath); - foreach (Item item in filteredItems) - { - if (item.Property?.Id is null || item.ResizedFileHolder is null) - continue; - mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder); - if (distinctItems) - { - if (distinct.Contains(item.Property.Id.Value)) - continue; - distinct.Add(item.Property.Id.Value); - } - count++; - anyValidFaces = false; - foreach (Shared.Models.Face face in item.Faces) - { - if (face.Mapping is null) - continue; - anyValidFaces = true; - mappingCollection.Add(face.Mapping); - if (face.Mapping.MappingFromPerson is null || face.Mapping.MappingFromPerson.LocationContainersFiles.Count == 0) - continue; - if (_Configuration.LocationContainerDistanceTolerance is null) - Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(propertyConfiguration, face.Mapping.MappingFromItem, face.Mapping.MappingFromPerson); - } - if (!anyValidFaces) - { - (mapping, notMapped) = GetMapping(mapLogic, locationContainersFiles, item, isFocusRelativePath, mappingFromItem); - mappingCollection.Add(mapping); - } - } - } - results = new((from l in mappingCollection orderby l.MappingFromItem.Id select l).ToArray()); - return results; - } - - private static void SavePropertyShortcutsForOutputResolutions(string eDistanceContentDirectory, ReadOnlyCollection distinctFilteredItems) - { -#if VerifyItem - bool found; - List notFound = new(); - foreach (Item item in distinctFilteredItems) - { - found = false; - if (item.Property?.Id is null) - continue; - foreach (Mapping mapping in distinctFilteredMappingCollection) - { - if (mapping.MappingFromItem.Id != item.Property.Id.Value) - continue; - found = true; - break; - } - if (!found) - notFound.Add(item); - } - if (notFound.Count > 0) - throw new NotSupportedException(); -#endif - string model; - string fileName; - string directory; - bool? isWrongYear; - List dateTimes; - List distinct = new(); - WindowsShortcut windowsShortcut; - List<(string, string, string)> collection = new(); - foreach (Item item in distinctFilteredItems) - { - if (item.Property?.Id is null || item.ImageFileHolder.LastWriteTime is null) - continue; - if (item.IsNotUniqueAndNeedsReview is null || !item.IsNotUniqueAndNeedsReview.Value) - continue; - directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(item.IsNotUniqueAndNeedsReview)})", item.ImageFileHolder.NameWithoutExtension); - fileName = Path.Combine(directory, $"{item.ImageFileHolder.Length} {item.ImageFileHolder.LastWriteTime.Value.Ticks}.lnk"); - collection.Add((item.ImageFileHolder.FullName, directory, fileName)); - if (distinct.Contains(directory)) - continue; - distinct.Add(directory); - } - foreach (Item item in distinctFilteredItems) - { - if (item.Property?.Id is null || item.Property.DateTimeOriginal is null) - continue; - dateTimes = item.Property.GetDateTimes(); - (isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(item.ImageFileHolder, item.Property.DateTimeOriginal, dateTimes); - if (isWrongYear is null || !isWrongYear.Value) - continue; - // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " - model = string.IsNullOrEmpty(item.Property.Model) ? "Unknown" : Regex.Replace(item.Property.Model.Trim(), @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"); - directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(Item)})", item.Property.DateTimeOriginal.Value.Year.ToString(), model); - fileName = item.IsNotUniqueAndNeedsReview is not null && item.IsNotUniqueAndNeedsReview.Value ? Path.Combine(directory, $"{item.ImageFileHolder.Name} {item.ImageFileHolder.Length}.lnk") : Path.Combine(directory, $"{item.ImageFileHolder.Name}.lnk"); - collection.Add((item.ImageFileHolder.FullName, directory, fileName)); - if (distinct.Contains(directory)) - continue; - distinct.Add(directory); - } -#if Mapping - foreach (Mapping mapping in distinctFilteredMappingCollection) - { - if (mapping.MappingFromItem.IsWrongYear is null || !mapping.MappingFromItem.IsWrongYear.Value) - continue; - directory = Path.Combine($"{eDistanceContentDirectory[..^1]}{nameof(Mapping)})", mapping.MappingFromItem.MinimumDateTime.Year.ToString()); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); - collection.Add((mapping.MappingFromItem.ResizedFileHolder.FullName, directory, fileName)); - if (distinct.Contains(directory)) - continue; - distinct.Add(directory); - } -#endif - foreach (string distinctDirectory in distinct) - { - if (!Directory.Exists(distinctDirectory)) - _ = Directory.CreateDirectory(distinctDirectory); - } - foreach ((string path, string checkDirectory, string checkFile) in collection) - { - if (File.Exists(checkFile)) - continue; - windowsShortcut = new() { Path = path }; - windowsShortcut.Save(checkFile); - windowsShortcut.Dispose(); - } - } - - private bool GetRunToDoCollectionFirst(long ticks) - { - bool result = false; - string[] directories; - string seasonDirectory; - DirectoryInfo directoryInfo; - DateTime dateTime = new(ticks); - string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; - string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); - (int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); - FileSystemInfo fileSystemInfo = new DirectoryInfo(eDistanceContentDirectory); - string[] checkDirectories = new string[] - { - Path.Combine(rootDirectory, "Ancestry"), - Path.Combine(rootDirectory, "Facebook"), - Path.Combine(rootDirectory, "LinkedIn"), - rootDirectory, - }; - foreach (string checkDirectory in checkDirectories) - { - if (checkDirectory == rootDirectory) - seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName}"); - else - seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}"); - if (!Directory.Exists(seasonDirectory)) - _ = Directory.CreateDirectory(seasonDirectory); - if (result) - continue; - directories = Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - directoryInfo = new(directory); - if (directoryInfo.LastWriteTime > fileSystemInfo.LastWriteTime) - { - result = true; - break; - } - } - } - return result; - } - private (string, List) GetFilesCollectionThenCopyOrMove(long ticks, string fileSearchFilter, string directorySearchFilter, ProgressBarOptions options, string outputResolution) { ProgressBar progressBar; @@ -1126,157 +1222,4 @@ public partial class DlibDotNet return (filesCollectionRootDirectory, filesCollection); } - private void Search(long ticks, ReadOnlyCollection personContainers, string argZero, string propertyRoot) - { - int t; - string message; - MapLogic? mapLogic; - Container[] containers; - A_Property propertyLogic; - string eDistanceContentDirectory; - string? a2PeopleContentDirectory; - string aResultsFullGroupDirectory; - string bResultsFullGroupDirectory; - string cResultsFullGroupDirectory; - string fPhotoPrismContentDirectory; - const string fileSearchFilter = "*"; - string fPhotoPrismSingletonDirectory; - bool filesCollectionCountIsOne = false; - List? filesCollection = null; - const string directorySearchFilter = "*"; - string? filesCollectionRootDirectory = null; - bool configurationOutputResolutionsHas = false; - ReadOnlyDictionary> personKeyToIds; - bool runToDoCollectionFirst = GetRunToDoCollectionFirst(ticks); - Dictionary> fileNameToCollection; - (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks); - a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); - eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); - string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton); - _ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, $"({ticks})")); - if (runToDoCollectionFirst) - mapLogic = null; - else - mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); - foreach (string outputResolution in _Configuration.OutputResolutions) - { - if (outputResolution.Any(l => char.IsNumber(l))) - continue; - configurationOutputResolutionsHas = true; - if (!runToDoCollectionFirst) - break; - (filesCollectionRootDirectory, filesCollection) = GetFilesCollectionThenCopyOrMove(ticks, fileSearchFilter, directorySearchFilter, options, outputResolution); - filesCollectionCountIsOne = filesCollection.Count == 1; - break; - } - fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent); - fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultSingleton); - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); - if (filesCollectionCountIsOne) - { - if (filesCollection is null) - throw new NullReferenceException(nameof(filesCollection)); - string resultsGroupDirectory; - a2PeopleContentDirectory = null; - eDistanceContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); - fPhotoPrismContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); - fPhotoPrismSingletonDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultSingleton); - for (int i = 1; i < 10; i++) - { - resultsGroupDirectory = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, string.Empty, create: true); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(resultsGroupDirectory); - } - argZero = SaveUrlAndGetNewRootDirectory(filesCollection.First()); - _Configuration.PropertyConfiguration.ChangeRootDirectory(argZero); - (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); - propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); - } - if (configurationOutputResolutionsHas) - { - int count; - foreach (string outputResolution in _Configuration.OutputResolutions) - { - if (outputResolution.Any(l => char.IsNumber(l))) - continue; - (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); - filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultAllInOne); - filesCollection = IDirectory.GetFilesCollection(filesCollectionRootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage: true); - count = filesCollection.Select(l => l.Length).Sum(); - break; - } - } - if (filesCollectionRootDirectory is null || filesCollection is null) - throw new NullReferenceException(nameof(filesCollection)); - message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - using (ProgressBar progressBar = new(2, message, options)) - { - progressBar.Tick(); - string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton); - if (!Directory.Exists(aPropertySingletonDirectory)) - _ = Directory.CreateDirectory(aPropertySingletonDirectory); - (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, filesCollection); - progressBar.Tick(); - } - fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); - B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); - mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); - FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, mapLogic); - ReadOnlyCollection distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, new(containers), distinctItems: true, filterItems: true); - if (_Configuration.LookForAbandoned) - { - string dResultsFullGroupDirectory; - string d2ResultsFullGroupDirectory; - foreach (string outputResolution in _Configuration.OutputResolutions) - { - (cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); - mapLogic.LookForAbandoned(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, containers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); - } - } - _Distance.Clear(); - ReadOnlyCollection distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); - ReadOnlyCollection distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true); - if (runToDoCollectionFirst) - { - string json = JsonSerializer.Serialize(distinctFilteredMappingCollection); - File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); - } - foreach (string outputResolution in _Configuration.OutputResolutions) - { - if (_PropertyRootExistedBefore) - break; - personKeyToIds = mapLogic.GetPersonKeyToIds(); - if (_Configuration.SavePropertyShortcutsForOutputResolutions.Contains(outputResolution)) - SavePropertyShortcutsForOutputResolutions(eDistanceContentDirectory, distinctFilteredItems); - if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection); - if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any() && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, personContainers, a2PeopleContentDirectory, personKeyToIds, distinctFilteredMappingCollection); - if (_ArgZeroIsConfigurationRootDirectory - && _Configuration.SaveResizedSubfiles - && outputResolution == _Configuration.OutputResolutions[0] - && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) - && _Exceptions.Count == 0) - MapLogic(ticks, new(containers), fPhotoPrismContentDirectory, mapLogic, outputResolution, new(personKeyToIds), distinctFilteredFaces, distinctFilteredMappingCollection); - if (_Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && distinctFilteredMappingCollection.Count > 0) - _Random.Random(_Configuration.PropertyConfiguration, _Configuration.RadomUseBirthdayMinimum, _Configuration.ValidKeyWordsToIgnoreInRandom, outputResolution, personKeyToIds, distinctFilteredMappingCollection); - if (_IsEnvironment.Development) - continue; - if (!_IsEnvironment.Development) - { - string dResultsFullGroupDirectory; - string c2ResultsFullGroupDirectory; - string d2ResultsFullGroupDirectory; - (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); - if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultCollection)); - } - } - } - } \ No newline at end of file diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 11148bc..4f74659 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -1,4 +1,4 @@ -using Humanizer; +using Humanizer; using ShellProgressBar; using System.Collections.ObjectModel; using System.Globalization; @@ -13,9 +13,207 @@ namespace View_by_Distance.Map.Models; public partial class MapLogic : Shared.Models.Methods.IMapLogic { + private bool IsUsed(bool ignoreXMatches, int id, ReadOnlyDictionary>? wholePercentagesToPersonContainers, int wholePercentages) + { + bool result; + List? wholePercentagesCollection; + ReadOnlyCollection? personContainers; + result = _SkipCollection.TryGetValue(id, out wholePercentagesCollection) && wholePercentagesCollection.Contains(wholePercentages); + if (!result && wholePercentagesToPersonContainers is not null) + if (wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers)) + if (!ignoreXMatches || !personContainers.Any(l => IPerson.IsDefaultName(l))) + result = true; + return result; + } + + public bool IsUsed(bool ignoreXMatches, int id, ReadOnlyDictionary>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) => + IsUsed(ignoreXMatches, id, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages); + [GeneratedRegex("[\\\\,\\/,\\:,\\*,\\?,\\\",\\<,\\>,\\|]")] private static partial Regex FileSystemSafe(); + public void SaveContainers(bool saveIndividually, int? updated, List saveContainers) + { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); + string fileName; + string checkFile; + string sourceFile; + List distinct = new(); + WindowsShortcut windowsShortcut; + string[] directories = (from l in saveContainers select l.Directory).Distinct().ToArray(); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); + string message; + if (updated is null) + message = $") {saveContainers.Count:000} save(s) - {totalSeconds} total second(s)"; + else + message = $") {saveContainers.Count:000} save(s) - {updated} Updated - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + foreach (string directory in directories) + { + if (string.IsNullOrEmpty(directory)) + continue; + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + } + using ProgressBar progressBar = new(saveContainers.Count, message, options); + foreach (SaveContainer saveContainer in saveContainers) + { + progressBar.Tick(); + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.FaceFileHolder is null) + continue; + if (saveContainer.FacePartsFileHolder is null && saveContainer.HiddenFaceFileHolder is null && saveContainer.ResizedFileHolder is null) + { + checkFile = saveContainer.CheckFile; + sourceFile = saveContainer.FaceFileHolder.FullName; + } + else if (!saveContainer.FaceFileHolder.Exists && saveContainer.ResizedFileHolder is not null && saveContainer.ResizedFileHolder.Exists) + { + checkFile = saveContainer.CheckFile; + sourceFile = saveContainer.ResizedFileHolder.FullName; + } + else if (saveContainer.FaceFileHolder.Exists) + { + sourceFile = saveContainer.FaceFileHolder.FullName; + checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesFileNameExtension}"; + } + else + continue; + if (saveIndividually) + { + fileName = Path.GetFileName(checkFile); + if (distinct.Contains(fileName)) + continue; + distinct.Add(fileName); + } + if (File.Exists(checkFile)) + continue; + File.Copy(sourceFile, checkFile); + if (saveIndividually) + continue; + if (saveContainer.MakeAllHidden) + File.SetAttributes(checkFile, FileAttributes.Hidden); + if (saveContainer.HiddenFaceFileHolder is not null && saveContainer.HiddenFaceFileHolder.Exists) + { + sourceFile = saveContainer.HiddenFaceFileHolder.FullName; + checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesHiddenFileNameExtension}"; + } + else if (saveContainer.FacePartsFileHolder is not null && saveContainer.FacePartsFileHolder.Exists) + { + sourceFile = saveContainer.FacePartsFileHolder.FullName; + checkFile = $"{saveContainer.CheckFile}{_Configuration.FacePartsFileNameExtension}"; + } + if (File.Exists(checkFile)) + continue; + File.Copy(sourceFile, checkFile); + if (saveContainer.MakeAllHidden) + File.SetAttributes(checkFile, FileAttributes.Hidden); + } + if (updated is null) + foreach (SaveContainer saveContainer in saveContainers) + { + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) + continue; + checkFile = saveContainer.CheckFile; + sourceFile = saveContainer.ResizedFileHolder.FullName; + if (File.Exists(checkFile)) + continue; + File.Copy(sourceFile, checkFile); + if (saveContainer.MakeAllHidden) + File.SetAttributes(checkFile, FileAttributes.Hidden); + } + foreach (SaveContainer saveContainer in saveContainers) + { + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.ShortcutFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) + continue; + try + { + string description = saveContainer.FaceFileHolder is not null ? saveContainer.FaceFileHolder.Name : string.Empty; + windowsShortcut = new() { Path = saveContainer.ResizedFileHolder.FullName, Description = description }; + windowsShortcut.Save(saveContainer.ShortcutFile); + windowsShortcut.Dispose(); + if (saveContainer.MakeAllHidden) + File.SetAttributes(saveContainer.ShortcutFile, FileAttributes.Hidden); + } + catch (Exception) + { } + } + } + + private List GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection mappingCollection) + { + List results = new(); + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); + int season; + long personKey; + string fileName; + string directory; + string weekOfYear; + DateTime dateTime; + string description; + string directoryName; + List? personKeys; + string personKeyFormatted; + Calendar calendar = new CultureInfo("en-US").Calendar; + ReadOnlyDictionary> idToPersonKeys = Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); + foreach (Mapping mapping in mappingCollection) + { + dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(); + description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey; + (season, _) = IProperty.GetSeason(dateTime.DayOfYear); + weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); + directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Year}.{season}-MM{dateTime.Month:00}-WW{weekOfYear}"); + fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); + if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null) + continue; + directoryName = Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName); + if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim())) + { + // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " + directory = Path.Combine($"{eDistanceContentDirectory}---", "Model Shortcuts", FileSystemSafe().Replace(mapping.MappingFromItem.Model.Trim(), "_"), directoryName); + fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); + } + if (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($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName); + fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); + if (IPerson.IsDefaultName(mapping.MappingFromPerson)) + continue; + directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName); + fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); + } + return results; + } + + private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List distinctFilteredIds) + { + List renameCollection = new(); + foreach (KeyValuePair>> keyValuePair in _IdToLocationContainers) + { + if (distinctFilteredIds.Contains(keyValuePair.Key)) + continue; + foreach (LocationContainer locationContainer in keyValuePair.Value) + { + if (locationContainer.File.Contains('!')) + continue; + renameCollection.Add(locationContainer.File); + } + } + if (renameCollection.Count > 0) + IDirectory.MoveFiles(renameCollection, propertyConfiguration.ResultContent, "(abd)"); + } + private readonly long _Ticks; private readonly Serilog.ILogger? _Log; private readonly Configuration? _Configuration; @@ -236,114 +434,6 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic return result; } - public void SaveContainers(bool saveIndividually, int? updated, List saveContainers) - { - if (_Configuration is null) - throw new NullReferenceException(nameof(_Configuration)); - string fileName; - string checkFile; - string sourceFile; - List distinct = new(); - WindowsShortcut windowsShortcut; - string[] directories = (from l in saveContainers select l.Directory).Distinct().ToArray(); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); - string message; - if (updated is null) - message = $") {saveContainers.Count:000} save(s) - {totalSeconds} total second(s)"; - else - message = $") {saveContainers.Count:000} save(s) - {updated} Updated - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - foreach (string directory in directories) - { - if (string.IsNullOrEmpty(directory)) - continue; - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - } - using ProgressBar progressBar = new(saveContainers.Count, message, options); - foreach (SaveContainer saveContainer in saveContainers) - { - progressBar.Tick(); - if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.FaceFileHolder is null) - continue; - if (saveContainer.FacePartsFileHolder is null && saveContainer.HiddenFaceFileHolder is null && saveContainer.ResizedFileHolder is null) - { - checkFile = saveContainer.CheckFile; - sourceFile = saveContainer.FaceFileHolder.FullName; - } - else if (!saveContainer.FaceFileHolder.Exists && saveContainer.ResizedFileHolder is not null && saveContainer.ResizedFileHolder.Exists) - { - checkFile = saveContainer.CheckFile; - sourceFile = saveContainer.ResizedFileHolder.FullName; - } - else if (saveContainer.FaceFileHolder.Exists) - { - sourceFile = saveContainer.FaceFileHolder.FullName; - checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesFileNameExtension}"; - } - else - continue; - if (saveIndividually) - { - fileName = Path.GetFileName(checkFile); - if (distinct.Contains(fileName)) - continue; - distinct.Add(fileName); - } - if (File.Exists(checkFile)) - continue; - File.Copy(sourceFile, checkFile); - if (saveIndividually) - continue; - if (saveContainer.MakeAllHidden) - File.SetAttributes(checkFile, FileAttributes.Hidden); - if (saveContainer.HiddenFaceFileHolder is not null && saveContainer.HiddenFaceFileHolder.Exists) - { - sourceFile = saveContainer.HiddenFaceFileHolder.FullName; - checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesHiddenFileNameExtension}"; - } - else if (saveContainer.FacePartsFileHolder is not null && saveContainer.FacePartsFileHolder.Exists) - { - sourceFile = saveContainer.FacePartsFileHolder.FullName; - checkFile = $"{saveContainer.CheckFile}{_Configuration.FacePartsFileNameExtension}"; - } - if (File.Exists(checkFile)) - continue; - File.Copy(sourceFile, checkFile); - if (saveContainer.MakeAllHidden) - File.SetAttributes(checkFile, FileAttributes.Hidden); - } - if (updated is null) - foreach (SaveContainer saveContainer in saveContainers) - { - if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) - continue; - checkFile = saveContainer.CheckFile; - sourceFile = saveContainer.ResizedFileHolder.FullName; - if (File.Exists(checkFile)) - continue; - File.Copy(sourceFile, checkFile); - if (saveContainer.MakeAllHidden) - File.SetAttributes(checkFile, FileAttributes.Hidden); - } - foreach (SaveContainer saveContainer in saveContainers) - { - if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.ShortcutFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists) - continue; - try - { - string description = saveContainer.FaceFileHolder is not null ? saveContainer.FaceFileHolder.Name : string.Empty; - windowsShortcut = new() { Path = saveContainer.ResizedFileHolder.FullName, Description = description }; - windowsShortcut.Save(saveContainer.ShortcutFile); - windowsShortcut.Dispose(); - if (saveContainer.MakeAllHidden) - File.SetAttributes(saveContainer.ShortcutFile, FileAttributes.Hidden); - } - catch (Exception) - { } - } - } - private SaveContainer? GetMatchSaveContainer(string dFacesContentDirectory, string d2FacePartsContentDirectory, string directory, Mapping mapping) { if (_Configuration is null) @@ -900,62 +990,6 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic SaveContainers(saveIndividually, null, saveContainers); } - private List GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection mappingCollection) - { - List results = new(); - if (_Configuration is null) - throw new NullReferenceException(nameof(_Configuration)); - int season; - long personKey; - string fileName; - string directory; - string weekOfYear; - DateTime dateTime; - string description; - string directoryName; - List? personKeys; - string personKeyFormatted; - Calendar calendar = new CultureInfo("en-US").Calendar; - ReadOnlyDictionary> idToPersonKeys = Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); - foreach (Mapping mapping in mappingCollection) - { - dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(); - description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey; - (season, _) = IProperty.GetSeason(dateTime.DayOfYear); - weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Year}.{season}-MM{dateTime.Month:00}-WW{weekOfYear}"); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); - if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null) - continue; - directoryName = Path.GetFileName(mapping.MappingFromItem.ImageFileHolder.DirectoryName); - if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim())) - { - // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " - directory = Path.Combine($"{eDistanceContentDirectory}---", "Model Shortcuts", FileSystemSafe().Replace(mapping.MappingFromItem.Model.Trim(), "_"), directoryName); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); - } - if (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($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); - if (IPerson.IsDefaultName(mapping.MappingFromPerson)) - continue; - directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); - } - return results; - } - public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary> personKeyToIds, ReadOnlyCollection mappingCollection) { string hiddenFile; @@ -1138,22 +1172,6 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic return result; } - private bool IsUsed(bool ignoreXMatches, int id, ReadOnlyDictionary>? wholePercentagesToPersonContainers, int wholePercentages) - { - bool result; - List? wholePercentagesCollection; - ReadOnlyCollection? personContainers; - result = _SkipCollection.TryGetValue(id, out wholePercentagesCollection) && wholePercentagesCollection.Contains(wholePercentages); - if (!result && wholePercentagesToPersonContainers is not null) - if (wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers)) - if (!ignoreXMatches || !personContainers.Any(l => IPerson.IsDefaultName(l))) - result = true; - return result; - } - - public bool IsUsed(bool ignoreXMatches, int id, ReadOnlyDictionary>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) => - IsUsed(ignoreXMatches, id, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages); - public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) => _SkipCollection.TryGetValue(id, out List? wholePercentagesCollection) && wholePercentagesCollection.Contains(mappingFromLocation.WholePercentages); @@ -1189,24 +1207,6 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic return result; } - private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List distinctFilteredIds) - { - List renameCollection = new(); - foreach (KeyValuePair>> keyValuePair in _IdToLocationContainers) - { - if (distinctFilteredIds.Contains(keyValuePair.Key)) - continue; - foreach (LocationContainer locationContainer in keyValuePair.Value) - { - if (locationContainer.File.Contains('!')) - continue; - renameCollection.Add(locationContainer.File); - } - } - if (renameCollection.Count > 0) - IDirectory.MoveFiles(renameCollection, propertyConfiguration.ResultContent, "(abd)"); - } - public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, Container[] containers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) { string[] directories; diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index b070d20..2d6e4e6 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -1,4 +1,4 @@ -using Humanizer; +using Humanizer; using ShellProgressBar; using System.Collections.ObjectModel; using System.Diagnostics; @@ -20,6 +20,11 @@ internal abstract class MapLogic bool IsDefault, string MappedFaceFile); + internal record Duplicate(long PersonKey, + int Id, + string File, + float? Percent); + internal record TicksDirectory(string Directory, string DirectoryName, DateTime DirectoryDateTime, @@ -104,6 +109,71 @@ internal abstract class MapLogic } } + internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, DateTime dateTimeOriginalThenMinimumDateTime, bool? isWrongYear) + { + string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTimeOriginalThenMinimumDateTime.Ticks, isWrongYear); + return result; + } + + private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long dateTimeOriginalThenMinimumDateTimeTicks, bool? isWrongYear) + { + int years; + string result; + TimeSpan? timeSpan = IPersonBirthday.GetTimeSpan(dateTimeOriginalThenMinimumDateTimeTicks, isWrongYear, personBirthday); + if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) + result = "!---"; + else if (timeSpan.HasValue) + { + (years, _) = IPersonBirthday.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, personBirthday); + result = $"^{years:000}"; + } + else if (approximateYears.HasValue) + { + DateTime dateTime = new(ticks); + (years, _) = IAge.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, dateTime.AddYears(-approximateYears.Value)); + result = $"~{years:000}"; + } + else + { + string isWrongYearFlag = IItem.GetWrongYearFlag(isWrongYear); + result = $"{isWrongYearFlag}{new DateTime(dateTimeOriginalThenMinimumDateTimeTicks):yyyy}"; + } + return result; + } + + internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection items) + { + Mapping[] results; + ReadOnlyCollection faces = GetFaces(items); + results = GetSelectedMappingCollection(faces); + return results; + } + + internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection faces) + { + Mapping[] results; + IEnumerable collection = from l in faces orderby l.Mapping?.MappingFromItem.Id select l.Mapping; + results = (from l in collection where l is not null select l).ToArray(); + return results; + } + + internal static ReadOnlyCollection GetFaces(ReadOnlyCollection items) + { + List results = new(); + foreach (Item item in items) + { + if (item.Property?.Id is null || item.ResizedFileHolder is null) + continue; + foreach (Face face in item.Faces) + { + if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) + continue; + results.Add(face); + } + } + return new(results); + } + private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames) { string checkFile; @@ -125,6 +195,129 @@ internal abstract class MapLogic } } + private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory) + { + string[] files; + string checkFile; + string? checkDirectory; + string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory)); + if (!Directory.Exists(checkDirectory)) + Directory.Move(directory, checkDirectory); + else + { + files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); + foreach (string file in files) + { + if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted)) + continue; + checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted); + checkDirectory = Path.GetDirectoryName(checkFile); + if (checkDirectory is null) + continue; + if (File.Exists(checkFile)) + continue; + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + File.Move(file, checkFile); + } + } + } + } + + private static List<(long, int?, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, ReadOnlyCollection personContainers) + { + List<(long, int?, string)> results = new(); + string fileName; + List distinct = new(); + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.Key is null) + continue; + for (int i = personContainer.DisplayDirectoryAllFiles.Length - 1; i > -1; i--) + { + if (!personContainer.DisplayDirectoryAllFiles[i].EndsWith(fileNameExtension)) + continue; + fileName = Path.GetFileName(personContainer.DisplayDirectoryAllFiles[i]); + if (distinct.Contains(fileName)) + continue; + distinct.Add(fileName); + results.Add(new(personContainer.Key.Value, null, personContainer.DisplayDirectoryAllFiles[i])); + } + } + return results; + } + + private static void OpenPossibleDuplicates(Configuration configuration, List duplicates) + { + string personKeyFormatted; + foreach (Duplicate duplicate in duplicates) + { + if (duplicate.Percent is null) + continue; + _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(duplicate.File), "\"")); + personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, duplicate.PersonKey); + } + foreach ((long personKey, int id, string file, float? percent) in duplicates) + { + if (percent is not null && percent.Value == 0) + continue; + _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); + personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); + } + foreach ((long personKey, int id, string file, float? percent) in duplicates) + { + if (percent is not null && percent.Value > 0) + continue; + _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); + personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); + } + } + + private static List UpdateDateVerifyAndGetTicksDirectories(string eDistanceContentDirectory) + { + List results = new(); + float? totalDays; + string ticksDirectoryName; + DateTime directoryDateTime; + DirectoryInfo directoryInfo; + long? lastDirectoryTicks = null; + DateTime dateTime = DateTime.Now; + for (int i = 1; i < 5; i++) + _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); + if (!Directory.Exists(eDistanceContentDirectory)) + _ = Directory.CreateDirectory(eDistanceContentDirectory); + string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string ticksDirectory in ticksDirectories) + { + ticksDirectoryName = Path.GetFileName(ticksDirectory); + if (ticksDirectoryName.Length < 3 || ticksDirectoryName.First() != '(' || ticksDirectoryName[^1] != ')') + continue; + if (!long.TryParse(ticksDirectoryName[1..^1], out long directoryTicks)) + { + if (!long.TryParse(ticksDirectoryName[1..^4], out directoryTicks)) + throw new NotSupportedException(); + } + directoryInfo = new(ticksDirectory); + directoryDateTime = new DateTime(directoryTicks); + if (directoryInfo.CreationTime.Ticks != directoryTicks) + Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); + if (directoryInfo.LastWriteTime.Ticks != directoryTicks) + Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); + totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays; + results.Add(new(ticksDirectory, ticksDirectoryName, new(directoryTicks), new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day + 1), totalDays)); + if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0) + continue; + lastDirectoryTicks = directoryTicks; + } + string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray(); + if (compare.Length > 0) + throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); + return results; + } + private static void Individually(Configuration configuration, TicksDirectory ticksDirectory, string directory) { bool isDefault; @@ -198,35 +391,13 @@ internal abstract class MapLogic } } - private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory) + private static void RenameUnknown(string[] files) { - string[] files; - string checkFile; - string? checkDirectory; - string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) + foreach (string file in files) { - checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory)); - if (!Directory.Exists(checkDirectory)) - Directory.Move(directory, checkDirectory); - else - { - files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); - foreach (string file in files) - { - if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted)) - continue; - checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted); - checkDirectory = Path.GetDirectoryName(checkFile); - if (checkDirectory is null) - continue; - if (File.Exists(checkFile)) - continue; - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - File.Move(file, checkFile); - } - } + if (file.EndsWith(".unk")) + continue; + File.Move(file, $"{file}.unk"); } } @@ -239,13 +410,428 @@ internal abstract class MapLogic Directory.Move(personKeyDirectory, newestPersonKeyDirectory); } - private static void RenameUnknown(string[] files) + private static (long, PersonContainer)[] GetDistinctCollection(Configuration configuration, IEnumerable personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer) { + (long, PersonContainer)[] results; + const int zero = 0; + List errors = new(); + string newestPersonKeyFormatted; + List<(long PersonKey, PersonContainer PersonContainer)> collection = new(); + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.Key is null) + continue; + if (!personKeyToPersonContainerCollection.ContainsKey(personContainer.Key.Value)) + personKeyToPersonContainerCollection.Add(personContainer.Key.Value, new()); + personKeyToPersonContainerCollection[personContainer.Key.Value].Add(personContainer); + newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value); + if (!personKeyFormattedToPersonContainer.ContainsKey(newestPersonKeyFormatted)) + personKeyFormattedToPersonContainer.Add(newestPersonKeyFormatted, personContainer); + } + foreach (KeyValuePair> keyValuePair in personKeyToPersonContainerCollection) + { + if (keyValuePair.Value.Count != 1 && (from l in keyValuePair.Value select l.DisplayDirectoryName).Distinct().Count() != 1) + errors.Add(keyValuePair.Value[zero].DisplayDirectoryName); + collection.Add(new(keyValuePair.Key, keyValuePair.Value[zero])); + } + if (errors.Count > 0) + throw new Exception(string.Join(Environment.NewLine, errors)); + results = (from l in collection orderby l.PersonKey descending select (l.PersonKey, l.PersonContainer)).ToArray(); + return results; + } + + private static Dictionary>> GetAll(Configuration configuration, ReadOnlyDictionary personKeyFormattedToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection) + { + Dictionary>> results = new(); + PersonBirthday? personBirthday; + PersonContainer? personContainer; + List? personContainers; + Dictionary>? idTo; + if (personKeyFormattedIdThenWholePercentagesCollection.Count > 0) + { + foreach (PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages in personKeyFormattedIdThenWholePercentagesCollection) + { + personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormattedIdThenWholePercentages.PersonKeyFormatted); + if (personBirthday is null) + throw new Exception(); + if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer)) + throw new Exception(); + if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo)) + { + results.Add(personKeyFormattedIdThenWholePercentages.Id, new()); + if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo)) + throw new Exception(); + } + if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers)) + { + idTo.Add(personKeyFormattedIdThenWholePercentages.WholePercentages, new()); + if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers)) + throw new Exception(); + } + personContainers.Add(personContainer); + } + } + return results; + } + + private static ReadOnlyDictionary>> GetReadOnly(Dictionary>> idThenWholePercentagesToPersonContainerCollection) + { + Dictionary>> results = new(); + List distinct = new(); + List personContainers; + Dictionary> keyValuePairs; + foreach (KeyValuePair>> idTo in idThenWholePercentagesToPersonContainerCollection) + { + keyValuePairs = new(); + foreach (KeyValuePair> wholePercentagesTo in idThenWholePercentagesToPersonContainerCollection[idTo.Key]) + { + distinct.Clear(); + personContainers = new(); + foreach (PersonContainer personContainer in wholePercentagesTo.Value) + { + if (personContainer.Key is null) + throw new Exception(); + if (distinct.Contains(personContainer.Key.Value)) + continue; + personContainers.Add(personContainer); + } + keyValuePairs.Add(wholePercentagesTo.Key, new(personContainers)); + } + results.Add(idTo.Key, new(keyValuePairs)); + } + return new(results); + } + + private static ReadOnlyDictionary> GetReadOnly(Dictionary> keyValuePairs) + { + Dictionary> results = new(); + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return new(results); + } + + private static List GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List personKeys, ReadOnlyDictionary personKeyToCount) + { + List results = new(); + bool check; + long personKey; + int? approximateYears = null; + PersonBirthday personBirthday; + PersonContainer personContainer; + string[] personDisplayDirectoryAllFiles = Array.Empty(); + DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1); + long oneHour = new DateTime(1, 1, 1, 1, 0, 0).Ticks - new DateTime(1, 1, 1).Ticks; + for (int i = 0; i < int.MaxValue; i++) + { + check = false; + personKey = incrementDate.Ticks; + incrementDate = incrementDate.AddDays(1); + if (incrementDate.Ticks > ticks) + break; + if (personKeys.Contains(personKey)) + continue; + if (personKeyToCount.ContainsKey(personKey)) + continue; + for (int j = 1; j < 24; j++) + { + if (personKeys.Contains(personKey + (oneHour * j))) + { + check = true; + break; + } + if (personKeyToCount.ContainsKey(personKey + (oneHour * j))) + { + check = true; + break; + } + } + if (check) + continue; + personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2)); + personContainer = new(approximateYears, new PersonBirthday[] { personBirthday }, personDisplayDirectoryAllFiles, configuration.MappingDefaultName, personKey); + results.Add(personContainer); + if (results.Count > 99) + break; + } + return results; + } + + private static string? GetDisplayDirectoryName(Dictionary personKeyToPersonContainer, long key) + { + string? result = null; + if (personKeyToPersonContainer.TryGetValue(key, out PersonContainer? personContainer)) + { + result = personContainer.DisplayDirectoryName; + if (string.IsNullOrEmpty(result)) + throw new NotSupportedException(); + } + return result; + } + + private static List<(long PersonKey, int? DirectoryNumber, string File)> GetCollection(Configuration configuration, ReadOnlyCollection personContainers, List records) + { + List<(long PersonKey, int? DirectoryNumber, string File)> results = new(); + string file; + long personKey; + string fileName; + List distinct = new(); + PersonBirthday? personBirthday; + results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, personContainers)); + foreach (Record record in records) + { + personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, record.PersonKeyFormatted); + if (personBirthday is null) + continue; + fileName = Path.GetFileName(record.MappedFaceFile); + if (distinct.Contains(fileName)) + continue; + distinct.Add(fileName); + personKey = personBirthday.Value.Ticks; + results.Add(new(personKey, record.DirectoryNumber, record.MappedFaceFile)); + } + for (int i = results.Count - 1; i > -1; i--) + { + file = results[i].File; + if (file.EndsWith(".old")) + { + results.RemoveAt(i); + continue; + } + if (!file.EndsWith(".dup") && !file.EndsWith(".unk") && !file.EndsWith(".abd")) + continue; + if (!File.Exists(file)) + continue; + File.Move(file, file[..^4]); + results[i] = new(results[i].PersonKey, results[i].DirectoryNumber, file[..^4]); + } + return results; + } + + private static void ParallelFor(Configuration configuration, string eDistanceContentDirectory, Dictionary> skipCollection, List> locationContainers, long personKey, int? directoryNumber, string file) + { + string checkFile; + string[] fileMatches; + const string lnk = ".lnk"; + int? id, wholePercentages; + IReadOnlyList directories; + List<(string File, int WholePercentages)>? wholePercentagesCollection; + bool fromDistanceContent = !file.EndsWith(lnk) && file.Contains(eDistanceContentDirectory); + if (!file.EndsWith(lnk)) + (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, file); + else + (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, file[..^4]); + if (id is null || wholePercentages is null) + return; + if (skipCollection.TryGetValue(id.Value, out wholePercentagesCollection)) + { + fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray(); + foreach (string fileMatch in fileMatches) + { + if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch)) + continue; + checkFile = $"{fileMatch}.dup"; + if (File.Exists(checkFile)) + continue; + File.Move(fileMatch, checkFile); + continue; + } + } + if (file.EndsWith(lnk) || (!configuration.DistanceMoveUnableToMatch && !configuration.DistanceRenameToMatch) || !File.Exists(file)) + directories = new List(); + else + directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); + RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value); + lock (locationContainers) + locationContainers.Add(new(fromDistanceContent, directoryNumber, file, personKey, id.Value, wholePercentages.Value, directories, rectangle, null)); + } + + private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection> locationContainers) + { + string key; + float? percent; + float itemPercentagesArea; + List delete = new(); + List duplicates = new(); + RectangleF? itemPercentagesRectangle; + (string File, int WholePercentages) item; + Dictionary distinct = new(); + foreach (LocationContainer locationContainer in locationContainers) + { + key = string.Concat(locationContainer.PersonKey, locationContainer.Id); + if (distinct.TryGetValue(key, out item)) + { + if (item.WholePercentages == locationContainer.WholePercentages) + continue; + itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages); + if (itemPercentagesRectangle is null || locationContainer.Rectangle is null) + percent = null; + else + { + itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height; + percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, locationContainer.Rectangle.Value); + } + delete.Add(item.File); + delete.Add(locationContainer.File); + duplicates.Add(new(locationContainer.PersonKey, locationContainer.Id, locationContainer.File, percent)); + continue; + } + distinct.Add(key, new(locationContainer.File, locationContainer.WholePercentages)); + } + if (!configuration.DeletePossibleDuplicates && duplicates.Count > 0) + OpenPossibleDuplicates(configuration, duplicates); + else + { + if (delete.Count > 5) + throw new Exception("Something maybe wrong!"); + foreach (string file in delete) + { + if (File.Exists(file)) + File.Delete(file); + } + } + } + + internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, MappingFromItem mappingFromItem) + { + string result; + (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, mappingFromItem.ImageFileHolder.NameWithoutExtension); + result = Path.Combine(dFacesContentDirectory, propertyConfiguration.ResultAllInOne, directoryName, mappingFromItem.ImageFileHolder.NameWithoutExtension); + return result; + } + + private static IEnumerable<(string, string)> GetCollection(string[] yearDirectories) + { + foreach (string l in yearDirectories) + yield return new(l, Path.GetFileName(l)); + } + + private static List<(string, long)> GetGenealogicalDataCommunicationDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat) + { + List<(string, long)> results = new(); + string directory; + DateTime dateTime; + string[] personKeyDirectories; + string[] personDisplayDirectoryNames; + string personKeyFormattedDirectoryName; + string? genealogicalDataCommunicationDirectory = Path.GetDirectoryName(genealogicalDataCommunicationFile); + foreach (string jLink in jLinks) + { + if (genealogicalDataCommunicationDirectory is null) + continue; + directory = Path.Combine(genealogicalDataCommunicationDirectory, jLink); + if (!Directory.Exists(directory)) + continue; + personDisplayDirectoryNames = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly); + foreach (string personDisplayDirectoryName in personDisplayDirectoryNames) + { + personKeyDirectories = Directory.GetDirectories(personDisplayDirectoryName, "*", SearchOption.TopDirectoryOnly); + foreach (string personKeyFormattedDirectory in personKeyDirectories) + { + personKeyFormattedDirectoryName = Path.GetFileName(personKeyFormattedDirectory); + if (personKeyFormattedDirectoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormattedDirectoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + continue; + results.Add((directory, dateTime.Ticks)); + } + } + } + return results; + } + + private static string? TryToFind(char[] personCharacters, string a2PeopleSingletonDirectory, List<(string Directory, string DirectoryName, string DirectoryNameSplitFirst)> a2PeopleSingletonDirectories, string file, string path) + { + string? result; + string? pathName = Path.GetFileName(path); + string? group = Path.GetDirectoryName(path); + string? groupName = Path.GetFileName(group); + if (pathName is null || group is null || groupName is null) + result = null; + else + { + string[] matches; + matches = (from l in a2PeopleSingletonDirectories where l.DirectoryName == pathName select l.Directory).ToArray(); + if (matches.Length == 1) + result = matches.First(); + else + { + string pathNameSplitFirst = pathName.Split(personCharacters).First(); + matches = (from l in a2PeopleSingletonDirectories where l.DirectoryNameSplitFirst == pathNameSplitFirst select l.Directory).ToArray(); + if (matches.Length == 1) + result = matches.First(); + else + { + string checkDirectory = Path.Combine(a2PeopleSingletonDirectory, groupName, pathName); + if (!Directory.Exists(checkDirectory)) + result = null; + else + result = checkDirectory; + } + } + if (!string.IsNullOrEmpty(result)) + { + try + { + WindowsShortcut windowsShortcut; + windowsShortcut = new() { Path = result }; + windowsShortcut.Save(file); + windowsShortcut.Dispose(); + } + catch (Exception) + { } + } + } + return result; + } + + private static List<(string, long)> GetJLinkResolvedDirectories(string personBirthdayFormat, List resolvedDirectories) + { + List<(string, long)> results = new(); + DateTime dateTime; + string directoryName; + string[] directories; + foreach (string resolvedDirectory in resolvedDirectories) + { + directories = Directory.GetDirectories(resolvedDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + directoryName = Path.GetFileName(directory); + if (directoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(directoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + continue; + results.Add((resolvedDirectory, dateTime.Ticks)); + } + } + if (results.Count != resolvedDirectories.Count) + results.Clear(); + return results; + } + + internal static void LookForAbandoned(List distinctFilteredIds, string directory, string directoryName) + { + string fileNameWithoutExtension; + bool nameWithoutExtensionIsIdFormat; + List renameCollection = new(); + bool nameWithoutExtensionIsPaddedIdFormat; + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); + string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray(); + string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); foreach (string file in files) { - if (file.EndsWith(".unk")) + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file))); + nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); + nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileNameWithoutExtension, sortOrderOnlyLengthIndex); + if (!nameWithoutExtensionIsIdFormat && !nameWithoutExtensionIsPaddedIdFormat) continue; - File.Move(file, $"{file}.unk"); + if (distinctFilteredIdsValues.Contains(fileNameWithoutExtension)) + continue; + renameCollection.Add(file); + } + if (renameCollection.Count > 0) + { + if (directoryName.Length == 2) + IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[0]}abd{directoryName[^1]}"); + else if (directoryName.Length == 4) + IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[..2]}abd{directoryName[^2..]}"); + else + throw new NotSupportedException(); } } @@ -488,68 +1074,6 @@ internal abstract class MapLogic } } - private static Dictionary>> GetAll(Configuration configuration, ReadOnlyDictionary personKeyFormattedToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection) - { - Dictionary>> results = new(); - PersonBirthday? personBirthday; - PersonContainer? personContainer; - List? personContainers; - Dictionary>? idTo; - if (personKeyFormattedIdThenWholePercentagesCollection.Count > 0) - { - foreach (PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages in personKeyFormattedIdThenWholePercentagesCollection) - { - personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormattedIdThenWholePercentages.PersonKeyFormatted); - if (personBirthday is null) - throw new Exception(); - if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer)) - throw new Exception(); - if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo)) - { - results.Add(personKeyFormattedIdThenWholePercentages.Id, new()); - if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo)) - throw new Exception(); - } - if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers)) - { - idTo.Add(personKeyFormattedIdThenWholePercentages.WholePercentages, new()); - if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers)) - throw new Exception(); - } - personContainers.Add(personContainer); - } - } - return results; - } - - private static ReadOnlyDictionary>> GetReadOnly(Dictionary>> idThenWholePercentagesToPersonContainerCollection) - { - Dictionary>> results = new(); - List distinct = new(); - List personContainers; - Dictionary> keyValuePairs; - foreach (KeyValuePair>> idTo in idThenWholePercentagesToPersonContainerCollection) - { - keyValuePairs = new(); - foreach (KeyValuePair> wholePercentagesTo in idThenWholePercentagesToPersonContainerCollection[idTo.Key]) - { - distinct.Clear(); - personContainers = new(); - foreach (PersonContainer personContainer in wholePercentagesTo.Value) - { - if (personContainer.Key is null) - throw new Exception(); - if (distinct.Contains(personContainer.Key.Value)) - continue; - personContainers.Add(personContainer); - } - keyValuePairs.Add(wholePercentagesTo.Key, new(personContainers)); - } - results.Add(idTo.Key, new(keyValuePairs)); - } - return new(results); - } - internal static ReadOnlyDictionary>> GetIdThenWholePercentagesToPersonContainers(Configuration configuration, ReadOnlyDictionary personKeyFormattedToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection) { ReadOnlyDictionary>> results; @@ -559,36 +1083,6 @@ internal abstract class MapLogic return results; } - private static (long, PersonContainer)[] GetDistinctCollection(Configuration configuration, IEnumerable personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer) - { - (long, PersonContainer)[] results; - const int zero = 0; - List errors = new(); - string newestPersonKeyFormatted; - List<(long PersonKey, PersonContainer PersonContainer)> collection = new(); - foreach (PersonContainer personContainer in personContainers) - { - if (personContainer.Key is null) - continue; - if (!personKeyToPersonContainerCollection.ContainsKey(personContainer.Key.Value)) - personKeyToPersonContainerCollection.Add(personContainer.Key.Value, new()); - personKeyToPersonContainerCollection[personContainer.Key.Value].Add(personContainer); - newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value); - if (!personKeyFormattedToPersonContainer.ContainsKey(newestPersonKeyFormatted)) - personKeyFormattedToPersonContainer.Add(newestPersonKeyFormatted, personContainer); - } - foreach (KeyValuePair> keyValuePair in personKeyToPersonContainerCollection) - { - if (keyValuePair.Value.Count != 1 && (from l in keyValuePair.Value select l.DisplayDirectoryName).Distinct().Count() != 1) - errors.Add(keyValuePair.Value[zero].DisplayDirectoryName); - collection.Add(new(keyValuePair.Key, keyValuePair.Value[zero])); - } - if (errors.Count > 0) - throw new Exception(string.Join(Environment.NewLine, errors)); - results = (from l in collection orderby l.PersonKey descending select (l.PersonKey, l.PersonContainer)).ToArray(); - return results; - } - internal static ReadOnlyCollection GetPersonKeyFormattedIdThenWholePercentages(Configuration configuration, long ticks, List collection) { List results = new(); @@ -616,52 +1110,6 @@ internal abstract class MapLogic return new(results); } - private static List GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List personKeys, ReadOnlyDictionary personKeyToCount) - { - List results = new(); - bool check; - long personKey; - int? approximateYears = null; - PersonBirthday personBirthday; - PersonContainer personContainer; - string[] personDisplayDirectoryAllFiles = Array.Empty(); - DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1); - long oneHour = new DateTime(1, 1, 1, 1, 0, 0).Ticks - new DateTime(1, 1, 1).Ticks; - for (int i = 0; i < int.MaxValue; i++) - { - check = false; - personKey = incrementDate.Ticks; - incrementDate = incrementDate.AddDays(1); - if (incrementDate.Ticks > ticks) - break; - if (personKeys.Contains(personKey)) - continue; - if (personKeyToCount.ContainsKey(personKey)) - continue; - for (int j = 1; j < 24; j++) - { - if (personKeys.Contains(personKey + (oneHour * j))) - { - check = true; - break; - } - if (personKeyToCount.ContainsKey(personKey + (oneHour * j))) - { - check = true; - break; - } - } - if (check) - continue; - personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2)); - personContainer = new(approximateYears, new PersonBirthday[] { personBirthday }, personDisplayDirectoryAllFiles, configuration.MappingDefaultName, personKey); - results.Add(personContainer); - if (results.Count > 99) - break; - } - return results; - } - internal static List GetNotMappedPersonContainers(Configuration configuration, long ticks, ReadOnlyCollection personContainers, ReadOnlyDictionary personKeyToCount) { List results = new(); @@ -687,18 +1135,6 @@ internal abstract class MapLogic return results; } - private static string? GetDisplayDirectoryName(Dictionary personKeyToPersonContainer, long key) - { - string? result = null; - if (personKeyToPersonContainer.TryGetValue(key, out PersonContainer? personContainer)) - { - result = personContainer.DisplayDirectoryName; - if (string.IsNullOrEmpty(result)) - throw new NotSupportedException(); - } - return result; - } - internal static void SetPersonKeyToPersonContainer(Configuration configuration, ReadOnlyCollection personContainers, ReadOnlyDictionary personKeyToCount, Dictionary personKeyToPersonContainer, ReadOnlyDictionary> personKeyToPersonContainerCollection) { string? displayDirectoryName; @@ -792,220 +1228,6 @@ internal abstract class MapLogic } } - private static List UpdateDateVerifyAndGetTicksDirectories(string eDistanceContentDirectory) - { - List results = new(); - float? totalDays; - string ticksDirectoryName; - DateTime directoryDateTime; - DirectoryInfo directoryInfo; - long? lastDirectoryTicks = null; - DateTime dateTime = DateTime.Now; - for (int i = 1; i < 5; i++) - _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); - if (!Directory.Exists(eDistanceContentDirectory)) - _ = Directory.CreateDirectory(eDistanceContentDirectory); - string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string ticksDirectory in ticksDirectories) - { - ticksDirectoryName = Path.GetFileName(ticksDirectory); - if (ticksDirectoryName.Length < 3 || ticksDirectoryName.First() != '(' || ticksDirectoryName[^1] != ')') - continue; - if (!long.TryParse(ticksDirectoryName[1..^1], out long directoryTicks)) - { - if (!long.TryParse(ticksDirectoryName[1..^4], out directoryTicks)) - throw new NotSupportedException(); - } - directoryInfo = new(ticksDirectory); - directoryDateTime = new DateTime(directoryTicks); - if (directoryInfo.CreationTime.Ticks != directoryTicks) - Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); - if (directoryInfo.LastWriteTime.Ticks != directoryTicks) - Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); - totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays; - results.Add(new(ticksDirectory, ticksDirectoryName, new(directoryTicks), new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day + 1), totalDays)); - if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0) - continue; - lastDirectoryTicks = directoryTicks; - } - string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray(); - if (compare.Length > 0) - throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); - return results; - } - - private static List<(long, int?, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, ReadOnlyCollection personContainers) - { - List<(long, int?, string)> results = new(); - string fileName; - List distinct = new(); - foreach (PersonContainer personContainer in personContainers) - { - if (personContainer.Key is null) - continue; - for (int i = personContainer.DisplayDirectoryAllFiles.Length - 1; i > -1; i--) - { - if (!personContainer.DisplayDirectoryAllFiles[i].EndsWith(fileNameExtension)) - continue; - fileName = Path.GetFileName(personContainer.DisplayDirectoryAllFiles[i]); - if (distinct.Contains(fileName)) - continue; - distinct.Add(fileName); - results.Add(new(personContainer.Key.Value, null, personContainer.DisplayDirectoryAllFiles[i])); - } - } - return results; - } - - private static List<(long PersonKey, int? DirectoryNumber, string File)> GetCollection(Configuration configuration, ReadOnlyCollection personContainers, List records) - { - List<(long PersonKey, int? DirectoryNumber, string File)> results = new(); - string file; - long personKey; - string fileName; - List distinct = new(); - PersonBirthday? personBirthday; - results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, personContainers)); - foreach (Record record in records) - { - personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, record.PersonKeyFormatted); - if (personBirthday is null) - continue; - fileName = Path.GetFileName(record.MappedFaceFile); - if (distinct.Contains(fileName)) - continue; - distinct.Add(fileName); - personKey = personBirthday.Value.Ticks; - results.Add(new(personKey, record.DirectoryNumber, record.MappedFaceFile)); - } - for (int i = results.Count - 1; i > -1; i--) - { - file = results[i].File; - if (file.EndsWith(".old")) - { - results.RemoveAt(i); - continue; - } - if (!file.EndsWith(".dup") && !file.EndsWith(".unk") && !file.EndsWith(".abd")) - continue; - if (!File.Exists(file)) - continue; - File.Move(file, file[..^4]); - results[i] = new(results[i].PersonKey, results[i].DirectoryNumber, file[..^4]); - } - return results; - } - - private static void ParallelFor(Configuration configuration, string eDistanceContentDirectory, Dictionary> skipCollection, List> locationContainers, long personKey, int? directoryNumber, string file) - { - string checkFile; - string[] fileMatches; - const string lnk = ".lnk"; - int? id, wholePercentages; - IReadOnlyList directories; - List<(string File, int WholePercentages)>? wholePercentagesCollection; - bool fromDistanceContent = !file.EndsWith(lnk) && file.Contains(eDistanceContentDirectory); - if (!file.EndsWith(lnk)) - (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, file); - else - (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, file[..^4]); - if (id is null || wholePercentages is null) - return; - if (skipCollection.TryGetValue(id.Value, out wholePercentagesCollection)) - { - fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray(); - foreach (string fileMatch in fileMatches) - { - if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch)) - continue; - checkFile = $"{fileMatch}.dup"; - if (File.Exists(checkFile)) - continue; - File.Move(fileMatch, checkFile); - continue; - } - } - if (file.EndsWith(lnk) || (!configuration.DistanceMoveUnableToMatch && !configuration.DistanceRenameToMatch) || !File.Exists(file)) - directories = new List(); - else - directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); - RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value); - lock (locationContainers) - locationContainers.Add(new(fromDistanceContent, directoryNumber, file, personKey, id.Value, wholePercentages.Value, directories, rectangle, null)); - } - - private static void OpenPossibleDuplicates(Configuration configuration, List<(long, int, string, float?)> duplicates) - { - string personKeyFormatted; - foreach ((long personKey, int id, string file, float? percent) in duplicates) - { - if (percent is null) - continue; - _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); - personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); - } - foreach ((long personKey, int id, string file, float? percent) in duplicates) - { - if (percent is not null && percent.Value == 0) - continue; - _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); - personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); - } - foreach ((long personKey, int id, string file, float? percent) in duplicates) - { - if (percent is not null && percent.Value > 0) - continue; - _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); - personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); - } - } - - private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection> locationContainers) - { - string key; - float? percent; - float itemPercentagesArea; - List delete = new(); - RectangleF? itemPercentagesRectangle; - (string File, int WholePercentages) item; - Dictionary distinct = new(); - List<(long, int, string, float?)> duplicates = new(); - foreach (LocationContainer locationContainer in locationContainers) - { - key = string.Concat(locationContainer.PersonKey, locationContainer.Id); - if (distinct.TryGetValue(key, out item)) - { - if (item.WholePercentages == locationContainer.WholePercentages) - continue; - itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages); - if (itemPercentagesRectangle is null || locationContainer.Rectangle is null) - percent = null; - else - { - itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height; - percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, locationContainer.Rectangle.Value); - } - delete.Add(item.File); - delete.Add(locationContainer.File); - duplicates.Add(new(locationContainer.PersonKey, locationContainer.Id, locationContainer.File, percent)); - continue; - } - distinct.Add(key, new(locationContainer.File, locationContainer.WholePercentages)); - } - if (!configuration.DeletePossibleDuplicates && duplicates.Count > 0) - OpenPossibleDuplicates(configuration, duplicates); - else - { - if (delete.Count > 5) - throw new Exception("Something maybe wrong!"); - foreach (string file in delete) - { - if (File.Exists(file)) - File.Delete(file); - } - } - } - internal static List> GetLocationContainers(Shared.Models.Methods.IDistance distance, int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection personContainers, string eDistanceContentDirectory, Dictionary> skipCollection, List records) { List> results = new(); @@ -1079,38 +1301,6 @@ internal abstract class MapLogic return result; } - private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long dateTimeOriginalThenMinimumDateTimeTicks, bool? isWrongYear) - { - int years; - string result; - TimeSpan? timeSpan = IPersonBirthday.GetTimeSpan(dateTimeOriginalThenMinimumDateTimeTicks, isWrongYear, personBirthday); - if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) - result = "!---"; - else if (timeSpan.HasValue) - { - (years, _) = IPersonBirthday.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, personBirthday); - result = $"^{years:000}"; - } - else if (approximateYears.HasValue) - { - DateTime dateTime = new(ticks); - (years, _) = IAge.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, dateTime.AddYears(-approximateYears.Value)); - result = $"~{years:000}"; - } - else - { - string isWrongYearFlag = IItem.GetWrongYearFlag(isWrongYear); - result = $"{isWrongYearFlag}{new DateTime(dateTimeOriginalThenMinimumDateTimeTicks):yyyy}"; - } - return result; - } - - internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, DateTime dateTimeOriginalThenMinimumDateTime, bool? isWrongYear) - { - string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTimeOriginalThenMinimumDateTime.Ticks, isWrongYear); - return result; - } - internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem) { string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear); @@ -1128,14 +1318,6 @@ internal abstract class MapLogic return result; } - internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, MappingFromItem mappingFromItem) - { - string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, mappingFromItem.ImageFileHolder.NameWithoutExtension); - result = Path.Combine(dFacesContentDirectory, propertyConfiguration.ResultAllInOne, directoryName, mappingFromItem.ImageFileHolder.NameWithoutExtension); - return result; - } - internal static string GetFacePartsDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, MappingFromItem mappingFromItem) { string result; @@ -1202,12 +1384,6 @@ internal abstract class MapLogic return (new(checkFile, directory, faceFileHolder), saveContainer); } - private static IEnumerable<(string, string)> GetCollection(string[] yearDirectories) - { - foreach (string l in yearDirectories) - yield return new(l, Path.GetFileName(l)); - } - internal static void SaveMappingShortcuts(string mappingDirectory) { string? shortcutFileName; @@ -1289,47 +1465,6 @@ internal abstract class MapLogic return new(results); } - internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection faces) - { - Mapping[] results; - IEnumerable collection = from l in faces orderby l.Mapping?.MappingFromItem.Id select l.Mapping; - results = (from l in collection where l is not null select l).ToArray(); - return results; - } - - internal static ReadOnlyCollection GetFaces(ReadOnlyCollection items) - { - List results = new(); - foreach (Item item in items) - { - if (item.Property?.Id is null || item.ResizedFileHolder is null) - continue; - foreach (Face face in item.Faces) - { - if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) - continue; - results.Add(face); - } - } - return new(results); - } - - internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection items) - { - Mapping[] results; - ReadOnlyCollection faces = GetFaces(items); - results = GetSelectedMappingCollection(faces); - return results; - } - - private static ReadOnlyDictionary> GetReadOnly(Dictionary> keyValuePairs) - { - Dictionary> results = new(); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - results.Add(keyValuePair.Key, new(keyValuePair.Value)); - return new(results); - } - internal static ReadOnlyDictionary> GetIdToWholePercentagesToFace(ReadOnlyCollection mappingCollection) { Dictionary> results = new(); @@ -1351,105 +1486,6 @@ internal abstract class MapLogic return GetReadOnly(results); } - private static string? TryToFind(char[] personCharacters, string a2PeopleSingletonDirectory, List<(string Directory, string DirectoryName, string DirectoryNameSplitFirst)> a2PeopleSingletonDirectories, string file, string path) - { - string? result; - string? pathName = Path.GetFileName(path); - string? group = Path.GetDirectoryName(path); - string? groupName = Path.GetFileName(group); - if (pathName is null || group is null || groupName is null) - result = null; - else - { - string[] matches; - matches = (from l in a2PeopleSingletonDirectories where l.DirectoryName == pathName select l.Directory).ToArray(); - if (matches.Length == 1) - result = matches.First(); - else - { - string pathNameSplitFirst = pathName.Split(personCharacters).First(); - matches = (from l in a2PeopleSingletonDirectories where l.DirectoryNameSplitFirst == pathNameSplitFirst select l.Directory).ToArray(); - if (matches.Length == 1) - result = matches.First(); - else - { - string checkDirectory = Path.Combine(a2PeopleSingletonDirectory, groupName, pathName); - if (!Directory.Exists(checkDirectory)) - result = null; - else - result = checkDirectory; - } - } - if (!string.IsNullOrEmpty(result)) - { - try - { - WindowsShortcut windowsShortcut; - windowsShortcut = new() { Path = result }; - windowsShortcut.Save(file); - windowsShortcut.Dispose(); - } - catch (Exception) - { } - } - } - return result; - } - - private static List<(string, long)> GetJLinkResolvedDirectories(string personBirthdayFormat, List resolvedDirectories) - { - List<(string, long)> results = new(); - DateTime dateTime; - string directoryName; - string[] directories; - foreach (string resolvedDirectory in resolvedDirectories) - { - directories = Directory.GetDirectories(resolvedDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - directoryName = Path.GetFileName(directory); - if (directoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(directoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - continue; - results.Add((resolvedDirectory, dateTime.Ticks)); - } - } - if (results.Count != resolvedDirectories.Count) - results.Clear(); - return results; - } - - private static List<(string, long)> GetGenealogicalDataCommunicationDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat) - { - List<(string, long)> results = new(); - string directory; - DateTime dateTime; - string[] personKeyDirectories; - string[] personDisplayDirectoryNames; - string personKeyFormattedDirectoryName; - string? genealogicalDataCommunicationDirectory = Path.GetDirectoryName(genealogicalDataCommunicationFile); - foreach (string jLink in jLinks) - { - if (genealogicalDataCommunicationDirectory is null) - continue; - directory = Path.Combine(genealogicalDataCommunicationDirectory, jLink); - if (!Directory.Exists(directory)) - continue; - personDisplayDirectoryNames = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly); - foreach (string personDisplayDirectoryName in personDisplayDirectoryNames) - { - personKeyDirectories = Directory.GetDirectories(personDisplayDirectoryName, "*", SearchOption.TopDirectoryOnly); - foreach (string personKeyFormattedDirectory in personKeyDirectories) - { - personKeyFormattedDirectoryName = Path.GetFileName(personKeyFormattedDirectory); - if (personKeyFormattedDirectoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormattedDirectoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - continue; - results.Add((directory, dateTime.Ticks)); - } - } - } - return results; - } - internal static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) { List<(string, long)> results; @@ -1551,37 +1587,6 @@ internal abstract class MapLogic } } - internal static void LookForAbandoned(List distinctFilteredIds, string directory, string directoryName) - { - string fileNameWithoutExtension; - bool nameWithoutExtensionIsIdFormat; - List renameCollection = new(); - bool nameWithoutExtensionIsPaddedIdFormat; - int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); - string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray(); - string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); - foreach (string file in files) - { - fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file))); - nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); - nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileNameWithoutExtension, sortOrderOnlyLengthIndex); - if (!nameWithoutExtensionIsIdFormat && !nameWithoutExtensionIsPaddedIdFormat) - continue; - if (distinctFilteredIdsValues.Contains(fileNameWithoutExtension)) - continue; - renameCollection.Add(file); - } - if (renameCollection.Count > 0) - { - if (directoryName.Length == 2) - IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[0]}abd{directoryName[^1]}"); - else if (directoryName.Length == 4) - IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[..2]}abd{directoryName[^2..]}"); - else - throw new NotSupportedException(); - } - } - internal static void LookForAbandoned(string bResultsFullGroupDirectory, List distinctFilteredIds) { string[] directories = Directory.GetDirectories(bResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index cf8281f..22c52ad 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -1,4 +1,4 @@ -using ShellProgressBar; +using ShellProgressBar; using System.Text; using System.Text.Json; using View_by_Distance.Property.Models.Stateless; @@ -176,6 +176,21 @@ public class A_Property return result; } + public void SetAngleBracketCollection(string aResultsFullGroupDirectory, string sourceDirectory, bool anyNullOrNoIsUniqueFileName = true) + { + _AngleBracketCollection.Clear(); + if (!anyNullOrNoIsUniqueFileName) + _AngleBracketCollection.AddRange(new[] { Path.Combine(aResultsFullGroupDirectory, "<>") }); + else + _AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration, + sourceDirectory, + aResultsFullGroupDirectory, + contentDescription: string.Empty, + singletonDescription: "Properties for each image", + collectionDescription: string.Empty, + converted: false)); + } + private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata metadata, string sourceDirectory, List> sourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) { Shared.Models.Property property; @@ -194,6 +209,18 @@ public class A_Property } } + private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName) + { + _AngleBracketCollection.Clear(); + string aResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(_PropertyConfiguration, + nameof(A_Property), + string.Empty, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false); + SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); + } + private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata metadata, List exceptions, List> sourceDirectoryChanges, Container container, List items, string message) { List> sourceDirectoryFileTuples = new(); @@ -223,33 +250,6 @@ public class A_Property }); } - public void SetAngleBracketCollection(string aResultsFullGroupDirectory, string sourceDirectory, bool anyNullOrNoIsUniqueFileName = true) - { - _AngleBracketCollection.Clear(); - if (!anyNullOrNoIsUniqueFileName) - _AngleBracketCollection.AddRange(new[] { Path.Combine(aResultsFullGroupDirectory, "<>") }); - else - _AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration, - sourceDirectory, - aResultsFullGroupDirectory, - contentDescription: string.Empty, - singletonDescription: "Properties for each image", - collectionDescription: string.Empty, - converted: false)); - } - - private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName) - { - _AngleBracketCollection.Clear(); - string aResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(_PropertyConfiguration, - nameof(A_Property), - string.Empty, - includeResizeGroup: false, - includeModel: false, - includePredictorModel: false); - SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); - } - public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata metadata, int t, Container[] containers) { if (_Log is null) diff --git a/Property/Models/Stateless/Property.cs b/Property/Models/Stateless/Property.cs index 990747e..5c19956 100644 --- a/Property/Models/Stateless/Property.cs +++ b/Property/Models/Stateless/Property.cs @@ -15,83 +15,12 @@ namespace View_by_Distance.Property.Models.Stateless; internal class Property { - internal static int GetDeterministicHashCode(byte[] value) + private static List GetDateTimes(DateTime dateTimeFromName, DateTime?[] dateTimes) { - int result; - unchecked + List results = new() { dateTimeFromName }; + foreach (DateTime? dateTime in dateTimes) { - int hash1 = (5381 << 16) + 5381; - int hash2 = hash1; - for (int i = 0; i < value.Length; i += 2) - { - hash1 = ((hash1 << 5) + hash1) ^ value[i]; - if (i == value.Length - 1) - break; - hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; - } - result = hash1 + (hash2 * 1566083941); - } - return result; - } - -#pragma warning disable CA1416 - - internal static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) - { - PropertyItem result = (PropertyItem)constructorInfo.Invoke(null); - int length; - byte[] bytes; - if (type == 2) - { - bytes = GetBytes(value); - length = value.Length + 1; - } - else if (type == 1) - { - bytes = Encoding.Unicode.GetBytes($"{value}\0"); - length = bytes.Length; - } - else - throw new NotSupportedException(); - result.Id = id; - result.Len = length; - result.Type = type; - result.Value = bytes; - return result; - } - -#pragma warning restore CA1416 - - internal static byte[] GetBytes(string value) - { - byte[] results = new byte[value.Length + 1]; - for (int i = 0; i < value.Length; i++) - results[i] = (byte)value[i]; - results[value.Length] = 0x00; - return results; - } - - internal static DateTime? GetDateTime(string dateTimeFormat, string? value) - { - DateTime? result; - string alternateFormat = "ddd MMM dd HH:mm:ss yyyy"; - if (value is not null && DateTime.TryParse(value, out DateTime dateTime)) - result = dateTime; - else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - result = dateTime; - else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - result = dateTime; - else - result = null; - return result; - } - - private static List GetDateTimes(DateTime?[] metadataDateTimes) - { - List results = new(); - foreach (DateTime? dateTime in metadataDateTimes) - { - if (dateTime is null || results.Contains(dateTime.Value)) + if (dateTime is null) continue; results.Add(dateTime.Value); } @@ -135,20 +64,15 @@ internal class Property return results; } - private static List GetDateTimes(DateTime dateTimeFromName, DateTime?[] dateTimes) + internal static byte[] GetBytes(string value) { - List results = new() { dateTimeFromName }; - foreach (DateTime? dateTime in dateTimes) - { - if (dateTime is null) - continue; - results.Add(dateTime.Value); - } + byte[] results = new byte[value.Length + 1]; + for (int i = 0; i < value.Length; i++) + results[i] = (byte)value[i]; + results[value.Length] = 0x00; return results; } -#pragma warning disable CA1416 - internal static DateTime? GetDateTimeFromName(FileHolder fileHolder) { DateTime? result = null; @@ -200,6 +124,82 @@ internal class Property return result; } + private static List GetDateTimes(DateTime?[] metadataDateTimes) + { + List results = new(); + foreach (DateTime? dateTime in metadataDateTimes) + { + if (dateTime is null || results.Contains(dateTime.Value)) + continue; + results.Add(dateTime.Value); + } + return results; + } + + internal static int GetDeterministicHashCode(byte[] value) + { + int result; + unchecked + { + int hash1 = (5381 << 16) + 5381; + int hash2 = hash1; + for (int i = 0; i < value.Length; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ value[i]; + if (i == value.Length - 1) + break; + hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; + } + result = hash1 + (hash2 * 1566083941); + } + return result; + } + +#pragma warning disable CA1416 + + internal static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) + { + PropertyItem result = (PropertyItem)constructorInfo.Invoke(null); + int length; + byte[] bytes; + if (type == 2) + { + bytes = GetBytes(value); + length = value.Length + 1; + } + else if (type == 1) + { + bytes = Encoding.Unicode.GetBytes($"{value}\0"); + length = bytes.Length; + } + else + throw new NotSupportedException(); + result.Id = id; + result.Len = length; + result.Type = type; + result.Value = bytes; + return result; + } + +#pragma warning restore CA1416 + + internal static DateTime? GetDateTime(string dateTimeFormat, string? value) + { + DateTime? result; + string alternateFormat = "ddd MMM dd HH:mm:ss yyyy"; + if (value is not null && DateTime.TryParse(value, out DateTime dateTime)) + result = dateTime; + else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + result = dateTime; + else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + result = dateTime; + else + result = null; + return result; + } + +#pragma warning disable CA1416 + internal static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata? metadata, FileHolder fileHolder, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) { Shared.Models.Property result; diff --git a/Property/Models/Stateless/Result.cs b/Property/Models/Stateless/Result.cs index 188f35b..6ec3516 100644 --- a/Property/Models/Stateless/Result.cs +++ b/Property/Models/Stateless/Result.cs @@ -5,16 +5,10 @@ namespace View_by_Distance.Property.Models.Stateless; internal class Result { - internal static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) + internal static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) { - string result = Shared.Models.Stateless.Methods.IPath.GetRelativePath(path, propertyConfiguration.RootDirectory.Length); - return result; - } - - internal static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) - { - string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace('_', ')')); - if (create && !Directory.Exists(result)) + string result = Path.Combine(GetResultsDateGroupDirectory(propertyConfiguration, description), jsonGroup); + if (!Directory.Exists(result)) _ = Directory.CreateDirectory(result); return result; } @@ -27,40 +21,9 @@ internal class Result return result; } - internal static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) + internal static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) { - string result = Path.Combine(GetResultsDateGroupDirectory(propertyConfiguration, description), jsonGroup); - if (!Directory.Exists(result)) - _ = Directory.CreateDirectory(result); - return result; - } - - internal static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) - { - string result = GetResultsDateGroupDirectory(propertyConfiguration, description); - if (includeResizeGroup) - result = Path.Combine(result, outputResolution); - if (includeModel && includePredictorModel) - { - string modelName; - string predictorModelName; - if (propertyConfiguration.ModelName is null) - modelName = Model.Hog.ToString(); - else - modelName = propertyConfiguration.ModelName; - if (propertyConfiguration.PredictorModelName is null) - predictorModelName = PredictorModel.Large.ToString(); - else - predictorModelName = propertyConfiguration.PredictorModelName; - string dateGroupDirectory = string.Concat(outputResolution.Replace(" ", string.Empty), "-", modelName, "-", predictorModelName, "-", propertyConfiguration.NumberOfJitters, "-", propertyConfiguration.NumberOfTimesToUpsample); - result = Path.Combine(result, dateGroupDirectory); - } - else if (includeModel) - throw new Exception(); - else if (includePredictorModel) - throw new Exception(); - if (!Directory.Exists(result)) - _ = Directory.CreateDirectory(result); + string result = Shared.Models.Stateless.Methods.IPath.GetRelativePath(path, propertyConfiguration.RootDirectory.Length); return result; } @@ -111,6 +74,35 @@ internal class Result _ = Directory.CreateDirectory(checkDirectory); } + internal static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) + { + string result = GetResultsDateGroupDirectory(propertyConfiguration, description); + if (includeResizeGroup) + result = Path.Combine(result, outputResolution); + if (includeModel && includePredictorModel) + { + string modelName; + string predictorModelName; + if (propertyConfiguration.ModelName is null) + modelName = Model.Hog.ToString(); + else + modelName = propertyConfiguration.ModelName; + if (propertyConfiguration.PredictorModelName is null) + predictorModelName = PredictorModel.Large.ToString(); + else + predictorModelName = propertyConfiguration.PredictorModelName; + string dateGroupDirectory = string.Concat(outputResolution.Replace(" ", string.Empty), "-", modelName, "-", predictorModelName, "-", propertyConfiguration.NumberOfJitters, "-", propertyConfiguration.NumberOfTimesToUpsample); + result = Path.Combine(result, dateGroupDirectory); + } + else if (includeModel) + throw new Exception(); + else if (includePredictorModel) + throw new Exception(); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + internal static List GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) { List results = new(); @@ -126,6 +118,14 @@ internal class Result return results; } + internal static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) + { + string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace('_', ')')); + if (create && !Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + internal static List GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) { List results; diff --git a/Rename/Rename.cs b/Rename/Rename.cs index be9ff60..e91b1b0 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -1,4 +1,4 @@ -using CliWrap; +using CliWrap; using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; @@ -72,6 +72,115 @@ public class Rename throw new NullReferenceException(nameof(_PropertyConfiguration)); } + private List RenameFilesInDirectories(ILogger log) + { + List results = new(); + string message; + bool nefPresentCheck; + bool nefPresent = false; + ProgressBar progressBar; + List records = new(); + const string fileSearchFilter = "*"; + int offset = IDirectory.GetOffset(); + const bool useCeilingAverage = false; + const string directorySearchFilter = "*"; + List distinctDirectories = new(); + B_Metadata metadata = new(_PropertyConfiguration); + List<(FileHolder, string, string)> toDoCollection = new(); + List<(FileHolder, string)> verifiedToDoCollection = new(); + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + List filesCollection = IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage); + int count = filesCollection.Select(l => l.Length).Sum(); + foreach (string[] files in filesCollection) + { + if (!files.Any()) + continue; + // foreach (string files[i] in files) + // { + // if (!files[i].EndsWith(".del")) + // continue; + // File.Move(files[i], files[i][..^4]); + // } + // continue; + distinctDirectories.Clear(); + if (_AppSettings.RenameUndo) + { + message = $") Undo renaming files for <{files.FirstOrDefault()}>"; + progressBar = new(files.Length, message, options); + toDoCollection.AddRange(GetRenameUndoToDoCollection(progressBar, files)); + } + else + { + message = $"{records.Count:00000}) Gathering records for files next to <{files.FirstOrDefault()}>"; + progressBar = new(files.Length, message, options); + nefPresentCheck = files.Any(l => l.EndsWith(".NEF")); + if (!nefPresentCheck) + records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, files)); + else + { + if (!nefPresent) + nefPresent = true; + records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray())); + } + } + progressBar.Dispose(); + } + if (records.Any()) + { + int intMinValueLength = int.MinValue.ToString().Length; + foreach (Record record in records) + { + if (record.Id is null) + continue; + if (intMinValueLength < record.Id.Value.ToString().Length) + throw new NotSupportedException(); + } + message = $"{intMinValueLength}) comparing records"; + progressBar = new(records.Count, message, options); + toDoCollection.AddRange(GetToDoCollection(progressBar, nefPresent, records, intMinValueLength)); + progressBar.Dispose(); + } + foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) + { + if (distinctDirectories.Contains(directory)) + continue; + distinctDirectories.Add(directory); + } + foreach (string distinctDirectory in distinctDirectories) + { + if (!Directory.Exists(distinctDirectory)) + _ = Directory.CreateDirectory(distinctDirectory); + } + foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) + { + if (File.Exists(to)) + continue; + verifiedToDoCollection.Add(new(fileHolder, to)); + File.WriteAllText($"{to}.paddedId", $"{to}{Environment.NewLine}{fileHolder.FullName}"); + } + ConsoleKey? consoleKey = null; + log.Information($"Ready to Move {verifiedToDoCollection.Count} files[i](s)?"); + for (int y = 0; y < int.MaxValue; y++) + { + log.Information("Press \"Y\" key to move files[i](s), \"N\" key to log files[i](s) or close console to not move files"); + consoleKey = System.Console.ReadKey().Key; + if (consoleKey is ConsoleKey.Y or ConsoleKey.N) + break; + } + log.Information(". . ."); + if (consoleKey is null || consoleKey.Value != ConsoleKey.Y) + log.Information("Nothing moved!"); + else + { + message = ") Renaming files"; + progressBar = new(count, message, options); + results.AddRange(Move(progressBar, verifiedToDoCollection)); + progressBar.Dispose(); + log.Information("Done Moving"); + } + return results; + } + private static List<(FileHolder, string, string)> GetRenameUndoToDoCollection(ProgressBar progressBar, string[] files) { List<(FileHolder, string, string)> results = new(); @@ -335,113 +444,4 @@ public class Rename return results; } - private List RenameFilesInDirectories(ILogger log) - { - List results = new(); - string message; - bool nefPresentCheck; - bool nefPresent = false; - ProgressBar progressBar; - List records = new(); - const string fileSearchFilter = "*"; - int offset = IDirectory.GetOffset(); - const bool useCeilingAverage = false; - const string directorySearchFilter = "*"; - List distinctDirectories = new(); - B_Metadata metadata = new(_PropertyConfiguration); - List<(FileHolder, string, string)> toDoCollection = new(); - List<(FileHolder, string)> verifiedToDoCollection = new(); - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - List filesCollection = IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage); - int count = filesCollection.Select(l => l.Length).Sum(); - foreach (string[] files in filesCollection) - { - if (!files.Any()) - continue; - // foreach (string files[i] in files) - // { - // if (!files[i].EndsWith(".del")) - // continue; - // File.Move(files[i], files[i][..^4]); - // } - // continue; - distinctDirectories.Clear(); - if (_AppSettings.RenameUndo) - { - message = $") Undo renaming files for <{files.FirstOrDefault()}>"; - progressBar = new(files.Length, message, options); - toDoCollection.AddRange(GetRenameUndoToDoCollection(progressBar, files)); - } - else - { - message = $"{records.Count:00000}) Gathering records for files next to <{files.FirstOrDefault()}>"; - progressBar = new(files.Length, message, options); - nefPresentCheck = files.Any(l => l.EndsWith(".NEF")); - if (!nefPresentCheck) - records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, files)); - else - { - if (!nefPresent) - nefPresent = true; - records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray())); - } - } - progressBar.Dispose(); - } - if (records.Any()) - { - int intMinValueLength = int.MinValue.ToString().Length; - foreach (Record record in records) - { - if (record.Id is null) - continue; - if (intMinValueLength < record.Id.Value.ToString().Length) - throw new NotSupportedException(); - } - message = $"{intMinValueLength}) comparing records"; - progressBar = new(records.Count, message, options); - toDoCollection.AddRange(GetToDoCollection(progressBar, nefPresent, records, intMinValueLength)); - progressBar.Dispose(); - } - foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) - { - if (distinctDirectories.Contains(directory)) - continue; - distinctDirectories.Add(directory); - } - foreach (string distinctDirectory in distinctDirectories) - { - if (!Directory.Exists(distinctDirectory)) - _ = Directory.CreateDirectory(distinctDirectory); - } - foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) - { - if (File.Exists(to)) - continue; - verifiedToDoCollection.Add(new(fileHolder, to)); - File.WriteAllText($"{to}.paddedId", $"{to}{Environment.NewLine}{fileHolder.FullName}"); - } - ConsoleKey? consoleKey = null; - log.Information($"Ready to Move {verifiedToDoCollection.Count} files[i](s)?"); - for (int y = 0; y < int.MaxValue; y++) - { - log.Information("Press \"Y\" key to move files[i](s), \"N\" key to log files[i](s) or close console to not move files"); - consoleKey = System.Console.ReadKey().Key; - if (consoleKey is ConsoleKey.Y or ConsoleKey.N) - break; - } - log.Information(". . ."); - if (consoleKey is null || consoleKey.Value != ConsoleKey.Y) - log.Information("Nothing moved!"); - else - { - message = ") Renaming files"; - progressBar = new(count, message, options); - results.AddRange(Move(progressBar, verifiedToDoCollection)); - progressBar.Dispose(); - log.Information("Done Moving"); - } - return results; - } - } \ No newline at end of file