From 0ca53436e5a4dc3cd332169f8ed237d54042fe27 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 7 May 2023 20:07:48 -0700 Subject: [PATCH] LookForAbandoned, DateTimeOriginalThenMinimumDateTime and IsNotUniqueAndNeedsReview --- Date-Group/DateGroup.cs | 50 ++- Date-Group/appsettings.Development.json | 342 +----------------- Date-Group/appsettings.json | 5 +- Distance/Models/_E_Distance.cs | 14 +- Drag-Drop-Move/Drag-Drop-Move.csproj | 1 + Drag-Drop-Move/DragDropMove.cs | 150 +++++++- Duplicate-Search/DuplicateSearch.cs | 2 +- Instance/DlibDotNet.cs | 136 +++++-- Instance/Models/Binder/Configuration.cs | 4 + Instance/Models/Configuration.cs | 3 + Instance/appsettings.Development.json | 225 +----------- Instance/appsettings.json | 1 + Map/Models/MapLogic.cs | 44 +-- Map/Models/Stateless/MapLogic.cs | 16 +- Property/Models/A_Property.cs | 182 ++-------- Property/Models/Configuration.cs | 4 - Resize/Models/_C_Resize.cs | 2 +- Shared/Models/FaceDistance.cs | 12 +- Shared/Models/FilePair.cs | 2 +- Shared/Models/Item.cs | 15 +- Shared/Models/Mapping.cs | 136 ------- Shared/Models/MappingFromFilter.cs | 29 ++ Shared/Models/MappingFromItem.cs | 58 +++ Shared/Models/MappingFromLocation.cs | 29 ++ Shared/Models/MappingFromPerson.cs | 29 ++ Shared/Models/MappingFromPhotoPrism.cs | 18 + Shared/Models/Properties/IFaceDistance.cs | 2 +- Shared/Models/Properties/IItem.cs | 3 +- Shared/Models/Properties/IMapping.cs | 51 --- .../Models/Properties/IMappingFromFilter.cs | 11 + Shared/Models/Properties/IMappingFromItem.cs | 17 + .../Models/Properties/IMappingFromLocation.cs | 11 + .../Models/Properties/IMappingFromPerson.cs | 11 + .../Properties/IMappingFromPhotoPrism.cs | 9 + Shared/Models/Properties/IProperty.cs | 28 +- .../Properties/IPropertyConfiguration.cs | 1 - Shared/Models/Property.cs | 106 ++---- Shared/Models/Stateless/Methods/Container.cs | 2 +- Shared/Models/Stateless/Methods/IProperty.cs | 10 +- Shared/Models/Stateless/Methods/Property.cs | 58 ++- Shared/Models/Stateless/Methods/Sorting.cs | 5 +- Shared/Models/Stateless/Methods/XDirectory.cs | 30 +- Tests/UnitTestHardCoded.cs | 8 +- Tests/UnitTestResize.cs | 5 +- .../UnitTestFace.cs | 5 +- 45 files changed, 721 insertions(+), 1161 deletions(-) create mode 100644 Shared/Models/MappingFromFilter.cs create mode 100644 Shared/Models/MappingFromItem.cs create mode 100644 Shared/Models/MappingFromLocation.cs create mode 100644 Shared/Models/MappingFromPerson.cs create mode 100644 Shared/Models/MappingFromPhotoPrism.cs create mode 100644 Shared/Models/Properties/IMappingFromFilter.cs create mode 100644 Shared/Models/Properties/IMappingFromItem.cs create mode 100644 Shared/Models/Properties/IMappingFromLocation.cs create mode 100644 Shared/Models/Properties/IMappingFromPerson.cs create mode 100644 Shared/Models/Properties/IMappingFromPhotoPrism.cs diff --git a/Date-Group/DateGroup.cs b/Date-Group/DateGroup.cs index c97d61b..6a5305d 100644 --- a/Date-Group/DateGroup.cs +++ b/Date-Group/DateGroup.cs @@ -154,13 +154,14 @@ public class DateGroup string? check; string fileName; string? pathRoot; + DateTime dateTime; string seasonName; string weekOfYear; bool? isWrongYear; string seasonValue; string directoryName; string topDirectoryName; - DateTime minimumDateTime; + List dateTimes; string[]? matches = null; string[] directorySegments; List destinationCollection; @@ -204,12 +205,22 @@ public class DateGroup directoryNames.Clear(); destinationCollection = new(); _ = destinationDirectoryName.Clear(); - if (item.ImageFileHolder.LastWriteTime is not null && item.Property is null) - minimumDateTime = item.ImageFileHolder.LastWriteTime.Value; + if (item.Property is not null) + dateTimes = item.Property.GetDateTimes(); else - minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); - day = minimumDateTime.ToString("MM-dd"); - month = minimumDateTime.ToString("MMMM"); + { + if (item.ImageFileHolder.LastWriteTime is null) + throw new Exception(); + dateTimes = new() { item.ImageFileHolder.LastWriteTime.Value }; + } + if (item.ImageFileHolder.LastWriteTime is not null && item.Property is null) + dateTime = item.ImageFileHolder.LastWriteTime.Value; + else if (item.Property is not null && item.Property.DateTimeOriginal is not null) + dateTime = item.Property.DateTimeOriginal.Value; + else + dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + day = dateTime.ToString("MM-dd"); + month = dateTime.ToString("MMMM"); if (item.Property?.Id is null) { flag = '#'; @@ -217,26 +228,26 @@ public class DateGroup } else { - (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder, minimumDateTime); + (isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(item.ImageFileHolder, item.Property.DateTimeOriginal, dateTimes); if (isWrongYear is null) flag = '#'; else if (isWrongYear.Value) flag = '~'; else { - if (item.Property.DateTimeOriginal.HasValue && minimumDateTime.DayOfYear != item.Property.DateTimeOriginal.Value.DayOfYear && Math.Abs(new TimeSpan(minimumDateTime.Ticks - item.Property.DateTimeOriginal.Value.Ticks).TotalHours) > 8) + if (item.Property.DateTimeOriginal is not null && dateTime.DayOfYear != item.Property.DateTimeOriginal.Value.DayOfYear && Math.Abs(new TimeSpan(dateTime.Ticks - item.Property.DateTimeOriginal.Value.Ticks).TotalHours) > 8) flag = '^'; else flag = '='; } } - (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(minimumDateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); if ((from l in topDirectorySegments where l == "Christmas" select true).Any()) seasonValue = string.Empty; else seasonValue = $".{season}"; if (isWrongYear is null || !isWrongYear.Value) - year = $"{flag}{minimumDateTime:yyyy}{seasonValue}"; + year = $"{flag}{dateTime:yyyy}{seasonValue}"; else if (matches is null || matches.Length < 3) year = "----"; else @@ -247,7 +258,7 @@ public class DateGroup year = $"{flag}{matches[0][1..].Split('.')[0]}{seasonValue}"; } topDirectoryName = Path.GetFileName(topDirectory); - weekOfYear = calendar.GetWeekOfYear(minimumDateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); + weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); if (_Configuration.ByHash) directoryNames.Add($"{year} {seasonName}"); else if (_Configuration.BySeason && topDirectoryName.Length == 1 && topDirectoryName[0] == '_') @@ -296,9 +307,9 @@ public class DateGroup if (item.ImageFileHolder.LastWriteTime is null) continue; if (item.Property is not null) - results.Add(new(item, item.Property.LastWriteTime.Ticks, minimumDateTime.Ticks, destinationCollection.ToArray())); + results.Add(new(item, item.Property.LastWriteTime.Ticks, dateTime.Ticks, destinationCollection.ToArray())); else - results.Add(new(item, item.ImageFileHolder.LastWriteTime.Value.Ticks, minimumDateTime.Ticks, destinationCollection.ToArray())); + results.Add(new(item, item.ImageFileHolder.LastWriteTime.Value.Ticks, dateTime.Ticks, destinationCollection.ToArray())); } return results; } @@ -470,11 +481,11 @@ public class DateGroup string path; string fileName; string directory; + DateTime dateTime; int selectedTotal; const int minimum = 3; List dateTimes; List selectedItems; - DateTime? minimumDateTime; const int maximumHours = 24; string? relativePathDirectory; WindowsShortcut windowsShortcut; @@ -499,9 +510,12 @@ public class DateGroup relativePathDirectory = Path.GetDirectoryName(item.RelativePath); if (string.IsNullOrEmpty(relativePathDirectory)) continue; - minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); - if (minimumDateTime is null) - continue; + if (item.ImageFileHolder.LastWriteTime is not null && item.Property is null) + dateTime = item.ImageFileHolder.LastWriteTime.Value; + else if (item.Property is not null && item.Property.DateTimeOriginal is not null) + dateTime = item.Property.DateTimeOriginal.Value; + else + dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); path = Path.GetFullPath($"{configuration.RootDirectory}{item.RelativePath[..^5]}"); directory = Path.Combine($"{aPropertyContentDirectory}{relativePathDirectory}", $"{dateTimes.Min():yyyy-MM-dd_HH-mm-ss}---{dateTimes.Max():yyyy-MM-dd_HH-mm-ss}"); if (!Directory.Exists(directory)) @@ -514,7 +528,7 @@ public class DateGroup windowsShortcut.Dispose(); if (!File.Exists(fileName)) continue; - File.SetLastWriteTime(fileName, minimumDateTime.Value); + File.SetLastWriteTime(fileName, dateTime); } } if (selectedTotal < container.Items.Count && selectedTotal < (from l in container.Items where l.Property is not null select true).Count()) diff --git a/Date-Group/appsettings.Development.json b/Date-Group/appsettings.Development.json index 9b24764..2532509 100644 --- a/Date-Group/appsettings.Development.json +++ b/Date-Group/appsettings.Development.json @@ -1,353 +1,25 @@ { - "Company": "Mike Phares", - "Linux": {}, "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Log4netProvider": "Debug", - "Microsoft.Hosting.Lifetime": "Information" + "Log4netProvider": "Debug" } }, "MaxDegreeOfParallelism": 6, "Serilog": { - "Using": [ - "Serilog.Sinks.Console", - "Serilog.Sinks.File" - ], - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "Debug", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "%workingDirectory% - Log/log-.txt", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", - "rollingInterval": "Hour" - } - } - ], - "Enrich": [ - "FromLogContext", - "WithMachineName", - "WithThreadId" - ], - "Properties": { - "Application": "Sample" - } + "MinimumLevel": "Debug" }, - "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { - "ByCreateDateShortcut": false, - "ByDay": false, - "ByHash": false, - "BySeason": true, - "ByWeek": false, - "DateGroup": "1e85c0ba", - "FileNameDirectorySeparator": ".Z.", - "ForcePropertyLastWriteTimeToCreationTime": false, - "KeepFullPath": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 10, - "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", - "PopulatePropertyId": false, - "PropertiesChangedForProperty": false, - "ResultAllInOne": "_ _ _", - "ResultCollection": "[]", - "ResultContent": "()", - "ResultSingleton": "{}", + "xByHash": false, + "ByHash": true, + "xPopulatePropertyId": false, + "PopulatePropertyId": true, "xRootDirectory": "C:/Tmp/phares/Pictures", "xxRootDirectory": "C:/Tmp/Phares/Compare/Images-1e85c0ba", "xxxRootDirectory": "F:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba", "xxxxRootDirectory": "C:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba", "xxxxxRootDirectory": "F:/Tmp/Phares/2022-11-03-DCIM/DCIM/100D3400 2022", - "xxxxxxRootDirectory": "E:/- - - Videos/-", - "RootDirectory": "D:/2) Images B/Not-Copy-Copy/New folder/-", - "WriteBitmapDataBytes": false, - "IgnoreExtensions": [ - ".gif", - ".GIF", - ".pdf", - ".PDF" - ], - "PropertyContentCollectionFiles": [], - "ValidImageFormatExtensions": [ - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidMetadataExtensions": [ - ".3gp", - ".3GP", - ".avi", - ".AVI", - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".ico", - ".ICO", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".m4v", - ".M4V", - ".mov", - ".MOV", - ".mp4", - ".MP4", - ".mta", - ".MTA", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "2000.0 Winter", - "2002.1 Spring", - "2002.4 Winter", - "2003.0 Winter", - "2003.1 Spring", - "2003.3 Fall", - "2003.4 Winter", - "2004.0 Winter", - "2005.1 Spring", - "2005.2 Summer", - "2005.3 Fall", - "2005.4 Winter", - "2006.0 Winter", - "2006.1 Spring", - "2006.3 Fall", - "2007.0 Winter", - "2007.2 Summer Logan Michael", - "2007.2 Summer", - "2007.3 Fall Logan Michael", - "2007.4 Winter Logan Michael", - "2008.0 Winter Logan Michael", - "2008.1 Spring Logan Michael", - "2008.2 Summer Logan Michael", - "2008.2 Summer", - "2008.3 Fall Logan Michael", - "2009.0 Winter Logan Michael", - "2009.0 Winter", - "2009.1 Spring Logan Michael", - "2009.1 Spring", - "2009.2 Summer Logan Michael", - "2009.2 Summer", - "2009.3 Fall Logan Michael", - "2009.3 Fall", - "2009.4 Winter Logan Michael", - "2009.4 Winter", - "2010.0 Winter Logan Michael", - "2010.0 Winter", - "2010.1 Spring Logan Michael", - "2010.1 Spring", - "2010.2 Summer", - "2010.3 Fall Logan Michael", - "2010.3 Fall", - "2010.4 Winter", - "2011.0 Winter", - "2011.1 Spring", - "2011.2 Summer", - "2011.3 Fall", - "2011.4 Winter", - "2012.0 Winter Chelsea 2012", - "2012.0 Winter Chelsea", - "2012.0 Winter", - "2012.1 Spring Chelsea", - "2012.1 Spring", - "2012.2 Summer Chelsea", - "2012.2 Summer", - "2012.3 Fall Chelsea", - "2012.3 Fall", - "2012.4 Winter Chelsea", - "2012.4 Winter", - "2013.0 Winter Chelsea 2013", - "2013.0 Winter Chelsea", - "2013.0 Winter", - "2013.1 Spring", - "2013.2 Summer Chelsea", - "2013.2 Summer", - "2013.3 Fall Chelsea", - "2013.3 Fall", - "2013.4 Winter", - "2014.0 Winter", - "2014.1 Spring", - "2014.2 Summer", - "2014.3 Fall", - "2014.4 Winter", - "2015.0 Winter", - "2015.1 Spring", - "2015.2 Summer", - "2015.3 Fall", - "2015.4 Winter", - "2016.0 Winter", - "2016.1 Spring", - "2016.2 Summer", - "2016.3 Fall", - "2016.4 Winter", - "2017.1 Spring", - "2017.2 Summer", - "2017.3 Fall", - "2017.4 Winter", - "2018.0 Winter", - "2018.1 Spring", - "2018.3 Fall", - "2018.4 Winter", - "2019.0 Winter", - "2019.1 Spring", - "2019.2 Summer", - "2019.3 Fall", - "2019.4 Winter", - "2020.0 Winter", - "2020.1 Spring", - "2020.2 Summer", - "2020.3 Fall", - "2020.4 Winter", - "2021.1 Spring", - "2021.2 Summer", - "2021.3 Fall", - "2021.4 Winter", - "2022.0 Winter", - "2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz 2005.0 Winter Tracy Pictures", - "zzz 2005.1 Spring Tracy Pictures", - "zzz 2005.2 Summer Tracy Pictures", - "zzz 2005.3 Fall Tracy Pictures", - "zzz 2005.4 Winter Tracy Pictures", - "zzz 2006.1 Spring Tracy Pictures", - "zzz 2007.0 Winter Tracy Pictures", - "zzz 2007.2 Summer Tracy Pictures", - "zzz 2008.0 Winter Tracy Pictures", - "zzz 2008.2 Summer Tracy Pictures", - "zzz 2009.0 Winter Tracy Pictures", - "zzz 2009.2 Summer Tracy Pictures", - "zzz 2009.3 Fall Tracy Pictures", - "zzz 2009.4 Winter Tracy Pictures", - "zzz 2010.0 Winter Tracy Pictures", - "zzz 2010.1 Spring Tracy Pictures", - "zzz 2010.2 Summer Tracy Pictures", - "zzz 2010.3 Fall Tracy Pictures", - "zzz 2011.0 Winter Tracy Pictures", - "zzz 2011.1 Spring Tracy Pictures", - "zzz 2011.2 Summer Tracy Pictures", - "zzz 2011.3 Fall Tracy Pictures", - "zzz 2011.4 Winter Tracy Pictures", - "zzz 2012.0 Winter Tracy Pictures", - "zzz 2012.1 Spring Tracy Pictures", - "zzz 2012.2 Summer Tracy Pictures", - "zzz 2012.3 Fall Tracy Pictures", - "zzz 2012.4 Winter Tracy Pictures", - "zzz 2013.0 Winter Tracy Pictures", - "zzz 2013.1 Spring Tracy Pictures", - "zzz 2013.2 Summer Tracy Pictures", - "zzz 2013.3 Fall Tracy Pictures", - "zzz 2013.4 Winter Tracy Pictures", - "zzz 2014.0 Winter Tracy Pictures", - "zzz 2014.1 Spring Tracy Pictures", - "zzz 2014.2 Summer Tracy Pictures", - "zzz 2014.3 Fall Tracy Pictures", - "zzz 2014.4 Winter Tracy Pictures", - "zzz 2015.0 Winter Tracy Pictures" - ] + "RootDirectory": "D:/1) Images A/Images-1e85c0ba/zzz Mackenzie Laptop !9/_" } } } \ No newline at end of file diff --git a/Date-Group/appsettings.json b/Date-Group/appsettings.json index 93f9cf5..0399e35 100644 --- a/Date-Group/appsettings.json +++ b/Date-Group/appsettings.json @@ -67,10 +67,7 @@ "ResultCollection": "[]", "ResultContent": "()", "ResultSingleton": "{}", - "xRootDirectory": "C:/Tmp/phares/Pictures", - "xxRootDirectory": "C:/Tmp/Phares/Compare/Images-1e85c0ba", - "RootDirectory": "F:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba", - "xxxxRootDirectory": "F:/Tmp/Phares/2022-11-03-DCIM/DCIM/100D3400 2022", + "RootDirectory": "C:/Tmp/phares/Pictures", "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", diff --git a/Distance/Models/_E_Distance.cs b/Distance/Models/_E_Distance.cs index 2b4f9e3..56c86fb 100644 --- a/Distance/Models/_E_Distance.cs +++ b/Distance/Models/_E_Distance.cs @@ -58,11 +58,11 @@ public partial class E_Distance confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_FaceConfidencePercent, _RangeFaceConfidence, face.Location.Confidence); normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) - faceDistance = new(confidencePercent, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedRectangle); + faceDistance = new(confidencePercent, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, normalizedRectangle); else { faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - faceDistance = new(confidencePercent, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedRectangle); + faceDistance = new(confidencePercent, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, normalizedRectangle); lock (intersectFaces) face.SetFaceDistance(faceDistance); } @@ -347,11 +347,11 @@ public partial class E_Distance confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_FaceConfidencePercent, _RangeFaceConfidence, face.Location.Confidence); normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) - faceDistance = new(confidencePercent, faceEncoding, id, isWrongYear, face.DateTime, normalizedRectangle); + faceDistance = new(confidencePercent, face.DateTime, faceEncoding, id, isWrongYear, normalizedRectangle); else { faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - faceDistance = new(confidencePercent, faceEncoding, id, isWrongYear, face.DateTime, normalizedRectangle); + faceDistance = new(confidencePercent, face.DateTime, faceEncoding, id, isWrongYear, normalizedRectangle); face.SetFaceDistance(faceDistance); } faceDistanceContainer = new(face, faceDistance); @@ -390,7 +390,7 @@ public partial class E_Distance return; progressBar.Tick(); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - FaceDistance faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); + FaceDistance faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.NormalizedRectangle); lock (face) face.SetFaceDistance(faceDistance); }); @@ -447,7 +447,7 @@ public partial class E_Distance throw new NotSupportedException(); if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) continue; - faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); + faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.NormalizedRectangle); faceDistanceContainer = new(face, faceDistance); collection.Add(faceDistanceContainer); } @@ -480,7 +480,7 @@ public partial class E_Distance { if (faceDistanceContainer.FaceDistance is null || faceDistanceContainer.Face.Mapping?.MappingFromLocation is null) throw new NotSupportedException(); - if (skipOlderThan is not null && (faceDistanceContainer.FaceDistance.MinimumDateTime is null || faceDistanceContainer.FaceDistance.MinimumDateTime.Value.Ticks < skipOlderThan.Value)) + if (skipOlderThan is not null && faceDistanceContainer.FaceDistance.DateTimeOriginalThenMinimumDateTime.Ticks < skipOlderThan.Value) continue; if (faceDistanceContainer.Face.Mapping.MappingFromLocation.ConfidencePercent < distanceLimits.FaceConfidencePercent) continue; diff --git a/Drag-Drop-Move/Drag-Drop-Move.csproj b/Drag-Drop-Move/Drag-Drop-Move.csproj index 3737d46..244aabf 100644 --- a/Drag-Drop-Move/Drag-Drop-Move.csproj +++ b/Drag-Drop-Move/Drag-Drop-Move.csproj @@ -37,6 +37,7 @@ + diff --git a/Drag-Drop-Move/DragDropMove.cs b/Drag-Drop-Move/DragDropMove.cs index c406f06..ffffd91 100644 --- a/Drag-Drop-Move/DragDropMove.cs +++ b/Drag-Drop-Move/DragDropMove.cs @@ -2,9 +2,11 @@ using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; using System.Diagnostics; +using System.Drawing.Imaging; using System.Reflection; using System.Text.Json; using View_by_Distance.Drag_Drop_Explorer.Models; +using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Shared.Models.Stateless.Methods; using WindowsShortcutFactory; @@ -64,7 +66,7 @@ public partial class DragDropMove : Form Controls.Add(_FirstTextBox); } - void Form1_Load(object? sender, EventArgs e) + private void Form1_Load(object? sender, EventArgs e) { try { @@ -73,6 +75,8 @@ public partial class DragDropMove : Form DragEnter += new DragEventHandler(Form1_DragEnter); _FirstTextBox.LostFocus += new EventHandler(TextBox_LostFocus); _PathTextBox.LostFocus += new EventHandler(TextBox_LostFocus); + if (_WorkingDirectory is null) + { } } catch (Exception) { @@ -86,14 +90,14 @@ public partial class DragDropMove : Form return result; } - void TextBox_LostFocus(object? sender, EventArgs e) + private void TextBox_LostFocus(object? sender, EventArgs e) { try { if (sender is TextBox textBox) { textBox.Text = GetConverted(textBox.Text); - if (textBox.Text == "ps") + if (textBox.Text == "315360000000000") throw new NotImplementedException(); } @@ -104,7 +108,7 @@ public partial class DragDropMove : Form } } - void Form1_DragEnter(object? sender, DragEventArgs e) + private void Form1_DragEnter(object? sender, DragEventArgs e) { try { @@ -172,12 +176,145 @@ public partial class DragDropMove : Form } } - void Form1_DragDrop(object? sender, DragEventArgs e) + public 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; + } + + private static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, string value) + { + PropertyItem result = (PropertyItem)constructorInfo.Invoke(null); + byte[] bytes = GetBytes(value); + result.Id = id; + result.Len = value.Length + 1; + result.Type = 2; + result.Value = bytes; + return result; + } + + private static List<(string, int, DateTime)> GetCollection(string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) + { + List<(string, int, DateTime)> results = new(); + DateTime dateTime; + Shared.Models.Property property; + string[] files = Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + property = Property.Models.A_Property.GetImageProperty(file); + if (property.Id is null || property.DateTimeOriginal is null) + continue; + dateTime = property.DateTimeOriginal.Value.AddTicks(ticks); + if (dateTime < minimumDateTime) + continue; + if (dateTime > maximumDateTime) + continue; + results.Add((file, property.Id.Value, property.DateTimeOriginal.Value.AddTicks(ticks))); + } + if (files.Length != results.Count) + throw new Exception(); + return results; + } + + private static void DateFix(string sourceDirectory, string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) + { + Bitmap bitmap; + string checkFile; + PropertyItem? propertyItem; + string? ticksDirectory = null; + Shared.Models.Property property; + int dateTimeOriginal = (int)IExif.Tags.DateTimeOriginal; + for (int i = 0; i < int.MaxValue; i++) + { + ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString()); + if (!Directory.Exists(ticksDirectory)) + { + _ = Directory.CreateDirectory(ticksDirectory); + break; + } + ticks++; + + } + List<(string, int, DateTime)> collection = GetCollection(checkDirectory, minimumDateTime, maximumDateTime, ticks); + ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null) ?? throw new Exception(); + foreach ((string file, int id, DateTime dateTime) in collection) + { + if (ticksDirectory is null) + throw new Exception(); + checkFile = Path.Combine(ticksDirectory, Path.GetFileName(file)); + if (File.Exists(checkFile)) + continue; + propertyItem = GetPropertyItem(constructorInfo, dateTimeOriginal, dateTime.ToString("yyyy:MM:dd HH:mm:ss")); + bitmap = new(file); + bitmap.SetPropertyItem(propertyItem); + bitmap.Save(checkFile); + bitmap.Dispose(); + property = Property.Models.A_Property.GetImageProperty(checkFile); + if (property.Id is null || property.Id.Value != id) + throw new Exception(); + } + } + + private void DateFix(string sourceDirectory) + { + string checkDirectory; + long oneYearTicks = DateTime.MinValue.AddYears(1).Ticks; + checkDirectory = Path.Combine(sourceDirectory, oneYearTicks.ToString()); + if (Directory.Exists(checkDirectory)) + DateFix(sourceDirectory, checkDirectory, DateTime.MinValue, DateTime.MaxValue, new TimeSpan(oneYearTicks - DateTime.MinValue.Ticks).Ticks); + else + { + checkDirectory = Path.Combine(sourceDirectory, "1"); + if (!Directory.Exists(checkDirectory)) + _Logger.Error($"<{checkDirectory}> doesn't exist!"); + else + { + string badDirectory = Path.Combine(sourceDirectory, "Bad"); + string targetDirectory = Path.Combine(sourceDirectory, "Target"); + string[] minimumDirectory = Directory.GetDirectories(targetDirectory, "*", SearchOption.TopDirectoryOnly); + if (minimumDirectory.Length != 1) + _Logger.Error($"<{checkDirectory}> doesn't exist!"); + else + { + string format = "yyyy-MM-dd"; + string[] maximumDirectory = Directory.GetDirectories(minimumDirectory.First(), "*", SearchOption.TopDirectoryOnly); + string[] badFiles = !Directory.Exists(badDirectory) ? Array.Empty() : Directory.GetFiles(badDirectory, "*", SearchOption.TopDirectoryOnly); + string[] targetFiles = !Directory.Exists(targetDirectory) ? Array.Empty() : Directory.GetFiles(targetDirectory, "*", SearchOption.TopDirectoryOnly); + if (badFiles.Length != 1 || targetFiles.Length != 1 || maximumDirectory.Length != 1) + _Logger.Error("bad file(s) or target file(s) or maximum directory doesn't equal 1!"); + else + { + DateTime minimumDateTime = DateTime.ParseExact(Path.GetFileName(minimumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None); + DateTime maximumDateTime = DateTime.ParseExact(Path.GetFileName(maximumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None).AddHours(23); + Shared.Models.Property badProperty = Property.Models.A_Property.GetImageProperty(badFiles.First()); + Shared.Models.Property targetProperty = Property.Models.A_Property.GetImageProperty(targetFiles.First()); + if (badProperty.DateTimeOriginal is null || targetProperty.DateTimeOriginal is null) + _Logger.Error("Date is null!"); + else + { + TimeSpan timeSpan = new(targetProperty.DateTimeOriginal.Value.Ticks - badProperty.DateTimeOriginal.Value.Ticks); + DateFix(sourceDirectory, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks); + } + } + } + } + } + } + + private void Form1_DragDrop(object? sender, DragEventArgs e) { try { if (e.Data is not null && e.Data.GetData(DataFormats.FileDrop) is string[] paths && paths.Any()) - MovePaths(paths); + { + if (paths.Length == 1 && Directory.Exists(paths.First())) + DateFix(paths.First()); + else + MovePaths(paths); + } else { _FirstTextBox.Text = string.Empty; @@ -191,5 +328,4 @@ public partial class DragDropMove : Form throw; } } - } \ No newline at end of file diff --git a/Duplicate-Search/DuplicateSearch.cs b/Duplicate-Search/DuplicateSearch.cs index 0790729..b66226c 100644 --- a/Duplicate-Search/DuplicateSearch.cs +++ b/Duplicate-Search/DuplicateSearch.cs @@ -192,7 +192,7 @@ public class DuplicateSearch if (mappingFromItem is not null) { resizedFileHolder = new(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}")); - collection[0] = new(mappingFromItem.ContainerDateTimes, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, mappingFromItem.RelativePath, resizedFileHolder); + collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder); } } resizedFileHolder = new(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath)); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index a569941..be8f811 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -3,6 +3,7 @@ using Phares.Shared; using ShellProgressBar; using System.Collections.ObjectModel; using System.Drawing.Imaging; +using System.Text.RegularExpressions; using View_by_Distance.Distance.Models; using View_by_Distance.Face.Models; using View_by_Distance.FaceParts.Models; @@ -14,6 +15,7 @@ using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; +using WindowsShortcutFactory; namespace View_by_Distance.Instance; @@ -267,34 +269,19 @@ public partial class DlibDotNet return result; } - private bool? GetIsFocusModel(ReadOnlyDictionary>> idToLocationContainers, MappingFromItem mappingFromItem) + private bool? GetIsFocusModel(Shared.Models.Property? property) { bool? result; - string? model; - List>? locationContainers; - IReadOnlyList directories; if (string.IsNullOrEmpty(_Configuration.FocusModel)) result = null; + else if (property is null || string.IsNullOrEmpty(property.Model)) + result = null; else - { - if (!idToLocationContainers.TryGetValue(mappingFromItem.Id, out locationContainers) || !locationContainers.Any()) - result = false; - else - { - directories = locationContainers.First().Directories; - model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(directories); - if (model is null) - directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(mappingFromItem.ResizedFileHolder.FullName); - model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(directories); - result = model is not null && model.Contains(_Configuration.FocusModel); - if (result.Value) - result = true; - } - } + result = property.Model.Contains(_Configuration.FocusModel); return result; } - private void SetMapping(ReadOnlyDictionary>> idToLocationContainers, MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem, List? mappingFromPhotoPrismCollection, List faces) + private void SetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem, List? mappingFromPhotoPrismCollection, List faces) { Mapping mapping; int faceAreaPermyriad; @@ -304,7 +291,7 @@ public partial class DlibDotNet string deterministicHashCodeKey; MappingFromFilter mappingFromFilter; MappingFromLocation? mappingFromLocation; - bool? isFocusModel = GetIsFocusModel(idToLocationContainers, mappingFromItem); + bool? isFocusModel = GetIsFocusModel(item.Property); foreach (Shared.Models.Face face in faces) { if (item.Property?.Id is null || face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) @@ -329,7 +316,7 @@ public partial class DlibDotNet } } - private Mapping GetMapping(ReadOnlyDictionary>> idToLocationContainers, MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem) + private Mapping GetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem) { Mapping result; bool? inSkipCollection; @@ -339,7 +326,7 @@ public partial class DlibDotNet string deterministicHashCodeKey; MappingFromFilter mappingFromFilter; MappingFromLocation? mappingFromLocation; - bool? isFocusModel = GetIsFocusModel(idToLocationContainers, mappingFromItem); + bool? isFocusModel = GetIsFocusModel(item.Property); if (item.Property?.Id is null) { inSkipCollection = null; @@ -461,7 +448,7 @@ public partial class DlibDotNet if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); - SetMapping(idToLocationContainers, mapLogic, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces); + SetMapping(mapLogic, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces); if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) _FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) @@ -663,8 +650,8 @@ public partial class DlibDotNet if (!filteredItems.Any()) continue; sourceDirectoryChanges.Clear(); + anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - anyNullOrNoIsUniqueFileName = filteredItems.Any(l => l.IsUniqueFileName is null || !l.IsUniqueFileName.Value); message = $"{i + 1:000} [{filteredItems.Length:000} collectionB] / {containersLength:000} - {total} / {t} total collectionB - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}"; if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) _Faces.SetAngleBracketCollection(dResultsFullGroupDirectory, container.SourceDirectory); @@ -929,7 +916,7 @@ public partial class DlibDotNet } } - private Mapping[] GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, ReadOnlyDictionary>> idToLocationContainers, bool distinctItems) + private Mapping[] GetMappings(Property.Models.Configuration propertyConfiguration, Container[] containers, MapLogic mapLogic, bool distinctItems) { Mapping[] results; int count = 0; @@ -976,7 +963,7 @@ public partial class DlibDotNet } if (!anyValidFaces) { - mapping = GetMapping(idToLocationContainers, mapLogic, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem); + mapping = GetMapping(mapLogic, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem); mappingCollection.Add(mapping); } } @@ -985,6 +972,95 @@ public partial class DlibDotNet return results; } + private static void Verify(string eDistanceContentDirectory, List 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.Any()) + 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 Search(long ticks, string argZero, string propertyRoot) { int t; @@ -1048,13 +1124,15 @@ public partial class DlibDotNet ReadOnlyDictionary>> idToLocationContainers = mapLogic.GetIdToLocationContainers(); fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, eDistanceContentDirectory, fileNameToCollection, idToLocationContainers, mapLogic); - LookForAbandoned(bResultsFullGroupDirectory, containers, idToLocationContainers); + if (_Configuration.LookForAbandoned) + LookForAbandoned(bResultsFullGroupDirectory, containers, idToLocationContainers); _Distance.Clear(); if (!personKeyToIds.Any()) personKeyToIds = mapLogic.GetPersonKeyToIds(); - Mapping[] distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, idToLocationContainers, distinctItems: true); List distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, containers, distinctItems: true, filterItems: true); + Verify(eDistanceContentDirectory, distinctFilteredItems); List distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); + Mapping[] distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true); int totalNotMapped = mapLogic.UpdateMappingFromPerson(distinctFilteredMappingCollection); string json = System.Text.Json.JsonSerializer.Serialize(distinctFilteredMappingCollection); File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 5ca88b4..bed6cd0 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -36,6 +36,7 @@ public class Configuration [Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; } [Display(Name = "Location Digits"), Required] public int? LocationDigits { get; set; } [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } + [Display(Name = "Look for Abandoned"), Required] public bool? LookForAbandoned { get; set; } [Display(Name = "Mapping Default Name"), Required] public string MappingDefaultName { get; set; } [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Add to Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { get; set; } [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Save Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { get; set; } @@ -146,6 +147,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.LocationDigits)); if (configuration.LocationFactor is null) throw new NullReferenceException(nameof(configuration.LocationFactor)); + if (configuration.LookForAbandoned is null) + throw new NullReferenceException(nameof(configuration.LookForAbandoned)); if (configuration.MappingDefaultName is null) throw new NullReferenceException(nameof(configuration.MappingDefaultName)); if (configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping is null) @@ -256,6 +259,7 @@ public class Configuration configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, configuration.LocationDigits.Value, configuration.LocationFactor.Value, + configuration.LookForAbandoned.Value, configuration.MappingDefaultName, configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping.Value, configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping.Value, diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 70bdd7e..d22e097 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -35,6 +35,7 @@ public class Configuration public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } public int LocationDigits { init; get; } public int LocationFactor { init; get; } + public bool LookForAbandoned { init; get; } public string MappingDefaultName { init; get; } public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { init; get; } @@ -111,6 +112,7 @@ public class Configuration string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, int locationDigits, int locationFactor, + bool lookForAbandoned, string mappingDefaultName, bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping, @@ -186,6 +188,7 @@ public class Configuration LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; LocationDigits = locationDigits; LocationFactor = locationFactor; + LookForAbandoned = lookForAbandoned; MappingDefaultName = mappingDefaultName; MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping; diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 33729df..25bdf2a 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -20,6 +20,7 @@ "xFocusDirectory": "/Hawaii 2022", "FocusModel": "", "xFocusModel": "NIKON D3400", + "LookForAbandoned": false, "xGenealogicalDataCommunicationFile": "", "GenealogicalDataCommunicationFile": "D:/5) Other Small/RootsMagic/Code-638160743318283885/638160743318283885-Export.ged.cln", "PersonCharactersCopyCount": 0, @@ -110,230 +111,6 @@ "Scanned Prints", "Slide in Name Order Originals (622)", "Slides Pictures" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "2000.0 Winter", - "2002.1 Spring", - "2002.4 Winter", - "2003.0 Winter", - "2003.1 Spring", - "2003.3 Fall", - "2003.4 Winter", - "2004.0 Winter", - "2005.1 Spring", - "2005.2 Summer", - "2005.3 Fall", - "2005.4 Winter", - "2006.0 Winter", - "2006.1 Spring", - "2006.3 Fall", - "2007.0 Winter", - "2007.2 Summer Logan Michael", - "2007.2 Summer", - "2007.3 Fall Logan Michael", - "2007.4 Winter Logan Michael", - "2008.0 Winter Logan Michael", - "2008.1 Spring Logan Michael", - "2008.2 Summer Logan Michael", - "2008.2 Summer", - "2008.3 Fall Logan Michael", - "2009.0 Winter Logan Michael", - "2009.0 Winter", - "2009.1 Spring Logan Michael", - "2009.1 Spring", - "2009.2 Summer Logan Michael", - "2009.2 Summer", - "2009.3 Fall Logan Michael", - "2009.3 Fall", - "2009.4 Winter Logan Michael", - "2009.4 Winter", - "2010.0 Winter Logan Michael", - "2010.0 Winter", - "2010.1 Spring Logan Michael", - "2010.1 Spring", - "2010.2 Summer", - "2010.3 Fall Logan Michael", - "2010.3 Fall", - "2010.4 Winter", - "2011.0 Winter", - "2011.1 Spring", - "2011.2 Summer", - "2011.3 Fall", - "2011.4 Winter", - "2012.0 Winter Chelsea 2012", - "2012.0 Winter Chelsea", - "2012.0 Winter", - "2012.1 Spring Chelsea", - "2012.1 Spring", - "2012.2 Summer Chelsea", - "2012.2 Summer", - "2012.3 Fall Chelsea", - "2012.3 Fall", - "2012.4 Winter Chelsea", - "2012.4 Winter", - "2013.0 Winter Chelsea 2013", - "2013.0 Winter Chelsea", - "2013.0 Winter", - "2013.1 Spring", - "2013.2 Summer Chelsea", - "2013.2 Summer", - "2013.3 Fall Chelsea", - "2013.3 Fall", - "2013.4 Winter", - "2014.0 Winter", - "2014.1 Spring", - "2014.2 Summer", - "2014.3 Fall", - "2014.4 Winter", - "2015.0 Winter", - "2015.1 Spring", - "2015.2 Summer", - "2015.3 Fall", - "2015.4 Winter", - "2016.0 Winter", - "2016.1 Spring", - "2016.2 Summer", - "2016.3 Fall", - "2016.4 Winter", - "2017.1 Spring", - "2017.2 Summer", - "2017.3 Fall", - "2017.4 Winter", - "2018.0 Winter", - "2018.1 Spring", - "2018.3 Fall", - "2018.4 Winter", - "2019.0 Winter", - "2019.1 Spring", - "2019.2 Summer", - "2019.3 Fall", - "2019.4 Winter", - "2020.0 Winter", - "2020.1 Spring", - "2020.2 Summer", - "2020.3 Fall", - "2020.4 Winter", - "2021.1 Spring", - "2021.2 Summer", - "2021.3 Fall", - "2021.4 Winter", - "2022.0 Winter", - "2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz 2005.0 Winter Tracy Pictures", - "zzz 2005.1 Spring Tracy Pictures", - "zzz 2005.2 Summer Tracy Pictures", - "zzz 2005.3 Fall Tracy Pictures", - "zzz 2005.4 Winter Tracy Pictures", - "zzz 2006.1 Spring Tracy Pictures", - "zzz 2007.0 Winter Tracy Pictures", - "zzz 2007.2 Summer Tracy Pictures", - "zzz 2008.0 Winter Tracy Pictures", - "zzz 2008.2 Summer Tracy Pictures", - "zzz 2009.0 Winter Tracy Pictures", - "zzz 2009.2 Summer Tracy Pictures", - "zzz 2009.3 Fall Tracy Pictures", - "zzz 2009.4 Winter Tracy Pictures", - "zzz 2010.0 Winter Tracy Pictures", - "zzz 2010.1 Spring Tracy Pictures", - "zzz 2010.2 Summer Tracy Pictures", - "zzz 2010.3 Fall Tracy Pictures", - "zzz 2011.0 Winter Tracy Pictures", - "zzz 2011.1 Spring Tracy Pictures", - "zzz 2011.2 Summer Tracy Pictures", - "zzz 2011.3 Fall Tracy Pictures", - "zzz 2011.4 Winter Tracy Pictures", - "zzz 2012.0 Winter Tracy Pictures", - "zzz 2012.1 Spring Tracy Pictures", - "zzz 2012.2 Summer Tracy Pictures", - "zzz 2012.3 Fall Tracy Pictures", - "zzz 2012.4 Winter Tracy Pictures", - "zzz 2013.0 Winter Tracy Pictures", - "zzz 2013.1 Spring Tracy Pictures", - "zzz 2013.2 Summer Tracy Pictures", - "zzz 2013.3 Fall Tracy Pictures", - "zzz 2013.4 Winter Tracy Pictures", - "zzz 2014.0 Winter Tracy Pictures", - "zzz 2014.1 Spring Tracy Pictures", - "zzz 2014.2 Summer Tracy Pictures", - "zzz 2014.3 Fall Tracy Pictures", - "zzz 2014.4 Winter Tracy Pictures", - "zzz 2015.0 Winter Tracy Pictures" ] } } diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 30c2ce8..987739e 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -73,6 +73,7 @@ "GenealogicalDataCommunicationFile": "", "LocationDigits": 9, "LocationFactor": 10000, + "LookForAbandoned": true, "MappingDefaultName": "John Doe~25", "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping": false, "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping": false, diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 9dd6e6e..75fe8d2 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -37,8 +37,6 @@ public class MapLogic : Shared.Models.Methods.IMapLogic _PropertyConfiguration = propertyConfiguration; if (_Log is null) { } - if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) - throw new NullReferenceException(nameof(propertyConfiguration.VerifyToSeason)); string json; string fullPath; List>? collection; @@ -812,7 +810,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic windowsShortcut.Dispose(); if (!File.Exists(shortcutFile)) continue; - File.SetLastWriteTime(shortcutFile, mapping.MappingFromItem.MinimumDateTime); + File.SetLastWriteTime(shortcutFile, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime()); } } } @@ -1129,45 +1127,35 @@ public class MapLogic : Shared.Models.Methods.IMapLogic if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); int season; - string? model; long personKey; string fileName; string directory; - int dateCount = 0; string weekOfYear; + DateTime dateTime; string description; - DateTime? dateTime; string directoryName; List? personKeys; string personKeyFormatted; Calendar calendar = new CultureInfo("en-US").Calendar; - IReadOnlyList directories; Dictionary> idToPersonKeys = Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); foreach (Mapping mapping in mappingCollection) { - directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(mapping.MappingFromItem.ResizedFileHolder.FullName); - dateTime = Metadata.Models.Stateless.Methods.IMetadata.GetMinimumDateTime(directories); + dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(); description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey; - if (dateTime is not null) - { - dateCount++; - (season, _) = IProperty.GetSeason(dateTime.Value.DayOfYear); - weekOfYear = calendar.GetWeekOfYear(dateTime.Value, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Value.Year}.{season}-MM{dateTime.Value.Month:00}-WW{weekOfYear}"); - fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, description, MakeAllHidden: false)); - } - model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(directories); + (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(model) && !string.IsNullOrEmpty(model.Trim())) + if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim())) { // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " - model = Regex.Replace(model.Trim(), @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"); - directory = Path.Combine($"{eDistanceContentDirectory}---", "Model Shortcuts", model, directoryName); + directory = Path.Combine($"{eDistanceContentDirectory}---", "Model Shortcuts", Regex.Replace(mapping.MappingFromItem.Model.Trim(), @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_"), directoryName); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ImageFileHolder.Name}.lnk"); - results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.MinimumDateTime, fileName, description, MakeAllHidden: false)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); } if (mapping.MappingFromPerson is null) continue; @@ -1179,12 +1167,12 @@ public class MapLogic : Shared.Models.Methods.IMapLogic 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.MinimumDateTime, fileName, description, MakeAllHidden: false)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); if (IPerson.IsDefaultName(_Configuration.MappingDefaultName, mapping.MappingFromPerson.DisplayDirectoryName)) 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.MinimumDateTime, fileName, description, MakeAllHidden: false)); + results.Add(new(mapping.MappingFromItem.ImageFileHolder.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); } return results; } @@ -1286,13 +1274,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne); personDirectory = Path.Combine(directory, "Unknown"); fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); - collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); facesDirectory = Stateless.MapLogic.GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); if (facesDirectory is null || mapping.MappingFromLocation is null) continue; fullName = Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"); fileName = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ResizedFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}.lnk"); - collection.Add(new(fullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true)); + collection.Add(new(fullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true)); } else { @@ -1313,7 +1301,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic else personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{personKeyToIds[personKey].Count} Face(s)"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); - collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.MinimumDateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); + collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); } } return new(directoriesAndDateTimes, collection); diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 7e27134..3c7aedf 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -765,41 +765,41 @@ internal abstract class MapLogic SavePossiblyNewPersonContainers(configuration.PersonBirthdayFormat, configuration.FacesFileNameExtension, a2PeopleSingletonDirectory, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } - private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long minimumDateTimeTicks, bool? isWrongYear) + private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long dateTimeOriginalThenMinimumDateTimeTicks, bool? isWrongYear) { int years; string result; - TimeSpan? timeSpan = IPersonBirthday.GetTimeSpan(minimumDateTimeTicks, isWrongYear, personBirthday); + TimeSpan? timeSpan = IPersonBirthday.GetTimeSpan(dateTimeOriginalThenMinimumDateTimeTicks, isWrongYear, personBirthday); if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) result = "!---"; else if (timeSpan.HasValue) { - (years, _) = IPersonBirthday.GetAge(minimumDateTimeTicks, personBirthday); + (years, _) = IPersonBirthday.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, personBirthday); result = $"^{years:000}"; } else if (approximateYears.HasValue) { DateTime dateTime = new(ticks); - (years, _) = IAge.GetAge(minimumDateTimeTicks, dateTime.AddYears(-approximateYears.Value)); + (years, _) = IAge.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, dateTime.AddYears(-approximateYears.Value)); result = $"~{years:000}"; } else { string isWrongYearFlag = IItem.GetWrongYearFlag(isWrongYear); - result = $"{isWrongYearFlag}{new DateTime(minimumDateTimeTicks):yyyy}"; + result = $"{isWrongYearFlag}{new DateTime(dateTimeOriginalThenMinimumDateTimeTicks):yyyy}"; } return result; } - internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, DateTime minimumDateTime, bool? isWrongYear) + internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, DateTime dateTimeOriginalThenMinimumDateTime, bool? isWrongYear) { - string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, minimumDateTime.Ticks, 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.MinimumDateTime, mappingFromItem.IsWrongYear); + string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear); return result; } diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index b0d4e1d..4340f76 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -1,5 +1,4 @@ using ShellProgressBar; -using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Globalization; @@ -22,7 +21,6 @@ public class A_Property private readonly Serilog.ILogger? _Log; private readonly string _OutputExtension; - private readonly string[] _VerifyToSeason; private readonly int _MaxDegreeOfParallelism; private readonly ASCIIEncoding _ASCIIEncoding; private readonly Configuration _Configuration; @@ -41,9 +39,6 @@ public class A_Property _AngleBracketCollection = new List(); _MaxDegreeOfParallelism = maxDegreeOfParallelism; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; - if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) - throw new Exception(); - _VerifyToSeason = configuration.VerifyToSeason.Select(l => Path.Combine(configuration.RootDirectory, l)).ToArray(); string checkDirectory; List collection = new(); for (int i = 0; i < 12; i++) @@ -107,27 +102,23 @@ public class A_Property return results; } - private Shared.Models.Property GetImageProperty(FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id) + private static Shared.Models.Property GetImageProperty(FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, ASCIIEncoding asciiEncoding, bool writeBitmapDataBytes, string? angleBracket) { Shared.Models.Property result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - long ticks; byte[] bytes; string value; long fileLength; - int encodingHash; int? width = null; int? height = null; + string? make = null; + string? model = null; string dateTimeFormat; DateTime checkDateTime; DateTime? dateTime = null; PropertyItem? propertyItem; - string make = string.Empty; - string model = string.Empty; + string? orientation = null; DateTime? gpsDateStamp = null; DateTime? dateTimeOriginal = null; - string orientation = string.Empty; DateTime? dateTimeDigitized = null; DateTime? dateTimeFromName = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder); if (!isValidImageFormatExtension && isValidMetadataExtensions && fileHolder.Exists) @@ -145,7 +136,6 @@ public class A_Property if (populateId && id is null) { using Bitmap bitmap = new(image); - string angleBracket = _AngleBracketCollection[0]; Rectangle rectangle = new(0, 0, image.Width, image.Height); BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); IntPtr intPtr = bitmapData.Scan0; @@ -153,25 +143,12 @@ public class A_Property bytes = new byte[length]; Marshal.Copy(intPtr, bytes, 0, length); bitmap.UnlockBits(bitmapData); - if (id is null) - { - ticks = DateTime.Now.Ticks; - id = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(bytes); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); - } - if (_Configuration.WriteBitmapDataBytes) + id ??= Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(bytes); + if (writeBitmapDataBytes && !string.IsNullOrEmpty(angleBracket)) { FileInfo contentFileInfo = new(Path.Combine(angleBracket.Replace("<>", "()"), fileHolder.Name)); File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); } - ticks = DateTime.Now.Ticks; - string encoding = Encoding.Default.GetString(bytes); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); - encodingHash = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(encoding); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); } width = image.Width; height = image.Height; @@ -181,7 +158,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); if (value.Length > dateTimeFormat.Length) value = value[..dateTimeFormat.Length]; if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) @@ -193,7 +170,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); if (value.Length > dateTimeFormat.Length) value = value[..dateTimeFormat.Length]; if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) @@ -205,7 +182,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); if (value.Length > dateTimeFormat.Length) value = value[..dateTimeFormat.Length]; if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) @@ -217,7 +194,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); if (value.Length > dateTimeFormat.Length) value = value[..dateTimeFormat.Length]; if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) @@ -229,7 +206,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); make = value; } } @@ -238,7 +215,7 @@ public class A_Property propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); if (propertyItem?.Value is not null) { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); model = value; } } @@ -252,10 +229,7 @@ public class A_Property } } } - catch (Exception) - { - _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", fileHolder.Name, ">")); - } + catch (Exception) { } } else dateTimeOriginal = null; @@ -276,6 +250,22 @@ public class A_Property return result; } + public static Shared.Models.Property GetImageProperty(string fileName) + { + int? id = null; + bool populateId = true; + string? angleBracket = null; + bool isIgnoreExtension = false; + bool writeBitmapDataBytes = false; + ASCIIEncoding asciiEncoding = new(); + bool isValidMetadataExtensions = true; + FileHolder fileHolder = new(fileName); + bool isValidImageFormatExtension = true; + Shared.Models.Property? property = null; + Shared.Models.Property result = GetImageProperty(fileHolder, property, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, asciiEncoding, writeBitmapDataBytes, angleBracket); + return result; + } + #pragma warning restore CA1416 private Shared.Models.Property GetPropertyOfPrivate(Item item, List> sourceDirectoryFileTuples, List parseExceptions, bool isIgnoreExtension, bool isValidMetadataExtensions) @@ -290,7 +280,7 @@ public class A_Property bool populateId = _Configuration.PopulatePropertyId; char directory = Shared.Models.Stateless.Methods.IDirectory.GetDirectory(item.ImageFileHolder.Name); int directoryIndex = Shared.Models.Stateless.Methods.IDirectory.GetDirectory(directory); - if (item.IsUniqueFileName is null || !item.IsUniqueFileName.Value) + if (!item.IsUniqueFileName) fileInfo = new(Path.Combine(angleBracket.Replace("<>", "{}"), $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}.json")); else fileInfo = new(Path.Combine(_JsonGroups["{}"][directoryIndex], $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}.json")); @@ -369,7 +359,7 @@ public class A_Property if (result is null) { id ??= item.ImageFileHolder.Id; - result = GetImageProperty(item.ImageFileHolder, result, populateId, isIgnoreExtension, item.IsValidImageFormatExtension, isValidMetadataExtensions, id); + result = GetImageProperty(item.ImageFileHolder, result, populateId, isIgnoreExtension, item.IsValidImageFormatExtension, isValidMetadataExtensions, id, _ASCIIEncoding, _Configuration.WriteBitmapDataBytes, angleBracket); json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) { @@ -398,106 +388,6 @@ public class A_Property return result; } - private bool AnyFilesMoved(string sourceDirectory, List items) - { - bool result = false; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - int season; - string[] matches; - string deleteFile; - bool? isWrongYear; - string seasonName; - DateTime dateTime; - string destinationFile; - DateTime minimumDateTime; - string destinationDirectory; - string[] sourceDirectorySegments; - DateTime directoryMaximumOfMinimumDateTime = DateTime.MinValue; - foreach (Item item in items) - { - if (!item.IsValidImageFormatExtension || item.Property is null || !item.ImageFileHolder.Exists) - continue; - minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); - if (minimumDateTime > directoryMaximumOfMinimumDateTime) - directoryMaximumOfMinimumDateTime = minimumDateTime; - if (minimumDateTime != item.ImageFileHolder.CreationTime) - { - (isWrongYear, matches) = item.Property.IsWrongYear(item.ImageFileHolder, minimumDateTime); - if (isWrongYear is null || !isWrongYear.Value) - dateTime = minimumDateTime; - else - { - if (!matches.Any()) - continue; - if (!DateTime.TryParseExact(matches[0], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - continue; - } - try - { File.SetCreationTime(item.ImageFileHolder.FullName, dateTime); } - catch (Exception) - { } - } - if (!_VerifyToSeason.Contains(sourceDirectory)) - continue; - if (!item.ImageFileHolder.FullName.Contains("zzz ") && !item.ImageFileHolder.FullName.Contains("Camera ") && item.Property.DateTimeOriginal.HasValue) - { - TimeSpan timeSpan = new(item.Property.DateTimeOriginal.Value.Ticks - item.Property.LastWriteTime.Ticks); - if (timeSpan.TotalHours > 7.2f) - { - _Log.Warning($"*** propertyHolder.FileInfo.FullName <{item.ImageFileHolder.FullName}>"); - _Log.Warning($"*** DateTimeOriginal <{item.Property.DateTimeOriginal.Value}>"); - _Log.Warning($"*** LastWriteTime <{item.Property.LastWriteTime}>"); - _Log.Warning($"*** TotalHours <{timeSpan.TotalHours}>"); - } - } - sourceDirectorySegments = Path.GetFileName(sourceDirectory).Split(' '); - (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(minimumDateTime.DayOfYear); - if (sourceDirectorySegments[0] == "zzz") - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"zzz ={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(3))}"); - else if (sourceDirectorySegments.Length > 2) - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(2))}"); - else - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName}"); - if (destinationDirectory == sourceDirectory) - continue; - lock (item) - item.SetMoved(true); - if (!result) - result = true; - if (!Directory.Exists(destinationDirectory)) - _ = Directory.CreateDirectory(destinationDirectory); - destinationFile = Path.Combine(destinationDirectory, item.ImageFileHolder.Name); - if (File.Exists(destinationFile)) - { - if (_OutputExtension is not ".jpg" and not ".jpeg") - throw new Exception(); - if (destinationFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) - destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(item.ImageFileHolder.Name, ".jpeg")); - else if (destinationFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) - destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(item.ImageFileHolder.Name, ".jpg")); - } - _Log.Information($"*** source <{item.ImageFileHolder.FullName}>"); - _Log.Information($"*** destination <{destinationFile}>"); - if (!File.Exists(destinationFile)) - File.Move(item.ImageFileHolder.FullName, destinationFile); - else - { - deleteFile = Path.ChangeExtension(item.ImageFileHolder.FullName, ".delete"); - if (File.Exists(deleteFile)) - File.Delete(deleteFile); - File.Move(item.ImageFileHolder.FullName, destinationFile); - } - } - if (directoryMaximumOfMinimumDateTime != DateTime.MinValue) - { - DirectoryInfo directoryInfo = new(sourceDirectory); - if (directoryInfo.LastWriteTime != directoryMaximumOfMinimumDateTime) - Directory.SetLastWriteTime(sourceDirectory, directoryMaximumOfMinimumDateTime); - } - return result; - } - private void SavePropertyParallelForWork(string sourceDirectory, List> sourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) { Shared.Models.Property property; @@ -579,7 +469,6 @@ public class A_Property throw new NullReferenceException(nameof(_Log)); string message; int totalSeconds; - bool? anyFilesMoved; Container container; bool anyNullOrNoIsUniqueFileName; List exceptions = new(); @@ -594,7 +483,7 @@ public class A_Property sourceDirectoryChanges.Clear(); if (!container.Items.Any()) continue; - anyNullOrNoIsUniqueFileName = container.Items.Any(l => l.IsUniqueFileName is null || !l.IsUniqueFileName.Value); + anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName); SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName); totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); message = $"{i + 1:000} / {containersCount:000}) {container.Items.Count:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}"; @@ -605,10 +494,6 @@ public class A_Property throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!")); if (exceptions.Count != 0) _ExceptionsDirectories.Add(container.SourceDirectory); - if (exceptions.Count != 0) - anyFilesMoved = null; - else - anyFilesMoved = AnyFilesMoved(container.SourceDirectory, container.Items); if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) { for (int y = 0; y < int.MaxValue; y++) @@ -630,8 +515,7 @@ public class A_Property { if (item.ImageFileHolder.DirectoryName is null) throw new NullReferenceException(nameof(item.ImageFileHolder.DirectoryName)); - bool anyNullOrNoIsUniqueFileName = item.IsUniqueFileName is null || !item.IsUniqueFileName.Value; - SetAngleBracketCollection(item.ImageFileHolder.DirectoryName, anyNullOrNoIsUniqueFileName); + SetAngleBracketCollection(item.ImageFileHolder.DirectoryName, !item.IsUniqueFileName); } bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); bool isIgnoreExtension = item.IsValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs index 5321246..6cf3535 100644 --- a/Property/Models/Configuration.cs +++ b/Property/Models/Configuration.cs @@ -34,7 +34,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration public string ResultSingleton { init; get; } public string[] ValidImageFormatExtensions { init; get; } public string[] ValidMetadataExtensions { init; get; } - public string[] VerifyToSeason { init; get; } public bool WriteBitmapDataBytes { init; get; } [JsonConstructor] @@ -75,7 +74,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration _RootDirectory = rootDirectory; ValidImageFormatExtensions = validImageFormatExtensions; ValidMetadataExtensions = validMetadataExtensions; - VerifyToSeason = verifyToSeason; WriteBitmapDataBytes = writeBitmapDataBytes; } @@ -110,8 +108,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration throw new NullReferenceException(nameof(propertyConfiguration.ValidImageFormatExtensions)); if (propertyConfiguration.ValidMetadataExtensions is null || !propertyConfiguration.ValidMetadataExtensions.Any()) throw new NullReferenceException(nameof(propertyConfiguration.ValidMetadataExtensions)); - if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) - throw new NullReferenceException(nameof(propertyConfiguration.VerifyToSeason)); if (propertyConfiguration is null) throw new NullReferenceException(nameof(propertyConfiguration)); if (string.IsNullOrEmpty(propertyConfiguration.DateGroup)) diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index 4a93255..562799a 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -284,7 +284,7 @@ public class C_Resize { // string subFile, Shared.Models.Property property, Shared.Models.FileHolder? fileHolder string dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); - DateTime dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); + DateTime dateTime = property.DateTimeOriginal is not null ? property.DateTimeOriginal.Value : Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); string dateTimeValue = dateTime.ToString(dateTimeFormat); byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue); if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue) diff --git a/Shared/Models/FaceDistance.cs b/Shared/Models/FaceDistance.cs index ddc2fd6..ea4c194 100644 --- a/Shared/Models/FaceDistance.cs +++ b/Shared/Models/FaceDistance.cs @@ -7,31 +7,31 @@ public record class FaceDistance : Properties.IFaceDistance { public int? ConfidencePercent { init; get; } + public DateTime DateTimeOriginalThenMinimumDateTime { init; get; } public object? Encoding { init; get; } public int Id { init; get; } public bool? IsWrongYear { init; get; } public double? Length { init; get; } - public DateTime? MinimumDateTime { init; get; } public int? NormalizedRectangle { init; get; } [JsonConstructor] - public FaceDistance(int? confidencePercent, object? encoding, int id, bool? isWrongYear, double? length, DateTime? minimumDateTime, int? normalizedRectangle) + public FaceDistance(int? confidencePercent, DateTime dateTimeOriginalThenMinimumDateTime, object? encoding, int id, bool? isWrongYear, double? length, int? normalizedRectangle) { ConfidencePercent = confidencePercent; + DateTimeOriginalThenMinimumDateTime = dateTimeOriginalThenMinimumDateTime; Encoding = encoding; Id = id; IsWrongYear = isWrongYear; Length = length; - MinimumDateTime = minimumDateTime; NormalizedRectangle = normalizedRectangle; } - public FaceDistance(int? confidencePercent, object? encoding, int id, bool? isWrongYear, DateTime? minimumDateTime, int? normalizedRectangle) : - this(confidencePercent, encoding, id, isWrongYear, null, minimumDateTime, normalizedRectangle) + public FaceDistance(int? confidencePercent, DateTime dateTimeOriginalThenMinimumDateTime, object? encoding, int id, bool? isWrongYear, int? normalizedRectangle) : + this(confidencePercent, dateTimeOriginalThenMinimumDateTime, encoding, id, isWrongYear, null, normalizedRectangle) { } public FaceDistance(FaceDistance faceDistance, double length) : - this(faceDistance.ConfidencePercent, null, faceDistance.Id, faceDistance.IsWrongYear, length, faceDistance.MinimumDateTime, faceDistance.NormalizedRectangle) + this(faceDistance.ConfidencePercent, faceDistance.DateTimeOriginalThenMinimumDateTime, null, faceDistance.Id, faceDistance.IsWrongYear, length, faceDistance.NormalizedRectangle) { } public FaceDistance(object encoding) => Encoding = encoding; diff --git a/Shared/Models/FilePair.cs b/Shared/Models/FilePair.cs index 9722211..808105e 100644 --- a/Shared/Models/FilePair.cs +++ b/Shared/Models/FilePair.cs @@ -1,3 +1,3 @@ namespace View_by_Distance.Shared.Models; -public record FilePair(string Path, bool IsUnique, List Collection, string? Match) { } \ No newline at end of file +public record FilePair(string Path, bool IsUnique, bool? IsNotUniqueAndNeedsReview, List Collection, string? Match) { } \ No newline at end of file diff --git a/Shared/Models/Item.cs b/Shared/Models/Item.cs index 43cfba1..f56a5bc 100644 --- a/Shared/Models/Item.cs +++ b/Shared/Models/Item.cs @@ -9,7 +9,8 @@ public class Item : Properties.IItem protected List _Faces; protected readonly bool? _FileSizeChanged; protected readonly FileHolder _ImageFileHolder; - protected bool? _IsUniqueFileName; + protected bool? _IsNotUniqueAndNeedsReview; + protected bool _IsUniqueFileName; protected bool _IsValidImageFormatExtension; protected bool? _LastWriteTimeChanged; protected bool? _Moved; @@ -20,7 +21,8 @@ public class Item : Properties.IItem public List Faces => _Faces; public bool? FileSizeChanged => _FileSizeChanged; public FileHolder ImageFileHolder => _ImageFileHolder; - public bool? IsUniqueFileName => _IsUniqueFileName; + public bool? IsNotUniqueAndNeedsReview => _IsNotUniqueAndNeedsReview; + public bool IsUniqueFileName => _IsUniqueFileName; public bool IsValidImageFormatExtension => _IsValidImageFormatExtension; public bool? LastWriteTimeChanged => _LastWriteTimeChanged; public bool? Moved => _Moved; @@ -30,11 +32,12 @@ public class Item : Properties.IItem public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder; [JsonConstructor] - public Item(List faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder) + public Item(List faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder) { _Faces = faces; _FileSizeChanged = fileSizeChanged; _ImageFileHolder = imageFileHolder; + _IsNotUniqueAndNeedsReview = isNotUniqueAndNeedsReview; _IsUniqueFileName = isUniqueFileName; _IsValidImageFormatExtension = isValidImageFormatExtension; _LastWriteTimeChanged = lastWriteTimeChanged; @@ -45,8 +48,8 @@ public class Item : Properties.IItem _SourceDirectoryFileHolder = sourceDirectoryFileHolder; } - public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool? isUniqueFileName, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) : - this(new(), fileSizeChanged, imageFileInfo, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder) + public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) : + this(new(), fileSizeChanged, imageFileInfo, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder) { if (relativePath.EndsWith(".json")) throw new ArgumentException("Can not be a *.json file!"); @@ -55,7 +58,7 @@ public class Item : Properties.IItem } public Item(FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) : - this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, null, isValidImageFormatExtension, null, null, null, null) + this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, null, false, isValidImageFormatExtension, null, null, null, null) { } public override string ToString() diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index c17ed6d..fdb705b 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -3,142 +3,6 @@ using System.Text.Json.Serialization; namespace View_by_Distance.Shared.Models; -public class MappingFromItem : Properties.IMappingFromItem -{ - - public DateTime[] ContainerDateTimes { init; get; } - public int Id { init; get; } - public FileHolder ImageFileHolder { init; get; } - public bool? IsWrongYear { init; get; } - public DateTime MinimumDateTime { init; get; } - public string RelativePath { init; get; } - public FileHolder ResizedFileHolder { init; get; } - - [JsonConstructor] - public MappingFromItem(DateTime[] containerDateTimes, int id, FileHolder imageFileHolder, bool? isWrongYear, DateTime minimumDateTime, string relativePath, FileHolder resizedFileHolder) - { - ContainerDateTimes = containerDateTimes; - Id = id; - ImageFileHolder = imageFileHolder; - IsWrongYear = isWrongYear; - MinimumDateTime = minimumDateTime; - RelativePath = relativePath; - ResizedFileHolder = resizedFileHolder; - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - - internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder) - { - MappingFromItem result; - bool? isWrongYear; - DateTime minimumDateTime; - if (item.Property?.Id is null) - throw new NotSupportedException(); - if (resizedFileHolder is null) - throw new NotSupportedException(); - minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); - (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder, minimumDateTime); - result = new(containerDateTimes, item.Property.Id.Value, item.ImageFileHolder, isWrongYear, minimumDateTime, item.RelativePath, resizedFileHolder); - return result; - } - -} - -public class MappingFromLocation : Properties.IMappingFromLocation -{ - - public int AreaPermyriad { init; get; } - public int ConfidencePercent { init; get; } - public string DeterministicHashCodeKey { init; get; } - public int NormalizedRectangle { init; get; } - - [JsonConstructor] - public MappingFromLocation(int areaPermyriad, int confidencePercent, string deterministicHashCodeKey, int normalizedRectangle) - { - AreaPermyriad = areaPermyriad; - ConfidencePercent = confidencePercent; - DeterministicHashCodeKey = deterministicHashCodeKey; - NormalizedRectangle = normalizedRectangle; - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - -} - -public class MappingFromFilter : Properties.IMappingFromFilter -{ - - public bool? IsFocusModel { init; get; } - public bool? IsFocusRelativePath { init; get; } - public bool? IsIgnoreRelativePath { init; get; } - public bool? InSkipCollection { init; get; } - - [JsonConstructor] - public MappingFromFilter(bool? isFocusModel, bool? isFocusRelativePath, bool? isIgnoreRelativePath, bool? inSkipCollection) - { - IsFocusModel = isFocusModel; - IsFocusRelativePath = isFocusRelativePath; - IsIgnoreRelativePath = isIgnoreRelativePath; - InSkipCollection = inSkipCollection; - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - -} - -public class MappingFromPhotoPrism : Properties.IMappingFromPhotoPrism -{ - - public DatabaseFile DatabaseFile { init; get; } - public List Markers { init; get; } - - [JsonConstructor] - public MappingFromPhotoPrism(DatabaseFile databaseFile, List markers) - { - DatabaseFile = databaseFile; - Markers = markers; - } - -} - -public class MappingFromPerson : Properties.IMappingFromPerson -{ - - public int? ApproximateYears { init; get; } - public string DisplayDirectoryName { init; get; } - public PersonBirthday PersonBirthday { init; get; } - public string SegmentB { init; get; } - - [JsonConstructor] - public MappingFromPerson(int? approximateYears, string displayDirectoryName, PersonBirthday personBirthday, string segmentB) - { - ApproximateYears = approximateYears; - DisplayDirectoryName = displayDirectoryName; - PersonBirthday = personBirthday; - SegmentB = segmentB; - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - -} - public class Mapping : Properties.IMapping { diff --git a/Shared/Models/MappingFromFilter.cs b/Shared/Models/MappingFromFilter.cs new file mode 100644 index 0000000..97fa55b --- /dev/null +++ b/Shared/Models/MappingFromFilter.cs @@ -0,0 +1,29 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MappingFromFilter : Properties.IMappingFromFilter +{ + + public bool? IsFocusModel { init; get; } + public bool? IsFocusRelativePath { init; get; } + public bool? IsIgnoreRelativePath { init; get; } + public bool? InSkipCollection { init; get; } + + [JsonConstructor] + public MappingFromFilter(bool? isFocusModel, bool? isFocusRelativePath, bool? isIgnoreRelativePath, bool? inSkipCollection) + { + IsFocusModel = isFocusModel; + IsFocusRelativePath = isFocusRelativePath; + IsIgnoreRelativePath = isIgnoreRelativePath; + InSkipCollection = inSkipCollection; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} diff --git a/Shared/Models/MappingFromItem.cs b/Shared/Models/MappingFromItem.cs new file mode 100644 index 0000000..64fcb73 --- /dev/null +++ b/Shared/Models/MappingFromItem.cs @@ -0,0 +1,58 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MappingFromItem : Properties.IMappingFromItem +{ + + public DateTime[] ContainerDateTimes { init; get; } + public DateTime? DateTimeDigitized { init; get; } + public DateTime? DateTimeOriginal { init; get; } + public int Id { init; get; } + public FileHolder ImageFileHolder { init; get; } + public bool? IsWrongYear { init; get; } + public DateTime MinimumDateTime { init; get; } + public string? Model { init; get; } + public string RelativePath { init; get; } + public FileHolder ResizedFileHolder { init; get; } + + [JsonConstructor] + public MappingFromItem(DateTime[] containerDateTimes, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, int id, FileHolder imageFileHolder, bool? isWrongYear, DateTime minimumDateTime, string? model, string relativePath, FileHolder resizedFileHolder) + { + ContainerDateTimes = containerDateTimes; + DateTimeDigitized = dateTimeDigitized; + DateTimeOriginal = dateTimeOriginal; + Id = id; + ImageFileHolder = imageFileHolder; + IsWrongYear = isWrongYear; + MinimumDateTime = minimumDateTime; + Model = model; + RelativePath = relativePath; + ResizedFileHolder = resizedFileHolder; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public DateTime GetDateTimeOriginalThenMinimumDateTime() => + DateTimeOriginal is not null ? DateTimeOriginal.Value : MinimumDateTime; + + internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder) + { + MappingFromItem result; + if (item.Property?.Id is null) + throw new NotSupportedException(); + if (resizedFileHolder is null) + throw new NotSupportedException(); + List dateTimes = item.Property.GetDateTimes(); + DateTime minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + (bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.ImageFileHolder, item.Property.DateTimeOriginal, dateTimes); + result = new(containerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, item.Property.Id.Value, item.ImageFileHolder, isWrongYear, minimumDateTime, item.Property.Model, item.RelativePath, resizedFileHolder); + return result; + } + +} diff --git a/Shared/Models/MappingFromLocation.cs b/Shared/Models/MappingFromLocation.cs new file mode 100644 index 0000000..485801f --- /dev/null +++ b/Shared/Models/MappingFromLocation.cs @@ -0,0 +1,29 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MappingFromLocation : Properties.IMappingFromLocation +{ + + public int AreaPermyriad { init; get; } + public int ConfidencePercent { init; get; } + public string DeterministicHashCodeKey { init; get; } + public int NormalizedRectangle { init; get; } + + [JsonConstructor] + public MappingFromLocation(int areaPermyriad, int confidencePercent, string deterministicHashCodeKey, int normalizedRectangle) + { + AreaPermyriad = areaPermyriad; + ConfidencePercent = confidencePercent; + DeterministicHashCodeKey = deterministicHashCodeKey; + NormalizedRectangle = normalizedRectangle; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} diff --git a/Shared/Models/MappingFromPerson.cs b/Shared/Models/MappingFromPerson.cs new file mode 100644 index 0000000..5afaa7b --- /dev/null +++ b/Shared/Models/MappingFromPerson.cs @@ -0,0 +1,29 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MappingFromPerson : Properties.IMappingFromPerson +{ + + public int? ApproximateYears { init; get; } + public string DisplayDirectoryName { init; get; } + public PersonBirthday PersonBirthday { init; get; } + public string SegmentB { init; get; } + + [JsonConstructor] + public MappingFromPerson(int? approximateYears, string displayDirectoryName, PersonBirthday personBirthday, string segmentB) + { + ApproximateYears = approximateYears; + DisplayDirectoryName = displayDirectoryName; + PersonBirthday = personBirthday; + SegmentB = segmentB; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} diff --git a/Shared/Models/MappingFromPhotoPrism.cs b/Shared/Models/MappingFromPhotoPrism.cs new file mode 100644 index 0000000..163ab7f --- /dev/null +++ b/Shared/Models/MappingFromPhotoPrism.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class MappingFromPhotoPrism : Properties.IMappingFromPhotoPrism +{ + + public DatabaseFile DatabaseFile { init; get; } + public List Markers { init; get; } + + [JsonConstructor] + public MappingFromPhotoPrism(DatabaseFile databaseFile, List markers) + { + DatabaseFile = databaseFile; + Markers = markers; + } + +} diff --git a/Shared/Models/Properties/IFaceDistance.cs b/Shared/Models/Properties/IFaceDistance.cs index 542b79b..4d2b511 100644 --- a/Shared/Models/Properties/IFaceDistance.cs +++ b/Shared/Models/Properties/IFaceDistance.cs @@ -4,11 +4,11 @@ public interface IFaceDistance { public int? ConfidencePercent { init; get; } + public DateTime DateTimeOriginalThenMinimumDateTime { init; get; } public object? Encoding { init; get; } public int Id { init; get; } public bool? IsWrongYear { init; get; } public double? Length { init; get; } - public DateTime? MinimumDateTime { init; get; } public int? NormalizedRectangle { init; get; } } \ No newline at end of file diff --git a/Shared/Models/Properties/IItem.cs b/Shared/Models/Properties/IItem.cs index a671a8c..f073564 100644 --- a/Shared/Models/Properties/IItem.cs +++ b/Shared/Models/Properties/IItem.cs @@ -6,7 +6,8 @@ public interface IItem public bool? FileSizeChanged { get; } public List Faces { get; } public FileHolder ImageFileHolder { get; } - public bool? IsUniqueFileName { get; } + public bool? IsNotUniqueAndNeedsReview { get; } + public bool IsUniqueFileName { get; } public bool IsValidImageFormatExtension { get; } public bool? Moved { get; } public Property? Property { get; } diff --git a/Shared/Models/Properties/IMapping.cs b/Shared/Models/Properties/IMapping.cs index 2308339..5093be5 100644 --- a/Shared/Models/Properties/IMapping.cs +++ b/Shared/Models/Properties/IMapping.cs @@ -1,56 +1,5 @@ namespace View_by_Distance.Shared.Models.Properties; -public interface IMappingFromItem -{ - - public DateTime[] ContainerDateTimes { init; get; } - public int Id { init; get; } - public FileHolder ImageFileHolder { init; get; } - public bool? IsWrongYear { init; get; } - public DateTime MinimumDateTime { init; get; } - public string RelativePath { init; get; } - public FileHolder ResizedFileHolder { init; get; } - -} - -public interface IMappingFromFilter -{ - - public bool? IsFocusModel { init; get; } - public bool? IsFocusRelativePath { init; get; } - public bool? IsIgnoreRelativePath { init; get; } - public bool? InSkipCollection { init; get; } - -} - -public interface IMappingFromLocation -{ - - public int AreaPermyriad { init; get; } - public int ConfidencePercent { init; get; } - public string DeterministicHashCodeKey { init; get; } - public int NormalizedRectangle { init; get; } - -} - -public interface IMappingFromPhotoPrism -{ - - public DatabaseFile DatabaseFile { init; get; } - public List Markers { init; get; } - -} - -public interface IMappingFromPerson -{ - - public int? ApproximateYears { init; get; } - public string DisplayDirectoryName { init; get; } - public PersonBirthday PersonBirthday { init; get; } - public string SegmentB { init; get; } - -} - public interface IMapping { diff --git a/Shared/Models/Properties/IMappingFromFilter.cs b/Shared/Models/Properties/IMappingFromFilter.cs new file mode 100644 index 0000000..f010c4a --- /dev/null +++ b/Shared/Models/Properties/IMappingFromFilter.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMappingFromFilter +{ + + public bool? IsFocusModel { init; get; } + public bool? IsFocusRelativePath { init; get; } + public bool? IsIgnoreRelativePath { init; get; } + public bool? InSkipCollection { init; get; } + +} diff --git a/Shared/Models/Properties/IMappingFromItem.cs b/Shared/Models/Properties/IMappingFromItem.cs new file mode 100644 index 0000000..0851a14 --- /dev/null +++ b/Shared/Models/Properties/IMappingFromItem.cs @@ -0,0 +1,17 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMappingFromItem +{ + + public DateTime[] ContainerDateTimes { init; get; } + public DateTime? DateTimeDigitized { init; get; } + public DateTime? DateTimeOriginal { init; get; } + public int Id { init; get; } + public FileHolder ImageFileHolder { init; get; } + public bool? IsWrongYear { init; get; } + public DateTime MinimumDateTime { init; get; } + public string? Model { init; get; } + public string RelativePath { init; get; } + public FileHolder ResizedFileHolder { init; get; } + +} diff --git a/Shared/Models/Properties/IMappingFromLocation.cs b/Shared/Models/Properties/IMappingFromLocation.cs new file mode 100644 index 0000000..a192a6d --- /dev/null +++ b/Shared/Models/Properties/IMappingFromLocation.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMappingFromLocation +{ + + public int AreaPermyriad { init; get; } + public int ConfidencePercent { init; get; } + public string DeterministicHashCodeKey { init; get; } + public int NormalizedRectangle { init; get; } + +} diff --git a/Shared/Models/Properties/IMappingFromPerson.cs b/Shared/Models/Properties/IMappingFromPerson.cs new file mode 100644 index 0000000..83ca754 --- /dev/null +++ b/Shared/Models/Properties/IMappingFromPerson.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMappingFromPerson +{ + + public int? ApproximateYears { init; get; } + public string DisplayDirectoryName { init; get; } + public PersonBirthday PersonBirthday { init; get; } + public string SegmentB { init; get; } + +} diff --git a/Shared/Models/Properties/IMappingFromPhotoPrism.cs b/Shared/Models/Properties/IMappingFromPhotoPrism.cs new file mode 100644 index 0000000..2e08e8a --- /dev/null +++ b/Shared/Models/Properties/IMappingFromPhotoPrism.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IMappingFromPhotoPrism +{ + + public DatabaseFile DatabaseFile { init; get; } + public List Markers { init; get; } + +} diff --git a/Shared/Models/Properties/IProperty.cs b/Shared/Models/Properties/IProperty.cs index 5c4fcdf..f1454da 100644 --- a/Shared/Models/Properties/IProperty.cs +++ b/Shared/Models/Properties/IProperty.cs @@ -3,19 +3,19 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IProperty { - public DateTime CreationTime { get; } - public DateTime? DateTime { get; } - public DateTime? DateTimeDigitized { get; } - public DateTime? DateTimeFromName { get; } - public DateTime? DateTimeOriginal { get; } - public long FileSize { get; } - public DateTime? GPSDateStamp { get; } - public int? Height { get; } - public int? Id { get; } - public DateTime LastWriteTime { get; } - public string Make { get; } - public string Model { get; } - public string Orientation { get; } - public int? Width { get; } + public DateTime CreationTime { init; get; } + public DateTime? DateTime { init; get; } + public DateTime? DateTimeDigitized { init; get; } + public DateTime? DateTimeFromName { init; get; } + public DateTime? DateTimeOriginal { init; get; } + public long FileSize { init; get; } + public DateTime? GPSDateStamp { init; get; } + public int? Height { init; get; } + public int? Id { init; get; } + public DateTime LastWriteTime { init; get; } + public string? Make { init; get; } + public string? Model { init; get; } + public string? Orientation { init; get; } + public int? Width { init; get; } } \ No newline at end of file diff --git a/Shared/Models/Properties/IPropertyConfiguration.cs b/Shared/Models/Properties/IPropertyConfiguration.cs index e7e143c..052487d 100644 --- a/Shared/Models/Properties/IPropertyConfiguration.cs +++ b/Shared/Models/Properties/IPropertyConfiguration.cs @@ -13,7 +13,6 @@ public interface IPropertyConfiguration public string ResultContent { init; get; } public string ResultSingleton { init; get; } public string[] ValidImageFormatExtensions { init; get; } - public string[] VerifyToSeason { init; get; } public string? ModelName { get; } public int? NumberOfJitters { get; } public int? NumberOfTimesToUpsample { get; } diff --git a/Shared/Models/Property.cs b/Shared/Models/Property.cs index 5c48358..c8bec8a 100644 --- a/Shared/Models/Property.cs +++ b/Shared/Models/Property.cs @@ -6,52 +6,38 @@ namespace View_by_Distance.Shared.Models; public class Property : Properties.IProperty { - protected DateTime _CreationTime; - protected DateTime? _DateTime; - protected DateTime? _DateTimeDigitized; - protected DateTime? _DateTimeFromName; - protected DateTime? _DateTimeOriginal; - protected long _FileSize; - protected DateTime? _GPSDateStamp; - protected int? _Height; - protected int? _Id; - protected DateTime _LastWriteTime; - protected string _Make; - protected string _Model; - protected string _Orientation; - protected int? _Width; - public DateTime CreationTime => _CreationTime; - public DateTime? DateTime => _DateTime; - public DateTime? DateTimeDigitized => _DateTimeDigitized; - public DateTime? DateTimeFromName => _DateTimeFromName; - public DateTime? DateTimeOriginal => _DateTimeOriginal; - public long FileSize => _FileSize; - public DateTime? GPSDateStamp => _GPSDateStamp; - public int? Height => _Height; - public int? Id => _Id; - public DateTime LastWriteTime => _LastWriteTime; - public string Make => _Make; - public string Model => _Model; - public string Orientation => _Orientation; - public int? Width => _Width; + public DateTime CreationTime { init; get; } + public DateTime? DateTime { init; get; } + public DateTime? DateTimeDigitized { init; get; } + public DateTime? DateTimeFromName { init; get; } + public DateTime? DateTimeOriginal { init; get; } + public long FileSize { init; get; } + public DateTime? GPSDateStamp { init; get; } + public int? Height { init; get; } + public int? Id { init; get; } + public DateTime LastWriteTime { init; get; } + public string? Make { init; get; } + public string? Model { init; get; } + public string? Orientation { init; get; } + public int? Width { init; get; } [JsonConstructor] - public Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, DateTime lastWriteTime, string make, string model, string orientation, int? width) + public Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, DateTime lastWriteTime, string? make, string? model, string? orientation, int? width) { - _DateTimeFromName = dateTimeFromName; - _CreationTime = creationTime; - _DateTime = dateTime; - _DateTimeDigitized = dateTimeDigitized; - _DateTimeOriginal = dateTimeOriginal; - _FileSize = fileSize; - _GPSDateStamp = gpsDateStamp; - _Height = height; - _Id = id; - _LastWriteTime = lastWriteTime; - _Make = make; - _Model = model; - _Orientation = orientation; - _Width = width; + DateTimeFromName = dateTimeFromName; + CreationTime = creationTime; + DateTime = dateTime; + DateTimeDigitized = dateTimeDigitized; + DateTimeOriginal = dateTimeOriginal; + FileSize = fileSize; + GPSDateStamp = gpsDateStamp; + Height = height; + Id = id; + LastWriteTime = lastWriteTime; + Make = make; + Model = model; + Orientation = orientation; + Width = width; } public override string ToString() @@ -60,38 +46,6 @@ public class Property : Properties.IProperty return result; } // ... - public List GetDateTimes() => Stateless.Methods.Property.GetDateTimes(_CreationTime, _LastWriteTime, _DateTime, _DateTimeDigitized, _DateTimeFromName, _DateTimeOriginal, _GPSDateStamp); - - public (bool?, string[]) IsWrongYear(FileHolder fileHolder, DateTime? minimumDateTime) - { - string[] results = Array.Empty(); - bool? result = null; - string year; - string directoryName; - string[] directorySegments; - string? check = Path.GetFullPath(fileHolder.FullName); - string? pathRoot = Path.GetPathRoot(fileHolder.FullName); - if (string.IsNullOrEmpty(pathRoot)) - throw new Exception(); - if (minimumDateTime.HasValue) - year = minimumDateTime.Value.ToString("yyyy"); - else - { - List dateTimes = GetDateTimes(); - year = dateTimes.Min().ToString("yyyy"); - } - for (int i = 0; i < int.MaxValue; i++) - { - check = Path.GetDirectoryName(check); - if (string.IsNullOrEmpty(check) || check == pathRoot) - break; - directoryName = Path.GetFileName(check); - directorySegments = directoryName.Split(' '); - (result, results) = Stateless.Methods.Property.IsWrongYear(directorySegments, year); - if (result.HasValue) - break; - } - return new(result, results); - } + public List GetDateTimes() => Stateless.Methods.Property.GetDateTimes(CreationTime, LastWriteTime, DateTime, DateTimeDigitized, DateTimeFromName, DateTimeOriginal, GPSDateStamp); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs index 158794a..259538a 100644 --- a/Shared/Models/Stateless/Methods/Container.cs +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -144,7 +144,7 @@ internal abstract class Container File.SetCreationTime(sourceDirectoryFileHolder.FullName, imageFileInfo.LastWriteTime.Value); File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value); } - Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged); + Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged); lock (results) results.Add(new(filePair.Path, imageFileInfo.DirectoryName, filePair.IsUnique, filePair.Collection, item)); } diff --git a/Shared/Models/Stateless/Methods/IProperty.cs b/Shared/Models/Stateless/Methods/IProperty.cs index 5fb21d7..11cfcf0 100644 --- a/Shared/Models/Stateless/Methods/IProperty.cs +++ b/Shared/Models/Stateless/Methods/IProperty.cs @@ -11,11 +11,6 @@ public interface IProperty static int GetDeterministicHashCode(byte[] value) => Property.GetDeterministicHashCode(value); - int TestStatic_GetDeterministicHashCode(string value) => - GetDeterministicHashCode(value); - static int GetDeterministicHashCode(string value) => - Property.GetDeterministicHashCode(value); - DateTime TestStatic_GetDateTime(Models.Property? property) => GetDateTime(property); static DateTime GetDateTime(Models.Property? property) => @@ -46,6 +41,11 @@ public interface IProperty static (bool?, string[]) IsWrongYear(string[] segments, string year) => Property.IsWrongYear(segments, year); + (bool?, string[]) TestStatic_IsWrongYear(Models.FileHolder fileHolder, DateTime? dateTimeOriginal, List dateTimes) => + IsWrongYear(fileHolder, dateTimeOriginal, dateTimes); + static (bool?, string[]) IsWrongYear(Models.FileHolder fileHolder, DateTime? dateTimeOriginal, List dateTimes) => + Property.IsWrongYear(fileHolder, dateTimeOriginal, dateTimes); + (DateTime?[], int?, string?) TestStatic_Get(Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension) => Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension); static (DateTime?[], int?, string?) Get(Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension) => diff --git a/Shared/Models/Stateless/Methods/Property.cs b/Shared/Models/Stateless/Methods/Property.cs index ae71b25..88992dc 100644 --- a/Shared/Models/Stateless/Methods/Property.cs +++ b/Shared/Models/Stateless/Methods/Property.cs @@ -42,25 +42,6 @@ internal abstract class Property return result; } - internal static int GetDeterministicHashCode(string 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; - } - internal static (bool?, string[]) IsWrongYear(string[] segments, string year) { bool? result; @@ -92,6 +73,45 @@ internal abstract class Property return new(result, results); } + internal static (bool?, string[]) IsWrongYear(Models.FileHolder fileHolder, DateTime? dateTimeOriginal, List dateTimes) + { + string[] results = Array.Empty(); + bool? result = null; + string year; + string directoryName; + string[] directorySegments; + List collection = new(); + string? check = Path.GetFullPath(fileHolder.FullName); + string? pathRoot = Path.GetPathRoot(fileHolder.FullName); + if (string.IsNullOrEmpty(pathRoot)) + throw new Exception(); + if (dateTimeOriginal is not null) + collection.Add(dateTimeOriginal.Value); + else + { + foreach (DateTime dateTime in dateTimes) + collection.Add(dateTime); + } + foreach (DateTime dateTime in collection) + { + year = dateTime.ToString("yyyy"); + for (int i = 0; i < int.MaxValue; i++) + { + check = Path.GetDirectoryName(check); + if (string.IsNullOrEmpty(check) || check == pathRoot) + break; + directoryName = Path.GetFileName(check); + directorySegments = directoryName.Split(' '); + (result, results) = IsWrongYear(directorySegments, year); + if (result is not null) + break; + } + if (result is not null && result.Value) + break; + } + return new(result, results); + } + internal static DateTime? GetDateTimeFromName(Models.FileHolder fileHolder) { DateTime? result = null; diff --git a/Shared/Models/Stateless/Methods/Sorting.cs b/Shared/Models/Stateless/Methods/Sorting.cs index 5997967..99f4368 100644 --- a/Shared/Models/Stateless/Methods/Sorting.cs +++ b/Shared/Models/Stateless/Methods/Sorting.cs @@ -10,10 +10,7 @@ internal abstract class Sorting throw new NotSupportedException(); if (faceDistanceLength.NormalizedRectangle is null) throw new NotSupportedException(); - if (faceDistanceEncoding.MinimumDateTime is null || faceDistanceLength.MinimumDateTime is null) - throw new NotSupportedException(); - long ticks = faceDistanceEncoding.MinimumDateTime.Value.Ticks; - TimeSpan timeSpan = new(faceDistanceLength.MinimumDateTime.Value.Ticks - ticks); + TimeSpan timeSpan = new(faceDistanceLength.DateTimeOriginalThenMinimumDateTime.Ticks - faceDistanceEncoding.DateTimeOriginalThenMinimumDateTime.Ticks); bool older = timeSpan.TotalMilliseconds < 0; int daysDelta = (int)Math.Round(Math.Abs(timeSpan.TotalDays), 0); int distancePermyriad = (int)(faceDistanceLength.Length.Value / rangeDistanceTolerance * faceDistancePermyriad); diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index f6c04bb..898f1d3 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -95,9 +95,9 @@ internal abstract partial class XDirectory return renameCollection.Count; } - private static void IsNotUniqueLoop(string file, List collection) + private static bool GetIsNotUniqueAndNeedsReview(string file, List collection) { - TimeSpan timeSpan; + bool result = false; FileInfo possibleFileInfo; FileInfo fileInfo = new(file); foreach (string possible in collection) @@ -105,18 +105,14 @@ internal abstract partial class XDirectory if (possible == file) continue; possibleFileInfo = new(possible); + if (possibleFileInfo.LastWriteTime != fileInfo.LastWriteTime) + File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Max()); if (possibleFileInfo.LastWriteTime == fileInfo.LastWriteTime && possibleFileInfo.Length == fileInfo.Length) continue; - timeSpan = new(possibleFileInfo.LastWriteTime.Ticks - fileInfo.LastWriteTime.Ticks); - if (possibleFileInfo.Length != fileInfo.Length) - throw new Exception(Path.GetFileNameWithoutExtension(file)); - if (timeSpan.TotalMinutes < 61) - { - File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Min()); - continue; - } - throw new Exception(Path.GetFileNameWithoutExtension(file)); + if (!result) + result = true; } + return result; } private static string? GetMatch(string file, List collection) @@ -148,28 +144,30 @@ internal abstract partial class XDirectory string fileName; bool uniqueFileName; List? collection; + bool? isNotUniqueAndNeedsReview; foreach (string[] files in filesCollection) { foreach (string file in files) { + isNotUniqueAndNeedsReview = null; fileName = Path.GetFileName(file); if (!fileNamesToFiles.TryGetValue(fileName, out collection)) throw new Exception(); uniqueFileName = collection.Count == 1; if (!uniqueFileName) - IsNotUniqueLoop(file, collection); + isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(file, collection); if (!compareFileNamesToFiles.TryGetValue(string.Concat(fileName, extension), out collection)) - results.Add(new(file, uniqueFileName, new(), null)); + results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, new(), null)); else { if (!collection.Any()) - results.Add(new(file, uniqueFileName, collection, null)); + results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, null)); else if (uniqueFileName && collection.Count == 1) - results.Add(new(file, uniqueFileName, collection, collection.First())); + results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, collection.First())); else { match = GetMatch(file, collection); - results.Add(new(file, uniqueFileName, collection, match)); + results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, match)); } } } diff --git a/Tests/UnitTestHardCoded.cs b/Tests/UnitTestHardCoded.cs index 444f599..153378a 100644 --- a/Tests/UnitTestHardCoded.cs +++ b/Tests/UnitTestHardCoded.cs @@ -762,13 +762,13 @@ public partial class UnitTestHardCoded public void TestMethodRename() { // string[] directories = Directory.GetDirectories(@"D:\2) Images B\Not-Copy-Copy-1e85c0ba", "*;*", SearchOption.AllDirectories); - // string[] directories = Directory.GetDirectories(@"D:\1) Images A\Images-1e85c0ba", "*;*", SearchOption.AllDirectories); - string[] directories = Directory.GetDirectories(@"D:\2) Images B\Not-Copy-Copy-1e85c0ba", "*", SearchOption.AllDirectories); + string[] directories = Directory.GetDirectories(@"D:\1) Images A\Images-1e85c0ba", "*;*", SearchOption.AllDirectories); + // string[] directories = Directory.GetDirectories(@"D:\2) Images B\Not-Copy-Copy-1e85c0ba", "*", SearchOption.AllDirectories); foreach (string directory in directories.OrderByDescending(l => l.Length - l.Replace(@"\", string.Empty).Length)) { - if (directory.EndsWith(";9")) + if (!directory.EndsWith(";9")) continue; - Directory.Move(directory, $"{directory};9"); + Directory.Move(directory, $"{directory[..^2]} !9"); } NonThrowTryCatch(); } diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index 458b0df..d0f168c 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -157,14 +157,15 @@ public class UnitTestResize _ = metadata.ToString(); C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); _ = resize.ToString(); - bool? isUniqueFileName = null; + bool isUniqueFileName = false; + bool? isNotUniqueAndNeedsReview = null; FileHolder sourceDirectoryFileHolder = new(".json"); FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); string relativePath = IPath.GetRelativePath(fileHolder.FullName, length); sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory); resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory); - item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); + item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) { diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index f51e49e..294dfb3 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -232,7 +232,8 @@ public class UnitTestFace _ = metadata.ToString(); C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); _ = resize.ToString(); - bool? isUniqueFileName = null; + bool isUniqueFileName = false; + bool? isNotUniqueAndNeedsReview = null; bool anyNullOrNoIsUniqueFileName = true; FileHolder sourceDirectoryFileHolder = new(".json"); FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); @@ -240,7 +241,7 @@ public class UnitTestFace sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory); - item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); + item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) {