From 818a1b0b38f8ba39e13d563e3363febaaeb03f2b Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 9 Jul 2023 23:36:39 -0700 Subject: [PATCH] Rename files to padded number string --- .kanbn/index.md | 12 +- .kanbn/tasks/find-incorrectly-mapped-faces.md | 4 +- .kanbn/tasks/merge-kristy-files.md | 4 +- .kanbn/tasks/nef-support.md | 6 +- .../photoview-in-docker-for-a-viewer-only.md | 5 +- .../rename-files-to-padded-number-string.md | 15 +- .kanbn/tasks/set-date-taken-when-missing.md | 13 +- .kanbn/tasks/use-eyes-to-find-orientation.md | 4 +- Compare/appsettings.Development.json | 31 -- Compare/appsettings.json | 28 -- Copy-Distinct/Models/AppSettings.cs | 2 +- Copy-Distinct/Models/Binder/AppSettings.cs | 2 +- Copy-Distinct/appsettings.json | 31 -- Date-Group/Date-Group.csproj | 1 + Date-Group/DateGroup.cs | 3 +- Date-Group/appsettings.json | 31 -- Delete-By-Distinct/appsettings.json | 31 -- Delete-By-Relative/appsettings.json | 31 -- .../Drag-Drop-Set-Property-Item.csproj | 1 + .../DragDropSetPropertyItem.cs | 68 ++- Drag-Drop-Set-Property-Item/appsettings.json | 45 +- Duplicate-Search/appsettings.json | 31 -- Face/Models/_D_Face.cs | 6 +- Instance/DlibDotNet.cs | 143 ++++--- Instance/Models/AppSettings.cs | 24 +- Instance/Models/Binder/AppSettings.cs | 11 +- Instance/appsettings.json | 31 -- Metadata-Query/appsettings.json | 31 -- Metadata/Metadata.csproj | 2 +- Metadata/Models/B_Metadata.cs | 127 +++++- .../Models/Stateless/Methods/IMetadata.cs | 5 - Metadata/Models/Stateless/Methods/Metadata.cs | 102 ----- Mirror-Length/appsettings.json | 31 -- Move-By-Id/Move-By-Id.csproj | 1 - Move-By-Id/MoveById.cs | 15 +- Move-By-Id/appsettings.json | 31 -- .../OffsetDateTimeOriginal.cs | 96 +++-- Offset-Date-Time-Original/appsettings.json | 31 -- Person/appsettings.json | 62 --- PrepareForOld/appsettings.Development.json | 31 -- Property/Models/A_Property.cs | 221 +--------- Property/Models/Binder/Configuration.cs | 9 +- Property/Models/Configuration.cs | 10 +- Property/Models/Stateless/IProperty.cs | 51 +++ Property/Models/Stateless/Property.cs | 395 ++++++++++++++++++ Rename/Models/AppSettings.cs | 2 +- Rename/Models/Binder/AppSettings.cs | 2 +- Rename/Rename.cs | 90 ++-- Rename/appsettings.json | 31 -- Resize/Models/_C_Resize.cs | 2 +- Set-Created-Date/Set-Created-Date.csproj | 1 + Set-Created-Date/SetCreatedDate.cs | 80 ++-- Set-Created-Date/appsettings.json | 31 -- Shared/Models/Methods/IMetadata.cs | 8 + Shared/Models/Stateless/Methods/IDirectory.cs | 31 +- Shared/Models/Stateless/Methods/IProperty.cs | 41 -- Shared/Models/Stateless/Methods/Property.cs | 258 +----------- Shared/Models/Stateless/Methods/XDirectory.cs | 121 +++--- Tests/UnitTestResize.cs | 5 +- .../UnitTestFace.cs | 5 +- 60 files changed, 1118 insertions(+), 1455 deletions(-) create mode 100644 Property/Models/Stateless/IProperty.cs create mode 100644 Property/Models/Stateless/Property.cs create mode 100644 Shared/Models/Methods/IMetadata.cs diff --git a/.kanbn/index.md b/.kanbn/index.md index c653826..1241cda 100644 --- a/.kanbn/index.md +++ b/.kanbn/index.md @@ -29,15 +29,12 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g - [determine-if-location-container-collection-is-needed-in-get-faces](tasks/determine-if-location-container-collection-is-needed-in-get-faces.md) - [import-know-faces-into-db](tasks/import-know-faces-into-db.md) - [skip-metadata-load-after-first-each-day](tasks/skip-metadata-load-after-first-each-day.md) +- [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md) +- [find-incorrectly-mapped-faces](tasks/find-incorrectly-mapped-faces.md) +- [nef-support](tasks/nef-support.md) ## In Progress -- [find-incorrectly-mapped-faces](tasks/find-incorrectly-mapped-faces.md) -- [nef-support](tasks/nef-support.md) -- [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md) -- [merge-kristy-files](tasks/merge-kristy-files.md) -- [set-date-taken-when-missing](tasks/set-date-taken-when-missing.md) -- [rename-files-to-padded-number-string](tasks/rename-files-to-padded-number-string.md) ## Done @@ -45,3 +42,6 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g - [run-scan-originals](tasks/run-scan-originals.md) - [shrink-percent](tasks/shrink-percent.md) - [setup-photo-prism-again-in-wsl-docker](tasks/setup-photo-prism-again-in-wsl-docker.md) +- [set-date-taken-when-missing](tasks/set-date-taken-when-missing.md) +- [rename-files-to-padded-number-string](tasks/rename-files-to-padded-number-string.md) +- [merge-kristy-files](tasks/merge-kristy-files.md) diff --git a/.kanbn/tasks/find-incorrectly-mapped-faces.md b/.kanbn/tasks/find-incorrectly-mapped-faces.md index 6f8ff0e..41f2839 100644 --- a/.kanbn/tasks/find-incorrectly-mapped-faces.md +++ b/.kanbn/tasks/find-incorrectly-mapped-faces.md @@ -1,10 +1,10 @@ --- created: 2023-06-18T20:29:10.288Z -updated: 2023-07-08T21:21:04.820Z +updated: 2023-07-09T23:00:08.674Z assigned: "" progress: 0 tags: [] -status: "3-In Progress" +status: '3-In Progress' type: kanbn --- diff --git a/.kanbn/tasks/merge-kristy-files.md b/.kanbn/tasks/merge-kristy-files.md index a1a12d4..9671311 100644 --- a/.kanbn/tasks/merge-kristy-files.md +++ b/.kanbn/tasks/merge-kristy-files.md @@ -1,6 +1,6 @@ --- created: 2023-06-25T16:35:28.627Z -updated: 2023-07-08T21:44:14.665Z +updated: 2023-07-09T22:16:11.849Z assigned: "" progress: 0 tags: [] @@ -23,4 +23,6 @@ return new(result, (from l in results orderby l.FileHolder.DirectoryName?.EndsWi - [ ] Copy to each backup from question - [x] Rotate the .jpg only - [x] Use Rename console app to rename for storage +- [x] Set created date +- [ ] Verify - [ ] Move to production ... diff --git a/.kanbn/tasks/nef-support.md b/.kanbn/tasks/nef-support.md index 25b6e35..3cb1401 100644 --- a/.kanbn/tasks/nef-support.md +++ b/.kanbn/tasks/nef-support.md @@ -1,10 +1,10 @@ --- created: 2023-06-24T02:13:16.426Z -updated: 2023-07-08T21:21:06.222Z +updated: 2023-07-09T23:00:05.524Z assigned: "" progress: 0 tags: [] -status: "3-In Progress" +status: '3-In Progress' type: kanbn --- @@ -15,4 +15,4 @@ type: kanbn - [x] Convert to .tiff with Nikon Nx Studio - [x] Keep .nef files in 2-Images-B - [x] Convert .tiff to .jpg with Nikon Nx Studio at 100% -- [x] Use Rename console app to rename for storage \ No newline at end of file +- [x] Use Rename console app to rename for storage diff --git a/.kanbn/tasks/photoview-in-docker-for-a-viewer-only.md b/.kanbn/tasks/photoview-in-docker-for-a-viewer-only.md index d26bc5d..868c404 100644 --- a/.kanbn/tasks/photoview-in-docker-for-a-viewer-only.md +++ b/.kanbn/tasks/photoview-in-docker-for-a-viewer-only.md @@ -1,12 +1,13 @@ --- created: 2023-07-08T21:26:25.403Z -updated: 2023-07-08T21:26:25.399Z +updated: 2023-07-10T06:35:46.076Z assigned: "" progress: 0 tags: [] +type: note --- -# Photoview in docker for a viewer only +# Photoview in Docker for a Viewer Only ## Sub-Tasks diff --git a/.kanbn/tasks/rename-files-to-padded-number-string.md b/.kanbn/tasks/rename-files-to-padded-number-string.md index 55616ce..7083a88 100644 --- a/.kanbn/tasks/rename-files-to-padded-number-string.md +++ b/.kanbn/tasks/rename-files-to-padded-number-string.md @@ -1,17 +1,22 @@ --- created: 2023-07-08T21:25:25.925Z -updated: 2023-07-08T21:45:42.263Z +updated: 2023-07-10T05:03:00.856Z assigned: "" progress: 0 tags: [] started: 2023-07-08T21:45:42.263Z +type: note --- -# Rename files to padded number string +# Rename Files to Padded Number String ## Sub-tasks - [ ] ~~Go Back to Index for Sort~~ -- [ ] New file for index to to id -- [ ] Count backwards -- [ ] Maybe skip some for scan images \ No newline at end of file +- [ ] ~~New file for index to to id~~ +- [ ] ~~Count backwards~~ +- [ ] ~~Maybe skip some for scan images~~ +- [Set Date Taken When Missing](set-date-taken-when-missing.md) +- [x] Rename production with padding names starting with one directory +- [x] Need equivalent to NameWithoutExtensionIsIdFormat method +- [x] Verify nothing broke (run from resize original now ... ?) diff --git a/.kanbn/tasks/set-date-taken-when-missing.md b/.kanbn/tasks/set-date-taken-when-missing.md index 65fac1e..2d2f5c6 100644 --- a/.kanbn/tasks/set-date-taken-when-missing.md +++ b/.kanbn/tasks/set-date-taken-when-missing.md @@ -1,6 +1,6 @@ --- created: 2023-07-05T22:17:38.271Z -updated: 2023-07-08T21:47:12.461Z +updated: 2023-07-10T00:16:19.096Z status: 2-Todo type: kanbn started: 2023-07-08T21:47:12.461Z @@ -8,6 +8,15 @@ started: 2023-07-08T21:47:12.461Z # Set Date Taken When Missing +```c# +records = (from l in unordered orderby l.DateTime, l.FileHolder.Name.Length, l.FileHolder.Name select l).ToArray(); +return new(result, (from l in results orderby l.FileHolder.CreationTime, l.FileHolder.FullName.Length descending select l).ToArray()); +``` + ## Sub-tasks -- [ ] [ ] +- [x] Set just one directory with no original and re-run Instance to verify it doesn't break anything +- [x] Set just one directory with all original and re-run Instance to verify it doesn't break anything +- [?] Set just one directory with mixed original and re-run Instance to verify it doesn't break anything +- [x] Set all and re-run Instance to verify it doesn't break anything +- [ ] Review above lines diff --git a/.kanbn/tasks/use-eyes-to-find-orientation.md b/.kanbn/tasks/use-eyes-to-find-orientation.md index e03555d..c29d69c 100644 --- a/.kanbn/tasks/use-eyes-to-find-orientation.md +++ b/.kanbn/tasks/use-eyes-to-find-orientation.md @@ -1,10 +1,10 @@ --- created: 2023-06-23T13:56:11.956Z -updated: 2023-07-08T21:21:06.224Z +updated: 2023-07-09T23:00:03.100Z assigned: "" progress: 0 tags: [] -status: "3-In Progress" +status: '3-In Progress' type: kanbn --- diff --git a/Compare/appsettings.Development.json b/Compare/appsettings.Development.json index b5adec2..0a88493 100644 --- a/Compare/appsettings.Development.json +++ b/Compare/appsettings.Development.json @@ -88,7 +88,6 @@ "PopulatePropertyId": true, "PropertiesChangedForProperty": false, "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -120,36 +119,6 @@ ".tif", ".TIF" ], - "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", - ".tif", - ".TIF" - ], "VerifyToSeason": [ ". 2000", ". 2001", diff --git a/Compare/appsettings.json b/Compare/appsettings.json index 2e2c827..bddb6d5 100644 --- a/Compare/appsettings.json +++ b/Compare/appsettings.json @@ -122,34 +122,6 @@ ".tif", ".TIF" ], - "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", diff --git a/Copy-Distinct/Models/AppSettings.cs b/Copy-Distinct/Models/AppSettings.cs index 3ed64e0..dfbf7c5 100644 --- a/Copy-Distinct/Models/AppSettings.cs +++ b/Copy-Distinct/Models/AppSettings.cs @@ -24,4 +24,4 @@ public record AppSettings(string Company, [JsonSerializable(typeof(AppSettings))] internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext { -} +} \ No newline at end of file diff --git a/Copy-Distinct/Models/Binder/AppSettings.cs b/Copy-Distinct/Models/Binder/AppSettings.cs index d445599..5707d0c 100644 --- a/Copy-Distinct/Models/Binder/AppSettings.cs +++ b/Copy-Distinct/Models/Binder/AppSettings.cs @@ -66,4 +66,4 @@ public class AppSettings [JsonSerializable(typeof(AppSettings))] internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext { -} +} \ No newline at end of file diff --git a/Copy-Distinct/appsettings.json b/Copy-Distinct/appsettings.json index 0d94920..c8ca0f8 100644 --- a/Copy-Distinct/appsettings.json +++ b/Copy-Distinct/appsettings.json @@ -70,7 +70,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -94,36 +93,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Date-Group/Date-Group.csproj b/Date-Group/Date-Group.csproj index a64e4c7..b091c3c 100644 --- a/Date-Group/Date-Group.csproj +++ b/Date-Group/Date-Group.csproj @@ -51,6 +51,7 @@ + diff --git a/Date-Group/DateGroup.cs b/Date-Group/DateGroup.cs index 0b36461..7c8d3b3 100644 --- a/Date-Group/DateGroup.cs +++ b/Date-Group/DateGroup.cs @@ -45,6 +45,7 @@ public class DateGroup if (!_IsEnvironment.Development) throw new Exception("This program only allows development environments!"); long ticks = DateTime.Now.Ticks; + Metadata.Models.B_Metadata metadata = new(propertyConfiguration); string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); foreach (string dbFile in dbFiles) File.Delete(dbFile); @@ -65,7 +66,7 @@ public class DateGroup throw new Exception(); if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers)) { - propertyLogic.SavePropertyParallelWork(ticks, t, containers); + propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(A_Property.SavePropertyParallelWork)); if (propertyLogic.ExceptionsDirectories.Any()) diff --git a/Date-Group/appsettings.json b/Date-Group/appsettings.json index fe3cda4..4629be4 100644 --- a/Date-Group/appsettings.json +++ b/Date-Group/appsettings.json @@ -69,7 +69,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/phares/Pictures", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -95,36 +94,6 @@ ".tif", ".TIF" ], - "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", - ".tif", - ".TIF" - ], "VerifyToSeason": [ ". 2000", ". 2001", diff --git a/Delete-By-Distinct/appsettings.json b/Delete-By-Distinct/appsettings.json index 9969fac..c0bf764 100644 --- a/Delete-By-Distinct/appsettings.json +++ b/Delete-By-Distinct/appsettings.json @@ -71,7 +71,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -95,36 +94,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Delete-By-Relative/appsettings.json b/Delete-By-Relative/appsettings.json index f6ddcd6..a9a0ba6 100644 --- a/Delete-By-Relative/appsettings.json +++ b/Delete-By-Relative/appsettings.json @@ -66,7 +66,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -90,36 +89,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Drag-Drop-Set-Property-Item/Drag-Drop-Set-Property-Item.csproj b/Drag-Drop-Set-Property-Item/Drag-Drop-Set-Property-Item.csproj index 43727a5..f8b27be 100644 --- a/Drag-Drop-Set-Property-Item/Drag-Drop-Set-Property-Item.csproj +++ b/Drag-Drop-Set-Property-Item/Drag-Drop-Set-Property-Item.csproj @@ -37,6 +37,7 @@ + diff --git a/Drag-Drop-Set-Property-Item/DragDropSetPropertyItem.cs b/Drag-Drop-Set-Property-Item/DragDropSetPropertyItem.cs index 219850e..4e15c64 100644 --- a/Drag-Drop-Set-Property-Item/DragDropSetPropertyItem.cs +++ b/Drag-Drop-Set-Property-Item/DragDropSetPropertyItem.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Text; using System.Text.Json; using View_by_Distance.Drag.Drop.Set.Item.Models; +using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Shared.Models.Stateless.Methods; @@ -15,6 +16,14 @@ namespace View_by_Distance.Drag.Drop.Set.Item; public partial class DragDropSetPropertyItem : Form { + private record Record(FileHolder FileHolder, + bool IsIgnoreExtension, + bool IsValidImageFormatExtension, + int Id, + DateTime? DateTimeOriginal, + short? PropertyItemType, + string? Value); + private readonly ILogger _Logger; private readonly TextBox _PathTextBox; private readonly TextBox _JsonTextBox; @@ -23,6 +32,7 @@ public partial class DragDropSetPropertyItem : Form private readonly ProgressBar _ProgressBar; private readonly string _WorkingDirectory; private readonly IsEnvironment _IsEnvironment; + private readonly Property.Models.Configuration _PropertyConfiguration; public DragDropSetPropertyItem() { @@ -50,6 +60,9 @@ public partial class DragDropSetPropertyItem : Form _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext(); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); + _PropertyConfiguration = propertyConfiguration; + propertyConfiguration.Update(); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; @@ -102,18 +115,28 @@ public partial class DragDropSetPropertyItem : Form _JsonTextBox.Text = message; } - private static List<(string, int, DateTime?, short?, string?)> GetCollection(ASCIIEncoding asciiEncoding, int tagId, List files) + private List GetRecords(ASCIIEncoding asciiEncoding, int tagId, List files) { - List<(string, int, DateTime?, short?, string?)> results = new(); + List results = new(); + int? id; string? value; + string? message; + FileHolder fileHolder; + bool isIgnoreExtension; + DateTime? dateTimeOriginal; PropertyItem? propertyItem; - Shared.Models.Property property; + bool isValidImageFormatExtension; foreach (string file in files) { - property = Property.Models.A_Property.GetImageProperty(file); - if (property.Id is null) + fileHolder = new(file); + isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); + isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); + (dateTimeOriginal, _, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + if (message is not null) + throw new Exception(message); + if (id is null) continue; - using Image image = Image.FromFile(file); + using Image image = Image.FromFile(fileHolder.FullName); if (!image.PropertyIdList.Contains(tagId)) (propertyItem, value) = (null, null); else @@ -131,36 +154,37 @@ public partial class DragDropSetPropertyItem : Form value = null; } } - results.Add((file, property.Id.Value, property.DateTimeOriginal, propertyItem?.Type, value)); + results.Add(new(fileHolder, isIgnoreExtension, isValidImageFormatExtension, id.Value, dateTimeOriginal, propertyItem?.Type, value)); } if (files.Count != results.Count) throw new NotSupportedException(); return results; } - private void SetPropertyItem(string setTo, int tagId, short type, ConstructorInfo constructorInfo, List<(string, int, DateTime?, short?, string?)> collection) + private void SetPropertyItem(string setTo, int tagId, short type, ASCIIEncoding asciiEncoding, ConstructorInfo constructorInfo, List records) { + int? id; Bitmap bitmap; + string? message; string checkFile; PropertyItem? propertyItem; - Shared.Models.Property property; - foreach ((string file, int id, DateTime? dateTimeOriginal, short? propertyItemType, string? value) in collection) + foreach (Record record in records) { - if (propertyItemType is not null && propertyItemType.Value != type) + if (record.PropertyItemType is not null && record.PropertyItemType.Value != type) throw new NotSupportedException(); - if ((dateTimeOriginal is null || !string.IsNullOrEmpty(value) || value == setTo) && !_AppSettings.IgnoreRulesKeyWords.Contains(setTo)) + if ((record.DateTimeOriginal is null || !string.IsNullOrEmpty(record.Value) || record.Value == setTo) && !_AppSettings.IgnoreRulesKeyWords.Contains(setTo)) continue; - checkFile = $"{file}.exif"; - propertyItem = IProperty.GetPropertyItem(constructorInfo, tagId, type, setTo); - bitmap = new(file); + checkFile = $"{record.FileHolder.FullName}.exif"; + propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, tagId, type, setTo); + bitmap = new(record.FileHolder.FullName); bitmap.SetPropertyItem(propertyItem); bitmap.Save(checkFile); bitmap.Dispose(); - property = Property.Models.A_Property.GetImageProperty(checkFile); - if (property.Id is null || property.Id.Value != id) + (_, _, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, record.FileHolder, record.IsIgnoreExtension, record.IsValidImageFormatExtension, asciiEncoding); + if (id is null || id.Value != record.Id) throw new NotSupportedException(); - File.Delete(file); - File.Move(checkFile, file); + File.Delete(record.FileHolder.FullName); + File.Move(checkFile, record.FileHolder.FullName); } } @@ -170,11 +194,11 @@ public partial class DragDropSetPropertyItem : Form ASCIIEncoding asciiEncoding = new(); int xpKeywords = (int)IExif.Tags.XPKeywords; ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null) ?? throw new Exception(); - List<(string, int, DateTime?, short?, string?)> collection = GetCollection(asciiEncoding, xpKeywords, files); - if (!collection.Any()) + List records = GetRecords(asciiEncoding, xpKeywords, files); + if (!records.Any()) SetMessage("No data"); else - SetPropertyItem(setTo, xpKeywords, type, constructorInfo, collection); + SetPropertyItem(setTo, xpKeywords, type, asciiEncoding, constructorInfo, records); } private void SetPropertyItem(string[] paths, string setTo) diff --git a/Drag-Drop-Set-Property-Item/appsettings.json b/Drag-Drop-Set-Property-Item/appsettings.json index 4ad5bd3..e64fd3b 100644 --- a/Drag-Drop-Set-Property-Item/appsettings.json +++ b/Drag-Drop-Set-Property-Item/appsettings.json @@ -50,5 +50,48 @@ "ValidKeyWords": [ "Review" ], - "WorkingDirectoryName": "PharesApps" + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "DateGroup": "dd514b88", + "DiffPropertyDirectory": "", + "FileNameDirectorySeparator": ".Z.", + "ForcePropertyLastWriteTimeToCreationTime": false, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, + "OutputExtension": ".jpg", + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PropertiesChangedForProperty": false, + "ResultAllInOne": "_ _ _", + "ResultAllInOneSubdirectoryLength": 2, + "ResultCollection": "[]", + "ResultContent": "()", + "ResultSingleton": "{}", + "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", + "IgnoreExtensions": [ + ".gif", + ".GIF", + ".nef", + ".NEF", + ".pdf", + ".PDF" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF", + ".tif", + ".TIF" + ] + } + } } \ No newline at end of file diff --git a/Duplicate-Search/appsettings.json b/Duplicate-Search/appsettings.json index 1e12fb4..b41cc57 100644 --- a/Duplicate-Search/appsettings.json +++ b/Duplicate-Search/appsettings.json @@ -68,7 +68,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -92,36 +91,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Face/Models/_D_Face.cs b/Face/Models/_D_Face.cs index 4e2ca01..a12d951 100644 --- a/Face/Models/_D_Face.cs +++ b/Face/Models/_D_Face.cs @@ -190,11 +190,11 @@ public class D_Face { using (graphics = Graphics.FromImage(bitmap)) graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); - propertyItem = Shared.Models.Stateless.Methods.IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson); + propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson); bitmap.SetPropertyItem(propertyItem); - propertyItem = Shared.Models.Stateless.Methods.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson); + propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson); bitmap.SetPropertyItem(propertyItem); - propertyItem = Shared.Models.Stateless.Methods.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson); + propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson); bitmap.SetPropertyItem(propertyItem); bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters); } diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 67f8264..cf4b4f0 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -16,6 +16,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 View_by_Distance.Shared.Models.Stateless.Methods; using WindowsShortcutFactory; namespace View_by_Distance.Instance; @@ -126,9 +127,9 @@ public partial class DlibDotNet string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People)); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception(); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, "{}")); - (_GenealogicalDataCommunicationHeaderLines, Dictionary> individuals, _GenealogicalDataCommunicationFooterLines) = Shared.Models.Stateless.Methods.IGenealogicalDataCommunication.GetIndividuals(configuration.GenealogicalDataCommunicationFile, requireNickName: true); - _PersonContainers = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.MappingDefaultName, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + (_GenealogicalDataCommunicationHeaderLines, Dictionary> individuals, _GenealogicalDataCommunicationFooterLines) = IGenealogicalDataCommunication.GetIndividuals(configuration.GenealogicalDataCommunicationFile, requireNickName: true); + _PersonContainers = IPersonContainer.GetPersonContainers(storage, configuration.MappingDefaultName, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals); VerifyPersonContainersDisplayDirectoryAllFiles(); } { @@ -321,9 +322,9 @@ public partial class DlibDotNet eyeα = α is null ? null : (int)Math.Round(Math.Abs(α.Value)); } confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_Configuration.FaceConfidencePercent, _Configuration.RangeFaceConfidence, face.Location.Confidence); - faceAreaPermyriad = Shared.Models.Stateless.Methods.IMapping.GetAreaPermyriad(_Configuration.FaceAreaPermyriad, face.Location, face.OutputResolution); + faceAreaPermyriad = IMapping.GetAreaPermyriad(_Configuration.FaceAreaPermyriad, face.Location, face.OutputResolution); wholePercentRectangle = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); + deterministicHashCodeKey = IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, eyeα, eyeReview, wholePercentRectangle); inSkipCollection = mapLogic.InSkipCollection(item.Property.Id.Value, mappingFromLocation); mappingFromFilter = new(isFocusModel, isFocusRelativePath, isIgnoreRelativePath, inSkipCollection); @@ -356,7 +357,7 @@ public partial class DlibDotNet else { wholePercentRectangle = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(Shared.Models.Stateless.ILocation.Digits); - deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, Shared.Models.Stateless.ILocation.Digits); + deterministicHashCodeKey = IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, Shared.Models.Stateless.ILocation.Digits); mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, eyeα, eyeReview, wholePercentRectangle); inSkipCollection = mapLogic.InSkipCollection(item.Property.Id.Value, mappingFromLocation); mappingFromFilter = new(isFocusModel, isFocusRelativePath, isIgnoreRelativePath, inSkipCollection); @@ -413,12 +414,13 @@ public partial class DlibDotNet List parseExceptions = new(); List> subFileTuples = new(); List> metadataCollection; + string[] changesFrom = new string[] { nameof(A_Property) }; FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber); if (item.Property is null || item.Property.Id is null || item.Any()) { LogItemPropertyIsNull(item); int? propertyHashCode = item.Property?.GetHashCode(); - property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); + property = propertyLogic.GetProperty(metadata, item, subFileTuples, parseExceptions); item.Update(property); if (propertyHashCode is null) { @@ -438,9 +440,13 @@ public partial class DlibDotNet subFileTuples.Add(new Tuple(nameof(A_Property), item.SourceDirectoryFileHolder.LastWriteTime.Value)); else subFileTuples.Add(new Tuple(nameof(A_Property), new FileInfo(item.SourceDirectoryFileHolder.FullName).LastWriteTime)); + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); bool nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(item.ImageFileHolder); + bool nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(item.ImageFileHolder, sortOrderOnlyLengthIndex); if (nameWithoutExtensionIsIdFormat && item.ImageFileHolder.NameWithoutExtension != item.Property.Id.ToString()) LogNameWithoutExtensionIsIdFormatBut(item); + if (nameWithoutExtensionIsPaddedIdFormat && item.ImageFileHolder.NameWithoutExtension.EndsWith(item.Property.Id.Value.ToString()[1..])) + LogNameWithoutExtensionIsIdFormatBut(item); if (_BlurHasher is not null && resizedFileHolder.Exists && item.Property.Width is not null && item.Property.Width.Value > 4 && _Configuration.SaveBlurHashForOutputResolutions.Contains(outputResolution)) { string? file = _BlurHasher.GetFile(resizedFileHolder); @@ -451,8 +457,8 @@ public partial class DlibDotNet if (property is null || item.Property is null) throw new NullReferenceException(nameof(property)); item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder); - MappingFromItem mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); - (int metadataGroups, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); + MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); + (int metadataGroups, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, changesFrom, mappingFromItem); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(B_Metadata.GetMetadataCollection)); Dictionary outputResolutionToResize = _Resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); @@ -794,10 +800,10 @@ public partial class DlibDotNet private void MapLogic(long ticks, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, Dictionary> personKeyToIds, List distinctFilteredFaces, Mapping[] distinctFilteredMappingCollection, int totalNotMapped) { - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); - string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, "()"); + string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); + string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, "[()]"); - string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.PropertyConfiguration.ResultAllInOne); + string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultCollection, _Configuration.PropertyConfiguration.ResultAllInOne); if (distinctFilteredMappingCollection.Any()) { Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, ticks); @@ -871,24 +877,29 @@ public partial class DlibDotNet private static void LookForAbandoned(List distinctFilteredIds, string directory, string directoryName) { string fileNameWithoutExtension; + bool nameWithoutExtensionIsIdFormat; List renameCollection = new(); + bool nameWithoutExtensionIsPaddedIdFormat; + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray(); string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); foreach (string file in files) { fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file))); - if (distinctFilteredIdsValues.Contains(fileNameWithoutExtension)) + nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); + nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileNameWithoutExtension, sortOrderOnlyLengthIndex); + if (!nameWithoutExtensionIsIdFormat && !nameWithoutExtensionIsPaddedIdFormat) continue; - if (!Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileNameWithoutExtension)) + if (distinctFilteredIdsValues.Contains(fileNameWithoutExtension)) continue; renameCollection.Add(file); } if (renameCollection.Any()) { if (directoryName.Length == 2) - Shared.Models.Stateless.Methods.IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[0]}abd{directoryName[^1]}"); + IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[0]}abd{directoryName[^1]}"); else if (directoryName.Length == 4) - Shared.Models.Stateless.Methods.IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[..2]}abd{directoryName[^2..]}"); + IDirectory.MoveFiles(renameCollection, directoryName, $"{directoryName[..2]}abd{directoryName[^2..]}"); else throw new NotSupportedException(); } @@ -906,7 +917,7 @@ public partial class DlibDotNet } } - private static void LookForAbandoned(ReadOnlyDictionary>> idToLocationContainers, List distinctFilteredIds) + private void LookForAbandoned(ReadOnlyDictionary>> idToLocationContainers, List distinctFilteredIds) { List renameCollection = new(); foreach (KeyValuePair>> keyValuePair in idToLocationContainers) @@ -921,7 +932,7 @@ public partial class DlibDotNet } } if (renameCollection.Any()) - Shared.Models.Stateless.Methods.IDirectory.MoveFiles(renameCollection, "()", "(abd)"); + IDirectory.MoveFiles(renameCollection, _Configuration.PropertyConfiguration.ResultContent, "(abd)"); } private void LookForAbandoned(string bResultsFullGroupDirectory, Container[] containers, ReadOnlyDictionary>> idToLocationContainers) @@ -994,7 +1005,7 @@ public partial class DlibDotNet { if (item.Property?.Id is null || item.ResizedFileHolder is null) continue; - mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder); + mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder); if (distinctItems) { if (distinct.Contains(item.Property.Id.Value)) @@ -1137,6 +1148,7 @@ public partial class DlibDotNet private void Search(long ticks, string argZero, string propertyRoot) { int t; + int count; string message; Container[] containers; A_Property propertyLogic; @@ -1151,26 +1163,53 @@ public partial class DlibDotNet string fPhotoPrismContentDirectory; const string fileSearchFilter = "*"; string fPhotoPrismSingletonDirectory; + bool filesCollectionCountIsOne = false; + List? filesCollection = null; const string directorySearchFilter = "*"; Dictionary> personKeyToIds; + bool eLastWriteTimeTimeSpanIsMoreThen = false; Dictionary> fileNameToCollection; (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); - a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); - eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), "()"); - fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "()"); - fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), "{}"); - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); - List filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_Configuration.PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter); - int count = filesCollection.Select(l => l.Length).Sum(); - if (filesCollection.Count == 1) + eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); + TimeSpan eLastWriteTimeTimeSpan = new(ticks - new DirectoryInfo(eDistanceContentDirectory).LastWriteTime.Ticks); + foreach (string outputResolution in _Configuration.OutputResolutions) { + if (outputResolution.Any(l => char.IsNumber(l))) + continue; + eLastWriteTimeTimeSpanIsMoreThen = true; + if (eLastWriteTimeTimeSpan.TotalDays < 1) + break; + ProgressBar progressBar; + (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); + IReadOnlyDictionary fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, new string[] { _Configuration.PropertyConfiguration.ResultContent }); + filesCollection = IDirectory.GetFilesCollection(_Configuration.PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter); + message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + count = filesCollection.Select(l => l.Length).Sum(); + filesCollectionCountIsOne = filesCollection.Count == 1; + progressBar = new(count, message, options); + (string[] distinctDirectories, List<(FileHolder, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filesCollection, fileGroups[_Configuration.PropertyConfiguration.ResultContent], () => progressBar.Tick()); + progressBar.Dispose(); + message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + progressBar = new(count, message, options); + _ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick()); + progressBar.Dispose(); + break; + } + a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); + fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultSingleton); + string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton); + propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); + if (filesCollectionCountIsOne) + { + if (filesCollection is null) + throw new NullReferenceException(nameof(filesCollection)); string resultsGroupDirectory; a2PeopleContentDirectory = null; - eDistanceContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "()"); - fPhotoPrismContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "()"); - fPhotoPrismSingletonDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", "{}"); + eDistanceContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismContentDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultContent); + fPhotoPrismSingletonDirectory = Path.Combine($"{Path.GetPathRoot(argZero)}", _Configuration.PropertyConfiguration.ResultSingleton); for (int i = 1; i < 10; i++) { resultsGroupDirectory = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, string.Empty, create: true); @@ -1182,31 +1221,25 @@ public partial class DlibDotNet propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); } - TimeSpan eLastWriteTimeTimeSpan = new(ticks - new DirectoryInfo(eDistanceContentDirectory).LastWriteTime.Ticks); - foreach (string outputResolution in _Configuration.OutputResolutions) + if (eLastWriteTimeTimeSpanIsMoreThen) { - if (outputResolution.Any(l => char.IsNumber(l))) - continue; - if (eLastWriteTimeTimeSpan.TotalDays < 1) + foreach (string outputResolution in _Configuration.OutputResolutions) + { + if (outputResolution.Any(l => char.IsNumber(l))) + continue; + (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); + filesCollection = IDirectory.GetFilesCollection(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultAllInOne), directorySearchFilter, fileSearchFilter); + count = filesCollection.Select(l => l.Length).Sum(); break; - ProgressBar progressBar; - (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); - IReadOnlyDictionary fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, new string[] { _Configuration.PropertyConfiguration.ResultContent }); - message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - progressBar = new(count, message, options); - (string[] distinctDirectories, List<(FileHolder, string)> toDoCollection) = Shared.Models.Stateless.Methods.IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, copyDuplicates: false, filesCollection, fileGroups[_Configuration.PropertyConfiguration.ResultContent], () => progressBar.Tick()); - progressBar.Dispose(); - message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - progressBar = new(count, message, options); - _ = Shared.Models.Stateless.Methods.IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick()); - progressBar.Dispose(); - break; + } } + if (filesCollection is null) + throw new NullReferenceException(nameof(filesCollection)); message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; using (ProgressBar progressBar = new(2, message, options)) { progressBar.Tick(); - string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}"); + string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton); if (!Directory.Exists(aPropertySingletonDirectory)) _ = Directory.CreateDirectory(aPropertySingletonDirectory); (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollection); @@ -1215,11 +1248,11 @@ public partial class DlibDotNet fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, new(_PersonContainers), ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); - _PersonContainers.AddRange(Shared.Models.Stateless.Methods.IPersonContainer.GetNonSpecificPeopleCollection(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonCharacters.ToArray(), _PersonContainers, ticks)); + _PersonContainers.AddRange(IPersonContainer.GetNonSpecificPeopleCollection(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonCharacters.ToArray(), _PersonContainers, ticks)); containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); personKeyToIds = mapLogic.GetPersonKeyToIds(); if (!string.IsNullOrEmpty(_Configuration.GenealogicalDataCommunicationFile) && !string.IsNullOrEmpty(a2PeopleContentDirectory) && _GenealogicalDataCommunicationHeaderLines is not null && _GenealogicalDataCommunicationFooterLines is not null && _GenealogicalDataCommunicationHeaderLines.Any() && _GenealogicalDataCommunicationFooterLines.Any()) - Shared.Models.Stateless.Methods.IGenealogicalDataCommunication.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GenealogicalDataCommunicationHeaderLines, _GenealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); + IGenealogicalDataCommunication.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GenealogicalDataCommunicationHeaderLines, _GenealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); ReadOnlyDictionary>> idToLocationContainers = mapLogic.GetIdToLocationContainers(); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, idToLocationContainers, mapLogic); if (_Configuration.LookForAbandoned) @@ -1257,11 +1290,11 @@ public partial class DlibDotNet continue; if (!_IsEnvironment.Development) { - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, "{}")); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, "{}")); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, "{}")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, "[]")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultCollection)); } } } diff --git a/Instance/Models/AppSettings.cs b/Instance/Models/AppSettings.cs index 9962a71..c39cbfd 100644 --- a/Instance/Models/AppSettings.cs +++ b/Instance/Models/AppSettings.cs @@ -3,25 +3,21 @@ using System.Text.Json.Serialization; namespace View_by_Distance.Instance.Models; -public class AppSettings +public record AppSettings(string Company, + int MaxDegreeOfParallelism, + string WorkingDirectoryName) { - public string Company { init; get; } - public int MaxDegreeOfParallelism { init; get; } - public string WorkingDirectoryName { init; get; } - - [JsonConstructor] - public AppSettings(string company, int maxDegreeOfParallelism, string workingDirectoryName) - { - Company = company; - MaxDegreeOfParallelism = maxDegreeOfParallelism; - WorkingDirectoryName = workingDirectoryName; - } - public override string ToString() { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings); return result; } +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(AppSettings))] +internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Instance/Models/Binder/AppSettings.cs b/Instance/Models/Binder/AppSettings.cs index 00338af..7b1c3dd 100644 --- a/Instance/Models/Binder/AppSettings.cs +++ b/Instance/Models/Binder/AppSettings.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using System.Text.Json; +using System.Text.Json.Serialization; namespace View_by_Distance.Instance.Models.Binder; @@ -16,7 +17,7 @@ public class AppSettings public override string ToString() { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + string result = JsonSerializer.Serialize(this, BinderAppSettingsSourceGenerationContext.Default.AppSettings); return result; } @@ -36,9 +37,17 @@ public class AppSettings public static Models.AppSettings Get(IConfigurationRoot configurationRoot) { Models.AppSettings result; +#pragma warning disable IL3050, IL2026 AppSettings? appSettings = configurationRoot.Get(); +#pragma warning restore IL3050, IL2026 result = Get(appSettings); return result; } +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(AppSettings))] +internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 30d16fa..a39f886 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -121,7 +121,6 @@ "SortingMinimumToUseSigma": 10, "TestDistanceResults": true, "UseFilterTries": 0, - "WriteBitmapDataBytes": false, "CopyFacesAndSaveFaceLandmarkForOutputResolutions": [], "IgnoreExtensions": [ ".gif", @@ -187,36 +186,6 @@ ".tif", ".TIF" ], - "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", - ".tif", - ".TIF" - ], "ValidResolutions": [ "Original", "176 x 176", diff --git a/Metadata-Query/appsettings.json b/Metadata-Query/appsettings.json index c5f1182..086a176 100644 --- a/Metadata-Query/appsettings.json +++ b/Metadata-Query/appsettings.json @@ -67,7 +67,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -91,36 +90,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Metadata/Metadata.csproj b/Metadata/Metadata.csproj index f44689e..6bdd637 100644 --- a/Metadata/Metadata.csproj +++ b/Metadata/Metadata.csproj @@ -39,7 +39,7 @@ - + \ No newline at end of file diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 5e74fed..4794290 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -1,8 +1,12 @@ +using MetadataExtractor; +using MetadataExtractor.Formats.Avi; +using MetadataExtractor.Formats.Exif; +using MetadataExtractor.Formats.QuickTime; using System.Diagnostics; using System.Text.Json; using View_by_Distance.Metadata.Models.Stateless; -using View_by_Distance.Property.Models; -using View_by_Distance.Property.Models.Stateless; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; @@ -11,7 +15,7 @@ namespace View_by_Distance.Metadata.Models; /// // Dictionary>> /// -public class B_Metadata +public class B_Metadata : IMetadata { private readonly Serilog.ILogger? _Log; @@ -21,6 +25,16 @@ public class B_Metadata private readonly IReadOnlyDictionary _FileGroups; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + public B_Metadata(IPropertyConfiguration propertyConfiguration) + { + _PropertiesChangedForMetadata = false; + _Log = Serilog.Log.ForContext(); + _PropertyConfiguration = propertyConfiguration; + _ForceMetadataLastWriteTimeToCreationTime = false; + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, new string[] { propertyConfiguration.ResultSingleton }); + } + public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory) { _Log = Serilog.Log.ForContext(); @@ -49,12 +63,12 @@ public class B_Metadata List tagNames = new(); int type = (int)IExif.Tags.Orientation; string key = nameof(IExif.Tags.Orientation); - IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(subFile); + IReadOnlyList directories = ImageMetadataReader.ReadMetadata(subFile); foreach (MetadataExtractor.Directory directory in directories) { if (!results.ContainsKey(directory.Name)) results.Add(directory.Name, new()); - foreach (MetadataExtractor.Tag tag in directory.Tags) + foreach (Tag tag in directory.Tags) { tagNames.Add(tag.Name); if (string.IsNullOrEmpty(tag.Description)) @@ -80,11 +94,10 @@ public class B_Metadata return results; } - public (int, List>) GetMetadataCollection(List> subFileTuples, List parseExceptions, Shared.Models.MappingFromItem mappingFromItem) + public (int, List>) GetMetadataCollection(List> subFileTuples, List parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem) { List> results = new(); string json = string.Empty; - string[] changesFrom = new string[] { nameof(A_Property) }; Dictionary>>? dictionary; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration.ResultAllInOneSubdirectoryLength, mappingFromItem.ImageFileHolder.Name); @@ -149,4 +162,104 @@ public class B_Metadata return new(dictionary.Count, results); } + (DateTime?, DateTime?[]) IMetadata.GetDateTimes(FileHolder fileHolder, IReadOnlyList directories) + { + List results = new(); + DateTime? result = null; + DateTime? dateTime; + DateTime checkDateTime; + string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat(); + ExifDirectoryBase? exifDirectoryBase = directories.OfType().FirstOrDefault(); + results.Add(fileHolder.CreationTime); + results.Add(fileHolder.LastWriteTime); + if (exifDirectoryBase is not null) + { + if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTime, out checkDateTime)) + results.Add(checkDateTime); + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTime)); + if (dateTime is not null) + results.Add(dateTime.Value); + } + if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeDigitized, out checkDateTime)) + results.Add(checkDateTime); + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeDigitized)); + if (dateTime is not null) + results.Add(dateTime.Value); + } + if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out checkDateTime)) + { + result ??= checkDateTime; + results.Add(checkDateTime); + } + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeOriginal)); + if (dateTime is not null) + { + result ??= dateTime.Value; + results.Add(dateTime.Value); + } + } + } + AviDirectory? aviDirectory = directories.OfType().FirstOrDefault(); + if (aviDirectory is not null) + { + if (aviDirectory.TryGetDateTime(AviDirectory.TagDateTimeOriginal, out checkDateTime)) + { + result ??= checkDateTime; + results.Add(checkDateTime); + } + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(AviDirectory.TagDateTimeOriginal)); + if (dateTime is not null) + { + result ??= dateTime.Value; + results.Add(dateTime.Value); + } + } + } + QuickTimeMovieHeaderDirectory? quickTimeMovieHeaderDirectory = directories.OfType().FirstOrDefault(); + if (quickTimeMovieHeaderDirectory is not null) + { + if (quickTimeMovieHeaderDirectory.TryGetDateTime(QuickTimeMovieHeaderDirectory.TagCreated, out checkDateTime)) + { + result ??= checkDateTime; + results.Add(checkDateTime); + } + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(QuickTimeMovieHeaderDirectory.TagCreated)); + if (dateTime is not null) + { + result ??= dateTime.Value; + results.Add(dateTime.Value); + } + } + } + QuickTimeTrackHeaderDirectory? quickTimeTrackHeaderDirectory = directories.OfType().FirstOrDefault(); + if (quickTimeTrackHeaderDirectory is not null) + { + if (quickTimeTrackHeaderDirectory.TryGetDateTime(QuickTimeTrackHeaderDirectory.TagCreated, out checkDateTime)) + { + result ??= checkDateTime; + results.Add(checkDateTime); + } + else + { + dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(QuickTimeTrackHeaderDirectory.TagCreated)); + if (dateTime is not null) + { + result ??= dateTime.Value; + results.Add(dateTime.Value); + } + } + } + return new(result, results.ToArray()); + } + } \ No newline at end of file diff --git a/Metadata/Models/Stateless/Methods/IMetadata.cs b/Metadata/Models/Stateless/Methods/IMetadata.cs index 77b3019..c521d23 100644 --- a/Metadata/Models/Stateless/Methods/IMetadata.cs +++ b/Metadata/Models/Stateless/Methods/IMetadata.cs @@ -3,11 +3,6 @@ namespace View_by_Distance.Metadata.Models.Stateless.Methods; public interface IMetadata { - (DateTime?, DateTime?[]) TestStatic_GetDateTimes(Shared.Models.FileHolder fileHolder, IReadOnlyList directories) => - GetDateTimes(fileHolder, directories); - static (DateTime?, DateTime?[]) GetDateTimes(Shared.Models.FileHolder fileHolder, IReadOnlyList directories) => - Metadata.GetDateTimes(fileHolder, directories); - string? TestStatic_GetModel(IReadOnlyList directories) => GetModel(directories); static string? GetModel(IReadOnlyList directories) => diff --git a/Metadata/Models/Stateless/Methods/Metadata.cs b/Metadata/Models/Stateless/Methods/Metadata.cs index 02288bf..23416fe 100644 --- a/Metadata/Models/Stateless/Methods/Metadata.cs +++ b/Metadata/Models/Stateless/Methods/Metadata.cs @@ -1,7 +1,5 @@ using MetadataExtractor; -using MetadataExtractor.Formats.Avi; using MetadataExtractor.Formats.Exif; -using MetadataExtractor.Formats.QuickTime; using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Metadata.Models.Stateless.Methods; @@ -53,106 +51,6 @@ internal class Metadata return result; } - internal static (DateTime?, DateTime?[]) GetDateTimes(Shared.Models.FileHolder fileHolder, IReadOnlyList directories) - { - List results = new(); - DateTime? result = null; - DateTime? dateTime; - DateTime checkDateTime; - string dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); - ExifDirectoryBase? exifDirectoryBase = directories.OfType().FirstOrDefault(); - results.Add(fileHolder.CreationTime); - results.Add(fileHolder.LastWriteTime); - if (exifDirectoryBase is not null) - { - if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTime, out checkDateTime)) - results.Add(checkDateTime); - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTime)); - if (dateTime is not null) - results.Add(dateTime.Value); - } - if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeDigitized, out checkDateTime)) - results.Add(checkDateTime); - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeDigitized)); - if (dateTime is not null) - results.Add(dateTime.Value); - } - if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out checkDateTime)) - { - result ??= checkDateTime; - results.Add(checkDateTime); - } - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeOriginal)); - if (dateTime is not null) - { - result ??= dateTime.Value; - results.Add(dateTime.Value); - } - } - } - AviDirectory? aviDirectory = directories.OfType().FirstOrDefault(); - if (aviDirectory is not null) - { - if (aviDirectory.TryGetDateTime(AviDirectory.TagDateTimeOriginal, out checkDateTime)) - { - result ??= checkDateTime; - results.Add(checkDateTime); - } - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(AviDirectory.TagDateTimeOriginal)); - if (dateTime is not null) - { - result ??= dateTime.Value; - results.Add(dateTime.Value); - } - } - } - QuickTimeMovieHeaderDirectory? quickTimeMovieHeaderDirectory = directories.OfType().FirstOrDefault(); - if (quickTimeMovieHeaderDirectory is not null) - { - if (quickTimeMovieHeaderDirectory.TryGetDateTime(QuickTimeMovieHeaderDirectory.TagCreated, out checkDateTime)) - { - result ??= checkDateTime; - results.Add(checkDateTime); - } - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(QuickTimeMovieHeaderDirectory.TagCreated)); - if (dateTime is not null) - { - result ??= dateTime.Value; - results.Add(dateTime.Value); - } - } - } - QuickTimeTrackHeaderDirectory? quickTimeTrackHeaderDirectory = directories.OfType().FirstOrDefault(); - if (quickTimeTrackHeaderDirectory is not null) - { - if (quickTimeTrackHeaderDirectory.TryGetDateTime(QuickTimeTrackHeaderDirectory.TagCreated, out checkDateTime)) - { - result ??= checkDateTime; - results.Add(checkDateTime); - } - else - { - dateTime = Shared.Models.Stateless.Methods.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(QuickTimeTrackHeaderDirectory.TagCreated)); - if (dateTime is not null) - { - result ??= dateTime.Value; - results.Add(dateTime.Value); - } - } - } - return new(result, results.ToArray()); - } - internal static string? GetModel(IReadOnlyList directories) { string? result; diff --git a/Mirror-Length/appsettings.json b/Mirror-Length/appsettings.json index c5f1182..086a176 100644 --- a/Mirror-Length/appsettings.json +++ b/Mirror-Length/appsettings.json @@ -67,7 +67,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -91,36 +90,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Move-By-Id/Move-By-Id.csproj b/Move-By-Id/Move-By-Id.csproj index b18a8b7..68162a5 100644 --- a/Move-By-Id/Move-By-Id.csproj +++ b/Move-By-Id/Move-By-Id.csproj @@ -45,7 +45,6 @@ - diff --git a/Move-By-Id/MoveById.cs b/Move-By-Id/MoveById.cs index 78dfd12..48a3413 100644 --- a/Move-By-Id/MoveById.cs +++ b/Move-By-Id/MoveById.cs @@ -2,9 +2,11 @@ using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; using ShellProgressBar; +using System.Text; using View_by_Distance.Move.By.Id.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; +using View_by_Distance.Shared.Models.Stateless.Methods; namespace View_by_Distance.Move.By.Id; @@ -104,12 +106,14 @@ public class MoveById int? id; string? message; string[] matches; - DateTime?[] dateTimes; FileHolder fileHolder; bool isIgnoreExtension; const string jpeg = ".jpeg"; bool isValidImageFormatExtension; + ASCIIEncoding asciiEncoding = new(); bool nameWithoutExtensionIsIdFormat; + bool nameWithoutExtensionIsPaddedIdFormat; + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); foreach (string file in allFiles) { progressBar.Tick(); @@ -119,16 +123,17 @@ public class MoveById if (allFiles.Contains($"{fileHolder.FullName}.id")) continue; isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); - isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileHolder); - if (!isIgnoreExtension && isValidImageFormatExtension) + isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); + nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex); + if (!isIgnoreExtension && !isValidImageFormatExtension) { if (fileHolder.ExtensionLowered == jpeg) continue; - if (nameWithoutExtensionIsIdFormat) + if (nameWithoutExtensionIsIdFormat || nameWithoutExtensionIsPaddedIdFormat) continue; } - (_, dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, _PropertyConfiguration.PopulatePropertyId); + (_, _, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); if (id is null) continue; matches = (from l in allFiles where l.Contains($"{id}{fileHolder.ExtensionLowered}") select l).ToArray(); diff --git a/Move-By-Id/appsettings.json b/Move-By-Id/appsettings.json index 4e8411b..01d0ff8 100644 --- a/Move-By-Id/appsettings.json +++ b/Move-By-Id/appsettings.json @@ -69,7 +69,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -93,36 +92,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Offset-Date-Time-Original/OffsetDateTimeOriginal.cs b/Offset-Date-Time-Original/OffsetDateTimeOriginal.cs index 6b8aa63..3356cdc 100644 --- a/Offset-Date-Time-Original/OffsetDateTimeOriginal.cs +++ b/Offset-Date-Time-Original/OffsetDateTimeOriginal.cs @@ -5,7 +5,9 @@ using ShellProgressBar; using System.Drawing; using System.Drawing.Imaging; using System.Reflection; +using System.Text; using View_by_Distance.Offset.Date.Time.Original.Models; +using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Stateless; @@ -14,6 +16,12 @@ namespace View_by_Distance.Offset.Date.Time.Original; public class OffsetDateTimeOriginal { + private record Record(FileHolder FileHolder, + bool IsIgnoreExtension, + bool IsValidImageFormatExtension, + int Id, + DateTime DateTime); + private readonly AppSettings _AppSettings; private readonly string _WorkingDirectory; private readonly Configuration _Configuration; @@ -60,23 +68,34 @@ public class OffsetDateTimeOriginal { } } - private static List<(string, int, DateTime)> GetCollection(string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) + private List GetRecords(ASCIIEncoding asciiEncoding, string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) { - List<(string, int, DateTime)> results = new(); + List results = new(); DateTime dateTime; - Shared.Models.Property property; + int? id; + string? message; + DateTime[] dateTimes; + FileHolder fileHolder; + bool isIgnoreExtension; + DateTime? dateTimeOriginal; + bool isValidImageFormatExtension; 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) + fileHolder = new(file); + isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); + isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); + (dateTimeOriginal, dateTimes, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + if (message is not null) + throw new Exception(message); + if (id is null || dateTimeOriginal is null) continue; - dateTime = property.DateTimeOriginal.Value.AddTicks(ticks); + dateTime = dateTimeOriginal.Value.AddTicks(ticks); if (dateTime < minimumDateTime) continue; if (dateTime > maximumDateTime) continue; - results.Add((file, property.Id.Value, property.DateTimeOriginal.Value.AddTicks(ticks))); + results.Add(new(fileHolder, isIgnoreExtension, isValidImageFormatExtension, id.Value, dateTimeOriginal.Value.AddTicks(ticks))); } if (files.Length != results.Count) throw new Exception(); @@ -85,14 +104,14 @@ public class OffsetDateTimeOriginal #pragma warning disable CA1416 - private static void DateFix(string sourceDirectory, string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) + private void DateFix(string sourceDirectory, ASCIIEncoding asciiEncoding, string checkDirectory, DateTime minimumDateTime, DateTime maximumDateTime, long ticks) { + int? id; Bitmap bitmap; short type = 2; 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++) { @@ -104,26 +123,28 @@ public class OffsetDateTimeOriginal } ticks++; } - List<(string, int, DateTime)> collection = GetCollection(checkDirectory, minimumDateTime, maximumDateTime, ticks); + List records = GetRecords(asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, ticks); ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null) ?? throw new Exception(); - string message = nameof(OffsetDateTimeOriginal); + string? message = nameof(OffsetDateTimeOriginal); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - ProgressBar progressBar = new(collection.Count, message, options); - foreach ((string file, int id, DateTime dateTime) in collection) + ProgressBar progressBar = new(records.Count, message, options); + foreach (Record record in records) { progressBar.Tick(); if (ticksDirectory is null) throw new Exception(); - checkFile = Path.Combine(ticksDirectory, Path.GetFileName(file)); + checkFile = Path.Combine(ticksDirectory, record.FileHolder.Name); if (File.Exists(checkFile)) continue; - propertyItem = Shared.Models.Stateless.Methods.IProperty.GetPropertyItem(constructorInfo, dateTimeOriginal, type, dateTime.ToString("yyyy:MM:dd HH:mm:ss")); - bitmap = new(file); + propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, dateTimeOriginal, type, record.DateTime.ToString("yyyy:MM:dd HH:mm:ss")); + bitmap = new(record.FileHolder.FullName); bitmap.SetPropertyItem(propertyItem); bitmap.Save(checkFile); bitmap.Dispose(); - property = Property.Models.A_Property.GetImageProperty(checkFile); - if (property.Id is null || property.Id.Value != id) + (_, _, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, record.FileHolder, record.IsIgnoreExtension, record.IsValidImageFormatExtension, asciiEncoding); + if (message is not null) + throw new Exception(message); + if (id is null || id.Value != record.Id) throw new Exception(); } progressBar.Dispose(); @@ -131,13 +152,14 @@ public class OffsetDateTimeOriginal #pragma warning restore CA1416 - private static void DateFix(ILogger log, string sourceDirectory) + private void DateFix(ILogger log, string sourceDirectory) { string checkDirectory; + ASCIIEncoding asciiEncoding = new(); 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); + DateFix(sourceDirectory, asciiEncoding, checkDirectory, DateTime.MinValue, DateTime.MaxValue, new TimeSpan(oneYearTicks - DateTime.MinValue.Ticks).Ticks); else { checkDirectory = Path.Combine(sourceDirectory, "1"); @@ -160,16 +182,40 @@ public class OffsetDateTimeOriginal log.Error("bad file(s) or target file(s) or maximum directory doesn't equal 1!"); else { + int? badId; + int? targetId; + string? badMessage; + string? targetMessage; + DateTime[] badDateTimes; + bool badIsIgnoreExtension; + DateTime[] targetDateTimes; + bool targetIsIgnoreExtension; + DateTime? badDateTimeOriginal; + DateTime? targetDateTimeOriginal; + FileHolder badFileHolder = new(badFiles.First()); + FileHolder targetFileHolder = new(targetFiles.First()); + bool badIsValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(badFileHolder.ExtensionLowered); + bool targetIsValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(targetFileHolder.ExtensionLowered); + badIsIgnoreExtension = badIsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(badFileHolder.ExtensionLowered); + targetIsIgnoreExtension = targetIsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(targetFileHolder.ExtensionLowered); 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) + (badDateTimeOriginal, badDateTimes, badId, badMessage) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, badFileHolder, badIsIgnoreExtension, badIsValidImageFormatExtension, asciiEncoding); + if (badMessage is not null) + throw new Exception(badMessage); + if (!badDateTimes.Any() || badId is null) + throw new Exception(badMessage); + (targetDateTimeOriginal, targetDateTimes, targetId, targetMessage) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, targetFileHolder, targetIsIgnoreExtension, targetIsValidImageFormatExtension, asciiEncoding); + if (targetMessage is not null) + throw new Exception(targetMessage); + if (!targetDateTimes.Any() || targetId is null) + throw new Exception(targetMessage); + if (badDateTimeOriginal is null || targetDateTimeOriginal is null) log.Error("Date is null!"); else { - TimeSpan timeSpan = new(targetProperty.DateTimeOriginal.Value.Ticks - badProperty.DateTimeOriginal.Value.Ticks); - DateFix(sourceDirectory, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks); + TimeSpan timeSpan = new(targetDateTimeOriginal.Value.Ticks - badDateTimeOriginal.Value.Ticks); + DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks); } } } diff --git a/Offset-Date-Time-Original/appsettings.json b/Offset-Date-Time-Original/appsettings.json index ed0997e..e733c41 100644 --- a/Offset-Date-Time-Original/appsettings.json +++ b/Offset-Date-Time-Original/appsettings.json @@ -66,7 +66,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -90,36 +89,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Person/appsettings.json b/Person/appsettings.json index 9b15739..3f52b70 100644 --- a/Person/appsettings.json +++ b/Person/appsettings.json @@ -19,7 +19,6 @@ "ResultSingleton": "{}", "RootDirectory": "/srv/samba/share", "SaveDirectory": "/home/vscode", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -43,36 +42,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } }, @@ -141,7 +110,6 @@ "ResultSingleton": "{}", "RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88", "SaveDirectory": "D:/Tmp", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -165,36 +133,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } }, diff --git a/PrepareForOld/appsettings.Development.json b/PrepareForOld/appsettings.Development.json index 909538b..a709607 100644 --- a/PrepareForOld/appsettings.Development.json +++ b/PrepareForOld/appsettings.Development.json @@ -59,7 +59,6 @@ "PopulatePropertyId": false, "PropertiesChangedForProperty": false, "RootDirectory": "C:/Tmp/Phares/Pictures", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -111,36 +110,6 @@ ".tif", ".TIF" ], - "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", - ".tif", - ".TIF" - ], "VerifyToSeason": [ ". 2000", ". 2001", diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 9f287fb..9d01508 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -1,14 +1,9 @@ using ShellProgressBar; -using System.Drawing; -using System.Drawing.Imaging; -using System.Globalization; -using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using View_by_Distance.Property.Models.Stateless; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Properties; -using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Property.Models; @@ -62,201 +57,7 @@ public class A_Property return result; } -#pragma warning disable CA1416 - - private static List GetMetadataDateTimesByPattern(string dateTimeFormat, FileHolder fileHolder) - { - List results = new(); - try - { - DateTime checkDateTime; - DateTime kristy = new(1976, 3, 8); - IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName); - foreach (MetadataExtractor.Directory directory in directories) - { - foreach (MetadataExtractor.Tag tag in directory.Tags) - { - if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length) - continue; - if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - continue; - if (checkDateTime < kristy) - continue; - results.Add(checkDateTime); - } - } - } - catch (Exception) { } - return results; - } - - 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; - byte[] bytes; - string value; - long fileLength; - int? width = null; - int? height = null; - string? make = null; - string? model = null; - string dateTimeFormat; - DateTime checkDateTime; - DateTime? dateTime = null; - PropertyItem? propertyItem; - string? orientation = null; - DateTime? gpsDateStamp = null; - DateTime? dateTimeOriginal = null; - DateTime? dateTimeDigitized = null; - DateTime? dateTimeFromName = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder); - if (!isValidImageFormatExtension && isValidMetadataExtensions && fileHolder.Exists) - { - dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy"; - List dateTimes = GetMetadataDateTimesByPattern(dateTimeFormat, fileHolder); - if (dateTimes.Any()) - dateTimeOriginal = dateTimes.Min(); - } - else if (!isIgnoreExtension && isValidImageFormatExtension && fileHolder.Exists) - { - try - { - using Image image = Image.FromFile(fileHolder.FullName); - width = image.Width; - height = image.Height; - if (populateId && id is null) - { - using Bitmap bitmap = new(image); - Rectangle rectangle = new(0, 0, image.Width, image.Height); - BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); - IntPtr intPtr = bitmapData.Scan0; - int length = bitmapData.Stride * bitmap.Height; - bytes = new byte[length]; - Marshal.Copy(intPtr, bytes, 0, length); - bitmap.UnlockBits(bitmapData); - 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); - } - } - dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); - if (propertyItem?.Value is not null) - { - 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)) - dateTime = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); - if (propertyItem?.Value is not null) - { - 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)) - dateTimeDigitized = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); - if (propertyItem?.Value is not null) - { - 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)) - dateTimeOriginal = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); - if (propertyItem?.Value is not null) - { - 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)) - gpsDateStamp = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Make)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); - if (propertyItem?.Value is not null) - { - value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - make = value; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Model)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); - if (propertyItem?.Value is not null) - { - value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - model = value; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation); - if (propertyItem?.Value is not null) - { - value = BitConverter.ToInt16(propertyItem.Value, 0).ToString(); - orientation = value; - } - } - } - catch (Exception) { } - } - else - dateTimeOriginal = null; - if (fileHolder.Length is null) - fileLength = 0; - else - fileLength = fileHolder.Length.Value; - if (fileHolder.CreationTime is null && property?.CreationTime is null) - throw new NullReferenceException(nameof(fileHolder.CreationTime)); - if (fileHolder.LastWriteTime is null && property?.LastWriteTime is null) - throw new NullReferenceException(nameof(fileHolder.LastWriteTime)); - if (fileHolder.CreationTime is not null && fileHolder.LastWriteTime is not null) - result = new(fileHolder.CreationTime.Value, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, fileHolder.LastWriteTime.Value, make, model, orientation, width); - else if (property is not null) - result = new(property.CreationTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, property.LastWriteTime, make, model, orientation, width); - else - throw new NullReferenceException(nameof(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) + private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata metadata, Item item, List> sourceDirectoryFileTuples, List parseExceptions, bool isIgnoreExtension) { Shared.Models.Property? result; int? id = null; @@ -348,7 +149,7 @@ public class A_Property if (result is null) { id ??= item.ImageFileHolder.Id; - result = GetImageProperty(item.ImageFileHolder, result, populateId, isIgnoreExtension, item.IsValidImageFormatExtension, isValidMetadataExtensions, id, _ASCIIEncoding, _Configuration.WriteBitmapDataBytes, angleBracket); + (_, _, result) = Stateless.Property.GetProperty(populateId, metadata, item.ImageFileHolder, result, isIgnoreExtension, item.IsValidImageFormatExtension, id, _ASCIIEncoding); json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) { @@ -377,18 +178,17 @@ public class A_Property return result; } - private void SavePropertyParallelForWork(string sourceDirectory, List> sourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) + private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata metadata, string sourceDirectory, List> sourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) { Shared.Models.Property property; List parseExceptions = new(); - bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}"); if (item.IsValidImageFormatExtension && item.ImageFileHolder.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.ImageFileHolder.FullName != filteredSourceDirectoryFileExtensionLowered) File.Move(item.ImageFileHolder.FullName, filteredSourceDirectoryFileExtensionLowered); if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.Property is null) { - property = GetPropertyOfPrivate(item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); + property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension); lock (sourceDirectoryChanges) sourceDirectoryChanges.Add(new Tuple(nameof(A_Property), DateTime.Now)); lock (item) @@ -396,7 +196,7 @@ public class A_Property } } - private void SavePropertyParallelWork(int maxDegreeOfParallelism, List exceptions, List> sourceDirectoryChanges, Container container, List items, string message) + private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata metadata, List exceptions, List> sourceDirectoryChanges, Container container, List items, string message) { List> sourceDirectoryFileTuples = new(); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; @@ -409,7 +209,7 @@ public class A_Property long ticks = DateTime.Now.Ticks; DateTime dateTime = DateTime.Now; List> collection; - SavePropertyParallelForWork(container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]); + SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]); if (i == 0 || sourceDirectoryChanges.Any()) progressBar.Tick(); lock (sourceDirectoryFileTuples) @@ -452,7 +252,7 @@ public class A_Property SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); } - public void SavePropertyParallelWork(long ticks, int t, Container[] containers) + public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata metadata, int t, Container[] containers) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -478,7 +278,7 @@ public class A_Property SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName); totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}"; - SavePropertyParallelWork(_MaxDegreeOfParallelism, exceptions, sourceDirectoryChanges, container, container.Items, message); + SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message); foreach (Exception exception in exceptions) _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception); if (exceptions.Count == container.Items.Count) @@ -499,7 +299,7 @@ public class A_Property } } - public Shared.Models.Property GetProperty(Item item, List> sourceDirectoryFileTuples, List parseExceptions) + public Shared.Models.Property GetProperty(Shared.Models.Methods.IMetadata metadata, Item item, List> sourceDirectoryFileTuples, List parseExceptions) { Shared.Models.Property result; bool angleBracketCollectionAny = _AngleBracketCollection.Any(); @@ -509,9 +309,8 @@ public class A_Property throw new NullReferenceException(nameof(item.ImageFileHolder.DirectoryName)); SetAngleBracketCollection(item.ImageFileHolder.DirectoryName, !item.IsUniqueFileName); } - bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); - result = GetPropertyOfPrivate(item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); + result = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension); if (!angleBracketCollectionAny) _AngleBracketCollection.Clear(); return result; diff --git a/Property/Models/Binder/Configuration.cs b/Property/Models/Binder/Configuration.cs index 3cb74d6..c1082af 100644 --- a/Property/Models/Binder/Configuration.cs +++ b/Property/Models/Binder/Configuration.cs @@ -27,9 +27,7 @@ public class Configuration [Display(Name = "Result Singleton"), Required] public string ResultSingleton { get; set; } [Display(Name = "Root Directory"), Required] public string RootDirectory { get; set; } [Display(Name = "Valid Image Format Extensions"), Required] public string[] ValidImageFormatExtensions { get; set; } - [Display(Name = "Valid Metadata Extensions"), Required] public string[] ValidMetadataExtensions { get; set; } [Display(Name = "Verify to Season"), Required] public string[] VerifyToSeason { get; set; } - [Display(Name = "Write Bitmap Data Bytes"), Required] public bool? WriteBitmapDataBytes { get; set; } #nullable restore @@ -62,12 +60,9 @@ public class Configuration throw new NullReferenceException(nameof(configuration.ResultContent)); if (configuration.ResultSingleton is null) throw new NullReferenceException(nameof(configuration.ResultSingleton)); - if (configuration.WriteBitmapDataBytes is null) - throw new NullReferenceException(nameof(configuration.WriteBitmapDataBytes)); configuration.IgnoreExtensions ??= Array.Empty(); configuration.PropertyContentCollectionFiles ??= Array.Empty(); configuration.ValidImageFormatExtensions ??= Array.Empty(); - configuration.ValidMetadataExtensions ??= Array.Empty(); configuration.VerifyToSeason ??= Array.Empty(); result = new(configuration.DateGroup, configuration.FileNameDirectorySeparator, @@ -86,9 +81,7 @@ public class Configuration configuration.ResultSingleton, configuration.RootDirectory, configuration.ValidImageFormatExtensions, - configuration.ValidMetadataExtensions, - configuration.VerifyToSeason, - configuration.WriteBitmapDataBytes.Value); + configuration.VerifyToSeason); return result; } diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs index de198b6..3c119b0 100644 --- a/Property/Models/Configuration.cs +++ b/Property/Models/Configuration.cs @@ -34,8 +34,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration public string ResultContent { init; get; } public string ResultSingleton { init; get; } public string[] ValidImageFormatExtensions { init; get; } - public string[] ValidMetadataExtensions { init; get; } - public bool WriteBitmapDataBytes { init; get; } [JsonConstructor] public Configuration(string dateGroup, @@ -55,9 +53,7 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration string resultSingleton, string rootDirectory, string[] validImageFormatExtensions, - string[] validMetadataExtensions, - string[] verifyToSeason, - bool writeBitmapDataBytes) + string[] verifyToSeason) { DateGroup = dateGroup; FileNameDirectorySeparator = fileNameDirectorySeparator; @@ -76,8 +72,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration ResultSingleton = resultSingleton; _RootDirectory = rootDirectory; ValidImageFormatExtensions = validImageFormatExtensions; - ValidMetadataExtensions = validMetadataExtensions; - WriteBitmapDataBytes = writeBitmapDataBytes; } public override string ToString() @@ -109,8 +103,6 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration throw new NullReferenceException(nameof(propertyConfiguration.PropertyContentCollectionFiles)); if (propertyConfiguration.ValidImageFormatExtensions is null || !propertyConfiguration.ValidImageFormatExtensions.Any()) throw new NullReferenceException(nameof(propertyConfiguration.ValidImageFormatExtensions)); - if (propertyConfiguration.ValidMetadataExtensions is null || !propertyConfiguration.ValidMetadataExtensions.Any()) - throw new NullReferenceException(nameof(propertyConfiguration.ValidMetadataExtensions)); if (propertyConfiguration is null) throw new NullReferenceException(nameof(propertyConfiguration)); if (string.IsNullOrEmpty(propertyConfiguration.DateGroup)) diff --git a/Property/Models/Stateless/IProperty.cs b/Property/Models/Stateless/IProperty.cs new file mode 100644 index 0000000..0903cd6 --- /dev/null +++ b/Property/Models/Stateless/IProperty.cs @@ -0,0 +1,51 @@ +using System.Drawing.Imaging; +using System.Reflection; +using System.Text; +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Property.Models.Stateless; + +public interface IProperty +{ + + string TestStatic_DateTimeFormat() => + DateTimeFormat(); + static string DateTimeFormat() => + "yyyy:MM:dd HH:mm:ss"; + + int TestStatic_GetDeterministicHashCode(byte[] value) => + GetDeterministicHashCode(value); + static int GetDeterministicHashCode(byte[] value) => + Property.GetDeterministicHashCode(value); + + byte[] TestStatic_GetBytes(string value) => + GetBytes(value); + static byte[] GetBytes(string value) => + Property.GetBytes(value); + + DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) => + GetDateTime(dateTimeFormat, value); + static DateTime? GetDateTime(string dateTimeFormat, string? value) => + Property.GetDateTime(dateTimeFormat, value); + + PropertyItem TestStatic_GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) => + GetPropertyItem(constructorInfo, id, type, value); + static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) => + Property.GetPropertyItem(constructorInfo, id, type, value); + + (string?, DateTime[], Shared.Models.Property) TestStatic_GetProperty(bool populateId, IMetadata? metadata, Shared.Models.FileHolder fileHolder, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) => + GetProperty(populateId, metadata, fileHolder, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding); + static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata? metadata, Shared.Models.FileHolder fileHolder, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) => + Property.GetProperty(populateId, metadata, fileHolder, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding); + + (DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, Shared.Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) => + Get(populateId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + static (DateTime?, DateTime[], int?, string?) Get(bool populateId, Shared.Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) => + Property.Get(populateId, null, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + + (DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, IMetadata? metadata, Shared.Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) => + Get(populateId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + static (DateTime?, DateTime[], int?, string?) Get(bool populateId, IMetadata? metadata, Shared.Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) => + Property.Get(populateId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + +} \ No newline at end of file diff --git a/Property/Models/Stateless/Property.cs b/Property/Models/Stateless/Property.cs new file mode 100644 index 0000000..d5f9ec6 --- /dev/null +++ b/Property/Models/Stateless/Property.cs @@ -0,0 +1,395 @@ +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Methods; +using View_by_Distance.Shared.Models.Stateless; + +namespace View_by_Distance.Property.Models.Stateless; + +internal class Property +{ + + internal static int GetDeterministicHashCode(byte[] value) + { + int result; + unchecked + { + int hash1 = (5381 << 16) + 5381; + int hash2 = hash1; + for (int i = 0; i < value.Length; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ value[i]; + if (i == value.Length - 1) + break; + hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; + } + result = hash1 + (hash2 * 1566083941); + } + return result; + } + +#pragma warning disable CA1416 + + internal static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) + { + PropertyItem result = (PropertyItem)constructorInfo.Invoke(null); + int length; + byte[] bytes; + if (type == 2) + { + bytes = GetBytes(value); + length = value.Length + 1; + } + else if (type == 1) + { + bytes = Encoding.Unicode.GetBytes($"{value}\0"); + length = bytes.Length; + } + else + throw new NotSupportedException(); + result.Id = id; + result.Len = length; + result.Type = type; + result.Value = bytes; + return result; + } + +#pragma warning restore CA1416 + + internal static byte[] GetBytes(string value) + { + byte[] results = new byte[value.Length + 1]; + for (int i = 0; i < value.Length; i++) + results[i] = (byte)value[i]; + results[value.Length] = 0x00; + return results; + } + + internal static DateTime? GetDateTime(string dateTimeFormat, string? value) + { + DateTime? result; + string alternateFormat = "ddd MMM dd HH:mm:ss yyyy"; + if (value is not null && DateTime.TryParse(value, out DateTime dateTime)) + result = dateTime; + else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + result = dateTime; + else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + result = dateTime; + else + result = null; + return result; + } + + private static List GetDateTimes(DateTime?[] metadataDateTimes) + { + List results = new(); + foreach (DateTime? dateTime in metadataDateTimes) + { + if (dateTime is null || results.Contains(dateTime.Value)) + continue; + results.Add(dateTime.Value); + } + return results; + } + + private static List GetDateTimes(DateTime?[] dateTimes, DateTime?[] metadataDateTimes) + { + List results = new(); + foreach (DateTime? dateTime in metadataDateTimes) + { + if (dateTime is null || results.Contains(dateTime.Value)) + continue; + results.Add(dateTime.Value); + } + foreach (DateTime? dateTime in dateTimes) + { + if (dateTime is null || results.Contains(dateTime.Value)) + continue; + results.Add(dateTime.Value); + } + return results; + } + + private static List GetDateTimes(FileHolder fileHolder, DateTime?[] dateTimes) + { + List results = new(); + string[] digits = Regex.Split(fileHolder.FullName, @"\D+"); + foreach (string digit in digits) + { + if (digit.Length != 4 || digit[..2] is not "19" and not "20" || !int.TryParse(digit, out int year)) + continue; + results.Add(new(year, 1, 1)); + } + foreach (DateTime? dateTime in dateTimes) + { + if (dateTime is null) + continue; + results.Add(dateTime.Value); + } + return results; + } + + private static List GetDateTimes(DateTime dateTimeFromName, DateTime?[] dateTimes) + { + List results = new() { dateTimeFromName }; + foreach (DateTime? dateTime in dateTimes) + { + if (dateTime is null) + continue; + results.Add(dateTime.Value); + } + return results; + } + +#pragma warning disable CA1416 + + internal static DateTime? GetDateTimeFromName(FileHolder fileHolder) + { + DateTime? result = null; + int length; + string format; + string fullFormat; + StringBuilder value = new(); + const string ticksExample = "##################"; + string[][] dateFormats = new string[][] + { + new string[] { string.Empty, "yyyyMMdd_HHmmss", string.Empty }, + new string[] { string.Empty, "yyyyMMddHHmmssfff", string.Empty }, + new string[] { string.Empty, "yyyyMMdd_", ticksExample }, + new string[] { string.Empty, "yyyy-MM-dd_", ticksExample }, + new string[] { string.Empty, "yyyy-MM-dd.", ticksExample }, + new string[] { string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}" }, + new string[] { string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty }, + new string[] { string.Empty, "yyyyMMdd_HHmmss", "_LLS" }, + new string[] { string.Empty, "yyyyMMdd_HHmmss", "_HDR" }, + new string[] { "WIN_", "yyyyMMdd_HH_mm_ss", "_Pro" }, + new string[] { "IMG_", "yyyyMMdd_HHmmss", string.Empty }, + new string[] { "IMG#####-", "yyyyMMdd-HHmm", string.Empty }, + new string[] { "CameraZOOM-", "yyyyMMddHHmmss", string.Empty }, + new string[] { "VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty } + }; + foreach (string[] dateFormat in dateFormats) + { + _ = value.Clear(); + if (dateFormat.Length != 3) + throw new Exception(); + fullFormat = string.Join(string.Empty, dateFormat); + if (fileHolder.NameWithoutExtension.Length != fullFormat.Length) + continue; + format = dateFormat[1]; + length = dateFormat[0].Length + dateFormat[1].Length; + for (int i = dateFormat[0].Length; i < length; i++) + _ = value.Append(fileHolder.NameWithoutExtension[i]); + if (value.Length != format.Length) + continue; + if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime)) + { + if (fileHolder.NameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileHolder.NameWithoutExtension[^ticksExample.Length..], out long ticks)) + result = checkDateTime; + else + result = new DateTime(ticks); + break; + } + } + return result; + } + + internal static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata? metadata, FileHolder fileHolder, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) + { + Shared.Models.Property result; + byte[] bytes; + string value; + long fileLength; + string? message; + int? width = null; + int? height = null; + string? make = null; + string? model = null; + DateTime?[] dateTimes; + string dateTimeFormat; + DateTime checkDateTime; + DateTime? dateTime = null; + PropertyItem? propertyItem; + string? orientation = null; + DateTime? gpsDateStamp = null; + List dateTimesByLogic; + DateTime? dateTimeOriginal = null; + DateTime? dateTimeDigitized = null; + DateTime? dateTimeOriginalByLogic = null; + IReadOnlyList directories; + DateTime? dateTimeFromName = GetDateTimeFromName(fileHolder); + if (!isValidImageFormatExtension && fileHolder.Exists && metadata is not null) + { + try + { + directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName); + (dateTimeOriginalByLogic, DateTime?[] metadataDateTimes) = metadata.GetDateTimes(fileHolder, directories); + dateTimesByLogic = GetDateTimes(metadataDateTimes); + message = null; + } + catch (Exception) + { + dateTimesByLogic = new(); + message = string.Concat(new StackFrame().GetMethod()?.Name, " <", fileHolder.FullName, ">"); + } + } + else if (!isIgnoreExtension && isValidImageFormatExtension && fileHolder.Exists) + { + try + { + using Image image = Image.FromFile(fileHolder.FullName); + width = image.Width; + height = image.Height; + if (populateId && id is null) + { + using Bitmap bitmap = new(image); + Rectangle rectangle = new(0, 0, image.Width, image.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + bitmap.UnlockBits(bitmapData); + id ??= GetDeterministicHashCode(bytes); + } + dateTimeFormat = IProperty.DateTimeFormat(); + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); + if (propertyItem?.Value is not null) + { + 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)) + dateTime = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); + if (propertyItem?.Value is not null) + { + 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)) + dateTimeDigitized = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); + if (propertyItem?.Value is not null) + { + 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)) + dateTimeOriginal = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); + if (propertyItem?.Value is not null) + { + 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)) + gpsDateStamp = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Make)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); + if (propertyItem?.Value is not null) + { + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + make = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Model)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); + if (propertyItem?.Value is not null) + { + value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + model = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation); + if (propertyItem?.Value is not null) + { + value = BitConverter.ToInt16(propertyItem.Value, 0).ToString(); + orientation = value; + } + } + message = null; + dateTimes = new DateTime?[] { fileHolder.LastWriteTime, fileHolder.CreationTime, dateTime, dateTimeDigitized, dateTimeOriginal, gpsDateStamp }; + } + catch (Exception) + { + dateTimes = Array.Empty(); + message = string.Concat(new StackFrame().GetMethod()?.Name, " <", fileHolder.FullName, ">"); + } + if (metadata is not null && dateTimeOriginal is null) + { + try + { + directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName); + (dateTimeOriginalByLogic, DateTime?[] metadataDateTimes) = metadata.GetDateTimes(fileHolder, directories); + dateTimesByLogic = GetDateTimes(dateTimes, metadataDateTimes); + message = null; + } + catch (Exception) { message = string.Concat(new StackFrame().GetMethod()?.Name, " <", fileHolder.FullName, ">"); } + } + if (dateTimeFromName is null) + (dateTimeOriginalByLogic, dateTimesByLogic) = (dateTimeOriginal, GetDateTimes(fileHolder, dateTimes)); + else + (dateTimeOriginalByLogic, dateTimesByLogic) = (dateTimeOriginal, GetDateTimes(dateTimeFromName.Value, dateTimes)); + } + else + (message, dateTimeOriginalByLogic, dateTimesByLogic) = (null, null, new()); + if (fileHolder.Length is null) + fileLength = 0; + else + fileLength = fileHolder.Length.Value; + if (fileHolder.CreationTime is null && property?.CreationTime is null) + throw new NullReferenceException(nameof(fileHolder.CreationTime)); + if (fileHolder.LastWriteTime is null && property?.LastWriteTime is null) + throw new NullReferenceException(nameof(fileHolder.LastWriteTime)); + if (fileHolder.CreationTime is not null && fileHolder.LastWriteTime is not null) + result = new(fileHolder.CreationTime.Value, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginalByLogic, fileLength, gpsDateStamp, height, id, fileHolder.LastWriteTime.Value, make, model, orientation, width); + else if (property is not null) + result = new(property.CreationTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginalByLogic, fileLength, gpsDateStamp, height, id, property.LastWriteTime, make, model, orientation, width); + else + throw new NullReferenceException(nameof(property)); + return (message, dateTimesByLogic.ToArray(), result); + } + +#pragma warning restore CA1416 + + internal static (DateTime?, DateTime[], int?, string?) Get(bool populateId, IMetadata? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) + { + int? id = null; + string? message; + DateTime[] dateTimes; + Shared.Models.Property? property = null; + if (isIgnoreExtension || !isValidImageFormatExtension) + (message, dateTimes, property) = (null, Array.Empty(), null); + else + (message, dateTimes, property) = GetProperty(populateId, metadata, fileHolder, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding); + return new(property?.DateTimeOriginal, dateTimes, property?.Id, message); + } + +} \ No newline at end of file diff --git a/Rename/Models/AppSettings.cs b/Rename/Models/AppSettings.cs index 6351b6f..4f5679c 100644 --- a/Rename/Models/AppSettings.cs +++ b/Rename/Models/AppSettings.cs @@ -24,4 +24,4 @@ public record AppSettings(string Company, [JsonSerializable(typeof(AppSettings))] internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext { -} +} \ No newline at end of file diff --git a/Rename/Models/Binder/AppSettings.cs b/Rename/Models/Binder/AppSettings.cs index ef998f0..d58e07d 100644 --- a/Rename/Models/Binder/AppSettings.cs +++ b/Rename/Models/Binder/AppSettings.cs @@ -66,4 +66,4 @@ public class AppSettings [JsonSerializable(typeof(AppSettings))] internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext { -} +} \ No newline at end of file diff --git a/Rename/Rename.cs b/Rename/Rename.cs index 3da3976..a83fd72 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -3,9 +3,12 @@ using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; using ShellProgressBar; +using System.Text; +using View_by_Distance.Metadata.Models; using View_by_Distance.Rename.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; +using View_by_Distance.Shared.Models.Stateless.Methods; namespace View_by_Distance.Rename; @@ -18,7 +21,7 @@ public class Rename List FileHolders, bool FfmpegFilesPresent, DateTime? DateTimeOriginal, - DateTime?[] DateTimes, + DateTime[] DateTimes, int? Id); private readonly AppSettings _AppSettings; @@ -85,7 +88,7 @@ public class Rename if (string.IsNullOrEmpty(directory)) continue; fileName = Path.GetFileName(file); - if (!fileName.EndsWith(".id")) + if (!fileName.EndsWith(".paddedId")) continue; lines = File.ReadAllLines(file); if (lines.Length < 2) @@ -99,20 +102,23 @@ public class Rename return results; } - private List GetRecords(int offset, ProgressBar progressBar, string[] files) + private List GetRecords(B_Metadata metadata, int offset, ProgressBar progressBar, string[] files) { List results = new(); int? id; string? message; string? directory; - DateTime?[] dateTimes; + DateTime[] dateTimes; FileHolder fileHolder; string[]? ffmpegFiles; bool isIgnoreExtension; DateTime? dateTimeOriginal; bool isValidImageFormatExtension; + ASCIIEncoding asciiEncoding = new(); bool nameWithoutExtensionIsIdFormat; + bool nameWithoutExtensionIsPaddedIdFormat; IReadOnlyList directories; + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); for (int i = 0; i < files.Length; i++) { progressBar.Tick(); @@ -122,12 +128,13 @@ public class Rename directory = Path.GetDirectoryName(files[i]); if (string.IsNullOrEmpty(directory)) continue; - if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) + if (fileHolder.ExtensionLowered == ".paddedId" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) continue; - if (files.Contains($"{fileHolder.FullName}.id")) + if (files.Contains($"{fileHolder.FullName}.paddedId")) continue; nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileHolder); - if (nameWithoutExtensionIsIdFormat) + nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex); + if (nameWithoutExtensionIsIdFormat || nameWithoutExtensionIsPaddedIdFormat) continue; isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); @@ -157,7 +164,7 @@ public class Rename if (fileHolder.DirectoryName is null) continue; } - (dateTimeOriginal, dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, _PropertyConfiguration.PopulatePropertyId); + (dateTimeOriginal, dateTimes, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); if (ffmpegFiles is not null) { fileHolder = new(files[i]); @@ -171,11 +178,11 @@ public class Rename return results; } - private List<(FileHolder, string, string)> GetToDoCollection(ProgressBar progressBar, bool nefPresent, List records, int length) + private List<(FileHolder, string, string)> GetToDoCollection(ProgressBar progressBar, bool nefPresent, List records, int intMinValueLength) { List<(FileHolder, string, string)> results = new(); - string id; int season; + string paddedId; string checkFile; bool? isWrongYear; DateTime dateTime; @@ -189,12 +196,9 @@ public class Rename string checkFileExtension; DateTime? dateTimeFromName; const string jpeg = ".jpeg"; - DateTime?[] metadataDateTimes; List distinct = new(); string[] directoryNameSegments; DateTime? dateTimeOriginalByLogic; - DateTime? metadataDateTimeOriginal; - IReadOnlyList directories; foreach (Record record in records) { progressBar.Tick(); @@ -205,19 +209,20 @@ public class Rename continue; if (string.IsNullOrEmpty(fileHolder.DirectoryName)) continue; + dateTimeFromName = !record.DateTimes.Any() ? null : record.DateTimes.First(); if (fileHolder.ExtensionLowered == jpeg) { if (!record.IsIgnoreExtension && record.IsValidImageFormatExtension) { - if (File.Exists($"{fileHolder.FullName}.id")) + if (File.Exists($"{fileHolder.FullName}.paddedId")) { - checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.id"); + checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.paddedId"); if (File.Exists(checkFile)) continue; if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); - results.Add(new(new($"{fileHolder.FullName}.id"), fileHolder.DirectoryName, checkFile)); + results.Add(new(new($"{fileHolder.FullName}.paddedId"), fileHolder.DirectoryName, checkFile)); } checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}"); if (File.Exists(checkFile)) @@ -238,7 +243,6 @@ public class Rename continue; } } - dateTimeFromName = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder); minimumDateTime = record.DateTimes.Min(); if (minimumDateTime is null) throw new NotSupportedException(); @@ -246,24 +250,10 @@ public class Rename timeSpan = null; else timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - record.DateTimeOriginal.Value.Ticks)); - if (timeSpan is not null && timeSpan.Value.TotalMinutes < _AppSettings.MaxMinutesDelta) - (dateTimeOriginalByLogic, metadataDateTimeOriginal, metadataDateTimes) = (record.DateTimeOriginal, null, Array.Empty()); + if (timeSpan is null || timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta) + timeSpan = null; else - { - if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - try - { directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName); } - catch (Exception) { continue; } - (metadataDateTimeOriginal, metadataDateTimes) = Metadata.Models.Stateless.Methods.IMetadata.GetDateTimes(fileHolder, directories); - dateTimeOriginalByLogic = record.DateTimeOriginal is not null ? record.DateTimeOriginal : metadataDateTimeOriginal; - if (record.FfmpegFilesPresent && dateTimeOriginalByLogic is not null) - minimumDateTime = dateTimeOriginalByLogic.Value; - if (dateTimeOriginalByLogic is null) - timeSpan = null; - else - timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTimeOriginalByLogic.Value.Ticks)); - } + dateTimeOriginalByLogic = record.DateTimeOriginal; if (timeSpan is null || timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta) { if (string.IsNullOrEmpty(_AppSettings.DefaultUnknownDirectoryName)) @@ -287,10 +277,8 @@ public class Rename { if (dateTimeFromName is not null && isWrongYear is not null && isWrongYear.Value) minimumDateTime = dateTimeFromName.Value; - else if (dateTimeOriginalByLogic is not null) - minimumDateTime = dateTimeOriginalByLogic.Value; - else - minimumDateTime = new DateTime?[] { record.DateTimes.Where(l => l is not null).Min(), metadataDateTimes.Where(l => l is not null).Min() }.Min(); + else if (record.DateTimeOriginal is not null) + minimumDateTime = record.DateTimeOriginal.Value; if (minimumDateTime is null) continue; checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; @@ -310,9 +298,9 @@ public class Rename { if (record.Id is null) continue; - id = Shared.Models.Stateless.Methods.IDirectory.GetPaddedId(length, record.Index, record.Id.Value); + paddedId = IDirectory.GetPaddedId(intMinValueLength, record.Index, record.Id.Value); checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered; - checkFile = Path.Combine(seasonDirectory, $"{id}{checkFileExtension}"); + checkFile = Path.Combine(seasonDirectory, $"{paddedId}{checkFileExtension}"); if (checkFile == fileHolder.FullName) continue; if (File.Exists(checkFile)) @@ -359,11 +347,12 @@ public class Rename const string fileSearchFilter = "*"; const string directorySearchFilter = "*"; List distinctDirectories = new(); + B_Metadata metadata = new(_PropertyConfiguration); List<(FileHolder, string)> verifiedToDoCollection = new(); List<(FileHolder, string, string)> toDoCollection = new(); - int offset = Shared.Models.Stateless.Methods.IDirectory.GetOffset(); + int offset = IDirectory.GetOffset(); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - List filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter); + List filesCollection = IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter); int count = filesCollection.Select(l => l.Length).Sum(); foreach (string[] files in filesCollection) { @@ -389,30 +378,29 @@ public class Rename progressBar = new(files.Length, message, options); nefPresentCheck = files.Any(l => l.EndsWith(".NEF")); if (!nefPresentCheck) - records.AddRange(GetRecords(offset + records.Count, progressBar, files)); + records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, files)); else { if (!nefPresent) nefPresent = true; - records.AddRange(GetRecords(offset + records.Count, progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray())); + records.AddRange(GetRecords(metadata, offset + records.Count, progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray())); } } progressBar.Dispose(); } if (records.Any()) { - int length = 0; + int intMinValueLength = int.MinValue.ToString().Length; foreach (Record record in records) { if (record.Id is null) continue; - if (length > record.Id.Value.ToString().Length) - continue; - length = record.Id.Value.ToString().Length; + if (intMinValueLength < record.Id.Value.ToString().Length) + throw new NotSupportedException(); } - message = $"{length}) comparing records"; + message = $"{intMinValueLength}) comparing records"; progressBar = new(records.Count, message, options); - toDoCollection.AddRange(GetToDoCollection(progressBar, nefPresent, records, length)); + toDoCollection.AddRange(GetToDoCollection(progressBar, nefPresent, records, intMinValueLength)); progressBar.Dispose(); } foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) @@ -431,7 +419,7 @@ public class Rename if (File.Exists(to)) continue; verifiedToDoCollection.Add(new(fileHolder, to)); - File.WriteAllText($"{to}.id", $"{to}{Environment.NewLine}{fileHolder.FullName}"); + File.WriteAllText($"{to}.paddedId", $"{to}{Environment.NewLine}{fileHolder.FullName}"); } ConsoleKey? consoleKey = null; log.Information($"Ready to Move {verifiedToDoCollection.Count} files[i](s)?"); diff --git a/Rename/appsettings.json b/Rename/appsettings.json index 88a5ebc..03a9ef9 100644 --- a/Rename/appsettings.json +++ b/Rename/appsettings.json @@ -70,7 +70,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -94,36 +93,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index e43dfba..35ea038 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -294,7 +294,7 @@ public class C_Resize private void SaveResizedSubfile(Shared.Models.Property property, MappingFromItem mappingFromItem, int[] resize) { - string dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); + string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat(); 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); diff --git a/Set-Created-Date/Set-Created-Date.csproj b/Set-Created-Date/Set-Created-Date.csproj index 1ed598a..300cdd6 100644 --- a/Set-Created-Date/Set-Created-Date.csproj +++ b/Set-Created-Date/Set-Created-Date.csproj @@ -45,6 +45,7 @@ + diff --git a/Set-Created-Date/SetCreatedDate.cs b/Set-Created-Date/SetCreatedDate.cs index 9a5c580..5f51511 100644 --- a/Set-Created-Date/SetCreatedDate.cs +++ b/Set-Created-Date/SetCreatedDate.cs @@ -2,6 +2,8 @@ using Phares.Shared; using Serilog; using ShellProgressBar; +using System.Text; +using View_by_Distance.Metadata.Models; using View_by_Distance.Set.Created.Date.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; @@ -11,6 +13,8 @@ namespace View_by_Distance.Set.Created.Date; public class SetCreatedDate { + private record Record(FileHolder FileHolder, bool OriginalSet, DateTime DateTime); + private readonly AppSettings _AppSettings; private readonly string _WorkingDirectory; private readonly Configuration _Configuration; @@ -61,52 +65,76 @@ public class SetCreatedDate { } } - private List<(FileHolder, DateTime)> GetToDoCollection(ProgressBar progressBar, List filesCollection) + private List GetRecords(ProgressBar progressBar, ASCIIEncoding asciiEncoding, B_Metadata metadata, string[] files) { - List<(FileHolder, DateTime)> results = new(); + List results = new(); int? id; string? message; - DateTime? dateTime; + DateTime[] dateTimes; FileHolder fileHolder; - DateTime?[] dateTimes; bool isIgnoreExtension; DateTime? dateTimeOriginal; bool isValidImageFormatExtension; + foreach (string file in files) + { + progressBar.Tick(); + fileHolder = new(file); + if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) + continue; + if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) + continue; + isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); + isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); + if (isIgnoreExtension || !isValidImageFormatExtension) + continue; + (dateTimeOriginal, dateTimes, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); + if (dateTimeOriginal is null) + results.Add(new(fileHolder, false, dateTimes.Min())); + else + results.Add(new(fileHolder, true, dateTimeOriginal.Value)); + } + return results; + } + + private List GetToDoCollection(ProgressBar progressBar, List filesCollection) + { + List results = new(); + int minutes; + Record[] records; + List unordered; + ASCIIEncoding asciiEncoding = new(); + B_Metadata metadata = new(_PropertyConfiguration); + List collections = new(); foreach (string[] files in filesCollection) { - foreach (string file in files) + minutes = 0; + unordered = GetRecords(progressBar, asciiEncoding, metadata, files); + records = (from l in unordered orderby l.DateTime, l.FileHolder.Name.Length, l.FileHolder.Name select l).ToArray(); + foreach (Record record in records) { - progressBar.Tick(); - fileHolder = new(file); - if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) + if (record.DateTime == record.FileHolder.CreationTime) continue; - if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered); - isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered); - if (isIgnoreExtension || !isValidImageFormatExtension) - continue; - (dateTimeOriginal, dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, _PropertyConfiguration.PopulatePropertyId); - dateTime = dateTimeOriginal is not null ? dateTimeOriginal : dateTime = dateTimes.Min(); - if (dateTime is null) - continue; - if (dateTime.Value == fileHolder.CreationTime) - continue; - results.Add((fileHolder, dateTime.Value)); + if (record.OriginalSet) + results.Add(new(record.FileHolder, record.OriginalSet, record.DateTime)); + else + { + minutes += 1; + results.Add(new(record.FileHolder, record.OriginalSet, record.DateTime.AddMinutes(minutes))); + } } } return results; } - private static List SetCreatedDateForeach(ProgressBar progressBar, List<(FileHolder, DateTime)> toDoCollection) + private static List SetCreatedDateForeach(ProgressBar progressBar, List toDoCollection) { List results = new(); - foreach ((FileHolder fileHolder, DateTime dateTime) in toDoCollection) + foreach (Record record in toDoCollection) { progressBar.Tick(); - results.Add(fileHolder.NameWithoutExtension); + results.Add(record.FileHolder.NameWithoutExtension); try - { File.SetCreationTime(fileHolder.FullName, dateTime); } + { File.SetCreationTime(record.FileHolder.FullName, record.DateTime); } catch (Exception) { } } return results; @@ -124,7 +152,7 @@ public class SetCreatedDate int count = filesCollection.Select(l => l.Length).Sum(); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; progressBar = new(count, message, options); - List<(FileHolder, DateTime)> toDoCollection = GetToDoCollection(progressBar, filesCollection); + List toDoCollection = GetToDoCollection(progressBar, filesCollection); progressBar.Dispose(); log.Information($"Ready to set created date {toDoCollection.Count} file(s)?"); for (int y = 0; y < int.MaxValue; y++) diff --git a/Set-Created-Date/appsettings.json b/Set-Created-Date/appsettings.json index 9001764..bafa145 100644 --- a/Set-Created-Date/appsettings.json +++ b/Set-Created-Date/appsettings.json @@ -68,7 +68,6 @@ "ResultContent": "()", "ResultSingleton": "{}", "RootDirectory": "D:/Images", - "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF", @@ -92,36 +91,6 @@ ".TIFF", ".tif", ".TIF" - ], - "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", - ".tif", - ".TIF" ] } } diff --git a/Shared/Models/Methods/IMetadata.cs b/Shared/Models/Methods/IMetadata.cs new file mode 100644 index 0000000..e296eb6 --- /dev/null +++ b/Shared/Models/Methods/IMetadata.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IMetadata +{ + + (DateTime?, DateTime?[]) GetDateTimes(FileHolder fileHolder, IReadOnlyList directories); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IDirectory.cs b/Shared/Models/Stateless/Methods/IDirectory.cs index 2597fbf..a955b09 100644 --- a/Shared/Models/Stateless/Methods/IDirectory.cs +++ b/Shared/Models/Stateless/Methods/IDirectory.cs @@ -6,6 +6,11 @@ public interface IDirectory static int GetOffset() => 1000000; + int TestStatic_GetSortOrderOnlyLengthIndex() => + GetSortOrderOnlyLengthIndex(); + static int GetSortOrderOnlyLengthIndex() => + GetOffset().ToString().Length + 3; + char TestStatic_GetDirectory(string fileName) => GetDirectory(fileName); static char GetDirectory(string fileName) => @@ -16,10 +21,23 @@ public interface IDirectory static int GetDirectory(char directory) => directory == '-' ? 10 : int.TryParse(directory.ToString(), out int value) ? value : 11; - string TestStatic_GetPaddedId(int length, int index, int id) => - GetPaddedId(length, index, id); - static string GetPaddedId(int length, int index, int id) => - id > -1 ? $"{index}070{id.ToString().PadLeft(length, '0')}" : $"{index}030{id.ToString()[1..].PadLeft(length, '0')}"; + string TestStatic_GetPaddedId(int intMinValueLength, int index, int id) => + GetPaddedId(intMinValueLength, index, id); + static string GetPaddedId(int intMinValueLength, int index, int id) => + id > -1 ? $"{index}070{id.ToString().PadLeft(intMinValueLength, '0')}" : $"{index}030{id.ToString()[1..].PadLeft(intMinValueLength, '0')}"; + + bool TestStatic_NameWithoutExtensionIsPaddedIdFormat(string fileNameWithoutExtension, int sortOrderOnlyLengthIndex) => + NameWithoutExtensionIsPaddedIdFormat(fileNameWithoutExtension, sortOrderOnlyLengthIndex); + static bool NameWithoutExtensionIsPaddedIdFormat(string fileNameWithoutExtension, int sortOrderOnlyLengthIndex) => + fileNameWithoutExtension.Length > sortOrderOnlyLengthIndex + && fileNameWithoutExtension[sortOrderOnlyLengthIndex] == '0' + && fileNameWithoutExtension[sortOrderOnlyLengthIndex - 3] == '0' + && fileNameWithoutExtension.All(l => char.IsNumber(l)); + + bool TestStatic_NameWithoutExtensionIsPaddedIdFormat(Models.FileHolder fileHolder, int sortOrderOnlyLengthIndex) => + NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex); + static bool NameWithoutExtensionIsPaddedIdFormat(Models.FileHolder fileHolder, int sortOrderOnlyLengthIndex) => + NameWithoutExtensionIsPaddedIdFormat(fileHolder.NameWithoutExtension, sortOrderOnlyLengthIndex); List TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) => GetFilesCollection(directory, directorySearchFilter, fileSearchFilter); @@ -51,6 +69,11 @@ public interface IDirectory static void MoveFiles(List files, string find, string replace) => XDirectory.MoveFiles(files, find, replace); + (string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => + GetToDoCollection(propertyConfiguration, filesCollection, directories, tick); + static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => + XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filesCollection, directories, tick); + (string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick); static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => diff --git a/Shared/Models/Stateless/Methods/IProperty.cs b/Shared/Models/Stateless/Methods/IProperty.cs index f4b7b0f..2a5729f 100644 --- a/Shared/Models/Stateless/Methods/IProperty.cs +++ b/Shared/Models/Stateless/Methods/IProperty.cs @@ -1,24 +1,8 @@ -using System.Drawing.Imaging; -using System.Reflection; - namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IProperty { // ... - string TestStatic_DateTimeFormat(); - static string DateTimeFormat() => "yyyy:MM:dd HH:mm:ss"; - - int TestStatic_GetDeterministicHashCode(byte[] value) => - GetDeterministicHashCode(value); - static int GetDeterministicHashCode(byte[] value) => - Property.GetDeterministicHashCode(value); - - DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) => - GetDateTime(dateTimeFormat, value); - static DateTime? GetDateTime(string dateTimeFormat, string? value) => - Property.GetDateTime(dateTimeFormat, value); - DateTime TestStatic_GetDateTime(Models.Property? property) => GetDateTime(property); static DateTime GetDateTime(Models.Property? property) => @@ -54,26 +38,11 @@ public interface IProperty static (bool?, string[]) IsWrongYear(Models.FileHolder fileHolder, DateTime? dateTimeOriginal, List dateTimes) => Property.IsWrongYear(fileHolder, dateTimeOriginal, dateTimes); - (DateTime?, DateTime?[], int?, string?) TestStatic_Get(Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, bool populateId) => - Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, populateId); - static (DateTime?, DateTime?[], int?, string?) Get(Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, bool populateId) => - Property.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, populateId); - - DateTime? TestStatic_GetDateTimeFromName(Models.FileHolder fileHolder) => - GetDateTimeFromName(fileHolder); - static DateTime? GetDateTimeFromName(Models.FileHolder fileHolder) => - Property.GetDateTimeFromName(fileHolder); - bool TestStatic_NameWithoutExtensionIsIdFormat(string fileNameWithoutExtension) => NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); static bool NameWithoutExtensionIsIdFormat(string fileNameWithoutExtension) => Property.NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); - bool TestStatic_NameWithoutExtensionIsIdFormat(string[] validImageFormatExtensions, Models.FileHolder fileHolder) => - NameWithoutExtensionIsIdFormat(validImageFormatExtensions, fileHolder); - static bool NameWithoutExtensionIsIdFormat(string[] validImageFormatExtensions, Models.FileHolder fileHolder) => - Property.NameWithoutExtensionIsIdFormat(validImageFormatExtensions, fileHolder); - bool TestStatic_NameWithoutExtensionIsIdFormat(Models.FileHolder fileHolder) => NameWithoutExtensionIsIdFormat(fileHolder); static bool NameWithoutExtensionIsIdFormat(Models.FileHolder fileHolder) => @@ -104,14 +73,4 @@ public interface IProperty static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) => Property.GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, gpsDateStamp); - byte[] TestStatic_GetBytes(string value) => - GetBytes(value); - static byte[] GetBytes(string value) => - Property.GetBytes(value); - - PropertyItem TestStatic_GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) => - GetPropertyItem(constructorInfo, id, type, value); - static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) => - Property.GetPropertyItem(constructorInfo, id, type, value); - } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Property.cs b/Shared/Models/Stateless/Methods/Property.cs index 1f7fd7d..85b8868 100644 --- a/Shared/Models/Stateless/Methods/Property.cs +++ b/Shared/Models/Stateless/Methods/Property.cs @@ -1,11 +1,3 @@ -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Globalization; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class Property @@ -24,25 +16,6 @@ internal abstract class Property return result; } - internal static int GetDeterministicHashCode(byte[] value) - { - int result; - unchecked - { - int hash1 = (5381 << 16) + 5381; - int hash2 = hash1; - for (int i = 0; i < value.Length; i += 2) - { - hash1 = ((hash1 << 5) + hash1) ^ value[i]; - if (i == value.Length - 1) - break; - hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; - } - result = hash1 + (hash2 * 1566083941); - } - return result; - } - internal static (bool?, string[]) IsWrongYear(string[] segments, string year) { bool? result; @@ -113,57 +86,6 @@ internal abstract class Property return new(result, results); } - internal static DateTime? GetDateTimeFromName(Models.FileHolder fileHolder) - { - DateTime? result = null; - int length; - string format; - string fullFormat; - StringBuilder value = new(); - const string ticksExample = "##################"; - string[][] dateFormats = new string[][] - { - new string[] { string.Empty, "yyyyMMdd_HHmmss", string.Empty }, - new string[] { string.Empty, "yyyyMMddHHmmssfff", string.Empty }, - new string[] { string.Empty, "yyyyMMdd_", ticksExample }, - new string[] { string.Empty, "yyyy-MM-dd_", ticksExample }, - new string[] { string.Empty, "yyyy-MM-dd.", ticksExample }, - new string[] { string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}" }, - new string[] { string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty }, - new string[] { string.Empty, "yyyyMMdd_HHmmss", "_LLS" }, - new string[] { string.Empty, "yyyyMMdd_HHmmss", "_HDR" }, - new string[] { "WIN_", "yyyyMMdd_HH_mm_ss", "_Pro" }, - new string[] { "IMG_", "yyyyMMdd_HHmmss", string.Empty }, - new string[] { "IMG#####-", "yyyyMMdd-HHmm", string.Empty }, - new string[] { "CameraZOOM-", "yyyyMMddHHmmss", string.Empty }, - new string[] { "VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty } - }; - foreach (string[] dateFormat in dateFormats) - { - _ = value.Clear(); - if (dateFormat.Length != 3) - throw new Exception(); - fullFormat = string.Join(string.Empty, dateFormat); - if (fileHolder.NameWithoutExtension.Length != fullFormat.Length) - continue; - format = dateFormat[1]; - length = dateFormat[0].Length + dateFormat[1].Length; - for (int i = dateFormat[0].Length; i < length; i++) - _ = value.Append(fileHolder.NameWithoutExtension[i]); - if (value.Length != format.Length) - continue; - if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime)) - { - if (fileHolder.NameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileHolder.NameWithoutExtension[^ticksExample.Length..], out long ticks)) - result = checkDateTime; - else - result = new DateTime(ticks); - break; - } - } - return result; - } - internal static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) { List results = new() @@ -355,7 +277,8 @@ internal abstract class Property internal static bool NameWithoutExtensionIsIdFormat(string fileNameWithoutExtension) { bool result; - if (fileNameWithoutExtension.Length < 5) + int intMinValueLength = int.MinValue.ToString().Length; + if (fileNameWithoutExtension.Length < 5 || fileNameWithoutExtension.Length > intMinValueLength) result = false; else { @@ -365,181 +288,4 @@ internal abstract class Property return result; } - internal static bool NameWithoutExtensionIsIdFormat(string[] validImageFormatExtensions, Models.FileHolder fileHolder) - { - bool result; - bool changed; - string? fileNameWithoutExtension = fileHolder.NameWithoutExtension; - for (int i = 0; i < validImageFormatExtensions.Length; i++) - { - changed = false; - foreach (string validImageFormatExtension in validImageFormatExtensions) - { - if (fileNameWithoutExtension.EndsWith(validImageFormatExtension)) - { - changed = true; - fileNameWithoutExtension = fileNameWithoutExtension[..^validImageFormatExtension.Length]; - break; - } - } - if (!changed) - break; - } - result = NameWithoutExtensionIsIdFormat(fileNameWithoutExtension); - return result; - } - -#pragma warning disable CA1416 - - internal static (DateTime?, DateTime?[], int?, string?) Get(Models.FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, bool populateId) - { - int? id = null; - string? message = null; - DateTime? dateTime = null; - DateTime? gpsDateStamp = null; - DateTime? dateTimeOriginal = null; - DateTime? dateTimeDigitized = null; - if (!isIgnoreExtension && isValidImageFormatExtension) - { - try - { - byte[] bytes; - string value; - DateTime checkDateTime; - PropertyItem? propertyItem; - ASCIIEncoding asciiEncoding = new(); - string dateTimeFormat = IProperty.DateTimeFormat(); - using Image image = Image.FromFile(fileHolder.FullName); - if (!populateId) - id = null; - else - { - using Bitmap bitmap = new(image); - Rectangle rectangle = new(0, 0, image.Width, image.Height); - BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); - IntPtr intPtr = bitmapData.Scan0; - int length = bitmapData.Stride * bitmap.Height; - bytes = new byte[length]; - Marshal.Copy(intPtr, bytes, 0, length); - bitmap.UnlockBits(bitmapData); - id = IProperty.GetDeterministicHashCode(bytes); - bitmap.Dispose(); - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); - if (propertyItem?.Value is not null) - { - 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)) - dateTime = checkDateTime; - else - dateTime = GetDateTime(dateTimeFormat, value); - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); - if (propertyItem?.Value is not null) - { - 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)) - dateTimeDigitized = checkDateTime; - else - dateTimeDigitized = GetDateTime(dateTimeFormat, value); - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); - if (propertyItem?.Value is not null) - { - 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)) - dateTimeOriginal = checkDateTime; - else - dateTimeOriginal = GetDateTime(dateTimeFormat, value); - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); - if (propertyItem?.Value is not null) - { - 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)) - gpsDateStamp = checkDateTime; - else - gpsDateStamp = GetDateTime(dateTimeFormat, value); - } - } - image.Dispose(); - } - } - catch (Exception) - { - message = string.Concat(new StackFrame().GetMethod()?.Name, " <", fileHolder.FullName, ">"); - } - } - DateTime?[] dateTimes = new DateTime?[] { fileHolder.LastWriteTime, fileHolder.CreationTime, dateTime, dateTimeDigitized, dateTimeOriginal, gpsDateStamp }; - return new(dateTimeOriginal, dateTimes, id, message); - } - - internal static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) - { - PropertyItem result = (PropertyItem)constructorInfo.Invoke(null); - int length; - byte[] bytes; - if (type == 2) - { - bytes = GetBytes(value); - length = value.Length + 1; - } - else if (type == 1) - { - bytes = Encoding.Unicode.GetBytes($"{value}\0"); - length = bytes.Length; - } - else - throw new NotSupportedException(); - result.Id = id; - result.Len = length; - result.Type = type; - result.Value = bytes; - return result; - } - -#pragma warning restore CA1416 - - internal static DateTime? GetDateTime(string dateTimeFormat, string? value) - { - DateTime? result; - string alternateFormat = "ddd MMM dd HH:mm:ss yyyy"; - if (value is not null && DateTime.TryParse(value, out DateTime dateTime)) - result = dateTime; - else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - result = dateTime; - else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - result = dateTime; - else - result = null; - return result; - } - - internal static byte[] GetBytes(string value) - { - byte[] results = new byte[value.Length + 1]; - for (int i = 0; i < value.Length; i++) - results[i] = (byte)value[i]; - results[value.Length] = 0x00; - return results; - } - } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index 89271d2..b7fee50 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -3,7 +3,7 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract partial class XDirectory { - private record SortedRecord(int? Id, Models.FileHolder FileHolder); + private record SortedRecord(Models.FileHolder FileHolder, bool NameWithoutExtensionIsIdFormat, int? Id); private static int GetCeilingAverage(List fileCollection) { @@ -244,7 +244,7 @@ internal abstract partial class XDirectory else if (fromFileInfo.Length == toFileInfo.Length && fromFileInfo.LastWriteTime == toFileInfo.LastWriteTime) checkDirectory = string.Concat(checkDirectory, ".del"); else - checkDirectory = string.Concat(checkDirectory, ".i"); + checkDirectory = string.Concat(checkDirectory, ".j"); } File.Move(from, checkDirectory); } @@ -280,79 +280,91 @@ internal abstract partial class XDirectory } } - private static (bool, SortedRecord[]) GetSortedRecords(List filesCollection) + private static SortedRecord[] GetSortedRecords(List filesCollection) { - bool result = true; List results = new(); int? id; short? multiplier; char negativeMarker; int absoluteValueOfId; Models.FileHolder fileHolder; - int offset = IDirectory.GetOffset(); - int offsetLength = offset.ToString().Length; - int sortOrderOnlyLengthIndex = offsetLength + 3; + bool nameWithoutExtensionIsIdFormat; + bool nameWithoutExtensionIsPaddedIdFormat; + int sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(); foreach (string[] files in filesCollection) { foreach (string file in files) { fileHolder = new Models.FileHolder(file); - if (!result) + nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileHolder); + nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex); + if (nameWithoutExtensionIsIdFormat) + { multiplier = null; + if (!int.TryParse(fileHolder.NameWithoutExtension, out absoluteValueOfId)) + id = null; + else + id = absoluteValueOfId; + } + else if (!nameWithoutExtensionIsPaddedIdFormat) + { + id = null; + multiplier = null; + } else { - if (fileHolder.NameWithoutExtension.Length < sortOrderOnlyLengthIndex) - { - result = false; + negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2]; + if (negativeMarker == '7') + multiplier = 1; + else if (negativeMarker == '3') + multiplier = -1; + else multiplier = null; - } + if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId)) + id = null; else { - negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2]; - if (negativeMarker == '7') - multiplier = 1; - else if (negativeMarker == '3') - multiplier = -1; - else - { - result = false; - multiplier = null; - } + id = absoluteValueOfId * multiplier; + if (id is null || !fileHolder.NameWithoutExtension.EndsWith(id.Value.ToString()[1..])) + id = null; } } - if (!result) - id = null; - else if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId)) - id = null; - else - id = absoluteValueOfId * multiplier; - results.Add(new(id, fileHolder)); + results.Add(new(fileHolder, nameWithoutExtensionIsIdFormat, id)); } } - return new(result, (from l in results orderby l.FileHolder.LastWriteTime, l.FileHolder.FullName.Length descending select l).ToArray()); + return (from l in results orderby l.FileHolder.CreationTime, l.FileHolder.FullName.Length descending select l).ToArray(); } internal static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) { List<(Models.FileHolder, string)> results = new(); + string paddedId; string checkFile; string directory; FileInfo fileInfo; int directoryIndex; - string directoryName; + string paddedIdFile; bool wrapped = false; + string directoryName; + bool paddedCheck = false; + SortedRecord sortedRecord; + Models.FileHolder fileHolder; List distinctIds = new(); List distinct = new(); + int offset = IDirectory.GetOffset(); List distinctDirectories = new(); - (bool all, SortedRecord[] sortedRecords) = GetSortedRecords(filesCollection); - foreach (SortedRecord sortedRecord in sortedRecords) + int intMinValueLength = int.MinValue.ToString().Length; + SortedRecord[] sortedRecords = GetSortedRecords(filesCollection); + for (int i = 0; i < sortedRecords.Length; i++) { tick?.Invoke(); - if (sortedRecord.FileHolder.Name.EndsWith("len") || sortedRecord.FileHolder.ExtensionLowered == ".id" || sortedRecord.FileHolder.ExtensionLowered == ".lsv" || sortedRecord.FileHolder.DirectoryName is null) + sortedRecord = sortedRecords[i]; + fileHolder = sortedRecord.FileHolder; + if (fileHolder.Name.EndsWith("len") || fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) continue; - (_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, sortedRecord.FileHolder.NameWithoutExtension); - directoryName = Path.GetFileName(sortedRecord.FileHolder.DirectoryName); - if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !sortedRecord.FileHolder.Name.StartsWith(directoryName)) + (_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension); + directoryName = Path.GetFileName(fileHolder.DirectoryName); + if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(directoryName)) { if (wrapped) continue; @@ -364,28 +376,35 @@ internal abstract partial class XDirectory wrapped = true; directory = Path.Combine(directories[directoryIndex], directoryName); } - if (all) + if (ifCanUseId && sortedRecord.NameWithoutExtensionIsIdFormat && sortedRecord.Id is not null && fileHolder.DirectoryName is not null) { - if (sortedRecord.Id is null || !sortedRecord.FileHolder.NameWithoutExtension.EndsWith(sortedRecord.Id.Value.ToString()[1..])) - throw new NotSupportedException(); + paddedId = IDirectory.GetPaddedId(intMinValueLength, offset + i, sortedRecord.Id.Value); + paddedIdFile = Path.Combine(fileHolder.DirectoryName, $"{paddedId}{fileHolder.ExtensionLowered}"); + if (!File.Exists(paddedIdFile)) + { + File.Move(fileHolder.FullName, paddedIdFile); + fileHolder = new(paddedIdFile); + if (!paddedCheck) + paddedCheck = true; + } } - if (all && ifCanUseId) - checkFile = Path.Combine(directory, $"{sortedRecord.Id}{sortedRecord.FileHolder.ExtensionLowered}"); + if (ifCanUseId) + checkFile = Path.Combine(directory, $"{sortedRecord.Id}{fileHolder.ExtensionLowered}"); else - checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}{sortedRecord.FileHolder.ExtensionLowered}"); + checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}{fileHolder.ExtensionLowered}"); if ((sortedRecord.Id is not null && distinctIds.Contains(sortedRecord.Id.Value)) || distinct.Contains(checkFile)) { - if (string.IsNullOrEmpty(sortedRecord.FileHolder.DirectoryName)) + if (string.IsNullOrEmpty(fileHolder.DirectoryName)) continue; if (!copyDuplicates) continue; - for (int i = 1; i < int.MaxValue; i++) + for (int j = 1; j < int.MaxValue; j++) { fileInfo = new(checkFile); - if (!fileInfo.Exists || sortedRecord.FileHolder.Length == fileInfo.Length && sortedRecord.FileHolder.LastWriteTime == fileInfo.LastWriteTime) - checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}dup{sortedRecord.FileHolder.ExtensionLowered}"); + if (!fileInfo.Exists || fileHolder.Length == fileInfo.Length && fileHolder.LastWriteTime == fileInfo.LastWriteTime) + checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{j}dup{fileHolder.ExtensionLowered}"); else - checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}why{sortedRecord.FileHolder.ExtensionLowered}"); + checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{j}why{fileHolder.ExtensionLowered}"); if (sortedRecord.Id is not null) { if (distinctIds.Contains(sortedRecord.Id.Value)) @@ -395,7 +414,7 @@ internal abstract partial class XDirectory if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); - results.Add(new(sortedRecord.FileHolder, checkFile)); + results.Add(new(fileHolder, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); break; @@ -405,10 +424,12 @@ internal abstract partial class XDirectory distinct.Add(checkFile); if (sortedRecord.Id is not null) distinctIds.Add(sortedRecord.Id.Value); - results.Add(new(sortedRecord.FileHolder, checkFile)); + results.Add(new(fileHolder, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); } + if (paddedCheck) + throw new Exception("Maybe need to restart application!"); return (distinctDirectories.ToArray(), results); } diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index 4f31c36..c7f5142 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -143,6 +143,7 @@ public class UnitTestResize List> subFileTuples = new(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; + string[] changesFrom = new string[] { nameof(A_Property) }; string outputResolution = _Configuration.OutputResolutions[0]; bool outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l)); (string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution); @@ -170,7 +171,7 @@ public class UnitTestResize Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) { - property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); + property = propertyLogic.GetProperty(metadata, item, subFileTuples, parseExceptions); item.Update(property); } if (property is null || item.Property is null) @@ -180,7 +181,7 @@ public class UnitTestResize _ = blurHasher.Encode(resizedFileHolder); item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder); MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item); - (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); + (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, changesFrom, mappingFromItem); outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); Assert.IsNotNull(mappingFromItem.ResizedFileHolder); resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize); diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 9129a6b..2d8cf6b 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -217,6 +217,7 @@ public class UnitTestFace List> subFileTuples = new(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; + string[] changesFrom = new string[] { nameof(A_Property) }; string outputResolution = _Configuration.OutputResolutions[0]; bool outputResolutionHasNumber = outputResolution.Any(l => char.IsNumber(l)); (string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution); @@ -244,7 +245,7 @@ public class UnitTestFace Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) { - property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); + property = propertyLogic.GetProperty(metadata, item, subFileTuples, parseExceptions); item.Update(property); } if (property is null || item.Property is null) @@ -252,7 +253,7 @@ public class UnitTestFace resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber); item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder); MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item); - (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); + (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, changesFrom, mappingFromItem); outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); Assert.IsNotNull(mappingFromItem.ResizedFileHolder); resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);