From e728838d25398d083a75360d32bd6827995832d0 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sat, 8 Mar 2025 16:44:08 -0700 Subject: [PATCH] CombinedEnumAndIndex --- .vscode/mklink.md | 5 + BlurHash/Models/BlurHasher.cs | 58 +++++-- Copy-Distinct/CopyDistinct.cs | 2 +- Distance/Models/_E_Distance.cs | 10 +- Face/Models/_D_Face.cs | 83 ++++++++-- FaceParts/Models/_D2_FaceParts.cs | 51 ++++-- Instance/DlibDotNet.cs | 39 +---- Instance/Models/Binder/Place.cs | 2 +- Instance/Models/_F_Random.cs | 2 +- Map/Models/MapLogic.cs | 6 +- Map/Models/Stateless/FaceFileLogic.cs | 2 +- Map/Models/Stateless/MapLogic.cs | 51 ++++-- Map/Models/Stateless/RelationLogic.cs | 6 +- Metadata/Models/B_Metadata.cs | 48 +++++- Property/Models/A_Property.cs | 40 ++++- Resize/Models/_C_Resize.cs | 46 ++++-- Set-Created-Date/SetCreatedDate.cs | 2 +- Shared/Models/CombinedEnumAndIndex.cs | 23 +++ Shared/Models/Datum.cs | 2 +- Shared/Models/FilePath.cs | 28 ++++ Shared/Models/Stateless/Methods/Container.cs | 30 +++- Shared/Models/Stateless/Methods/IDirectory.cs | 8 +- Shared/Models/Stateless/Methods/IPath.cs | 12 +- Shared/Models/Stateless/Methods/Property.cs | 4 +- Shared/Models/Stateless/Methods/XDirectory.cs | 18 +-- Shared/Models/Stateless/Methods/XPath.cs | 151 +++++++++++++----- Tests/UnitTestHardCoded.cs | 2 +- 27 files changed, 539 insertions(+), 192 deletions(-) create mode 100644 Shared/Models/CombinedEnumAndIndex.cs diff --git a/.vscode/mklink.md b/.vscode/mklink.md index 8c71e4f..c086128 100644 --- a/.vscode/mklink.md +++ b/.vscode/mklink.md @@ -13,3 +13,8 @@ mklink /J "D:\1-Images-A\Images-4083e56a-Results\A2)People\4083e56a\{}\!" "D:\1- ```bash mklink /J "L:\Git\View-by-Distance-MKLink-Console\.Immich" "D:\1-Images-A\Images-c9dbce3b-Results\F)Immich\c9dbce3b\{}" ``` + +```bash 1740946894364 = 638765436943640000 = 2025-0.Winter = Sun Mar 02 2025 13:21:33 GMT-0700 (Mountain Standard Time) +mklink /J "V:\Tmp\Phares\Pictures-Results" "V:\6-Other-Large-Z\Current-Results-Test" +mklink /J "V:\1-Images-A\Images-0b793904-Results" "V:\6-Other-Large-Z\Current-Results" +``` diff --git a/BlurHash/Models/BlurHasher.cs b/BlurHash/Models/BlurHasher.cs index a8d6c00..bcfc4a4 100644 --- a/BlurHash/Models/BlurHasher.cs +++ b/BlurHash/Models/BlurHasher.cs @@ -11,20 +11,28 @@ public class C2_BlurHasher : IBlurHasher { private readonly IPropertyConfiguration _PropertyConfiguration; - private readonly Dictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultContentFileGroups; + private readonly ReadOnlyDictionary>[] _ResultSingletonFileGroups; public C2_BlurHasher(IPropertyConfiguration propertyConfiguration) { - _FileGroups = []; _PropertyConfiguration = propertyConfiguration; + _ResultContentFileGroups = [new(new Dictionary>())]; + _ResultSingletonFileGroups = [new(new Dictionary>())]; } public void Update(string resultsFullGroupDirectory) { - _FileGroups.Clear(); - ReadOnlyDictionary> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - _FileGroups.Add(keyValuePair.Key, keyValuePair.Value); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultContent) + _ResultContentFileGroups[0] = keyValuePair.Value; + else if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton) + _ResultSingletonFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } string IBlurHasher.Encode(FileHolder fileHolder) @@ -40,20 +48,39 @@ public class C2_BlurHasher : IBlurHasher return result; } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, fullFileName); + } + } + string IBlurHasher.GetFile(FilePath filePath) { string result; - if (_FileGroups.Count == 0) + if (_ResultSingletonFileGroups[0].Count == 0) throw new Exception("Call Update first!"); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - result = Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{filePath.Name}.csv"); + string fileName = $"{filePath.Name}.csv"; + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index]; + result = Path.Combine(directory, fileName); + MoveIf(fileName, cei, directory, result); return result; } string IBlurHasher.EncodeAndSave(FilePath filePath, FileHolder fileHolder) { string result; - if (_FileGroups.Count == 0) + if (_ResultSingletonFileGroups[0].Count == 0) throw new Exception("Call Update first!"); int actualByte; string extension = ".png"; @@ -70,15 +97,18 @@ public class C2_BlurHasher : IBlurHasher byte[] blurHashBytes = Encoding.UTF8.GetBytes(result); string joined = string.Join(string.Empty, blurHashBytes.Select(l => l.ToString("000"))); string fileNameWithoutExtension = $"{componentsX}x{componentsY}-{outputWidth}x{outputHeight}-{joined}"; + string fileName = $"{fileNameWithoutExtension}{extension}"; string contents = string.Concat(result, Environment.NewLine, fileNameWithoutExtension, Environment.NewLine, extension); _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(file, contents, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - file = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], $"{fileNameWithoutExtension}{extension}"); - if (!File.Exists(file)) + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index]; + string fullFileName = Path.Combine(directory, fileName); + MoveIf(fileName, cei, directory, fullFileName); + if (!File.Exists(fullFileName)) { try { - using FileStream fileStream = new(file, FileMode.CreateNew); + using FileStream fileStream = new(fullFileName, FileMode.CreateNew); actualImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png); _ = fileStream.Seek(0, SeekOrigin.Begin); actualByte = fileStream.ReadByte(); diff --git a/Copy-Distinct/CopyDistinct.cs b/Copy-Distinct/CopyDistinct.cs index 2d04dfc..dc53d50 100644 --- a/Copy-Distinct/CopyDistinct.cs +++ b/Copy-Distinct/CopyDistinct.cs @@ -19,7 +19,7 @@ public class CopyDistinct private readonly IsEnvironment _IsEnvironment; private readonly IConfigurationRoot _ConfigurationRoot; private readonly Property.Models.Configuration _PropertyConfiguration; - private readonly ReadOnlyDictionary> _FileGroups; + private readonly ReadOnlyDictionary>> _FileGroups; public CopyDistinct(List args, ILogger logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { diff --git a/Distance/Models/_E_Distance.cs b/Distance/Models/_E_Distance.cs index 4028883..634c03c 100644 --- a/Distance/Models/_E_Distance.cs +++ b/Distance/Models/_E_Distance.cs @@ -358,7 +358,7 @@ public partial class E_Distance : IDistance } results.Add(keyValuePair.Key, new(keyValuePairs)); } - return new(results); + return results.AsReadOnly(); } public static List GetPreFilterLocationContainer(int maxDegreeOfParallelism, Configuration configuration, string focusDirectory, string focusModel, int? skipPersonWithMoreThen, long ticks, MapLogic mapLogic, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary> mapped, List available) @@ -509,7 +509,7 @@ public partial class E_Distance : IDistance faceDistanceContainer = new(face, faceDistance); collection.Add(faceDistanceContainer); } - results = new(collection.ToArray()); + results = collection.AsReadOnly(); return results; } @@ -568,7 +568,7 @@ public partial class E_Distance : IDistance foreach (KeyValuePair keyValue in keyValuePair.Value) results.Add(keyValue.Value); } - return new(results); + return results.AsReadOnly(); } public static ReadOnlyCollection GetMatrixLocationContainers(IDlibDotNet dlibDotNet, Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary> mappedWithEncoding, List preFiltered, DistanceLimits distanceLimits, List postFiltered) @@ -624,7 +624,7 @@ public partial class E_Distance : IDistance results = ISortingContainer.Sort(results); else results = ISortingContainer.SortUsingDaysDelta(results); - return new(results); + return results.AsReadOnly(); } private static ReadOnlyCollection GetRelationCollections(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float distanceTolerance, List records) @@ -672,7 +672,7 @@ public partial class E_Distance : IDistance mappedRelations = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList(); results.Add(new(fileHolder, new(mappedRelations))); } - return new(results); + return results.AsReadOnly(); } ReadOnlyCollection IDistance.GetRelationContainers(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection locationContainers) diff --git a/Face/Models/_D_Face.cs b/Face/Models/_D_Face.cs index 6839fef..80ea83a 100644 --- a/Face/Models/_D_Face.cs +++ b/Face/Models/_D_Face.cs @@ -46,7 +46,8 @@ public class D_Face : IFaceD private readonly EncoderParameters _HiddenEncoderParameters; private readonly IPropertyConfiguration _PropertyConfiguration; private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull; - private readonly Dictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultContentFileGroups; + private readonly ReadOnlyDictionary>[] _ResultCollectionFileGroups; public D_Face( string argZero, @@ -69,7 +70,6 @@ public class D_Face : IFaceD float[] rectangleIntersectMinimums) { _ArgZero = argZero; - _FileGroups = []; _ImageCodecInfo = imageCodecInfo; _EncoderParameters = encoderParameters; _FileNameExtension = filenameExtension; @@ -84,6 +84,8 @@ public class D_Face : IFaceD _RectangleIntersectMinimum = rectangleIntersectMinimums.Min(); _FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; _ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; + _ResultContentFileGroups = [new(new Dictionary>())]; + _ResultCollectionFileGroups = [new(new Dictionary>())]; (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName); _Model = model; _PredictorModel = predictorModel; @@ -101,10 +103,16 @@ public class D_Face : IFaceD public void Update(string dResultsFullGroupDirectory) { - _FileGroups.Clear(); - ReadOnlyDictionary> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - _FileGroups.Add(keyValuePair.Key, keyValuePair.Value); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultContent) + _ResultContentFileGroups[0] = keyValuePair.Value; + else if (keyValuePair.Key == _PropertyConfiguration.ResultCollection) + _ResultCollectionFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName) @@ -295,6 +303,25 @@ public class D_Face : IFaceD #pragma warning restore CA1416 + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + { + File.Move(checkFile, fileInfo.FullName); + fileInfo.Refresh(); + } + } + } + public List GetFaces(string outputResolution, string cResultsFullGroupDirectory, FilePath filePath, List> subFileTuples, List parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary outputResolutionToResize, List? mappingFromPhotoPrismCollection) { List? results; @@ -302,8 +329,11 @@ public class D_Face : IFaceD List locations; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)]; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultCollection][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json")); + string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"; + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string directory = _ResultCollectionFileGroups[0][cei.Enum][cei.Index]; + FileInfo fileInfo = new(Path.Combine(directory, fileName)); + MoveIf(fileName, cei, directory, fileInfo); if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) { File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); @@ -366,6 +396,25 @@ public class D_Face : IFaceD return results; } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (Directory.Exists(checkFile)) + { + Directory.Move(checkFile, directoryInfo.FullName); + directoryInfo.Refresh(); + } + } + } + public List<(Shared.Models.Face, FileHolder?, string, bool)> SaveFaces(FilePath filePath, List> subFileTuples, List parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List faces) { List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = []; @@ -373,11 +422,13 @@ public class D_Face : IFaceD FileInfo fileInfo; FileHolder fileHolder; string deterministicHashCodeKey; + string fileName = mappingFromItem.FilePath.NameWithoutExtension; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)]; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension); - bool directoryExists = Directory.Exists(directory); + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index]; + DirectoryInfo directoryInfo = new(Path.Combine(directory, fileName)); + MoveIf(fileName, cei, directory, directoryInfo); foreach (Shared.Models.Face face in faces) { save = false; @@ -387,9 +438,9 @@ public class D_Face : IFaceD continue; } deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); + fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); fileHolder = FileHolder.Get(fileInfo); - if (!directoryExists) + if (!directoryInfo.Exists) save = true; else if (_OverrideForFaceImages) save = true; @@ -397,12 +448,12 @@ public class D_Face : IFaceD save = true; else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime) save = true; - results.Add(new(face, fileHolder, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save)); + results.Add(new(face, fileHolder, Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save)); } if (results.Any(l => l.Save)) { - if (!directoryExists) - _ = Directory.CreateDirectory(directory); + if (!directoryInfo.Exists) + _ = Directory.CreateDirectory(directoryInfo.FullName); SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results); } return results; diff --git a/FaceParts/Models/_D2_FaceParts.cs b/FaceParts/Models/_D2_FaceParts.cs index 03bf81a..3cff1a3 100644 --- a/FaceParts/Models/_D2_FaceParts.cs +++ b/FaceParts/Models/_D2_FaceParts.cs @@ -32,17 +32,17 @@ public class D2_FaceParts private readonly bool _OverrideForFaceLandmarkImages; private readonly EncoderParameters _EncoderParameters; private readonly IPropertyConfiguration _PropertyConfiguration; - private readonly Dictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultContentFileGroups; public D2_FaceParts(IPropertyConfiguration propertyConfiguration, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension, bool checkDFaceAndUpWriteDates, bool overrideForFaceLandmarkImages) { - _FileGroups = []; _ImageCodecInfo = imageCodecInfo; _EncoderParameters = encoderParameters; _FileNameExtension = filenameExtension; _PropertyConfiguration = propertyConfiguration; _CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; + _ResultContentFileGroups = [new(new Dictionary>())]; ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception(); _ConstructorInfo = constructorInfo; } @@ -55,10 +55,14 @@ public class D2_FaceParts public void Update(string dResultsFullGroupDirectory) { - _FileGroups.Clear(); - ReadOnlyDictionary> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - _FileGroups.Add(keyValuePair.Key, keyValuePair.Value); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultContent) + _ResultContentFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum) @@ -380,6 +384,25 @@ public class D2_FaceParts #pragma warning restore CA1416 + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (Directory.Exists(checkFile)) + { + Directory.Move(checkFile, directoryInfo.FullName); + directoryInfo.Refresh(); + } + } + } + public void SaveFaceLandmarkImages(Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List> subFileTuples, List parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List faces, bool saveRotated) { FileInfo fileInfo; @@ -390,11 +413,13 @@ public class D2_FaceParts string deterministicHashCodeKey; bool updateDateWhenMatches = false; List<(Shared.Models.Face, string, string)> collection = []; + string fileName = mappingFromItem.FilePath.NameWithoutExtension; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face)]; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension); - bool directoryExists = Directory.Exists(directory); + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index]; + DirectoryInfo directoryInfo = new(Path.Combine(directory, mappingFromItem.FilePath.NameWithoutExtension)); + MoveIf(fileName, cei, directory, directoryInfo); foreach (Shared.Models.Face face in faces) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) @@ -403,14 +428,14 @@ public class D2_FaceParts continue; } deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); + fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); if (string.IsNullOrEmpty(fileInfo.DirectoryName)) continue; rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName)); if (check) continue; - else if (!directoryExists) + else if (!directoryInfo.Exists) check = true; else if (_OverrideForFaceLandmarkImages) check = true; @@ -428,8 +453,8 @@ public class D2_FaceParts } if (check) { - if (!directoryExists) - _ = Directory.CreateDirectory(directory); + if (!directoryInfo.Exists) + _ = Directory.CreateDirectory(directoryInfo.FullName); SaveFaceParts(mappingFromItem, exifDirectory, collection); if (saveRotated) SaveRotated(mappingFromItem, collection); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 2f5ec56..6055856 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -636,37 +636,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable } } - private static ReadOnlyDictionary> GetKeyValuePairs(ReadOnlyCollection> filePathsCollection) - { - Dictionary> results = []; - List? collection; - Dictionary> keyValuePairs = []; - foreach (ReadOnlyCollection filePaths in filePathsCollection) - { - if (filePaths.Count == 0) - continue; - foreach (FilePath filePath in filePaths) - { - if (filePath.Id is null) - continue; - if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection)) - { - keyValuePairs.Add(filePath.Id.Value, []); - if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection)) - throw new Exception(); - } - collection.Add(filePath); - } - } - foreach (KeyValuePair> keyValuePair in keyValuePairs) - results.Add(keyValuePair.Key, new(keyValuePair.Value)); - return new(results); - } - private static ReadOnlyDictionary GetSplatNineIdentifiersAndHideSplatNine(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection> filePathsCollection) { Dictionary results = []; - ReadOnlyDictionary> keyValuePairs = GetKeyValuePairs(filePathsCollection); + ReadOnlyDictionary> keyValuePairs = FilePath.GetKeyValuePairs(filePathsCollection); if (keyValuePairs.Count > 0) { string json; @@ -711,7 +684,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable json = JsonSerializer.Serialize((from l in identifiers orderby l.DirectoryNames.Length descending, l.Id select l).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(bMetadataCollectionDirectory, ".json"), json.Replace(rootDirectory, string.Empty), updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); } - return new(results); + return results.AsReadOnly(); } private ReadOnlyCollection GetMappings(Property.Models.Configuration propertyConfiguration, string eDistanceContentDirectory, ReadOnlyCollection readOnlyContainers, MapLogic mapLogic, bool distinctItems) @@ -768,7 +741,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable } if (_Configuration.MoveToDecade && _Configuration.LocationContainerDistanceTolerance is null) _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(eDistanceContentDirectory); - return new(results); + return results.AsReadOnly(); } private static void SavePropertyShortcutsForOutputResolutions(string eDistanceContentDirectory, ReadOnlyCollection distinctValidImageItems) @@ -877,7 +850,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable continue; results.Add(filePath); } - return new(results); + return results.AsReadOnly(); } public ReadOnlyDictionary GetOnlyOne(IDistanceLimits distanceLimits, ReadOnlyCollection matrix) @@ -905,7 +878,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable added.Add(locationContainer.LengthSource.Name); results.Add(locationContainer.LengthSource.Name, locationContainer); } - return new(results); + return results.AsReadOnly(); } private List GetSaveContainers(long ticks, ReadOnlyCollection personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, ProgressBarOptions options, MapLogic mapLogic, string outputResolution) @@ -1489,7 +1462,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable ProgressBar progressBar; string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory; (string cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); - IReadOnlyDictionary> fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultContentCollection]); + IReadOnlyDictionary>> fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultContentCollection]); ReadOnlyCollection> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: false); int count = filePathsCollection.Select(l => l.Count).Sum(); bool filesCollectionCountIsOne = IsFilesCollectionCountIsOne(filePathsCollection); diff --git a/Instance/Models/Binder/Place.cs b/Instance/Models/Binder/Place.cs index fbdfc1d..720a3da 100644 --- a/Instance/Models/Binder/Place.cs +++ b/Instance/Models/Binder/Place.cs @@ -54,7 +54,7 @@ public class Place results.Add(Get(place)); } } - return new(results); + return results.AsReadOnly(); } } diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index 82bf031..8d96bd9 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -63,7 +63,7 @@ internal class F_Random relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]); } } - return new(results); + return results.AsReadOnly(); } private static Dictionary GetImmichAssets(string immichAssetsFile) diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index a0f5163..c2e5fd4 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -356,7 +356,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic else results = []; } - return new(results); + return results.AsReadOnly(); } public ReadOnlyDictionary> GetPersonKeyToIds() @@ -393,7 +393,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic } if (shouldMove.Count > 0) throw new Exception(string.Join(Environment.NewLine, shouldMove)); - return new(results); + return results.AsReadOnly(); } (bool, ReadOnlyDictionary>?) Shared.Models.Methods.IMapLogic.GetWholePercentagesToPersonContainers(int id) @@ -1089,7 +1089,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic results.Add(new(keyMapping, sortingContainer.Sorting, sortingContainer.Source)); } } - return new(results); + return results.AsReadOnly(); } private (string, PersonBirthday?) GetPersonBirthday(string[] directoryNames) diff --git a/Map/Models/Stateless/FaceFileLogic.cs b/Map/Models/Stateless/FaceFileLogic.cs index 2c6f975..28a2f00 100644 --- a/Map/Models/Stateless/FaceFileLogic.cs +++ b/Map/Models/Stateless/FaceFileLogic.cs @@ -87,7 +87,7 @@ internal abstract class FaceFileLogic Dictionary> results = []; foreach (KeyValuePair> keyValuePair in keyValuePairs) results.Add(keyValuePair.Key, new(keyValuePair.Value)); - return new(results); + return results.AsReadOnly(); } internal static ReadOnlyDictionary> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 7aca655..3c106ff 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -174,7 +174,7 @@ internal abstract class MapLogic results.Add(face); } } - return new(results); + return results.AsReadOnly(); } internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem) @@ -234,11 +234,28 @@ internal abstract class MapLogic } } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, fullFileName); + } + } + internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, FilePath filePath, MappingFromItem mappingFromItem) { string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); - result = Path.Combine(dFacesContentDirectory, directoryName, mappingFromItem.FilePath.NameWithoutExtension); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); + result = Path.Combine(dFacesContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension); + MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, dFacesContentDirectory, result); return result; } @@ -369,7 +386,7 @@ internal abstract class MapLogic } results.Add(idTo.Key, new(keyValuePairs)); } - return new(results); + return results.AsReadOnly(); } private static ReadOnlyDictionary> GetReadOnly(Dictionary> keyValuePairs) @@ -377,7 +394,7 @@ internal abstract class MapLogic Dictionary> results = []; foreach (KeyValuePair> keyValuePair in keyValuePairs) results.Add(keyValuePair.Key, new(keyValuePair.Value)); - return new(results); + return results.AsReadOnly(); } private static List GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List personKeys, ReadOnlyDictionary personKeyToCount) @@ -793,7 +810,7 @@ internal abstract class MapLogic idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value].Add(wholePercentages.Value); results.Add(new(record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.IsDefault, record.LinksCount, record.MappedFaceFilePath, record.MappedFaceFilePath.Id.Value, wholePercentages.Value)); } - return new(results); + return results.AsReadOnly(); } internal static List GetNotMappedPersonContainers(Configuration configuration, long ticks, ReadOnlyCollection personContainers, ReadOnlyDictionary personKeyToCount) @@ -998,24 +1015,26 @@ internal abstract class MapLogic internal static string GetFacePartsDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath, MappingFromItem mappingFromItem) { string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); - result = Path.Combine(d2FacePartsContentDirectory, directoryName, mappingFromItem.FilePath.NameWithoutExtension); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); + result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension); + MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result); return result; } internal static string GetFacePartsDirectoryX(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath) { string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); - result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); + result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension); + MoveIf(filePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result); return result; } internal static string GetResizeContentDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string cContentDirectory, FilePath filePath) { string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); - result = Path.Combine(cContentDirectory, directoryName); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); + result = Path.Combine(cContentDirectory, cei.Combined); return result; } @@ -1124,7 +1143,7 @@ internal abstract class MapLogic collection.Add(keyValuePair.Key); } } - return new(results); + return results.AsReadOnly(); } internal static ReadOnlyDictionary> GetIdToWholePercentagesToFace(ReadOnlyCollection distinctValidImageMappingCollection) @@ -1274,7 +1293,7 @@ internal abstract class MapLogic foreach ((string _, int wholePercentage) in keyValuePair.Value) wholePercentagesCollection.Add(wholePercentage); } - return new(results); + return results.AsReadOnly(); } internal static ReadOnlyDictionary> ConvertSkipNotSkip(Dictionary> skipNotSkipCollection) @@ -1292,7 +1311,7 @@ internal abstract class MapLogic foreach ((string _, int wholePercentage) in keyValuePair.Value) wholePercentagesCollection.Add(wholePercentage); } - return new(results); + return results.AsReadOnly(); } internal static ReadOnlyDictionary> ConvertLocationContainers(List locationContainers) @@ -1304,7 +1323,7 @@ internal abstract class MapLogic results.Add(locationContainer.Id, []); results[locationContainer.Id].Add(locationContainer); } - return new(results); + return results.AsReadOnly(); } internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary>? wholePercentagesToPersonContainers, int wholePercentages) diff --git a/Map/Models/Stateless/RelationLogic.cs b/Map/Models/Stateless/RelationLogic.cs index 3adf25a..01fe0d2 100644 --- a/Map/Models/Stateless/RelationLogic.cs +++ b/Map/Models/Stateless/RelationLogic.cs @@ -82,12 +82,12 @@ internal abstract class RelationLogic locationContainer = collection[0]; if (locationContainer.PersonKey is null) continue; - results.Add(new(key, locationContainer.PersonKey.Value, new(collection))); + results.Add(new(key, locationContainer.PersonKey.Value, collection.AsReadOnly())); collection = []; years.Clear(); } } - return new(results); + return results.AsReadOnly(); } private static ReadOnlyDictionary MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection relationContainers, List> linked) @@ -202,7 +202,7 @@ internal abstract class RelationLogic _ = Directory.CreateDirectory(checkDirectory); } } - return new(results); + return results.AsReadOnly(); } private static string? GetDisplayDirectoryName(ReadOnlyDictionary> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted) diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 25406e4..fe34414 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -17,15 +17,23 @@ public class B_Metadata : IMetadata private readonly IPropertyConfiguration _PropertyConfiguration; private readonly bool _ForceMetadataLastWriteTimeToCreationTime; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - private readonly ReadOnlyDictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultSingletonFileGroups; public B_Metadata(IPropertyConfiguration propertyConfiguration) { _PropertiesChangedForMetadata = false; _PropertyConfiguration = propertyConfiguration; _ForceMetadataLastWriteTimeToCreationTime = false; + _ResultSingletonFileGroups = [new(new Dictionary>())]; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; - _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton) + _ResultSingletonFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory) @@ -33,8 +41,16 @@ public class B_Metadata : IMetadata _PropertyConfiguration = propertyConfiguration; _PropertiesChangedForMetadata = propertiesChangedForMetadata; _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + _ResultSingletonFileGroups = [new(new Dictionary>())]; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; - _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, bResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, bResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton) + _ResultSingletonFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } public override string ToString() @@ -43,12 +59,34 @@ public class B_Metadata : IMetadata return result; } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && System.IO.Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + { + File.Move(checkFile, fileInfo.FullName); + fileInfo.Refresh(); + } + } + } + public ExifDirectory GetMetadataCollection(FilePath filePath, List> subFileTuples, List parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem) { ExifDirectory? result = null; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json")); + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"; + string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index]; + FileInfo fileInfo = new(Path.Combine(directory, fileName)); + MoveIf(fileName, cei, directory, fileInfo); if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) { File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 5f4bc70..cd037cb 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -22,19 +22,27 @@ public class A_Property private readonly Configuration _Configuration; private readonly List _AngleBracketCollection; private readonly IPropertyConfiguration _PropertyConfiguration; - private readonly ReadOnlyDictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultSingletonFileGroups; public A_Property(int maxDegreeOfParallelism, Configuration propertyConfiguration, string outputExtension, bool reverse, string aResultsFullGroupDirectory) { Reverse = reverse; _ExceptionsDirectories = []; + _AngleBracketCollection = []; _OutputExtension = outputExtension; _ASCIIEncoding = new ASCIIEncoding(); _Configuration = propertyConfiguration; - _AngleBracketCollection = []; _PropertyConfiguration = propertyConfiguration; _MaxDegreeOfParallelism = maxDegreeOfParallelism; - _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, aResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]); + _ResultSingletonFileGroups = [new(new Dictionary>())]; + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, aResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton) + _ResultSingletonFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } public override string ToString() @@ -43,6 +51,25 @@ public class A_Property return result; } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + { + File.Move(checkFile, fileInfo.FullName); + fileInfo.Refresh(); + } + } + } + private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata metadata, Item item, List> sourceDirectoryFileTuples, List parseExceptions, bool isIgnoreExtension) { Shared.Models.Property? result; @@ -57,8 +84,11 @@ public class A_Property fileInfo = new(Path.Combine(angleBracket.Replace("<>", _PropertyConfiguration.ResultSingleton), $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json")); else { - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, item.FilePath); - fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json")); + string fileName = $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"; + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, item.FilePath); + string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index]; + fileInfo = new(Path.Combine(directory, fileName)); + MoveIf(fileName, cei, directory, fileInfo); } List dateTimes = (from l in sourceDirectoryFileTuples where l is not null && changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index fac7589..bd523ae 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -40,11 +40,10 @@ public class C_Resize private readonly bool _ForceResizeLastWriteTimeToCreationTime; private readonly IPropertyConfiguration _PropertyConfiguration; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - private readonly Dictionary> _FileGroups; + private readonly ReadOnlyDictionary>[] _ResultSingletonFileGroups; public C_Resize(IPropertyConfiguration propertyConfiguration, bool forceResizeLastWriteTimeToCreationTime, bool overrideForResizeImages, bool propertiesChangedForResize, string[] validResolutions, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) { - _FileGroups = []; _Original = "Original"; _TempResolutionWidth = 3; _TempResolutionHeight = 4; @@ -61,6 +60,7 @@ public class C_Resize _OverrideForResizeImages = overrideForResizeImages; _PropertiesChangedForResize = propertiesChangedForResize; _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + _ResultSingletonFileGroups = [new(new Dictionary>())]; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception(); _ConstructorInfo = constructorInfo; @@ -74,10 +74,14 @@ public class C_Resize public void Update(string cResultsFullGroupDirectory) { - _FileGroups.Clear(); - ReadOnlyDictionary> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, [_PropertyConfiguration.ResultSingleton]); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - _FileGroups.Add(keyValuePair.Key, keyValuePair.Value); + ReadOnlyDictionary>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, [_PropertyConfiguration.ResultSingleton]); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton) + _ResultSingletonFileGroups[0] = keyValuePair.Value; + else + throw new Exception(); + } } public void SetAngleBracketCollection(string cResultsFullGroupDirectory, string sourceDirectory) @@ -427,8 +431,8 @@ public class C_Resize result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), fileName)); else { - (string directoryName, _) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, directoryName, fileName)); + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, cei.Combined, fileName)); } return result; } @@ -439,14 +443,36 @@ public class C_Resize public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, int id) => GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, $"{id}{item.FilePath.ExtensionLowered}"); + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + { + File.Move(checkFile, fileInfo.FullName); + fileInfo.Refresh(); + } + } + } + public Dictionary GetResizeKeyValuePairs(Configuration configuration, string cResultsFullGroupDirectory, FilePath filePath, List> subFileTuples, List parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem) { Dictionary? results; string json; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata)]; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); - FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json")); + CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath); + string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"; + string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index]; + FileInfo fileInfo = new(Path.Combine(directory, fileName)); + MoveIf(fileName, cei, directory, fileInfo); if (_ForceResizeLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) { File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); diff --git a/Set-Created-Date/SetCreatedDate.cs b/Set-Created-Date/SetCreatedDate.cs index 5795dcf..b608ec0 100644 --- a/Set-Created-Date/SetCreatedDate.cs +++ b/Set-Created-Date/SetCreatedDate.cs @@ -22,7 +22,7 @@ public class SetCreatedDate private readonly IsEnvironment _IsEnvironment; private readonly IConfigurationRoot _ConfigurationRoot; private readonly Property.Models.Configuration _PropertyConfiguration; - private readonly ReadOnlyDictionary> _FileGroups; + private readonly ReadOnlyDictionary>> _FileGroups; public SetCreatedDate(List args, ILogger logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { diff --git a/Shared/Models/CombinedEnumAndIndex.cs b/Shared/Models/CombinedEnumAndIndex.cs new file mode 100644 index 0000000..f5af1d8 --- /dev/null +++ b/Shared/Models/CombinedEnumAndIndex.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public record CombinedEnumAndIndex(string Combined, + byte Enum, + int Index) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, CombinedEnumAndIndexSourceGenerationContext.Default.CombinedEnumAndIndex); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(CombinedEnumAndIndex))] +internal partial class CombinedEnumAndIndexSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Shared/Models/Datum.cs b/Shared/Models/Datum.cs index 65b0f45..6753853 100644 --- a/Shared/Models/Datum.cs +++ b/Shared/Models/Datum.cs @@ -4,7 +4,7 @@ namespace View_by_Distance.Shared.Models; public record Datum( [property: JsonPropertyName("accessRuleIds")] IReadOnlyList AccessRuleIds, - [property: JsonPropertyName("childAssetTypeInfo")] IReadOnlyList ChildAssetTypeInfo, + [property: JsonPropertyName("childAssetTyceinfo")] IReadOnlyList ChildAssetTyceinfo, [property: JsonPropertyName("contentProperties")] ContentProperties ContentProperties, [property: JsonPropertyName("createdBy")] string CreatedBy, [property: JsonPropertyName("createdDate")] DateTime CreatedDate, diff --git a/Shared/Models/FilePath.cs b/Shared/Models/FilePath.cs index c856784..cf813e2 100644 --- a/Shared/Models/FilePath.cs +++ b/Shared/Models/FilePath.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Text.Json; using System.Text.Json.Serialization; using View_by_Distance.Shared.Models.Stateless.Methods; @@ -83,6 +84,33 @@ public record FilePath(long CreationTicks, return result; } + public static ReadOnlyDictionary> GetKeyValuePairs(ReadOnlyCollection> filePathsCollection) + { + Dictionary> results = []; + List? collection; + Dictionary> keyValuePairs = []; + foreach (ReadOnlyCollection filePaths in filePathsCollection) + { + if (filePaths.Count == 0) + continue; + foreach (FilePath filePath in filePaths) + { + if (filePath.Id is null) + continue; + if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection)) + { + keyValuePairs.Add(filePath.Id.Value, []); + if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection)) + throw new Exception(); + } + collection.Add(filePath); + } + } + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return results.AsReadOnly(); + } + } [JsonSourceGenerationOptions(WriteIndented = true)] diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs index 2455d53..057499d 100644 --- a/Shared/Models/Stateless/Methods/Container.cs +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -26,7 +26,7 @@ internal abstract class Container continue; results.Add(item); } - return container.Items.Count == results.Count ? container.Items : new(results); + return container.Items.Count == results.Count ? container.Items : results.AsReadOnly(); } private static List GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, ReadOnlyCollection> filePathsCollection) @@ -71,6 +71,22 @@ internal abstract class Container return result; } + private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName) + { + string[] segments = directory.Split(cei.Combined); + string? checkDirectory = segments.Length == 1 ? + Path.Combine(segments[0], $"{cei.Combined[2..]}") : + segments.Length == 2 ? + $"{segments[0]}{cei.Combined[2..]}{segments[1]}" : + null; + if (checkDirectory is not null && Directory.Exists(checkDirectory)) + { + string checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, fullFileName); + } + } + private static void ParallelFor(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int rootDirectoryLength, ReadOnlyDictionary? splatNineIdentifiers, Models.FilePair filePair, List results) { dlibDotNet?.Tick(); @@ -108,8 +124,12 @@ internal abstract class Container else { string fileName = Path.GetFileName(filePair.Path); - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); - sourceDirectoryFileHolder = IFileHolder.Get(Path.Combine(aPropertySingletonDirectory, directoryName, $"{fileName}{extension}")); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); + string directory = Path.Combine(aPropertySingletonDirectory, cei.Combined); + string jsonFileName = $"{fileName}{extension}"; + string fullFileName = Path.Combine(directory, jsonFileName); + MoveIf(jsonFileName, cei, directory, fullFileName); + sourceDirectoryFileHolder = IFileHolder.Get(fullFileName); } if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks) { @@ -183,7 +203,7 @@ internal abstract class Container Models.Container[] results; const string directorySearchFilter = "*"; (_, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter); - return new(results); + return results.AsReadOnly(); } internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary? splatNineIdentifiers, string aPropertySingletonDirectory) @@ -276,7 +296,7 @@ internal abstract class Container results.Add(item); } } - return new(results); + return results.AsReadOnly(); } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IDirectory.cs b/Shared/Models/Stateless/Methods/IDirectory.cs index 6f02146..ed4c8ca 100644 --- a/Shared/Models/Stateless/Methods/IDirectory.cs +++ b/Shared/Models/Stateless/Methods/IDirectory.cs @@ -30,14 +30,14 @@ public interface IDirectory static void MoveFiles(List files, string find, string replace) => XDirectory.MoveFiles(files, find, replace); - (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) => + (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary>> fileGroups, Action? tick) => GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, tick); - static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) => + static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary>> fileGroups, Action? tick) => XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, tick); - (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) => + (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary>> fileGroups, Action? tick) => GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick); - static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) => + static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary>> fileGroups, Action? tick) => XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick); List TestStatic_CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) => diff --git a/Shared/Models/Stateless/Methods/IPath.cs b/Shared/Models/Stateless/Methods/IPath.cs index 4af440e..6ad6a96 100644 --- a/Shared/Models/Stateless/Methods/IPath.cs +++ b/Shared/Models/Stateless/Methods/IPath.cs @@ -62,14 +62,14 @@ public interface IPath static string GetDirectory(string sourceDirectory, int level, string directoryName) => XPath.GetDirectory(sourceDirectory, level, directoryName); - (string, int) TestStatic_GetDirectoryNameAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) => - GetDirectoryNameAndIndex(propertyConfiguration, filePath); - static (string, int) GetDirectoryNameAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) => - XPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); + CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) => + GetCombinedEnumAndIndex(propertyConfiguration, filePath); + static CombinedEnumAndIndex GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) => + XPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); - ReadOnlyDictionary> TestStatic_GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) => + ReadOnlyDictionary>> TestStatic_GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) => GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups); - static ReadOnlyDictionary> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) => + static ReadOnlyDictionary>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) => XPath.GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Property.cs b/Shared/Models/Stateless/Methods/Property.cs index 7e7f69f..97383af 100644 --- a/Shared/Models/Stateless/Methods/Property.cs +++ b/Shared/Models/Stateless/Methods/Property.cs @@ -75,13 +75,15 @@ internal abstract class Property for (int i = 0; i < int.MaxValue; i++) { check = Path.GetDirectoryName(check); - if (string.IsNullOrEmpty(check) || check == pathRoot) + if (string.IsNullOrEmpty(check)) break; directoryName = Path.GetFileName(check); directorySegments = directoryName.Split(' '); (result, results) = IsWrongYear(directorySegments, year); if (result is not null) break; + if (check == pathRoot) + break; } if (result is not null && !result.Value) break; diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index 60397af..8bae115 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -51,7 +51,7 @@ internal abstract partial class XDirectory int ceilingAverage = directory[^1] == '_' || results.Count == 0 ? 0 : GetCeilingAverage(results); if (useCeilingAverage) results = GetFilesCollection(results, ceilingAverage); - return new(results); + return results.AsReadOnly(); } internal static ReadOnlyCollection> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage) @@ -326,10 +326,10 @@ internal abstract partial class XDirectory } results.Add(new(filePaths)); } - return new(results); + return results.AsReadOnly(); } - internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) + internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary>> fileGroups, Action? tick) { List<(FilePath, string)> results = []; string key; @@ -338,18 +338,18 @@ internal abstract partial class XDirectory string directory; FileInfo fileInfo; FilePath filePath; - int directoryIndex; string paddedIdFile; bool wrapped = false; string intelligentId; + CombinedEnumAndIndex cei; bool paddedCheck = false; string fileDirectoryName; List distinctIds = []; List distinct = []; Models.FileHolder fileHolder; List distinctDirectories = []; - ReadOnlyCollection? directories; FilePath[] sortedRecords = GetSortedRecords(filePathsCollection); + ReadOnlyDictionary>? keyValuePairs; bool isOffsetDeterministicHashCode = IId.IsOffsetDeterministicHashCode(propertyConfiguration); for (int i = 0; i < sortedRecords.Length; i++) { @@ -358,21 +358,21 @@ internal abstract partial class XDirectory if (filePath.Name.EndsWith("len") || filePath.ExtensionLowered == ".id" || filePath.ExtensionLowered == ".lsv" || filePath.DirectoryFullPath is null) continue; key = propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? propertyConfiguration.ResultContentCollection : propertyConfiguration.ResultContent; - if (!fileGroups.TryGetValue(key, out directories)) + if (!fileGroups.TryGetValue(key, out keyValuePairs)) continue; - (_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); + cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath); fileDirectoryName = Path.GetFileName(filePath.DirectoryFullPath); if (fileDirectoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !filePath.Name.StartsWith(fileDirectoryName)) { if (wrapped) continue; - directory = directories[directoryIndex]; + directory = keyValuePairs[cei.Enum][cei.Index]; } else { if (!wrapped) wrapped = true; - directory = Path.Combine(directories[directoryIndex], fileDirectoryName); + directory = Path.Combine(keyValuePairs[cei.Enum][cei.Index], fileDirectoryName); } if (ifCanUseId && filePath.IsIntelligentIdFormat && filePath.Id is not null && filePath.DirectoryFullPath is not null) { diff --git a/Shared/Models/Stateless/Methods/XPath.cs b/Shared/Models/Stateless/Methods/XPath.cs index 8762d6d..20d77cb 100644 --- a/Shared/Models/Stateless/Methods/XPath.cs +++ b/Shared/Models/Stateless/Methods/XPath.cs @@ -266,78 +266,155 @@ internal abstract class XPath } } - internal static (string, int) GetDirectoryNameAndIndex(int resultAllInOneSubdirectoryLength, string fileName) + private static byte GetEnum(bool? ik, bool? dto) { + byte result; + if (ik is not null && ik.Value && dto is not null && dto.Value) + result = 11; + else if (ik is not null && ik.Value && dto is not null && !dto.Value) + result = 15; + else if (ik is not null && ik.Value && dto is null) + result = 19; + else if (ik is not null && !ik.Value && dto is not null && dto.Value) + result = 51; + else if (ik is not null && !ik.Value && dto is not null && !dto.Value) + result = 55; + else if (ik is not null && !ik.Value && dto is null) + result = 59; + else if (ik is null && dto is not null && dto.Value) + result = 91; + else if (ik is null && dto is not null && !dto.Value) + result = 95; + else if (ik is null && dto is null) + result = 99; + else + throw new Exception(); + return result; + } + + internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileName) + { + CombinedEnumAndIndex result; int converted; - string result; - string check = fileName.Length < resultAllInOneSubdirectoryLength ? new('-', resultAllInOneSubdirectoryLength) : fileName.Split('.')[0][^resultAllInOneSubdirectoryLength..]; + string combined; + byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); + string check = fileName.Length < resultAllInOneSubdirectoryLength ? + new('-', resultAllInOneSubdirectoryLength) : + fileName.Split('.')[0][^resultAllInOneSubdirectoryLength..]; if (check.Any(l => !char.IsNumber(l))) { - result = new('-', resultAllInOneSubdirectoryLength); + combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}"; converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}"); } else { - result = check; + combined = $"{@enum}{check}"; converted = int.Parse(check); } - return (result, converted); + result = new(combined, @enum, converted); + return result; } - internal static (string, int) GetDirectoryNameAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) + internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) { - int converted; - string result; + CombinedEnumAndIndex result; if (filePath.Id is not null) - (result, converted) = GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, filePath.Id.Value.ToString()); + result = GetCombinedEnumAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString()); else - (result, converted) = GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, filePath.FileNameFirstSegment); - return (result, converted); + result = GetCombinedEnumAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, filePath, filePath.FileNameFirstSegment); + return result; } - internal static ReadOnlyDictionary> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) + private static byte[] GetBytes() => + [ + 11, + 15, + 19, + 51, + 55, + 59, + 91, + 95, + 99 + ]; + + private static ReadOnlyDictionary> Convert(Dictionary> keyValuePairs) { - Dictionary> results = []; - int converted = int.Parse($"1{new string('0', propertyConfiguration.ResultAllInOneSubdirectoryLength)}"); + Dictionary> results = []; + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return results.AsReadOnly(); + } + + private static ReadOnlyDictionary> Convert(List collection) + { + Dictionary> results = []; + List? c; + foreach (CombinedEnumAndIndex cei in collection) + { + if (!results.TryGetValue(cei.Enum, out c)) + { + results.Add(cei.Enum, []); + if (!results.TryGetValue(cei.Enum, out c)) + throw new Exception(); + } + c.Add(cei.Combined); + } + return Convert(results); + } + + internal static ReadOnlyDictionary>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) + { + Dictionary>> results = []; + int plusOne; string directory; string checkDirectory; - List collection; - int plusOne = converted + 1; + CombinedEnumAndIndex cei; + byte[] bytes = GetBytes(); + List collection; + ReadOnlyDictionary> keyValuePairs; + int converted = int.Parse($"1{new string('0', propertyConfiguration.ResultAllInOneSubdirectoryLength)}"); if (jsonGroups is not null) { + plusOne = converted + 1; foreach (string jsonGroup in jsonGroups) { + collection = []; if (resultsFullGroupDirectory is null) continue; - collection = []; - for (int i = 0; i < plusOne; i++) + foreach (byte @enum in bytes) { - if (string.IsNullOrEmpty(jsonGroup)) + for (int i = 0; i < plusOne; i++) { - if (i == converted) - checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength))); + if (string.IsNullOrEmpty(jsonGroup)) + { + if (i == converted) + checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength)}")); + else + checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{i.ToString().PadLeft(propertyConfiguration.ResultAllInOneSubdirectoryLength, '0')}")); + } else - checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, i.ToString().PadLeft(propertyConfiguration.ResultAllInOneSubdirectoryLength, '0'))); + { + directory = Path.Combine(resultsFullGroupDirectory, jsonGroup); + if (i == converted) + checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength)}")); + else + checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{i.ToString().PadLeft(propertyConfiguration.ResultAllInOneSubdirectoryLength, '0')}")); + } + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + cei = new(Combined: checkDirectory, Enum: @enum, Index: -1); + collection.Add(cei); } - else - { - directory = Path.Combine(resultsFullGroupDirectory, jsonGroup); - if (i == converted) - checkDirectory = Path.GetFullPath(Path.Combine(directory, new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength))); - else - checkDirectory = Path.GetFullPath(Path.Combine(directory, i.ToString().PadLeft(propertyConfiguration.ResultAllInOneSubdirectoryLength, '0'))); - } - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - collection.Add(checkDirectory); } + keyValuePairs = Convert(collection); if (!string.IsNullOrEmpty(jsonGroup)) - results.Add(jsonGroup, new(collection)); + results.Add(jsonGroup, keyValuePairs); else - results.Add(propertyConfiguration.ResultAllInOne, new(collection)); + results.Add(propertyConfiguration.ResultAllInOne, keyValuePairs); } } - return new(results); + return results.AsReadOnly(); } } \ No newline at end of file diff --git a/Tests/UnitTestHardCoded.cs b/Tests/UnitTestHardCoded.cs index 8a47f97..1a0b65d 100644 --- a/Tests/UnitTestHardCoded.cs +++ b/Tests/UnitTestHardCoded.cs @@ -45,7 +45,7 @@ public partial class UnitTestHardCoded Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); - _Git = "d8013da9"; + _Git = "0b793904"; _AppSettings = appSettings; _Configuration = configuration; _IsEnvironment = isEnvironment;