Compare commits

...

20 Commits

Author SHA1 Message Date
ee0219f321 Using PersonContainer for PersonDisplayDirectoryName 2024-12-29 11:51:08 -07:00
75cfb2a0d9 Alignment with AA 2024-12-28 19:36:44 -07:00
17be39bef9 Updated Offset date to update images from new camera 2024-12-08 19:05:54 -07:00
c085ac3f76 Random with Immich and IsArchive 2024-11-24 15:47:19 -07:00
a6b3318eec net9.0 2024-11-23 21:37:12 -07:00
49e9daea8f IgnoreExtensions 2024-11-09 09:38:28 -07:00
e2e6e15ea2 d8013da9 2024-11-09 09:38:20 -07:00
d8013da912 ResultContentCollection
ValidVideoFormatExtensions
2024-11-03 10:33:56 -07:00
4da353d150 Season breakout
DirectoryName to DirectoryFullPath
2024-11-02 14:24:28 -07:00
444e7ed71a Fast Forward Moving Picture Experts Group 2024-10-30 17:16:52 -07:00
99198cc378 Small changes 2024-10-20 20:12:05 -07:00
e532c3ef1e FaceFile for D2 2024-10-20 17:49:11 -07:00
c580c7eaa4 Identifier new properties 2024-10-14 08:59:26 -07:00
43b66f01b6 Bump 2024-10-14 08:59:18 -07:00
304b5e2a0e Patch but not understood 2024-08-31 09:31:03 -07:00
326e579d5c Runs but broken 2024-08-31 08:32:06 -07:00
f458af776a Body Changes Only 2024-08-31 08:17:11 -07:00
3b63279545 New Models Only 2024-08-31 08:09:06 -07:00
61d1ae71f6 PreVerify 2024-08-31 08:01:45 -07:00
368138bb78 Bump 2024-08-31 07:53:10 -07:00
194 changed files with 4060 additions and 1606 deletions

View File

@ -82,33 +82,60 @@ csharp_style_var_elsewhere = false:warning
csharp_style_var_for_built_in_types = false:warning csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = false:warning csharp_style_var_when_type_is_apparent = false:warning
csharp_using_directive_placement = outside_namespace csharp_using_directive_placement = outside_namespace
dotnet_analyzer_diagnostic.category-Design.severity = error
dotnet_analyzer_diagnostic.category-Documentation.severity = error
dotnet_analyzer_diagnostic.category-Globalization.severity = none
dotnet_analyzer_diagnostic.category-Interoperability.severity = error
dotnet_analyzer_diagnostic.category-Maintainability.severity = error
dotnet_analyzer_diagnostic.category-Naming.severity = none
dotnet_analyzer_diagnostic.category-Performance.severity = none
dotnet_analyzer_diagnostic.category-Reliability.severity = error
dotnet_analyzer_diagnostic.category-Security.severity = error
dotnet_analyzer_diagnostic.category-SingleFile.severity = error
dotnet_analyzer_diagnostic.category-Style.severity = error
dotnet_analyzer_diagnostic.category-Usage.severity = error
dotnet_code_quality_unused_parameters = all dotnet_code_quality_unused_parameters = all
dotnet_code_quality_unused_parameters = non_public # IDE0060: Remove unused parameter dotnet_code_quality_unused_parameters = non_public # IDE0060: Remove unused parameter
dotnet_code_quality.CAXXXX.api_surface = private, internal dotnet_code_quality.CAXXXX.api_surface = private, internal
dotnet_diagnostic.CA1001.severity = none # CA1001: Types that own disposable fields should be disposable
dotnet_diagnostic.CA1051.severity = none # CA1051: Do not declare visible instance fields
dotnet_diagnostic.CA1511.severity = warning # CA1511: Use 'ArgumentException.ThrowIfNullOrEmpty' instead of explicitly throwing a new exception instance dotnet_diagnostic.CA1511.severity = warning # CA1511: Use 'ArgumentException.ThrowIfNullOrEmpty' instead of explicitly throwing a new exception instance
dotnet_diagnostic.CA1511.severity = warning # CA1511: Use 'ArgumentException.ThrowIfNullOrEmpty' instead of explicitly throwing a new exception instance
dotnet_diagnostic.CA1513.severity = warning # Use 'ObjectDisposedException.ThrowIf' instead of explicitly throwing a new exception instance
dotnet_diagnostic.CA1816.severity = none # CA1816: Call GC.SuppressFinalize correctly
dotnet_diagnostic.CA1825.severity = warning # CA1823: Avoid zero-length array allocations dotnet_diagnostic.CA1825.severity = warning # CA1823: Avoid zero-length array allocations
dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available
dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable
dotnet_diagnostic.CA1854.severity = warning # CA1854: Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' check to avoid double lookup
dotnet_diagnostic.CA1860.severity = warning # CA1860: Prefer comparing 'Count' to 0 rather than using 'Any()', both for clarity and for performance dotnet_diagnostic.CA1860.severity = warning # CA1860: Prefer comparing 'Count' to 0 rather than using 'Any()', both for clarity and for performance
dotnet_diagnostic.CA1861.severity = none # CA1861: Prefer 'static readonly' fields over constant array arguments
dotnet_diagnostic.CA1862.severity = warning # CA1862: Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase' dotnet_diagnostic.CA1862.severity = warning # CA1862: Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'
dotnet_diagnostic.CA1866.severity = none # CA1866: Use 'string.EndsWith(char)' instead of 'string.EndsWith(string)' when you have a string with a single char
dotnet_diagnostic.CA1869.severity = none # CA1869: Avoid creating a new 'JsonSerializerOptions' instance for every serialization operation. Cache and reuse instances instead. dotnet_diagnostic.CA1869.severity = none # CA1869: Avoid creating a new 'JsonSerializerOptions' instance for every serialization operation. Cache and reuse instances instead.
dotnet_diagnostic.CA2201.severity = none # CA2201: Exception type System.NullReferenceException is reserved by the runtime
dotnet_diagnostic.CA2254.severity = none # CA2254: The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' dotnet_diagnostic.CA2254.severity = none # CA2254: The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'
dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name
dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2"); dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2");
dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant. dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant.
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement (IDE0010)
dotnet_diagnostic.IDE0028.severity = warning # IDE0028: Collection initialization can be simplified dotnet_diagnostic.IDE0028.severity = warning # IDE0028: Collection initialization can be simplified
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031) dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)
dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed
dotnet_diagnostic.IDE0048.severity = none # Parentheses preferences (IDE0047 and IDE0048)
dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049) dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049)
dotnet_diagnostic.IDE0051.severity = error # Private member '' is unused [, ]
dotnet_diagnostic.IDE0058.severity = warning # IDE0058: Expression value is never used dotnet_diagnostic.IDE0058.severity = warning # IDE0058: Expression value is never used
dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter
dotnet_diagnostic.IDE0074.severity = warning # IDE0074: Use compound assignment dotnet_diagnostic.IDE0074.severity = warning # IDE0074: Use compound assignment
dotnet_diagnostic.IDE0130.severity = none # Namespace does not match folder structure (IDE0130)
dotnet_diagnostic.IDE0200.severity = warning # IDE0200: Lambda expression can be removed [Map] dotnet_diagnostic.IDE0200.severity = warning # IDE0200: Lambda expression can be removed [Map]
dotnet_diagnostic.IDE0230.severity = warning # IDE0230: Use UTF-8 string literal
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290) dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290)
dotnet_diagnostic.IDE0300.severity = warning # IDE0300: Collection initialization can be simplified dotnet_diagnostic.IDE0300.severity = warning # IDE0300: Collection initialization can be simplified
dotnet_diagnostic.IDE0301.severity = warning #IDE0301: Collection initialization can be simplified dotnet_diagnostic.IDE0301.severity = warning #IDE0301: Collection initialization can be simplified
dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified
dotnet_diagnostic.JSON002.severity = warning # JSON002: Probable JSON string detected
dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning
dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method

3
.gitignore vendored
View File

@ -468,3 +468,6 @@ globalStorage/
[Ll]ib/ [Ll]ib/
Shared/.kanbn Shared/.kanbn
.Immich/immich-assets.json
Instance/.vscode/.UserSecrets/*

80
.vscode/launch.json vendored
View File

@ -10,8 +10,8 @@
"name": "Compare", "name": "Compare",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Compare/bin/Debug/net8.0/win-x64/Compare.dll", "program": "${workspaceFolder}/Compare/bin/Debug/net9.0/win-x64/Compare.dll",
"args": [ "args": [
"s" "s"
], ],
@ -27,8 +27,8 @@
"name": "Copy-Distinct", "name": "Copy-Distinct",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Copy-Distinct/bin/Debug/net8.0/win-x64/Copy-Distinct.dll", "program": "${workspaceFolder}/Copy-Distinct/bin/Debug/net9.0/win-x64/Copy-Distinct.dll",
"args": [], "args": [],
"env": { "env": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
@ -42,8 +42,8 @@
"name": "Duplicate-Search", "name": "Duplicate-Search",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Duplicate-Search/bin/Debug/net8.0/win-x64/Duplicate-Search.dll", "program": "${workspaceFolder}/Duplicate-Search/bin/Debug/net9.0/win-x64/Duplicate-Search.dll",
"args": [ "args": [
"s" "s"
], ],
@ -59,8 +59,8 @@
"name": "Date-Group", "name": "Date-Group",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Date-Group/bin/Debug/net8.0/win-x64/Date-Group.dll", "program": "${workspaceFolder}/Date-Group/bin/Debug/net9.0/win-x64/Date-Group.dll",
"args": [ "args": [
"s" "s"
], ],
@ -76,8 +76,8 @@
"name": "Delete-By-Distinct", "name": "Delete-By-Distinct",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Delete-By-Distinct/bin/Debug/net8.0/win-x64/Delete-By-Distinct.dll", "program": "${workspaceFolder}/Delete-By-Distinct/bin/Debug/net9.0/win-x64/Delete-By-Distinct.dll",
"args": [ "args": [
"s" "s"
], ],
@ -93,8 +93,8 @@
"name": "Delete-By-Relative", "name": "Delete-By-Relative",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Delete-By-Relative/bin/Debug/net8.0/win-x64/Delete-By-Relative.dll", "program": "${workspaceFolder}/Delete-By-Relative/bin/Debug/net9.0/win-x64/Delete-By-Relative.dll",
"args": [ "args": [
"s" "s"
], ],
@ -110,8 +110,8 @@
"name": "Drag-Drop", "name": "Drag-Drop",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Drag-Drop/bin/Debug/net8.0-windows/win-x64/Drag-Drop.dll", "program": "${workspaceFolder}/Drag-Drop/bin/Debug/net9.0-windows/win-x64/Drag-Drop.dll",
"args": [ "args": [
"s" "s"
], ],
@ -127,8 +127,8 @@
"name": "Drag-Drop-Explorer", "name": "Drag-Drop-Explorer",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Drag-Drop-Explorer/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Explorer.dll", "program": "${workspaceFolder}/Drag-Drop-Explorer/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Explorer.dll",
"args": [ "args": [
"s" "s"
], ],
@ -144,8 +144,8 @@
"name": "Drag-Drop-Move", "name": "Drag-Drop-Move",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Drag-Drop-Move/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Move.dll", "program": "${workspaceFolder}/Drag-Drop-Move/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Move.dll",
"args": [ "args": [
"s" "s"
], ],
@ -161,8 +161,8 @@
"name": "Drag-Drop-Set-Property-Item", "name": "Drag-Drop-Set-Property-Item",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Drag-Drop-Set-Property-Item/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Set-Property-Item.dll", "program": "${workspaceFolder}/Drag-Drop-Set-Property-Item/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Set-Property-Item.dll",
"args": [ "args": [
"s" "s"
], ],
@ -178,8 +178,8 @@
"name": "Instance", "name": "Instance",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildInstance",
"program": "${workspaceFolder}/Instance/bin/Debug/net8.0/win-x64/Instance.dll", "program": "${workspaceFolder}/Instance/bin/Debug/net9.0/win-x64/Instance.dll",
"args": [ "args": [
"s" "s"
], ],
@ -195,8 +195,8 @@
"name": "Mirror-Length", "name": "Mirror-Length",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Mirror-Length/bin/Debug/net8.0/win-x64/Mirror-Length.dll", "program": "${workspaceFolder}/Mirror-Length/bin/Debug/net9.0/win-x64/Mirror-Length.dll",
"args": [], "args": [],
"env": { "env": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
@ -210,8 +210,8 @@
"name": "Metadata-Query", "name": "Metadata-Query",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Metadata-Query/bin/Debug/net8.0/win-x64/Metadata-Query.dll", "program": "${workspaceFolder}/Metadata-Query/bin/Debug/net9.0/win-x64/Metadata-Query.dll",
"args": [ "args": [
"s" "s"
], ],
@ -227,8 +227,8 @@
"name": "Move-By-Id", "name": "Move-By-Id",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Move-By-Id/bin/Debug/net8.0/win-x64/Move-By-Id.dll", "program": "${workspaceFolder}/Move-By-Id/bin/Debug/net9.0/win-x64/Move-By-Id.dll",
"args": [ "args": [
"s" "s"
], ],
@ -244,8 +244,8 @@
"name": "Not-Copy-Copy", "name": "Not-Copy-Copy",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Not-Copy-Copy/bin/Debug/net8.0/win-x64/Not-Copy-Copy.dll", "program": "${workspaceFolder}/Not-Copy-Copy/bin/Debug/net9.0/win-x64/Not-Copy-Copy.dll",
"args": [ "args": [
"s" "s"
], ],
@ -261,8 +261,8 @@
"name": "Offset-Date-Time-Original", "name": "Offset-Date-Time-Original",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Offset-Date-Time-Original/bin/Debug/net8.0/win-x64/Offset-Date-Time-Original.dll", "program": "${workspaceFolder}/Offset-Date-Time-Original/bin/Debug/net9.0/win-x64/Offset-Date-Time-Original.dll",
"args": [ "args": [
"s" "s"
], ],
@ -278,8 +278,8 @@
"name": "PrepareForOld", "name": "PrepareForOld",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/PrepareForOld/bin/Debug/net8.0/win-x64/PrepareForOld.dll", "program": "${workspaceFolder}/PrepareForOld/bin/Debug/net9.0/win-x64/PrepareForOld.dll",
"args": [ "args": [
"s" "s"
], ],
@ -295,8 +295,8 @@
"name": "Person", "name": "Person",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Person/bin/Debug/net8.0/Person.dll", "program": "${workspaceFolder}/Person/bin/Debug/net9.0/Person.dll",
"args": [ "args": [
"s" "s"
], ],
@ -312,8 +312,8 @@
"name": "Rename", "name": "Rename",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Rename/bin/Debug/net8.0/win-x64/Rename.dll", "program": "${workspaceFolder}/Rename/bin/Debug/net9.0/win-x64/Rename.dll",
"args": [ "args": [
"s" "s"
], ],
@ -329,8 +329,8 @@
"name": "Set-Created-Date", "name": "Set-Created-Date",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "buildSolution",
"program": "${workspaceFolder}/Set-Created-Date/bin/Debug/net8.0/win-x64/Set-Created-Date.dll", "program": "${workspaceFolder}/Set-Created-Date/bin/Debug/net9.0/win-x64/Set-Created-Date.dll",
"args": [ "args": [
"s" "s"
], ],

3
.vscode/mklink.md vendored
View File

@ -7,8 +7,9 @@ updated: "2023-10-20T03:57:15.006Z"
# mklink # mklink
```bash ```bash
mklink /J "D:\1-Images-A\Images-4083e56a-Results\A2)People\4083e56a\{}\!" "D:\1-Images-A\Images-4083e56a-Results\E)Distance\4083e56a\{}\!"
``` ```
```bash ```bash
mklink /J "D:\1-Images-A\Images-4083e56a-Results\A2)People\4083e56a\{}\!" "D:\1-Images-A\Images-4083e56a-Results\E)Distance\4083e56a\{}\!" mklink /J "L:\Git\View-by-Distance-MKLink-Console\.Immich" "D:\1-Images-A\Images-c9dbce3b-Results\F)Immich\c9dbce3b\{}"
``` ```

View File

@ -20,8 +20,10 @@
"Hasher", "Hasher",
"Hmmss", "Hmmss",
"Hmmssfff", "Hmmssfff",
"Immich",
"jfif", "jfif",
"JOSN", "JOSN",
"makernote",
"Makernote", "Makernote",
"Makernotes", "Makernotes",
"mmod", "mmod",
@ -34,13 +36,16 @@
"Phares", "Phares",
"Phgtv", "Phgtv",
"photoshop", "photoshop",
"Photoshop",
"RDHC", "RDHC",
"Rects", "Rects",
"resnet", "resnet",
"Rijndael",
"Serilog", "Serilog",
"Subfile", "Subfile",
"Subfiles", "Subfiles",
"Syncthing", "Syncthing",
"Thumbhash",
"Unmanaged", "Unmanaged",
"Upsample", "Upsample",
"Vericruz" "Vericruz"

60
.vscode/tasks.json vendored
View File

@ -43,7 +43,17 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "build", "label": "Format-Whitespaces",
"command": "dotnet",
"type": "process",
"args": [
"format",
"whitespace"
],
"problemMatcher": "$msCompile"
},
{
"label": "buildSolution",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
@ -53,6 +63,54 @@
"/consoleloggerparameters:NoSummary" "/consoleloggerparameters:NoSummary"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
},
{
"label": "buildInstance",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Instance/Instance.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/property:WarningLevel=0",
"--verbosity",
"quiet",
"--no-restore"
],
"problemMatcher": "$msCompile"
},
{
"label": "buildShared",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Shared/View-by-Distance.Shared.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/property:WarningLevel=0",
"--verbosity",
"quiet",
"--no-restore"
],
"problemMatcher": "$msCompile"
},
{
"label": "buildMetadata",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Metadata/Metadata.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/property:WarningLevel=0",
"--verbosity",
"quiet",
"--no-restore"
],
"problemMatcher": "$msCompile"
} }
] ]
} }

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>BlurHash.Core</PackageId> <PackageId>BlurHash.Core</PackageId>
@ -18,6 +18,6 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.5" /> <PackageReference Include="System.Memory" Version="4.6.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -24,6 +24,6 @@
<ProjectReference Include="..\BlurHash.Core\BlurHash.Core.csproj" /> <ProjectReference Include="..\BlurHash.Core\BlurHash.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.BlurHash</PackageId> <PackageId>Phares.View.by.Distance.BlurHash</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -33,8 +33,8 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -10,8 +10,8 @@ namespace View_by_Distance.BlurHash.Models;
public class C2_BlurHasher : IBlurHasher public class C2_BlurHasher : IBlurHasher
{ {
private readonly Dictionary<string, string[]> _FileGroups;
private readonly IPropertyConfiguration _PropertyConfiguration; private readonly IPropertyConfiguration _PropertyConfiguration;
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration) public C2_BlurHasher(IPropertyConfiguration propertyConfiguration)
{ {
@ -22,8 +22,8 @@ public class C2_BlurHasher : IBlurHasher
public void Update(string resultsFullGroupDirectory) public void Update(string resultsFullGroupDirectory)
{ {
_FileGroups.Clear(); _FileGroups.Clear();
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]); ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs) foreach (KeyValuePair<string, ReadOnlyCollection<string>> keyValuePair in keyValuePairs)
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value); _FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
} }

View File

@ -211,7 +211,7 @@ public class Compare
} }
_Logger?.LogInformation(". . ."); _Logger?.LogInformation(". . .");
} }
string aPropertyContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "[()]"); string aPropertyContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), propertyConfiguration.ResultContentCollection);
ThirdPassToMove(propertyConfiguration, mapLogic, propertyLogic, containers, aPropertyContentCollectionDirectory); ThirdPassToMove(propertyConfiguration, mapLogic, propertyLogic, containers, aPropertyContentCollectionDirectory);
if (!isSilent) if (!isSilent)
{ {

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Compare</PackageId> <PackageId>Phares.View.by.Distance.Compare</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -33,14 +33,14 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Map\Map.csproj" /> <ProjectReference Include="..\Map\Map.csproj" />

View File

@ -20,6 +20,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -5,7 +5,6 @@ namespace View_by_Distance.Compare.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable
public string DiffPropertyDirectory { get; set; } public string DiffPropertyDirectory { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; } public Property.Models.Configuration PropertyConfiguration { get; set; }
public string[] Rename { get; set; } public string[] Rename { get; set; }
@ -13,8 +12,6 @@ public class Configuration
public string[] RenameC { get; set; } public string[] RenameC { get; set; }
public string[] Spelling { get; set; } public string[] Spelling { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>d862524f-2b48-4f47-b4c3-5a8615814ec2</UserSecretsId> <UserSecretsId>d862524f-2b48-4f47-b4c3-5a8615814ec2</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Copy.Distinct</PackageId> <PackageId>Phares.View.by.Distance.Copy.Distinct</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -35,9 +35,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -18,8 +18,8 @@ public class CopyDistinct
private readonly Configuration _Configuration; private readonly Configuration _Configuration;
private readonly IsEnvironment _IsEnvironment; private readonly IsEnvironment _IsEnvironment;
private readonly IConfigurationRoot _ConfigurationRoot; private readonly IConfigurationRoot _ConfigurationRoot;
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
private readonly Property.Models.Configuration _PropertyConfiguration; private readonly Property.Models.Configuration _PropertyConfiguration;
private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _FileGroups;
public CopyDistinct(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) public CopyDistinct(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
{ {
@ -179,8 +179,10 @@ public class CopyDistinct
{ {
progressBar = new(count, message, options); progressBar = new(count, message, options);
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey; string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
string[] directories = _FileGroups[key]; if (key != _PropertyConfiguration.ResultContent)
(distinctDirectories, toDoCollection) = IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filesCollection, directories, () => progressBar.Tick()); throw new NotImplementedException("Changed but didn't update!");
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, filesCollection);
(distinctDirectories, toDoCollection) = IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filePathsCollection, _FileGroups, () => progressBar.Tick());
progressBar.Dispose(); progressBar.Dispose();
} }
foreach (string distinctDirectory in distinctDirectories) foreach (string distinctDirectory in distinctDirectories)

View File

@ -21,6 +21,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -56,6 +73,7 @@ public class AppSettings
#pragma warning disable IL3050, IL2026 #pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026 #pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,13 +7,9 @@ namespace View_by_Distance.Copy.Distinct.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable public string[]? IgnoreExtensions { get; set; }
public Property.Models.Configuration? PropertyConfiguration { get; set; }
public string[] IgnoreExtensions { get; set; } public string? PersonBirthdayFormat { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; }
public string PersonBirthdayFormat { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -21,16 +17,32 @@ public class Configuration
return result; return result;
} }
private static Models.Configuration Get(Configuration? configuration) private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.IgnoreExtensions is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
result = new( result = new(propertyConfiguration,
configuration.IgnoreExtensions, configuration.IgnoreExtensions,
configuration.PersonBirthdayFormat, configuration.PersonBirthdayFormat);
configuration.PropertyConfiguration);
return result; return result;
} }
@ -39,15 +51,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
result = Get(configuration); PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -13,10 +13,9 @@ public class Configuration
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
[JsonConstructor] [JsonConstructor]
public Configuration( public Configuration(Property.Models.Configuration propertyConfiguration,
string[] ignoreExtensions, string[] ignoreExtensions,
string personBirthdayFormat, string personBirthdayFormat)
Property.Models.Configuration propertyConfiguration)
{ {
IgnoreExtensions = ignoreExtensions; IgnoreExtensions = ignoreExtensions;
PersonBirthdayFormat = personBirthdayFormat; PersonBirthdayFormat = personBirthdayFormat;

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>8004d966-1a9e-4545-a220-83f32b6a13e9</UserSecretsId> <UserSecretsId>8004d966-1a9e-4545-a220-83f32b6a13e9</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Date.Group</PackageId> <PackageId>Phares.View.by.Distance.Date.Group</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -34,15 +34,15 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -422,7 +422,7 @@ public class DateGroup
{ {
try try
{ {
windowsShortcut = new() { Path = item.FilePath.DirectoryName, Description = item.FilePath.Name }; windowsShortcut = new() { Path = item.FilePath.DirectoryFullPath, Description = item.FilePath.Name };
windowsShortcut.Save(string.Concat(fullFileName, ".lnk")); windowsShortcut.Save(string.Concat(fullFileName, ".lnk"));
windowsShortcut.Dispose(); windowsShortcut.Dispose();
} }

View File

@ -20,6 +20,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,17 +7,13 @@ namespace View_by_Distance.Date.Group.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable
public bool? ByCreateDateShortcut { get; set; } public bool? ByCreateDateShortcut { get; set; }
public bool? ByDay { get; set; } public bool? ByDay { get; set; }
public bool? ByHash { get; set; } public bool? ByHash { get; set; }
public bool? BySeason { get; set; } public bool? BySeason { get; set; }
public bool? ByWeek { get; set; } public bool? ByWeek { get; set; }
public bool? KeepFullPath { get; set; } public bool? KeepFullPath { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; } public Property.Models.Configuration? PropertyConfiguration { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -25,10 +21,28 @@ public class Configuration
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.ByCreateDateShortcut is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration) private static Models.Configuration Get(Configuration? configuration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
if (configuration.ByCreateDateShortcut is null) throw new NullReferenceException(nameof(configuration.ByCreateDateShortcut)); if (configuration.ByCreateDateShortcut is null) throw new NullReferenceException(nameof(configuration.ByCreateDateShortcut));
if (configuration.ByDay is null) throw new NullReferenceException(nameof(configuration.ByDay)); if (configuration.ByDay is null) throw new NullReferenceException(nameof(configuration.ByDay));
if (configuration.ByHash is null) throw new NullReferenceException(nameof(configuration.ByHash)); if (configuration.ByHash is null) throw new NullReferenceException(nameof(configuration.ByHash));
@ -51,16 +65,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
PreVerify(configurationRoot, configuration);
result = Get(configuration); result = Get(configuration);
if (configuration is null) throw new NullReferenceException(nameof(configuration));
return result; return result;
} }

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>0589ecff-b296-48be-a3f7-7bf27f453975</UserSecretsId> <UserSecretsId>0589ecff-b296-48be-a3f7-7bf27f453975</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Delete.By.Distinct</PackageId> <PackageId>Phares.View.by.Distance.Delete.By.Distinct</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -34,14 +34,14 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -27,6 +27,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -58,7 +75,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>ead2e5ee-5f40-4151-bdb6-31d630d94f28</UserSecretsId> <UserSecretsId>ead2e5ee-5f40-4151-bdb6-31d630d94f28</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Delete.By.Relative</PackageId> <PackageId>Phares.View.by.Distance.Delete.By.Relative</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -34,14 +34,14 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -22,6 +22,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -40,7 +57,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Distance</PackageId> <PackageId>Phares.View.by.Distance.Distance</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -36,7 +36,7 @@
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />

View File

@ -14,24 +14,26 @@ public class DistanceLimits : IDistanceLimits
public double FaceDistancePermyriad { init; get; } public double FaceDistancePermyriad { init; get; }
public int SortingMaximumPerFaceShouldBeHigh { init; get; } public int SortingMaximumPerFaceShouldBeHigh { init; get; }
public bool RangeDaysDeltaTargetLessThenUpper { init; get; } public bool RangeDaysDeltaTargetLessThenUpper { init; get; }
public double RangeDistanceToleranceUpperLimit { init; get; }
public DistanceLimits(int faceAreaPermyriad, public DistanceLimits(int faceAreaPermyriad,
int faceConfidencePercent, int faceConfidencePercent,
int faceDistancePermyriad, int faceDistancePermyriad,
int[] rangeDaysDeltaTolerance, int[] rangeDaysDeltaTolerance,
float[] rangeDistanceTolerance, float[] rangeDistanceTolerance,
float[] rangeFaceAreaPermyriadTolerance, float[] rangeFaceAreaTolerance,
float[] rangeFaceConfidence, float[] rangeFaceConfidence,
int sortingMaximumPerFaceShouldBeHigh, int sortingMaximumPerFaceShouldBeHigh,
int? useFiltersCounter = null) int? useFiltersCounter = null)
{ {
RangeDistanceToleranceUpperLimit = rangeDistanceTolerance[2];
SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh;
RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2]; RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2];
if (useFiltersCounter is null) if (useFiltersCounter is null)
{ {
RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1]; RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1];
FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1]; FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1];
FaceAreaPermyriad = faceAreaPermyriad * rangeFaceAreaPermyriadTolerance[1]; FaceAreaPermyriad = faceAreaPermyriad * rangeFaceAreaTolerance[1];
FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1]; FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1];
} }
else else
@ -39,7 +41,7 @@ public class DistanceLimits : IDistanceLimits
RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[1]; RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[1];
FaceConfidencePercent = faceConfidencePercent * ((rangeFaceConfidence[2] - rangeFaceConfidence[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceConfidence[1]; FaceConfidencePercent = faceConfidencePercent * ((rangeFaceConfidence[2] - rangeFaceConfidence[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceConfidence[1];
FaceDistancePermyriad = faceDistancePermyriad * ((rangeDistanceTolerance[2] - rangeDistanceTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDistanceTolerance[1]; FaceDistancePermyriad = faceDistancePermyriad * ((rangeDistanceTolerance[2] - rangeDistanceTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDistanceTolerance[1];
FaceAreaPermyriad = faceAreaPermyriad * ((rangeFaceAreaPermyriadTolerance[2] - rangeFaceAreaPermyriadTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceAreaPermyriadTolerance[1]; FaceAreaPermyriad = faceAreaPermyriad * ((rangeFaceAreaTolerance[2] - rangeFaceAreaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceAreaTolerance[1];
} }
} }

View File

@ -1,10 +1,13 @@
using ShellProgressBar; using ShellProgressBar;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Data;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.FaceRecognitionDotNet;
using View_by_Distance.Map.Models;
using View_by_Distance.Property.Models.Stateless; using View_by_Distance.Property.Models.Stateless;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Methods;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Distance.Models; namespace View_by_Distance.Distance.Models;
@ -50,6 +53,7 @@ public partial class E_Distance : IDistance
private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> intersectFaces) private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> intersectFaces)
{ {
FaceDistanceContainer[] results; FaceDistanceContainer[] results;
DateTime dateTime;
int wholePercentages; int wholePercentages;
int confidencePercent; int confidencePercent;
FaceDistance faceDistance; FaceDistance faceDistance;
@ -61,14 +65,15 @@ public partial class E_Distance : IDistance
throw new NotSupportedException(); throw new NotSupportedException();
if (face.Mapping?.MappingFromFilterPost is null) if (face.Mapping?.MappingFromFilterPost is null)
throw new NotSupportedException(); throw new NotSupportedException();
dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_FaceConfidencePercent, face.Location.Confidence); confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_FaceConfidencePercent, face.Location.Confidence);
wholePercentages = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); wholePercentages = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding)
faceDistance = new(confidencePercent, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping?.MappingFromFilterPost, mappingFromItem.Id, mappingFromItem.IsWrongYear, wholePercentages); faceDistance = new(confidencePercent, dateTime, faceEncoding, face.Mapping?.MappingFromFilterPost, mappingFromItem.Id, mappingFromItem.IsWrongYear, wholePercentages);
else else
{ {
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
faceDistance = new(confidencePercent, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping?.MappingFromFilterPost, mappingFromItem.Id, mappingFromItem.IsWrongYear, wholePercentages); faceDistance = new(confidencePercent, dateTime, faceEncoding, face.Mapping?.MappingFromFilterPost, mappingFromItem.Id, mappingFromItem.IsWrongYear, wholePercentages);
lock (intersectFaces) lock (intersectFaces)
face.SetFaceDistance(faceDistance); face.SetFaceDistance(faceDistance);
} }
@ -91,7 +96,7 @@ public partial class E_Distance : IDistance
return new(faceDistanceEncodings); return new(faceDistanceEncodings);
} }
private List<(Face Face, double? Length)> GetValues(MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding) private List<(Face Face, double? Length)> GetValues(IDistanceLimits distanceLimits, MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding)
{ {
List<(Face Face, double? Length)> results = []; List<(Face Face, double? Length)> results = [];
Face face; Face face;
@ -112,6 +117,8 @@ public partial class E_Distance : IDistance
{ {
face = intersectFaces[i]; face = intersectFaces[i];
faceDistanceLength = faceDistanceLengths[i]; faceDistanceLength = faceDistanceLengths[i];
if (faceDistanceLength.Length is null || faceDistanceLength.Length > distanceLimits.RangeDistanceToleranceUpperLimit)
continue;
if (faceDistanceLength.Length is null) if (faceDistanceLength.Length is null)
throw new NotSupportedException(); throw new NotSupportedException();
results.Add(new(face, faceDistanceLength.Length.Value)); results.Add(new(face, faceDistanceLength.Length.Value));
@ -119,10 +126,10 @@ public partial class E_Distance : IDistance
return results; return results;
} }
private (Face, double?)[] GetClosestFaceByDistanceIgnoringTolerance(MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding) private (Face, double?)[] GetClosestFaceByDistanceIgnoringTolerance(IDistanceLimits distanceLimits, MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding)
{ {
(Face, double?)[] results; (Face, double?)[] results;
List<(Face Face, double? Length)> collection = GetValues(mappingFromItem, intersectFaces, modelsFaceEncoding); List<(Face Face, double? Length)> collection = GetValues(distanceLimits, mappingFromItem, intersectFaces, modelsFaceEncoding);
results = (from l in collection where l.Length < _RangeDistanceToleranceAverage orderby l.Length select l).Take(1).ToArray(); results = (from l in collection where l.Length < _RangeDistanceToleranceAverage orderby l.Length select l).Take(1).ToArray();
if (results.Length > 0) if (results.Length > 0)
{ {
@ -132,11 +139,11 @@ public partial class E_Distance : IDistance
return results; return results;
} }
private static List<(Face, double?)> GetMatchingFacesByFaceEncoding(Face[] filteredFaces, string? json) private static List<(Face, double?)> GetMatchingFacesByFaceEncoding(List<Face> faces, string? json)
{ {
List<(Face, double?)> results = []; List<(Face, double?)> results = [];
string check; string check;
foreach (Face face in filteredFaces) foreach (Face face in faces)
{ {
if (json is null || face.FaceEncoding is null) if (json is null || face.FaceEncoding is null)
continue; continue;
@ -165,7 +172,7 @@ public partial class E_Distance : IDistance
mappedFaceDirectory = Path.GetDirectoryName(file); mappedFaceDirectory = Path.GetDirectoryName(file);
if (mappedFaceDirectory is null) if (mappedFaceDirectory is null)
throw new NotSupportedException(); throw new NotSupportedException();
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); deterministicHashCodeKey = IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
checkFile = Path.Combine(mappedFaceDirectory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}"); checkFile = Path.Combine(mappedFaceDirectory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}");
if (checkFile == file) if (checkFile == file)
continue; continue;
@ -201,17 +208,14 @@ public partial class E_Distance : IDistance
} }
} }
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, FilePath filePath, MappingFromItem mappingFromItem, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers) public void LookForMatchFacesAndPossiblyRename(bool overrideForFaceImages, IDistanceLimits distanceLimits, IFaceD dFace, FilePath filePath, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
{ {
string? json; string? json;
string[] matches; string[] matches;
FileInfo? fileInfo; FileInfo? fileInfo;
List<Face> intersectFaces; List<Face> intersectFaces;
List<(Face, double?)> checkFaces = [];
Shared.Models.FaceEncoding? modelsFaceEncoding; Shared.Models.FaceEncoding? modelsFaceEncoding;
Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray(); List<(Face Face, double? Distance)> checkFaces = [];
if (filteredFaces.Length != faces.Count)
checkFaces.Clear();
foreach (LocationContainer locationContainer in locationContainers) foreach (LocationContainer locationContainer in locationContainers)
{ {
if (_Renamed.Contains(locationContainer.FilePath.FullName)) if (_Renamed.Contains(locationContainer.FilePath.FullName))
@ -232,8 +236,8 @@ public partial class E_Distance : IDistance
MoveUnableToMatch(locationContainer.FilePath); MoveUnableToMatch(locationContainer.FilePath);
continue; continue;
} }
if (filteredFaces.Length > 0) if (faces.Count > 0)
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, json)); checkFaces.AddRange(GetMatchingFacesByFaceEncoding(faces, json));
if (checkFaces.Count == 1) if (checkFaces.Count == 1)
_Debug.Add(0); _Debug.Add(0);
if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json)) if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json))
@ -242,11 +246,11 @@ public partial class E_Distance : IDistance
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json); modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
if (modelsFaceEncoding is null) if (modelsFaceEncoding is null)
throw new NotSupportedException(); throw new NotSupportedException();
if (filteredFaces.Length > 0) if (faces.Count > 0)
{ {
intersectFaces = Shared.Models.Stateless.Methods.ILocation.FilterByIntersect(filteredFaces, _RectangleIntersectMinimum, locationContainer.WholePercentages); intersectFaces = Shared.Models.Stateless.Methods.ILocation.FilterByIntersect(faces, _RectangleIntersectMinimum, locationContainer.WholePercentages);
if (intersectFaces.Count > 0) if (intersectFaces.Count > 0)
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(mappingFromItem, intersectFaces, modelsFaceEncoding)); checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(distanceLimits, mappingFromItem, intersectFaces, modelsFaceEncoding));
} }
} }
if (checkFaces.Count == 0) if (checkFaces.Count == 0)
@ -261,7 +265,7 @@ public partial class E_Distance : IDistance
MoveUnableToMatch(locationContainer.FilePath); MoveUnableToMatch(locationContainer.FilePath);
continue; continue;
} }
fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, filePath, mappingFromItem, locationContainer.FilePath.FullName, checkFaces); fileInfo = CheckFileThenGetFileInfo(dFace.FileNameExtension, filePath, mappingFromItem, locationContainer.FilePath.FullName, checkFaces);
if (fileInfo is not null) if (fileInfo is not null)
{ {
if (_DistanceRenameToMatch && fileInfo is not null) if (_DistanceRenameToMatch && fileInfo is not null)
@ -275,6 +279,15 @@ public partial class E_Distance : IDistance
} }
continue; continue;
} }
if (overrideForFaceImages)
{
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
if (json is null || !json.Contains(nameof(DateTime)))
{
if (checkFaces.Count == 1)
dFace.ReSaveFace(exifDirectory, locationContainer.FilePath, checkFaces[0].Face, mappedFile: true);
}
}
if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name)) if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name))
{ {
lock (_AllMappedFaceFiles) lock (_AllMappedFaceFiles)
@ -322,10 +335,88 @@ public partial class E_Distance : IDistance
File.WriteAllLines(eDistanceContentFileName, results); File.WriteAllLines(eDistanceContentFileName, results);
} }
public static void PreFilterSetFaceDistances(int maxDegreeOfParallelism, long ticks, ReadOnlyCollection<Face> distinctFilteredFaces) public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedWithEncoding(ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped)
{
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
string? json;
LocationContainer? locationContainer;
Shared.Models.FaceEncoding? faceEncoding;
FaceRecognitionDotNet.FaceEncoding? encoding;
Dictionary<int, LocationContainer> keyValuePairs;
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mapped)
{
keyValuePairs = [];
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
{
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(keyValue.Value.ExifDirectory);
faceEncoding = json is null ? null : JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
if (faceEncoding is null)
continue;
encoding = FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
locationContainer = LocationContainer.Get(keyValue.Value, encoding, keepExifDirectory: false);
keyValuePairs.Add(keyValue.Key, locationContainer);
}
results.Add(keyValuePair.Key, new(keyValuePairs));
}
return new(results);
}
public static List<LocationContainer> GetPreFilterLocationContainer(int maxDegreeOfParallelism, Configuration configuration, string focusDirectory, string focusModel, int? skipPersonWithMoreThen, long ticks, MapLogic mapLogic, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped, List<LocationContainer> available)
{
List<LocationContainer> results = [];
string? json;
string? model;
bool? canReMap;
bool? isFocusPerson;
bool? inSkipCollection;
Shared.Models.FaceEncoding? faceEncoding;
FaceRecognitionDotNet.FaceEncoding? encoding;
ReadOnlyDictionary<int, LocationContainer>? keyValuePairs;
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
foreach (LocationContainer locationContainer in available)
{
if (mapped.TryGetValue(locationContainer.Id, out keyValuePairs))
{
if (keyValuePairs.ContainsKey(locationContainer.WholePercentages))
continue;
}
if (locationContainer.ExifDirectory is null || locationContainer.FaceFile is null)
continue;
inSkipCollection = mapLogic.InSkipCollection(locationContainer.Id, locationContainer.WholePercentages);
if (inSkipCollection is not null && inSkipCollection.Value)
continue;
wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(locationContainer.Id);
canReMap = Map.Models.Stateless.Methods.IMapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, locationContainer.WholePercentages);
if (canReMap is not null && !canReMap.Value)
continue;
isFocusPerson = mapLogic.IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, locationContainer.WholePercentages);
if (isFocusPerson is not null && !isFocusPerson.Value)
continue;
if (!string.IsNullOrEmpty(focusModel))
{
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(locationContainer.ExifDirectory);
if (string.IsNullOrEmpty(model) || !model.Contains(focusModel))
continue;
}
if (!string.IsNullOrEmpty(focusDirectory))
{
if (!locationContainer.FilePath.DirectoryFullPath.Contains(focusDirectory))
continue;
}
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.ExifDirectory);
faceEncoding = json is null ? null : JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
if (faceEncoding is null)
continue;
encoding = FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
results.Add(LocationContainer.Get(locationContainer, encoding, keepExifDirectory: false));
}
return results;
}
public static void PreFilterSetFaceDistances(int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<Face> distinctValidImageFaces)
{ {
List<Face> faces = []; List<Face> faces = [];
foreach (Face face in distinctFilteredFaces) foreach (Face face in distinctValidImageFaces)
{ {
if (face.Mapping?.MappingFromFilterPre is null) if (face.Mapping?.MappingFromFilterPre is null)
throw new NotSupportedException(); throw new NotSupportedException();
@ -335,8 +426,10 @@ public partial class E_Distance : IDistance
continue; continue;
if (face.Mapping.MappingFromFilterPre.IsFocusRelativePath is not null && !face.Mapping.MappingFromFilterPre.IsFocusRelativePath.Value) if (face.Mapping.MappingFromFilterPre.IsFocusRelativePath is not null && !face.Mapping.MappingFromFilterPre.IsFocusRelativePath.Value)
continue; continue;
if (face.FaceEncoding is not null && face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding _) // if (!configuration.ReMap && face.Mapping.MappingFromPerson is not null)
continue; // continue;
if (!configuration.ReMap && face.FaceEncoding is not null && face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding)
throw new NotSupportedException($"{face.FaceEncoding} should not be null!");
faces.Add(face); faces.Add(face);
} }
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
@ -352,18 +445,19 @@ public partial class E_Distance : IDistance
throw new NotSupportedException(); throw new NotSupportedException();
progressBar.Tick(); progressBar.Tick();
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
FaceDistance faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping.MappingFromFilterPost, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.WholePercentages); DateTime dateTime = face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
FaceDistance faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, dateTime, faceEncoding, face.Mapping.MappingFromFilterPost, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.WholePercentages);
lock (face) lock (face)
face.SetFaceDistance(faceDistance); face.SetFaceDistance(faceDistance);
}); });
} }
private static List<SortingContainer> GetSortingContainers(Map.Models.Configuration mapConfiguration, IDistanceLimits distanceLimits, Face face, FaceDistance faceDistanceEncoding, List<Sorting> sortingCollection) private static List<SortingContainer> GetSortingContainers(Configuration mapConfiguration, IDistanceLimits distanceLimits, Face face, FaceDistance faceDistanceEncoding, List<Sorting> sortingCollection)
{ {
List<SortingContainer> results = []; List<SortingContainer> results = [];
SortingContainer sortingContainer;
int days = 0, distance = 0; int days = 0, distance = 0;
Sorting[] collection = Shared.Models.Stateless.Methods.ISorting.Sort(sortingCollection); SortingContainer sortingContainer;
Sorting[] collection = ISorting.Sort(sortingCollection);
foreach (Sorting sorting in collection) foreach (Sorting sorting in collection)
{ {
if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.WholePercentages is null) if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.WholePercentages is null)
@ -389,7 +483,7 @@ public partial class E_Distance : IDistance
return results; return results;
} }
private static List<Sorting> GetSortingCollection(Map.Models.MapLogic mapLogic, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, int i, Face face, FaceDistance faceDistanceEncoding) private static List<Sorting> GetSortingCollection(MapLogic mapLogic, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, int i, Face face, FaceDistance faceDistanceEncoding)
{ {
List<Sorting> results; List<Sorting> results;
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
@ -397,19 +491,21 @@ public partial class E_Distance : IDistance
return results; return results;
} }
public static ReadOnlyCollection<FaceDistanceContainer> GetFaceDistanceContainers(ReadOnlyCollection<Face> distinctFilteredFaces) public static ReadOnlyCollection<FaceDistanceContainer> GetFaceDistanceContainers(ReadOnlyCollection<Face> distinctValidImageFaces)
{ {
ReadOnlyCollection<FaceDistanceContainer> results; ReadOnlyCollection<FaceDistanceContainer> results;
DateTime dateTime;
FaceDistance faceDistance; FaceDistance faceDistance;
FaceDistanceContainer faceDistanceContainer; FaceDistanceContainer faceDistanceContainer;
List<FaceDistanceContainer> collection = []; List<FaceDistanceContainer> collection = [];
foreach (Face face in distinctFilteredFaces) foreach (Face face in distinctValidImageFaces)
{ {
if (face.Mapping?.MappingFromLocation is null) if (face.Mapping?.MappingFromLocation is null)
throw new NotSupportedException(); throw new NotSupportedException();
if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding)
continue; continue;
faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), faceEncoding, face.Mapping.MappingFromFilterPost, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.WholePercentages); dateTime = face.Mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, dateTime, faceEncoding, face.Mapping.MappingFromFilterPost, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromLocation.WholePercentages);
faceDistanceContainer = new(face, faceDistance); faceDistanceContainer = new(face, faceDistance);
collection.Add(faceDistanceContainer); collection.Add(faceDistanceContainer);
} }
@ -417,7 +513,23 @@ public partial class E_Distance : IDistance
return results; return results;
} }
public static FaceDistanceContainer[] FilteredPostLoadFaceDistanceContainers(Map.Models.MapLogic mapLogic, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits) public static List<LocationContainer> GetPostFilterLocationContainer(MapLogic mapLogic, List<LocationContainer> preFiltered, DistanceLimits distanceLimits)
{
List<LocationContainer> results = [];
foreach (LocationContainer locationContainer in preFiltered)
{
if (locationContainer.FaceFile is null)
continue;
if (locationContainer.FaceFile.AreaPermyriad < distanceLimits.FaceAreaPermyriad)
continue;
if (locationContainer.FaceFile.ConfidencePercent < distanceLimits.FaceConfidencePercent)
continue;
results.Add(locationContainer);
}
return results;
}
public static FaceDistanceContainer[] FilteredPostLoadFaceDistanceContainers(MapLogic mapLogic, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits)
{ {
List<FaceDistanceContainer> results = []; List<FaceDistanceContainer> results = [];
foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers)
@ -446,7 +558,46 @@ public partial class E_Distance : IDistance
return results.ToArray(); return results.ToArray();
} }
public static ReadOnlyCollection<SortingContainer> SetFaceMappingSortingCollectionThenGetSortedSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration mapConfiguration, long ticks, Map.Models.MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers) private static ReadOnlyCollection<LocationContainer> GetReadOnlyLocationContainer(ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> postFiltered)
{
List<LocationContainer> results = [];
foreach (LocationContainer locationContainer in postFiltered)
results.Add(locationContainer);
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mappedWithEncoding)
{
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
results.Add(keyValue.Value);
}
return new(results);
}
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(IDlibDotNet dlibDotNet, Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> preFiltered, DistanceLimits distanceLimits, List<LocationContainer> postFiltered)
{
List<LocationContainer> results = [];
ReadOnlyCollection<LocationContainer> locationContainers;
ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered);
foreach (LocationContainer locationContainer in postFiltered)
{
dlibDotNet.Tick();
locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer);
foreach (LocationContainer item in locationContainers)
{
if (item.LengthPermyriad is null)
continue;
if (item.LengthPermyriad > distanceLimits.FaceDistancePermyriad)
break;
if (!mapConfiguration.SaveSortingWithoutPerson && item.PersonKey is null)
continue;
if (item.Id == locationContainer.Id && item.WholePercentages == locationContainer.WholePercentages)
continue;
results.Add(item);
}
}
LocationContainer[] array = results.OrderBy(l => l.LengthPermyriad).ToArray();
return new(array);
}
public static ReadOnlyCollection<SortingContainer> SetFaceMappingSortingCollectionThenGetSortedSortingContainers(int maxDegreeOfParallelism, Configuration mapConfiguration, long ticks, MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers)
{ {
List<SortingContainer> results = []; List<SortingContainer> results = [];
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
@ -470,13 +621,13 @@ public partial class E_Distance : IDistance
} }
}); });
if (distanceLimits is not null && distanceLimits.RangeDaysDeltaTargetLessThenUpper) if (distanceLimits is not null && distanceLimits.RangeDaysDeltaTargetLessThenUpper)
results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(results); results = ISortingContainer.Sort(results);
else else
results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(results); results = ISortingContainer.SortUsingDaysDelta(results);
return new(results); return new(results);
} }
private static ReadOnlyCollection<RelationContainer> GetRelationCollections(int faceDistancePermyriad, int locationContainerDistanceTake, float distanceTolerance, List<Record> records) private static ReadOnlyCollection<RelationContainer> GetRelationCollections(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float distanceTolerance, List<Record> records)
{ {
List<RelationContainer> results = []; List<RelationContainer> results = [];
string fileName; string fileName;
@ -496,6 +647,7 @@ public partial class E_Distance : IDistance
foreach (Record record in records) foreach (Record record in records)
{ {
mappedRelations = []; mappedRelations = [];
FaceDistance faceDistanceLength;
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(record.FilePath.FullName); fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(record.FilePath.FullName);
if (files.Count > 1) if (files.Count > 1)
{ {
@ -508,10 +660,12 @@ public partial class E_Distance : IDistance
fileName = Path.GetFileName(files[i]); fileName = Path.GetFileName(files[i]);
if (fileName == fileHolder.Name) if (fileName == fileHolder.Name)
continue; continue;
FaceDistance faceDistance = faceDistanceLengths[i]; faceDistanceLength = faceDistanceLengths[i];
if (faceDistance.Length is null || faceDistance.Length.Value > distanceTolerance) if (faceDistanceLength.Length is null || faceDistanceLength.Length > distanceLimits.RangeDistanceToleranceUpperLimit)
continue; continue;
distancePermyriad = (int)(faceDistance.Length.Value * faceDistancePermyriad); if (faceDistanceLength.Length is null || faceDistanceLength.Length.Value > distanceTolerance)
continue;
distancePermyriad = (int)(faceDistanceLength.Length.Value * faceDistancePermyriad);
mappedRelations.Add(new(distancePermyriad, files[i])); mappedRelations.Add(new(distancePermyriad, files[i]));
} }
} }
@ -521,7 +675,7 @@ public partial class E_Distance : IDistance
return new(results); return new(results);
} }
ReadOnlyCollection<RelationContainer> IDistance.GetRelationContainers(int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer> locationContainers) ReadOnlyCollection<RelationContainer> IDistance.GetRelationContainers(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer> locationContainers)
{ {
ReadOnlyCollection<RelationContainer> result; ReadOnlyCollection<RelationContainer> result;
string? json; string? json;
@ -539,7 +693,7 @@ public partial class E_Distance : IDistance
faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding); faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding);
records.Add(new(locationContainer.FilePath, faceRecognitionDotNetFaceEncoding)); records.Add(new(locationContainer.FilePath, faceRecognitionDotNetFaceEncoding));
} }
result = GetRelationCollections(faceDistancePermyriad, locationContainerDistanceTake, locationContainerDistanceTolerance, records); result = GetRelationCollections(distanceLimits, faceDistancePermyriad, locationContainerDistanceTake, locationContainerDistanceTolerance, records);
return result; return result;
} }

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -26,9 +26,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -59,7 +59,7 @@ public partial class DragDropExplorer : Form
Controls.Add(_FirstTextBox); Controls.Add(_FirstTextBox);
} }
void Form1_Load(object? sender, EventArgs e) private void Form1_Load(object? sender, EventArgs e)
{ {
try try
{ {
@ -81,7 +81,7 @@ public partial class DragDropExplorer : Form
return result; return result;
} }
void TextBox_LostFocus(object? sender, EventArgs e) private void TextBox_LostFocus(object? sender, EventArgs e)
{ {
try try
{ {
@ -99,7 +99,7 @@ public partial class DragDropExplorer : Form
} }
} }
void Form1_DragEnter(object? sender, DragEventArgs e) private void Form1_DragEnter(object? sender, DragEventArgs e)
{ {
try try
{ {
@ -112,7 +112,7 @@ public partial class DragDropExplorer : Form
} }
} }
void Form1_DragDrop(object? sender, DragEventArgs e) private void Form1_DragDrop(object? sender, DragEventArgs e)
{ {
try try
{ {

View File

@ -20,6 +20,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -6,9 +6,9 @@ public class Program
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
ApplicationConfiguration.Initialize(); // ApplicationConfiguration.Initialize();
Application.Run(new DragDropExplorer()); Application.Run(new DragDropExplorer());
} }

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -26,10 +26,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -16,6 +16,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -6,9 +6,9 @@ public class Program
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
ApplicationConfiguration.Initialize(); // ApplicationConfiguration.Initialize();
Application.Run(new DragDropMove()); Application.Run(new DragDropMove());
} }

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<UserSecretsId>7b153e3d-672b-4f7a-888a-cb31645a2439</UserSecretsId> <UserSecretsId>7b153e3d-672b-4f7a-888a-cb31645a2439</UserSecretsId>
</PropertyGroup> </PropertyGroup>
@ -27,9 +27,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />

View File

@ -64,7 +64,7 @@ public partial class DragDropSearch : Form
Controls.Add(_TextBox); Controls.Add(_TextBox);
} }
void Form1_Load(object? sender, EventArgs e) private void Form1_Load(object? sender, EventArgs e)
{ {
try try
{ {
@ -79,7 +79,7 @@ public partial class DragDropSearch : Form
} }
} }
void TextBox_LostFocus(object? sender, EventArgs e) private void TextBox_LostFocus(object? sender, EventArgs e)
{ {
try try
{ {
@ -92,7 +92,7 @@ public partial class DragDropSearch : Form
} }
} }
void Form1_DragEnter(object? sender, DragEventArgs e) private void Form1_DragEnter(object? sender, DragEventArgs e)
{ {
try try
{ {
@ -105,7 +105,7 @@ public partial class DragDropSearch : Form
} }
} }
void LoadData() private void LoadData()
{ {
Container[] containers; Container[] containers;
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}"); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}");
@ -162,13 +162,13 @@ public partial class DragDropSearch : Form
{ {
Text = item.FilePath.Name; Text = item.FilePath.Name;
_TextBox.Text = item.FilePath.FullName; _TextBox.Text = item.FilePath.FullName;
if (!string.IsNullOrEmpty(item.FilePath.DirectoryName)) if (!string.IsNullOrEmpty(item.FilePath.DirectoryFullPath))
_ = Process.Start("explorer.exe", string.Concat("\"", item.FilePath.DirectoryName, "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", item.FilePath.DirectoryFullPath, "\""));
} }
} }
} }
void Form1_DragDrop(object? sender, DragEventArgs e) private void Form1_DragDrop(object? sender, DragEventArgs e)
{ {
try try
{ {

View File

@ -20,6 +20,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,8 +7,6 @@ namespace View_by_Distance.Drag_Drop.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable
public bool? CheckDFaceAndUpWriteDates { get; set; } public bool? CheckDFaceAndUpWriteDates { get; set; }
public bool? CheckJsonForDistanceResults { get; set; } public bool? CheckJsonForDistanceResults { get; set; }
public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; }
@ -16,40 +14,38 @@ public class Configuration
public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } public bool? ForceFaceLastWriteTimeToCreationTime { get; set; }
public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; }
public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } public bool? ForceResizeLastWriteTimeToCreationTime { get; set; }
public string[] IgnoreExtensions { get; set; } public string[]? IgnoreExtensions { get; set; }
public string[] JLinks { get; set; } public string[]? JLinks { get; set; }
public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { get; set; } public string[]? LoadOrCreateThenSaveDistanceResultsForOutputResolutions { get; set; }
public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; } public string[]? LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; }
public string[] MixedYearRelativePaths { get; set; } public string[]? MixedYearRelativePaths { get; set; }
public string ModelDirectory { get; set; } public string? ModelDirectory { get; set; }
public string ModelName { get; set; } public string? ModelName { get; set; }
public int? NumberOfJitters { get; set; } public int? NumberOfJitters { get; set; }
public int? NumberOfTimesToUpsample { get; set; } public int? NumberOfTimesToUpsample { get; set; }
public string OutputExtension { get; set; } public string? OutputExtension { get; set; }
public int? OutputQuality { get; set; } public int? OutputQuality { get; set; }
public string[] OutputResolutions { get; set; } public string[]? OutputResolutions { get; set; }
public bool? OverrideForFaceImages { get; set; } public bool? OverrideForFaceImages { get; set; }
public bool? OverrideForFaceLandmarkImages { get; set; } public bool? OverrideForFaceLandmarkImages { get; set; }
public bool? OverrideForResizeImages { get; set; } public bool? OverrideForResizeImages { get; set; }
public string PersonBirthdayFormat { get; set; } public string? PersonBirthdayFormat { get; set; }
public string PredictorModelName { get; set; } public string? PredictorModelName { get; set; }
public bool? PropertiesChangedForDistance { get; set; } public bool? PropertiesChangedForDistance { get; set; }
public bool? PropertiesChangedForFaces { get; set; } public bool? PropertiesChangedForFaces { get; set; }
public bool? PropertiesChangedForIndex { get; set; } public bool? PropertiesChangedForIndex { get; set; }
public bool? PropertiesChangedForMetadata { get; set; } public bool? PropertiesChangedForMetadata { get; set; }
public bool? PropertiesChangedForResize { get; set; } public bool? PropertiesChangedForResize { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; } public Property.Models.Configuration? PropertyConfiguration { get; set; }
public bool? Reverse { get; set; } public bool? Reverse { get; set; }
public string[] SaveFaceLandmarkForOutputResolutions { get; set; } public string[]? SaveFaceLandmarkForOutputResolutions { get; set; }
public bool? SaveFullYearOfRandomFiles { get; set; } public bool? SaveFullYearOfRandomFiles { get; set; }
public string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions { get; set; } public string[]? SaveFilteredOriginalImagesFromJLinksForOutputResolutions { get; set; }
public string[] SaveShortcutsForOutputResolutions { get; set; } public string[]? SaveShortcutsForOutputResolutions { get; set; }
public bool? SaveResizedSubfiles { get; set; } public bool? SaveResizedSubfiles { get; set; }
public bool? SkipSearch { get; set; } public bool? SkipSearch { get; set; }
public bool? TestDistanceResults { get; set; } public bool? TestDistanceResults { get; set; }
public string[] ValidResolutions { get; set; } public string[]? ValidResolutions { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -57,10 +53,28 @@ public class Configuration
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.CheckDFaceAndUpWriteDates is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration) private static Models.Configuration Get(Configuration? configuration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
if (configuration.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates));
if (configuration.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults));
if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection));
@ -68,18 +82,23 @@ public class Configuration
if (configuration.ForceFaceLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime)); if (configuration.ForceFaceLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime));
if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime));
if (configuration.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); if (configuration.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime));
if (configuration.JLinks is null) throw new NullReferenceException(nameof(configuration.JLinks));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions ??= []; configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions ??= [];
configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions ??= []; configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions ??= [];
if (configuration.MixedYearRelativePaths is null) throw new NullReferenceException(nameof(configuration.MixedYearRelativePaths)); if (configuration.MixedYearRelativePaths is null) throw new NullReferenceException(nameof(configuration.MixedYearRelativePaths));
if (configuration.ModelDirectory is null) throw new NullReferenceException(nameof(configuration.ModelDirectory));
if (configuration.ModelName is null) throw new NullReferenceException(nameof(configuration.ModelName));
if (configuration.NumberOfJitters is null) throw new NullReferenceException(nameof(configuration.NumberOfJitters)); if (configuration.NumberOfJitters is null) throw new NullReferenceException(nameof(configuration.NumberOfJitters));
if (configuration.NumberOfTimesToUpsample is null) throw new NullReferenceException(nameof(configuration.NumberOfTimesToUpsample)); if (configuration.NumberOfTimesToUpsample is null) throw new NullReferenceException(nameof(configuration.NumberOfTimesToUpsample));
if (configuration.OutputExtension is null) throw new NullReferenceException(nameof(configuration.OutputExtension));
if (configuration.OutputQuality is null) throw new NullReferenceException(nameof(configuration.OutputQuality)); if (configuration.OutputQuality is null) throw new NullReferenceException(nameof(configuration.OutputQuality));
if (configuration.OutputResolutions is null) throw new NullReferenceException(nameof(configuration.OutputResolutions)); if (configuration.OutputResolutions is null) throw new NullReferenceException(nameof(configuration.OutputResolutions));
if (configuration.OverrideForFaceImages is null) throw new NullReferenceException(nameof(configuration.OverrideForFaceImages)); if (configuration.OverrideForFaceImages is null) throw new NullReferenceException(nameof(configuration.OverrideForFaceImages));
if (configuration.OverrideForFaceLandmarkImages is null) throw new NullReferenceException(nameof(configuration.OverrideForFaceLandmarkImages)); if (configuration.OverrideForFaceLandmarkImages is null) throw new NullReferenceException(nameof(configuration.OverrideForFaceLandmarkImages));
if (configuration.OverrideForResizeImages is null) throw new NullReferenceException(nameof(configuration.OverrideForResizeImages)); if (configuration.OverrideForResizeImages is null) throw new NullReferenceException(nameof(configuration.OverrideForResizeImages));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
if (configuration.PredictorModelName is null) throw new NullReferenceException(nameof(configuration.PredictorModelName));
if (configuration.PropertiesChangedForDistance is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); if (configuration.PropertiesChangedForDistance is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance));
if (configuration.PropertiesChangedForFaces is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForFaces)); if (configuration.PropertiesChangedForFaces is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForFaces));
if (configuration.PropertiesChangedForIndex is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForIndex)); if (configuration.PropertiesChangedForIndex is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForIndex));
@ -141,14 +160,19 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
PreVerify(configurationRoot, configuration);
result = Get(configuration); result = Get(configuration);
return result; return result;
} }

View File

@ -8,9 +8,9 @@ public class Program
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
ApplicationConfiguration.Initialize(); // ApplicationConfiguration.Initialize();
Application.Run(new DragDropSearch()); Application.Run(new DragDropSearch());
} }

View File

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net9.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<UserSecretsId>c64a15ed-0ba3-4378-8f80-0c19d0531747</UserSecretsId> <UserSecretsId>c64a15ed-0ba3-4378-8f80-0c19d0531747</UserSecretsId>
</PropertyGroup> </PropertyGroup>
@ -27,9 +27,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />

View File

@ -17,6 +17,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -6,9 +6,9 @@ public class Program
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
ApplicationConfiguration.Initialize(); // ApplicationConfiguration.Initialize();
Application.Run(new DragDropSetPropertyItem()); Application.Run(new DragDropSetPropertyItem());
} }

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Duplicate-Search</PackageId> <PackageId>Phares.View.by.Distance.Duplicate-Search</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -33,14 +33,14 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -2,6 +2,7 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Phares.Shared; using Phares.Shared;
using ShellProgressBar; using ShellProgressBar;
using System.Collections.ObjectModel;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Duplicate.Search.Models; using View_by_Distance.Duplicate.Search.Models;
@ -145,11 +146,11 @@ public class DuplicateSearch
Dictionary<int, List<MappingFromItem?>> results = []; Dictionary<int, List<MappingFromItem?>> results = [];
string directory; string directory;
const int zero = 0; const int zero = 0;
Item[] filteredItems;
FileHolder resizedFileHolder; FileHolder resizedFileHolder;
DateTime[] containerDateTimes; DateTime[] containerDateTimes;
MappingFromItem? mappingFromItem; MappingFromItem? mappingFromItem;
List<MappingFromItem?>? collection; List<MappingFromItem?>? collection;
ReadOnlyCollection<Item> validImageItems;
const string duplicates = "-Duplicate(s)"; const string duplicates = "-Duplicate(s)";
if (containers.Length != 0) if (containers.Length != 0)
{ {
@ -162,11 +163,11 @@ public class DuplicateSearch
continue; continue;
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero)) if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue; continue;
filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(configuration, container); validImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container);
if (filteredItems.Length == 0) if (validImageItems.Count == 0)
continue; continue;
containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
foreach (Item item in filteredItems) foreach (Item item in validImageItems)
{ {
if (item.Property?.Id is null) if (item.Property?.Id is null)
{ {
@ -188,7 +189,7 @@ public class DuplicateSearch
if (mappingFromItem is not null) if (mappingFromItem is not null)
{ {
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}")); resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, item.Property.Keywords ?? [], mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder); collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.IsArchive, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, item.Property.Keywords ?? [], mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder);
} }
} }
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath)); resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath));
@ -207,11 +208,11 @@ public class DuplicateSearch
{ {
foreach (MappingFromItem? mappingFromItem in keyValuePair.Value) foreach (MappingFromItem? mappingFromItem in keyValuePair.Value)
{ {
if (mappingFromItem?.ResizedFileHolder.DirectoryName is null) if (mappingFromItem?.ResizedFileHolder.DirectoryFullPath is null)
continue; continue;
if (mappingFromItem.ResizedFileHolder.Exists) if (mappingFromItem.ResizedFileHolder.Exists)
continue; continue;
collection.Add(mappingFromItem.ResizedFileHolder.DirectoryName); collection.Add(mappingFromItem.ResizedFileHolder.DirectoryFullPath);
results.Add(new(mappingFromItem.FilePath, mappingFromItem.ResizedFileHolder.FullName)); results.Add(new(mappingFromItem.FilePath, mappingFromItem.ResizedFileHolder.FullName));
} }
} }

View File

@ -23,6 +23,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -46,7 +63,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Face</PackageId> <PackageId>Phares.View.by.Distance.Face</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -33,7 +33,7 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />

View File

@ -6,19 +6,20 @@ using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.FaceRecognitionDotNet;
using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models;
using View_by_Distance.Metadata.Models.Stateless.Methods;
using View_by_Distance.Property.Models; using View_by_Distance.Property.Models;
using View_by_Distance.Property.Models.Stateless;
using View_by_Distance.Resize.Models; using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Shared.Models.Stateless;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Face.Models; namespace View_by_Distance.Face.Models;
/// <summary> /// <summary>
// List<D_Faces> // List<D_Faces>
/// </summary> /// </summary>
public class D_Face public class D_Face : IFaceD
{ {
protected readonly string _FileNameExtension; protected readonly string _FileNameExtension;
@ -41,11 +42,11 @@ public class D_Face
private readonly int _FaceDistanceHiddenImageFactor; private readonly int _FaceDistanceHiddenImageFactor;
private readonly EncoderParameters _EncoderParameters; private readonly EncoderParameters _EncoderParameters;
private readonly ImageCodecInfo _HiddenImageCodecInfo; private readonly ImageCodecInfo _HiddenImageCodecInfo;
private readonly Dictionary<string, string[]> _FileGroups;
private readonly bool _ForceFaceLastWriteTimeToCreationTime; private readonly bool _ForceFaceLastWriteTimeToCreationTime;
private readonly EncoderParameters _HiddenEncoderParameters; private readonly EncoderParameters _HiddenEncoderParameters;
private readonly IPropertyConfiguration _PropertyConfiguration; private readonly IPropertyConfiguration _PropertyConfiguration;
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull; private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
public D_Face( public D_Face(
string argZero, string argZero,
@ -101,8 +102,8 @@ public class D_Face
public void Update(string dResultsFullGroupDirectory) public void Update(string dResultsFullGroupDirectory)
{ {
_FileGroups.Clear(); _FileGroups.Clear();
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]); ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs) foreach (KeyValuePair<string, ReadOnlyCollection<string>> keyValuePair in keyValuePairs)
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value); _FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
} }
@ -111,8 +112,8 @@ public class D_Face
(Model, PredictorModel, ModelParameter) result; (Model, PredictorModel, ModelParameter) result;
Array array; Array array;
Model? model = null; Model? model = null;
array = Enum.GetValues<Model>();
PredictorModel? predictorModel = null; PredictorModel? predictorModel = null;
array = Enum.GetValues(typeof(Model));
foreach (Model check in array) foreach (Model check in array)
{ {
if (modelName.Contains(check.ToString())) if (modelName.Contains(check.ToString()))
@ -124,7 +125,7 @@ public class D_Face
if (model is null) if (model is null)
throw new Exception("Destination directory must have Model name!"); throw new Exception("Destination directory must have Model name!");
model = model.Value; model = model.Value;
array = Enum.GetValues(typeof(PredictorModel)); array = Enum.GetValues<PredictorModel>();
foreach (PredictorModel check in array) foreach (PredictorModel check in array)
{ {
if (predictorModelName.Contains(check.ToString())) if (predictorModelName.Contains(check.ToString()))
@ -149,51 +150,68 @@ public class D_Face
#pragma warning disable CA1416 #pragma warning disable CA1416
private void SaveFaces(FileHolder resizedFileHolder, List<(Shared.Models.Face, FileInfo?, string, bool)> collection) private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
{ {
int width; int width;
int height; int height;
Bitmap bitmap; Bitmap bitmap;
short type = 2; short type = 2;
FaceFile faceFile;
Graphics graphics; Graphics graphics;
Location? location; Location? location;
Rectangle rectangle; Rectangle rectangle;
string locationJson; string faceFileJson;
string faceEncodingJson; string faceEncodingJson;
PropertyItem? propertyItem; PropertyItem? propertyItem;
string outputResolutionJson; string? maker = IMetadata.GetMaker(exifDirectory);
string? model = IMetadata.GetModel(exifDirectory);
using Bitmap source = new(resizedFileHolder.FullName); using Bitmap source = new(resizedFileHolder.FullName);
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
int fileSource = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagFileSource; const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment; const int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection) foreach ((Shared.Models.Face face, FileHolder? fileHolder, string fileName, bool save) in collection)
{ {
if (!save) if (!save)
continue; continue;
if (fileInfo is null) if (fileHolder is null)
continue; continue;
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null) if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
continue; continue;
if (_OverrideForFaceImages && fileHolder.Exists)
{
IFaceD dFace = this;
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
continue;
}
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count); location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
if (location is null) if (location is null)
continue; continue;
width = location.Right - location.Left; width = location.Right - location.Left;
height = location.Bottom - location.Top; height = location.Bottom - location.Top;
locationJson = JsonSerializer.Serialize(face.Location);
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding); faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
outputResolutionJson = JsonSerializer.Serialize(face.OutputResolution);
rectangle = new Rectangle(location.Left, location.Top, width, height); rectangle = new Rectangle(location.Left, location.Top, width, height);
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
null,
face.FaceParts,
face.Location,
maker,
null,
model,
face.OutputResolution);
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
using (bitmap = new(width, height)) using (bitmap = new(width, height))
{ {
using (graphics = Graphics.FromImage(bitmap)) using (graphics = Graphics.FromImage(bitmap))
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson); propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
bitmap.SetPropertyItem(propertyItem); bitmap.SetPropertyItem(propertyItem);
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson); propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
bitmap.SetPropertyItem(propertyItem); bitmap.SetPropertyItem(propertyItem);
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson); bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
bitmap.SetPropertyItem(propertyItem);
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
} }
if (File.Exists(fileName)) if (File.Exists(fileName))
File.Delete(fileName); File.Delete(fileName);
@ -213,7 +231,7 @@ public class D_Face
} }
} }
private List<Shared.Models.Face> GetFaces(string outputResolution, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location>? locations) private List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
{ {
if (_PropertyConfiguration.NumberOfJitters is null) if (_PropertyConfiguration.NumberOfJitters is null)
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters)); throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
@ -222,7 +240,24 @@ public class D_Face
List<Shared.Models.Face> results = []; List<Shared.Models.Face> results = [];
FaceRecognitionDotNet.Image? unknownImage; FaceRecognitionDotNet.Image? unknownImage;
try try
{ unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName); } {
if (mappingFromItem.ResizedFileHolder.ExtensionLowered != ".tif")
unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
else
{
int outputQuality = 100;
string extension = ".png";
string file = Path.Combine(cResultsFullGroupDirectory, $"{mappingFromItem.ResizedFileHolder.Name}{extension}");
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(extension, outputQuality);
#pragma warning disable CA1416
System.Drawing.Image image = System.Drawing.Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
image.Save(Path.Combine(cResultsFullGroupDirectory, $"{mappingFromItem.ResizedFileHolder.Name}{filenameExtension}"), imageCodecInfo, encoderParameters);
image.Dispose();
#pragma warning restore CA1416
unknownImage = FaceRecognition.LoadImageFile(file);
File.Delete(file);
}
}
catch (Exception) catch (Exception)
{ unknownImage = null; } { unknownImage = null; }
if (unknownImage is not null) if (unknownImage is not null)
@ -260,69 +295,11 @@ public class D_Face
#pragma warning restore CA1416 #pragma warning restore CA1416
private static List<LocationContainer> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces) public List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{
List<LocationContainer> results = [];
string? json;
Location? location;
Rectangle? rectangle;
List<int> skip = [];
OutputResolution? outputResolutionCheck = null;
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
foreach (Shared.Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution));
}
foreach (LocationContainer locationContainer in locationContainers)
{
if (locationContainer.ExifDirectory is null)
continue;
if (skip.Contains(locationContainer.WholePercentages))
continue;
foreach (Shared.Models.Face face in faces)
{
if (face.Location is not null && face.OutputResolution is not null)
continue;
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
if (json is null)
continue;
outputResolutionCheck = JsonSerializer.Deserialize<OutputResolution>(json);
if (outputResolutionCheck is null || outputResolutionCheck.Width != outputResolutionWidth || outputResolutionCheck.Height != outputResolutionHeight)
continue;
rectangle = Shared.Models.Stateless.Methods.ILocation.GetRectangle(Shared.Models.Stateless.ILocation.Digits, outputResolutionCheck, locationContainer.WholePercentages);
if (rectangle is null)
continue;
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(outputResolutionHeight, rectangle.Value, outputResolutionWidth);
if (location is null)
continue;
if (!results.Any(l => l.WholePercentages == locationContainer.WholePercentages))
results.Add(new(locationContainer.CreationDateOnly,
locationContainer.ExifDirectory,
locationContainer.DirectoryNumber,
locationContainer.DisplayDirectoryName,
locationContainer.FilePath,
locationContainer.FromDistanceContent,
locationContainer.Id,
location,
locationContainer.PersonKey,
rectangle.Value,
locationContainer.WholePercentages));
}
}
if (results.Count > 0)
outputResolutionCheck = null;
return results;
}
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, ReadOnlyCollection<LocationContainer>? locationContainers, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{ {
List<Shared.Models.Face>? results; List<Shared.Models.Face>? results;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
string? json; string? json;
List<Location>? locations; List<Location> locations;
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)]; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
@ -359,18 +336,13 @@ public class D_Face
parseExceptions.Add(nameof(D_Face)); parseExceptions.Add(nameof(D_Face));
} }
} }
List<LocationContainer> collection;
if (results is null || locationContainers is null)
collection = [];
else
collection = GetLocationContainers(outputResolution, locationContainers, outputResolutionToResize, results);
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null) if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
locations = (from l in collection where l is not null select l.Location).ToList(); locations = [];
else else
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum); locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
if (results is null || (locations is not null && locations.Count > 0)) if (results is null || locations.Count > 0)
{ {
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations); results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
if (results.Count == 0) if (results.Count == 0)
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err"); File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
else else
@ -394,11 +366,12 @@ public class D_Face
return results; return results;
} }
public List<(Shared.Models.Face, FileInfo?, string, bool)> SaveFaces(string f, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, List<Shared.Models.Face> faces) public List<(Shared.Models.Face, FileHolder?, string, bool)> SaveFaces(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
{ {
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = []; List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = [];
bool save; bool save;
FileInfo fileInfo; FileInfo fileInfo;
FileHolder fileHolder;
string deterministicHashCodeKey; string deterministicHashCodeKey;
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)]; string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
@ -415,23 +388,93 @@ public class D_Face
} }
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}")); fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
fileHolder = FileHolder.Get(fileInfo);
if (!directoryExists) if (!directoryExists)
save = true; save = true;
else if (_OverrideForFaceImages) else if (_OverrideForFaceImages)
save = true; save = true;
else if (!fileInfo.Exists) else if (!fileHolder.Exists)
save = true; save = true;
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime) else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
save = true; save = true;
results.Add(new(face, fileInfo, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save)); results.Add(new(face, fileHolder, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
} }
if (results.Any(l => l.Save)) if (results.Any(l => l.Save))
{ {
if (!directoryExists) if (!directoryExists)
_ = Directory.CreateDirectory(directory); _ = Directory.CreateDirectory(directory);
SaveFaces(mappingFromItem.ResizedFileHolder, results); SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
} }
return results; return results;
} }
#pragma warning disable CA1416
private static (string?, string?) Get(string? json)
{
string? model;
string? maker;
FaceFile? faceFile = json is null ? null : JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
if (faceFile is null || faceFile.Location is null)
(maker, model) = (null, null);
else
(maker, model) = (faceFile.Maker, faceFile.Model);
return (maker, model);
}
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Shared.Models.Face face, bool mappedFile)
{
FileInfo fileInfo = new(filePath.FullName);
if (fileInfo.Exists)
{
string? json;
short type = 2;
string? model;
string? maker;
string checkFile = $"{filePath.FullName}.exif";
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
// const int author = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor; // 40093
if (mappedFile)
{
json = IMetadata.GetOutputResolution(exifDirectory);
if (json is not null && json.Contains(nameof(DateTime)))
return;
(maker, model) = Get(json);
}
else
{
maker = IMetadata.GetMaker(exifDirectory);
model = IMetadata.GetModel(exifDirectory);
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
json = IMetadata.GetOutputResolution(faceExifDirectory);
if (json is not null && json.Contains(nameof(DateTime)))
return;
}
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
FaceFile faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
null,
face.FaceParts,
face.Location,
maker,
null,
model,
face.OutputResolution);
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
Bitmap bitmap = new(fileInfo.FullName);
bitmap.SetPropertyItem(propertyItem);
bitmap.Save(checkFile);
bitmap.Dispose();
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
File.Delete(fileInfo.FullName);
File.Move(checkFile, fileInfo.FullName);
}
}
#pragma warning restore CA1416
} }

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.FaceParts</PackageId> <PackageId>Phares.View.by.Distance.FaceParts</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -33,7 +33,7 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />

View File

@ -2,9 +2,12 @@ using System.Collections.ObjectModel;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Reflection;
using System.Text;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Face.Models; using View_by_Distance.Face.Models;
using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models;
using View_by_Distance.Metadata.Models.Stateless.Methods;
using View_by_Distance.Property.Models; using View_by_Distance.Property.Models;
using View_by_Distance.Property.Models.Stateless; using View_by_Distance.Property.Models.Stateless;
using View_by_Distance.Resize.Models; using View_by_Distance.Resize.Models;
@ -25,11 +28,11 @@ public class D2_FaceParts
private readonly ImageCodecInfo _ImageCodecInfo; private readonly ImageCodecInfo _ImageCodecInfo;
private readonly bool _CheckDFaceAndUpWriteDates; private readonly bool _CheckDFaceAndUpWriteDates;
private readonly ConstructorInfo _ConstructorInfo;
private readonly bool _OverrideForFaceLandmarkImages; private readonly bool _OverrideForFaceLandmarkImages;
private readonly EncoderParameters _EncoderParameters; private readonly EncoderParameters _EncoderParameters;
private readonly List<string> _AngleBracketCollection;
private readonly Dictionary<string, string[]> _FileGroups;
private readonly IPropertyConfiguration _PropertyConfiguration; private readonly IPropertyConfiguration _PropertyConfiguration;
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
public D2_FaceParts(IPropertyConfiguration propertyConfiguration, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension, bool checkDFaceAndUpWriteDates, bool overrideForFaceLandmarkImages) public D2_FaceParts(IPropertyConfiguration propertyConfiguration, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension, bool checkDFaceAndUpWriteDates, bool overrideForFaceLandmarkImages)
{ {
@ -37,10 +40,11 @@ public class D2_FaceParts
_ImageCodecInfo = imageCodecInfo; _ImageCodecInfo = imageCodecInfo;
_EncoderParameters = encoderParameters; _EncoderParameters = encoderParameters;
_FileNameExtension = filenameExtension; _FileNameExtension = filenameExtension;
_AngleBracketCollection = [];
_PropertyConfiguration = propertyConfiguration; _PropertyConfiguration = propertyConfiguration;
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; _CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
_OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages;
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
_ConstructorInfo = constructorInfo;
} }
public override string ToString() public override string ToString()
@ -52,46 +56,11 @@ public class D2_FaceParts
public void Update(string dResultsFullGroupDirectory) public void Update(string dResultsFullGroupDirectory)
{ {
_FileGroups.Clear(); _FileGroups.Clear();
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]); ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs) foreach (KeyValuePair<string, ReadOnlyCollection<string>> keyValuePair in keyValuePairs)
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value); _FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
} }
public void SetAngleBracketCollection(Configuration configuration, string d2ResultsFullGroupDirectory, string sourceDirectory)
{
_AngleBracketCollection.Clear();
_AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(configuration,
sourceDirectory,
d2ResultsFullGroupDirectory,
contentDescription: "n gif file(s) for each face found",
singletonDescription: string.Empty,
collectionDescription: string.Empty,
converted: true));
}
public string GetFacePartsDirectory(Configuration configuration, string dResultsFullGroupDirectory, Item item, bool includeNameWithoutExtension)
{
string result;
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
if (!angleBracketCollectionAny)
{
if (item.FilePath.DirectoryName is null)
throw new NullReferenceException(nameof(item.FilePath.DirectoryName));
SetAngleBracketCollection(configuration, dResultsFullGroupDirectory, item.FilePath.DirectoryName);
}
if (includeNameWithoutExtension)
result = Path.Combine(_AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), item.FilePath.NameWithoutExtension);
else
{
result = _AngleBracketCollection[0].Replace("<>", $"[{_PropertyConfiguration.ResultContent}]");
if (!Directory.Exists(result))
_ = Directory.CreateDirectory(result);
}
if (!angleBracketCollectionAny)
_AngleBracketCollection.Clear();
return result;
}
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum) private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
{ {
xMinimum = points[0].X; xMinimum = points[0].X;
@ -183,73 +152,238 @@ public class D2_FaceParts
return result; return result;
} }
private void SaveFaceParts(int pointSize, FileHolder resizedFileHolder, bool saveRotated, List<(Shared.Models.Face, string, string)> collection) private void SaveRotated(MappingFromItem mappingFromItem, List<(Shared.Models.Face, string, string)> collection)
{
double? α;
Bitmap rotated;
foreach ((Shared.Models.Face face, string _, string rotatedFileName) in collection)
{
if (face.FaceParts is null)
continue;
(_, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts);
if (α is null)
continue;
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
rotated = RotateBitmap(image, (float)α.Value);
if (rotated is not null)
{
rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters);
rotated.Dispose();
}
}
}
private string GetSeasonDirectory(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, bool any)
{
string result;
string minimumDateYear = mappingFromItem.MinimumDateTime.ToString("yyyy");
DateTime dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
string year = mappingFromItem.DateTimeOriginal is null ? $"{minimumDateYear[1..]}{minimumDateYear[0]}" : mappingFromItem.DateTimeOriginal.Value.ToString("yyyy");
string directory = Path.Combine(d2ResultsFullGroupDirectory, $"[{_PropertyConfiguration.ResultContent}]", $"{year}.{season} {seasonName}");
result = any ? Path.Combine(directory, "---") : Path.Combine(directory, "Complete");
if (!Directory.Exists(result))
_ = Directory.CreateDirectory(result);
return result;
}
private void SaveImage(MappingFromItem mappingFromItem, string directory, Image image, List<FaceFile> faceFiles)
{
short type = 2;
string faceFileJson;
PropertyItem? propertyItem;
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
string fileName = Path.Combine(directory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
try
{
foreach (int propertyId in image.PropertyIdList)
{
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
continue;
image.RemovePropertyItem(propertyId);
}
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
image.SetPropertyItem(propertyItem);
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
}
catch (Exception ex)
{
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
File.Delete(fileName);
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
if (!string.IsNullOrEmpty(faceFileJson))
File.WriteAllText($"{fileName}.json", faceFileJson);
}
}
private void SaveAllFaceParts(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
{ {
int x; int x;
int y; int y;
double? α; Brush brush;
int width; int pointSize;
int height; bool any = false;
Bitmap rotated; FaceFile faceFile;
foreach ((Shared.Models.Face face, string fileName, string rotatedFileName) in collection) bool? isDefaultName;
List<long> personKeys = [];
List<FaceFile> faceFiles = [];
StringBuilder stringBuilder = new();
MappingFromPerson? mappingFromPerson;
string? maker = IMetadata.GetMaker(exifDirectory);
string? model = IMetadata.GetModel(exifDirectory);
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
using Graphics graphics = Graphics.FromImage(image);
foreach (Shared.Models.Face face in faces)
{ {
if (face.FaceEncoding is null) if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
continue; continue;
if (!any && face.Mapping?.MappingFromPerson is null)
any = true;
mappingFromPerson = face.Mapping?.MappingFromPerson;
brush = mappingFromPerson is null ? Brushes.Red : Brushes.GreenYellow;
isDefaultName = mappingFromPerson is null ? null : Shared.Models.Stateless.Methods.IPerson.IsDefaultName(mappingFromPerson);
if (mappingFromPerson is not null && isDefaultName is not null && !isDefaultName.Value)
personKeys.Add(mappingFromPerson.PersonKey);
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
face.FaceEncoding,
face.FaceParts,
face.Location,
maker,
mappingFromPerson,
model,
face.OutputResolution);
faceFiles.Add(faceFile);
pointSize = GetPointSize(face.FaceParts, defaultPointSize: 2);
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
{
foreach (FacePoint facePoint in facePoints)
graphics.FillEllipse(brush, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2);
if (facePart == FacePart.Chin)
continue;
if (facePoints.Length < 3)
continue;
x = (int)(from l in facePoints select l.X).Average();
y = (int)(from l in facePoints select l.Y).Average();
graphics.FillEllipse(Brushes.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2);
}
}
_ = graphics.Save();
string directory = GetSeasonDirectory(d2ResultsFullGroupDirectory, mappingFromItem, any);
SaveImage(mappingFromItem, directory, image, faceFiles);
}
private void SaveImage(string fileName, Image image, FaceFile faceFile)
{
short type = 2;
string faceFileJson;
PropertyItem? propertyItem;
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
try
{
foreach (int propertyId in image.PropertyIdList)
{
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
continue;
image.RemovePropertyItem(propertyId);
}
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
image.SetPropertyItem(propertyItem);
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
}
catch (Exception ex)
{
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
File.Delete(fileName);
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
if (!string.IsNullOrEmpty(faceFileJson))
File.WriteAllText($"{fileName}.json", faceFileJson);
}
}
private void SaveFaceParts(MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<(Shared.Models.Face, string, string)> collection)
{
int x;
int y;
Brush brush;
int pointSize;
FaceFile faceFile;
MappingFromPerson? mappingFromPerson;
string? maker = IMetadata.GetMaker(exifDirectory);
string? model = IMetadata.GetModel(exifDirectory);
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
foreach ((Shared.Models.Face face, string fileName, string _) in collection)
{
try try
{ {
using (Image image = Image.FromFile(resizedFileHolder.FullName)) if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
continue;
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
mappingFromPerson = face.Mapping?.MappingFromPerson;
brush = mappingFromPerson is null ? Brushes.Red : Brushes.GreenYellow;
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
face.FaceEncoding,
face.FaceParts,
face.Location,
maker,
mappingFromPerson,
model,
face.OutputResolution);
using Graphics graphics = Graphics.FromImage(image);
pointSize = GetPointSize(face.FaceParts, defaultPointSize: 2);
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
{ {
using Graphics graphic = Graphics.FromImage(image); foreach (FacePoint facePoint in facePoints)
if (face.FaceParts is null || face.FaceParts.Count == 0) graphics.FillEllipse(brush, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2);
{ if (facePart == FacePart.Chin)
if (face.Location is null)
continue;
width = face.Location.Right - face.Location.Left;
height = face.Location.Bottom - face.Location.Top;
graphic.DrawEllipse(Pens.Red, face.Location.Left, face.Location.Top, width, height);
}
else
{
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
{
foreach (FacePoint facePoint in facePoints)
graphic.DrawEllipse(Pens.GreenYellow, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2);
if (facePart == FacePart.Chin)
continue;
if (facePoints.Length < 3)
continue;
x = (int)(from l in facePoints select l.X).Average();
y = (int)(from l in facePoints select l.Y).Average();
graphic.DrawEllipse(Pens.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2);
}
}
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
}
if (saveRotated && face.FaceParts is not null)
{
(_, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts);
if (α is null)
continue; continue;
using Image image = Image.FromFile(resizedFileHolder.FullName); if (facePoints.Length < 3)
rotated = RotateBitmap(image, (float)α.Value); continue;
if (rotated is not null) x = (int)(from l in facePoints select l.X).Average();
{ y = (int)(from l in facePoints select l.Y).Average();
rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters); graphics.FillEllipse(Brushes.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2);
rotated.Dispose();
}
} }
_ = graphics.Save();
SaveImage(fileName, image, faceFile);
}
catch (Exception)
{
if (File.Exists(fileName))
File.Delete(fileName);
} }
catch (Exception) { }
} }
} }
private int GetPointSize(Dictionary<FacePart, FacePoint[]> faceParts, int defaultPointSize)
{
int result;
FacePoint[]? facePoints;
if (faceParts.TryGetValue(FacePart.LeftEye, out facePoints))
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
else
{
if (faceParts.TryGetValue(FacePart.RightEye, out facePoints))
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
else
result = defaultPointSize;
}
return result;
}
#pragma warning restore CA1416 #pragma warning restore CA1416
public void SaveFaceLandmarkImages(Configuration configuration, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, List<Shared.Models.Face> faces, bool saveRotated) public void SaveFaceLandmarkImages(Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces, bool saveRotated)
{ {
FileInfo fileInfo; FileInfo fileInfo;
bool check = false; bool check = false;
const int pointSize = 2;
FileInfo rotatedFileInfo; FileInfo rotatedFileInfo;
DateTime? dateTime = null; DateTime? dateTime = null;
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
@ -296,48 +430,23 @@ public class D2_FaceParts
{ {
if (!directoryExists) if (!directoryExists)
_ = Directory.CreateDirectory(directory); _ = Directory.CreateDirectory(directory);
SaveFaceParts(pointSize, mappingFromItem.ResizedFileHolder, saveRotated, collection); SaveFaceParts(mappingFromItem, exifDirectory, collection);
if (saveRotated)
SaveRotated(mappingFromItem, collection);
} }
} }
#pragma warning disable CA1416 private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileHolder?, string, bool)> faceCollection)
private void SaveFaceLandmarkImage(MappingFromItem mappingFromItem, List<(Shared.Models.Face, FileInfo?, string, bool)> faceCollection, string fileName)
{
Pen pen;
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
using Graphics graphic = Graphics.FromImage(image);
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection)
{
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.FaceParts is null || face.FaceParts.Count == 0)
continue;
pen = face.Mapping?.MappingFromPerson is null ? Pens.Red : Pens.GreenYellow;
try
{
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
{
for (int i = 0; i < facePoints.Length - 1; i++)
graphic.DrawLine(pen, new Point(facePoints[i].X, facePoints[i].Y), new Point(facePoints[i + 1].X, facePoints[i + 1].Y));
}
}
catch (Exception) { }
}
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
}
#pragma warning restore CA1416
private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection)
{ {
bool results = false; bool results = false;
string checkFile; string checkFile;
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection) foreach ((Shared.Models.Face face, FileHolder? fileHolder, string _, bool _) in faceCollection)
{ {
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
continue; continue;
if (fileInfo is not null) if (fileHolder is not null)
{ {
checkFile = Path.Combine(facePartsCollectionDirectory, fileInfo.Name); checkFile = Path.Combine(facePartsCollectionDirectory, fileHolder.Name);
if (face.Mapping?.MappingFromPerson is not null) if (face.Mapping?.MappingFromPerson is not null)
{ {
if (File.Exists(checkFile)) if (File.Exists(checkFile))
@ -353,26 +462,25 @@ public class D2_FaceParts
if (!results) if (!results)
results = true; results = true;
if (!File.Exists(checkFile)) if (!File.Exists(checkFile))
File.Copy(fileInfo.FullName, checkFile); File.Copy(fileHolder.FullName, checkFile);
} }
} }
} }
return results; return results;
} }
public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection) public void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
{ {
bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection); bool any = false;
string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}"); foreach (Shared.Models.Face face in faces)
bool save = faceCollection.Any(l => l.Face.FaceEncoding is not null && l.Face.Location is not null && l.Face.OutputResolution is not null && l.Face.FaceParts is not null && l.Face.FaceParts.Count != 0);
FileInfo fileInfo = new(fileName);
if (save && (!fileInfo.Exists || new TimeSpan(DateTime.Now.Ticks - fileInfo.LastWriteTime.Ticks).TotalDays > 10))
{ {
SaveFaceLandmarkImage(mappingFromItem, faceCollection, fileName); if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
fileInfo.Refresh(); continue;
if (!any)
any = true;
} }
if (!hasNotMapped && !fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && (fileInfo.Exists || save)) if (any)
File.SetAttributes(fileName, FileAttributes.Hidden); SaveAllFaceParts(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
} }
} }

View File

@ -26,16 +26,15 @@ public abstract class DisposableObject : IDisposable
/// <summary> /// <summary>
/// If this object is disposed, then <see cref="ObjectDisposedException"/> is thrown. /// If this object is disposed, then <see cref="ObjectDisposedException"/> is thrown.
/// </summary> /// </summary>
public void ThrowIfDisposed() public void ThrowIfDisposed() =>
{ ObjectDisposedException.ThrowIf(IsDisposed, this);
if (IsDisposed)
throw new ObjectDisposedException(GetType().FullName);
}
internal void ThrowIfDisposed(string objectName) internal void ThrowIfDisposed(string objectName)
{ {
#pragma warning disable CA1513
if (IsDisposed) if (IsDisposed)
throw new ObjectDisposedException(objectName); throw new ObjectDisposedException(objectName);
#pragma warning restore CA1513
} }
#region Overrides #region Overrides

View File

@ -167,7 +167,13 @@ public class FaceRecognition : DisposableObject
} }
else else
{ {
ShapePredictor posePredictor = _PredictorModel switch { PredictorModel.Large => _PosePredictor68Point, PredictorModel.Small => _PosePredictor5Point, _ => throw new Exception() }; ShapePredictor posePredictor = _PredictorModel switch
{
PredictorModel.Large => _PosePredictor68Point,
PredictorModel.Small => _PosePredictor5Point,
PredictorModel.Custom => throw new NotImplementedException(),
_ => throw new Exception()
};
foreach (Location location in locations) foreach (Location location in locations)
{ {
DlibDotNet.Rectangle rectangle = new(location.Left, location.Top, location.Right, location.Bottom); DlibDotNet.Rectangle rectangle = new(location.Left, location.Top, location.Right, location.Bottom);
@ -197,7 +203,7 @@ public class FaceRecognition : DisposableObject
return results; return results;
} }
public List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> GetCollection(Image image, List<Location>? locations, bool includeFaceEncoding, bool includeFaceParts) public List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> GetCollection(Image image, List<Location> locations, bool includeFaceEncoding, bool includeFaceParts)
{ {
List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> results = []; List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> results = [];
if (image is null) if (image is null)
@ -206,9 +212,7 @@ public class FaceRecognition : DisposableObject
ThrowIfDisposed(); ThrowIfDisposed();
if (_PredictorModel == PredictorModel.Custom) if (_PredictorModel == PredictorModel.Custom)
throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported."); throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported.");
if (locations is null) if (locations.Count == 0)
locations = GetLocations(image);
else if (locations.Count == 0)
locations.AddRange(GetLocations(image)); locations.AddRange(GetLocations(image));
List<FullObjectDetection> fullObjectDetections = GetFullObjectDetections(image, locations); List<FullObjectDetection> fullObjectDetections = GetFullObjectDetections(image, locations);
if (fullObjectDetections.Count != locations.Count) if (fullObjectDetections.Count != locations.Count)
@ -408,22 +412,50 @@ public class FaceRecognition : DisposableObject
return null; return null;
} }
public static ReadOnlyCollection<LocationContainer> GetLocationContainers(int permyriad, ReadOnlyCollection<LocationContainer> readOnlyLocationContainers, LocationContainer locationContainer)
{
List<LocationContainer> results = [];
int lengthPermyriad;
if (readOnlyLocationContainers.Count != 0)
{
double length;
LocationContainer result;
if (locationContainer.Encoding is not FaceEncoding faceEncodingToCompare)
throw new NullReferenceException(nameof(locationContainer));
faceEncodingToCompare.ThrowIfDisposed();
foreach (LocationContainer item in readOnlyLocationContainers)
{
#pragma warning disable CA1513
if (item.Encoding is not FaceEncoding faceEncoding || faceEncoding.IsDisposed)
throw new ObjectDisposedException($"{nameof(item)} contains disposed object.");
#pragma warning restore CA1513
using (Matrix<double> diff = faceEncoding.Encoding - faceEncodingToCompare.Encoding)
length = DlibDotNet.Dlib.Length(diff);
lengthPermyriad = (int)(length * permyriad);
result = LocationContainer.Get(locationContainer, item, lengthPermyriad, keepExifDirectory: false, keepEncoding: false);
results.Add(result);
}
}
LocationContainer[] array = results.OrderBy(l => l.LengthPermyriad).ToArray();
return new(array);
}
public static List<FaceDistance> FaceDistances(ReadOnlyCollection<FaceDistance> faceDistances, FaceDistance faceDistanceToCompare) public static List<FaceDistance> FaceDistances(ReadOnlyCollection<FaceDistance> faceDistances, FaceDistance faceDistanceToCompare)
{ {
List<FaceDistance> results = []; List<FaceDistance> results = [];
if (faceDistances is null)
throw new NullReferenceException(nameof(faceDistances));
if (faceDistances.Count != 0) if (faceDistances.Count != 0)
{ {
double length; double length;
FaceDistance result; FaceDistance result;
if (faceDistanceToCompare is null || faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare) if (faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare)
throw new NullReferenceException(nameof(faceDistanceToCompare)); throw new NullReferenceException(nameof(faceDistanceToCompare));
faceEncodingToCompare.ThrowIfDisposed(); faceEncodingToCompare.ThrowIfDisposed();
foreach (FaceDistance faceDistance in faceDistances) foreach (FaceDistance faceDistance in faceDistances)
{ {
#pragma warning disable CA1513
if (faceDistance.Encoding is not FaceEncoding faceEncoding || faceEncoding.IsDisposed) if (faceDistance.Encoding is not FaceEncoding faceEncoding || faceEncoding.IsDisposed)
throw new ObjectDisposedException($"{nameof(faceDistances)} contains disposed object."); throw new ObjectDisposedException($"{nameof(faceDistances)} contains disposed object.");
#pragma warning restore CA1513
using (Matrix<double> diff = faceEncoding.Encoding - faceEncodingToCompare.Encoding) using (Matrix<double> diff = faceEncoding.Encoding - faceEncodingToCompare.Encoding)
length = DlibDotNet.Dlib.Length(diff); length = DlibDotNet.Dlib.Length(diff);
result = new(faceDistance, length); result = new(faceDistance, length);

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.FaceRecognitionDotNet</PackageId> <PackageId>Phares.View.by.Distance.FaceRecognitionDotNet</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>

5
Instance/.vscode/mklink.md vendored Normal file
View File

@ -0,0 +1,5 @@
# mklink
```bash Sat Aug 17 2024 15:24:10 GMT-0700 (Mountain Standard Time)
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Instance\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\2999dda1-5329-4d9f-9d68-cccfabe0e47f"
```

File diff suppressed because it is too large Load Diff

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>2999dda1-5329-4d9f-9d68-cccfabe0e47f</UserSecretsId> <UserSecretsId>2999dda1-5329-4d9f-9d68-cccfabe0e47f</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Instance</PackageId> <PackageId>Phares.View.by.Distance.Instance</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -34,15 +34,15 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlurHash\BlurHash.csproj" /> <ProjectReference Include="..\BlurHash\BlurHash.csproj" />

View File

@ -19,6 +19,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -42,6 +59,7 @@ public class AppSettings
#pragma warning disable IL3050, IL2026 #pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026 #pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -9,7 +9,6 @@ public class Configuration
public bool? CheckDFaceAndUpWriteDates { get; set; } public bool? CheckDFaceAndUpWriteDates { get; set; }
public bool? CheckJsonForDistanceResults { get; set; } public bool? CheckJsonForDistanceResults { get; set; }
public string[]? CopyFacesAndSaveFaceLandmarkForOutputResolutions { get; set; }
public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; }
public bool? DeletePossibleDuplicates { get; set; } public bool? DeletePossibleDuplicates { get; set; }
public int? DistanceFactor { get; set; } public int? DistanceFactor { get; set; }
@ -27,6 +26,9 @@ public class Configuration
public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; }
public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } public bool? ForceResizeLastWriteTimeToCreationTime { get; set; }
public string? GenealogicalDataCommunicationFile { get; set; } public string? GenealogicalDataCommunicationFile { get; set; }
public string? ImmichAssetsFile { get; set; }
public string? ImmichOwnerId { get; set; }
public string? ImmichRoot { get; set; }
public string[]? IgnoreExtensions { get; set; } public string[]? IgnoreExtensions { get; set; }
public string[]? JLinks { get; set; } public string[]? JLinks { get; set; }
public string? LinkedAlpha { get; set; } public string? LinkedAlpha { get; set; }
@ -76,6 +78,7 @@ public class Configuration
public string[]? SaveBlurHashForOutputResolutions { get; set; } public string[]? SaveBlurHashForOutputResolutions { get; set; }
public string[]? SaveFaceDistancesForOutputResolutions { get; set; } public string[]? SaveFaceDistancesForOutputResolutions { get; set; }
public string[]? SaveFaceLandmarkForOutputResolutions { get; set; } public string[]? SaveFaceLandmarkForOutputResolutions { get; set; }
public string[]? SaveFaceLandmarkForOutputResolutionsV2 { get; set; }
public string[]? SaveFilteredOriginalImagesFromJLinksForOutputResolutions { get; set; } public string[]? SaveFilteredOriginalImagesFromJLinksForOutputResolutions { get; set; }
public bool? SaveFullYearOfRandomFiles { get; set; } public bool? SaveFullYearOfRandomFiles { get; set; }
public bool? SaveIndividually { get; set; } public bool? SaveIndividually { get; set; }
@ -93,6 +96,7 @@ public class Configuration
public int? SortingMaximumPerKey { get; set; } public int? SortingMaximumPerKey { get; set; }
public int? SortingMinimumToUseSigma { get; set; } public int? SortingMinimumToUseSigma { get; set; }
public bool? TestDistanceResults { get; set; } public bool? TestDistanceResults { get; set; }
public bool? UseExtraPersonKeyCheck { get; set; }
public int? UseFilterTries { get; set; } public int? UseFilterTries { get; set; }
public string[]? ValidKeyWordsToIgnoreInRandom { get; set; } public string[]? ValidKeyWordsToIgnoreInRandom { get; set; }
public string[]? ValidResolutions { get; set; } public string[]? ValidResolutions { get; set; }
@ -103,7 +107,22 @@ public class Configuration
return result; return result;
} }
#pragma warning restore csharp_preserve_single_line_statements private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.CheckDFaceAndUpWriteDates is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration) private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
@ -112,7 +131,6 @@ public class Configuration
if (configuration.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates));
if (configuration?.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration?.CheckDFaceAndUpWriteDates is null) throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates));
if (configuration?.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration?.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults));
// if (configuration?.CopyFacesAndSaveFaceLandmarkForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions));
if (configuration?.CrossDirectoryMaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration?.CrossDirectoryMaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection));
if (configuration?.DeletePossibleDuplicates is null) throw new NullReferenceException(nameof(configuration.DeletePossibleDuplicates)); if (configuration?.DeletePossibleDuplicates is null) throw new NullReferenceException(nameof(configuration.DeletePossibleDuplicates));
if (configuration?.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor)); if (configuration?.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor));
@ -130,6 +148,9 @@ public class Configuration
if (configuration?.ForceMetadataLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); if (configuration?.ForceMetadataLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime));
if (configuration?.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); if (configuration?.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime));
if (configuration?.GenealogicalDataCommunicationFile is null) throw new NullReferenceException(nameof(configuration.GenealogicalDataCommunicationFile)); if (configuration?.GenealogicalDataCommunicationFile is null) throw new NullReferenceException(nameof(configuration.GenealogicalDataCommunicationFile));
if (configuration?.ImmichAssetsFile is null) throw new NullReferenceException(nameof(configuration.ImmichAssetsFile));
if (configuration?.ImmichOwnerId is null) throw new NullReferenceException(nameof(configuration.ImmichOwnerId));
if (configuration?.ImmichRoot is null) throw new NullReferenceException(nameof(configuration.ImmichRoot));
// if (configuration?.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); // if (configuration?.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
// if (configuration?.JLinks is null) throw new NullReferenceException(nameof(configuration.JLinks)); // if (configuration?.JLinks is null) throw new NullReferenceException(nameof(configuration.JLinks));
// if (configuration?.LinkedAlpha is null) throw new NullReferenceException(nameof(configuration.LinkedAlpha)); // if (configuration?.LinkedAlpha is null) throw new NullReferenceException(nameof(configuration.LinkedAlpha));
@ -179,6 +200,7 @@ public class Configuration
// if (configuration?.SaveBlurHashForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveBlurHashForOutputResolutions)); // if (configuration?.SaveBlurHashForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveBlurHashForOutputResolutions));
// if (configuration?.SaveFaceDistancesForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceDistancesForOutputResolutions)); // if (configuration?.SaveFaceDistancesForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceDistancesForOutputResolutions));
// if (configuration?.SaveFaceLandmarkForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); // if (configuration?.SaveFaceLandmarkForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions));
// if (configuration?.SaveFaceLandmarkForOutputResolutionsV2 is null) throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutionsV2));
// if (configuration?.SaveFilteredOriginalImagesFromJLinksForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions)); // if (configuration?.SaveFilteredOriginalImagesFromJLinksForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions));
if (configuration?.SaveFullYearOfRandomFiles is null) throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles)); if (configuration?.SaveFullYearOfRandomFiles is null) throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles));
if (configuration?.SaveIndividually is null) throw new NullReferenceException(nameof(configuration.SaveIndividually)); if (configuration?.SaveIndividually is null) throw new NullReferenceException(nameof(configuration.SaveIndividually));
@ -196,13 +218,13 @@ public class Configuration
if (configuration?.SortingMaximumPerKey is null) throw new NullReferenceException(nameof(configuration.SortingMaximumPerKey)); if (configuration?.SortingMaximumPerKey is null) throw new NullReferenceException(nameof(configuration.SortingMaximumPerKey));
if (configuration?.SortingMinimumToUseSigma is null) throw new NullReferenceException(nameof(configuration.SortingMinimumToUseSigma)); if (configuration?.SortingMinimumToUseSigma is null) throw new NullReferenceException(nameof(configuration.SortingMinimumToUseSigma));
if (configuration?.TestDistanceResults is null) throw new NullReferenceException(nameof(configuration.TestDistanceResults)); if (configuration?.TestDistanceResults is null) throw new NullReferenceException(nameof(configuration.TestDistanceResults));
if (configuration?.UseExtraPersonKeyCheck is null) throw new NullReferenceException(nameof(configuration.UseExtraPersonKeyCheck));
if (configuration?.UseFilterTries is null) throw new NullReferenceException(nameof(configuration.UseFilterTries)); if (configuration?.UseFilterTries is null) throw new NullReferenceException(nameof(configuration.UseFilterTries));
// if (configuration?.ValidKeyWordsToIgnoreInRandom is null) throw new NullReferenceException(nameof(configuration.ValidKeyWordsToIgnoreInRandom)); // if (configuration?.ValidKeyWordsToIgnoreInRandom is null) throw new NullReferenceException(nameof(configuration.ValidKeyWordsToIgnoreInRandom));
// if (configuration?.ValidResolutions is null) throw new NullReferenceException(nameof(configuration.ValidResolutions)); // if (configuration?.ValidResolutions is null) throw new NullReferenceException(nameof(configuration.ValidResolutions));
result = new(propertyConfiguration, result = new(propertyConfiguration,
configuration.CheckDFaceAndUpWriteDates.Value, configuration.CheckDFaceAndUpWriteDates.Value,
configuration.CheckJsonForDistanceResults.Value, configuration.CheckJsonForDistanceResults.Value,
configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions ?? [],
configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value,
configuration.DeletePossibleDuplicates.Value, configuration.DeletePossibleDuplicates.Value,
configuration.DistanceFactor.Value, configuration.DistanceFactor.Value,
@ -220,6 +242,9 @@ public class Configuration
configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.ForceMetadataLastWriteTimeToCreationTime.Value,
configuration.ForceResizeLastWriteTimeToCreationTime.Value, configuration.ForceResizeLastWriteTimeToCreationTime.Value,
configuration.GenealogicalDataCommunicationFile, configuration.GenealogicalDataCommunicationFile,
configuration.ImmichAssetsFile,
configuration.ImmichOwnerId,
configuration.ImmichRoot,
configuration.IgnoreExtensions ?? [], configuration.IgnoreExtensions ?? [],
configuration.JLinks ?? [], configuration.JLinks ?? [],
configuration.LinkedAlpha, configuration.LinkedAlpha,
@ -269,6 +294,7 @@ public class Configuration
configuration.SaveBlurHashForOutputResolutions ?? [], configuration.SaveBlurHashForOutputResolutions ?? [],
configuration.SaveFaceDistancesForOutputResolutions ?? [], configuration.SaveFaceDistancesForOutputResolutions ?? [],
configuration.SaveFaceLandmarkForOutputResolutions ?? [], configuration.SaveFaceLandmarkForOutputResolutions ?? [],
configuration.SaveFaceLandmarkForOutputResolutionsV2 ?? [],
configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions ?? [], configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions ?? [],
configuration.SaveFullYearOfRandomFiles.Value, configuration.SaveFullYearOfRandomFiles.Value,
configuration.SaveIndividually.Value, configuration.SaveIndividually.Value,
@ -286,6 +312,7 @@ public class Configuration
configuration.SortingMaximumPerKey.Value, configuration.SortingMaximumPerKey.Value,
configuration.SortingMinimumToUseSigma.Value, configuration.SortingMinimumToUseSigma.Value,
configuration.TestDistanceResults.Value, configuration.TestDistanceResults.Value,
configuration.UseExtraPersonKeyCheck.Value,
configuration.UseFilterTries.Value, configuration.UseFilterTries.Value,
configuration.ValidKeyWordsToIgnoreInRandom ?? [], configuration.ValidKeyWordsToIgnoreInRandom ?? [],
configuration.ValidResolutions ?? []); configuration.ValidResolutions ?? []);
@ -297,14 +324,19 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration); result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -3,7 +3,6 @@ namespace View_by_Distance.Instance.Models;
public record Configuration(Property.Models.Configuration PropertyConfiguration, public record Configuration(Property.Models.Configuration PropertyConfiguration,
bool CheckDFaceAndUpWriteDates, bool CheckDFaceAndUpWriteDates,
bool CheckJsonForDistanceResults, bool CheckJsonForDistanceResults,
string[] CopyFacesAndSaveFaceLandmarkForOutputResolutions,
int CrossDirectoryMaxItemsInDistanceCollection, int CrossDirectoryMaxItemsInDistanceCollection,
bool DeletePossibleDuplicates, bool DeletePossibleDuplicates,
int DistanceFactor, int DistanceFactor,
@ -21,6 +20,9 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
bool ForceMetadataLastWriteTimeToCreationTime, bool ForceMetadataLastWriteTimeToCreationTime,
bool ForceResizeLastWriteTimeToCreationTime, bool ForceResizeLastWriteTimeToCreationTime,
string GenealogicalDataCommunicationFile, string GenealogicalDataCommunicationFile,
string ImmichAssetsFile,
string ImmichOwnerId,
string ImmichRoot,
string[] IgnoreExtensions, string[] IgnoreExtensions,
string[] JLinks, string[] JLinks,
string? LinkedAlpha, string? LinkedAlpha,
@ -62,7 +64,7 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
int RadomUseBirthdayMinimum, int RadomUseBirthdayMinimum,
int[] RangeDaysDeltaTolerance, int[] RangeDaysDeltaTolerance,
float[] RangeDistanceTolerance, float[] RangeDistanceTolerance,
float[] RangeFaceAreaPermyriadTolerance, float[] RangeFaceAreaTolerance,
float[] RangeFaceConfidence, float[] RangeFaceConfidence,
float[] RectangleIntersectMinimums, float[] RectangleIntersectMinimums,
bool ReMap, bool ReMap,
@ -70,6 +72,7 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
string[] SaveBlurHashForOutputResolutions, string[] SaveBlurHashForOutputResolutions,
string[] SaveFaceDistancesForOutputResolutions, string[] SaveFaceDistancesForOutputResolutions,
string[] SaveFaceLandmarkForOutputResolutions, string[] SaveFaceLandmarkForOutputResolutions,
string[] SaveFaceLandmarkForOutputResolutionsV2,
string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions, string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions,
bool SaveFullYearOfRandomFiles, bool SaveFullYearOfRandomFiles,
bool SaveIndividually, bool SaveIndividually,
@ -87,6 +90,7 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
int SortingMaximumPerKey, int SortingMaximumPerKey,
int SortingMinimumToUseSigma, int SortingMinimumToUseSigma,
bool TestDistanceResults, bool TestDistanceResults,
bool UseExtraPersonKeyCheck,
int UseFilterTries, int UseFilterTries,
string[] ValidKeyWordsToIgnoreInRandom, string[] ValidKeyWordsToIgnoreInRandom,
string[] ValidResolutions); string[] ValidResolutions);

View File

@ -1,27 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Instance.Models;
internal record Identifier(int Id, string PaddedId)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, IdentifierSourceGenerationContext.Default.Identifier);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Identifier))]
internal partial class IdentifierSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Identifier[]))]
internal partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,5 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Instance.Models; namespace View_by_Distance.Instance.Models;
@ -24,16 +25,18 @@ internal class F_Random
return result; return result;
} }
private static ReadOnlyDictionary<string, List<string>> GetDayToRelativePaths(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection, string dateFormat, ReadOnlyDictionary<int, List<long>> idToPersonKeys) private static ReadOnlyDictionary<string, List<string>> GetDayToRelativePaths(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, string dateFormat, string immichOwnerId, string immichRoot, Dictionary<string, ImmichAsset> immichAssets, ReadOnlyDictionary<int, List<long>> idToPersonKeys)
{ {
Dictionary<string, List<string>> results = []; Dictionary<string, List<string>> results = [];
string key; string key;
DateTime dateTime; DateTime dateTime;
List<long>? personKeys; List<long>? personKeys;
ImmichAsset? immichAsset;
List<string>? relativePaths; List<string>? relativePaths;
foreach (Shared.Models.Mapping mapping in mappingCollection) bool immichAssetsCountIsZero = immichAssets.Count == 0;
foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
if (mapping.MappingFromItem.FilePath.DirectoryName is null || mapping.MappingFromPerson is null) if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null || mapping.MappingFromPerson is null)
continue; continue;
if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys)) if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys))
continue; continue;
@ -49,39 +52,79 @@ internal class F_Random
if (!results.TryGetValue(key, out relativePaths)) if (!results.TryGetValue(key, out relativePaths))
throw new Exception(); throw new Exception();
} }
relativePaths.Add(mapping.MappingFromItem.RelativePath); if (immichAssetsCountIsZero)
relativePaths.Add(mapping.MappingFromItem.RelativePath);
else
{
if (!immichAssets.TryGetValue($"{immichRoot}{mapping.MappingFromItem.RelativePath}", out immichAsset))
continue;
if (!immichAsset.Path.Contains(immichOwnerId))
continue;
relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]);
}
} }
return new(results); return new(results);
} }
internal void Random(Property.Models.Configuration configuration, int radomUseBirthdayMinimum, string[] validKeyWordsToIgnoreInRandom, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<int>? notNineCollection, ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) private static Dictionary<string, ImmichAsset> GetImmichAssets(string immichAssetsFile)
{
Dictionary<string, ImmichAsset> results = [];
if (!string.IsNullOrEmpty(immichAssetsFile) && File.Exists(immichAssetsFile))
{
string json = File.ReadAllText(immichAssetsFile);
ImmichAsset[]? immichAssets = JsonSerializer.Deserialize(json, ImmichAssetCollectionSourceGenerationContext.Default.ImmichAssetArray);
if (immichAssets is not null)
{
foreach (ImmichAsset immichAsset in immichAssets)
results.Add(immichAsset.OriginalPath, immichAsset);
}
}
return results;
}
internal void Random(Property.Models.Configuration configuration, string immichAssetsFile, string immichOwnerId, string immichRoot, int radomUseBirthdayMinimum, string[] validKeyWordsToIgnoreInRandom, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyDictionary<int, Identifier> splatNineIdentifiers, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
string key; string key;
string json; string json;
string jsonFile; string jsonFile;
Random random = new(); Random random = new();
List<string>? collection; List<string>? collection;
ImmichAsset? immichAsset;
string dateFormat = "MM-dd"; string dateFormat = "MM-dd";
List<string> relativePaths = []; List<string> relativePaths = [];
List<int> distinctCollection = []; List<int> distinctCollection = [];
DateTime dateTime = new(2024, 1, 1); //Leap year DateTime dateTime = new(2024, 1, 1); //Leap year
Dictionary<string, ImmichAsset> immichAssets = GetImmichAssets(immichAssetsFile);
int[] splatNineIdentifiersKeys = splatNineIdentifiers.Select(l => l.Key).ToArray();
ReadOnlyDictionary<int, List<long>> idToPersonKeys = Map.Models.Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds); ReadOnlyDictionary<int, List<long>> idToPersonKeys = Map.Models.Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds);
ReadOnlyDictionary<string, List<string>> dayToRelativePaths = GetDayToRelativePaths(mappingCollection, dateFormat, idToPersonKeys); ReadOnlyDictionary<string, List<string>> dayToRelativePaths = GetDayToRelativePaths(distinctValidImageMappingCollection, dateFormat, immichOwnerId, immichRoot, immichAssets, idToPersonKeys);
string fRandomCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "[]"); string fRandomCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "[]");
string[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly); string[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files) foreach (string file in files)
File.Delete(file); File.Delete(file);
foreach (Shared.Models.Mapping mapping in mappingCollection) bool immichAssetsCountIsZero = immichAssets.Count == 0;
foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
if (mapping.MappingFromItem.IsArchive is not null && mapping.MappingFromItem.IsArchive.Value)
continue;
if (distinctCollection.Contains(mapping.MappingFromItem.Id)) if (distinctCollection.Contains(mapping.MappingFromItem.Id))
continue; continue;
if (mapping.MappingFromItem.FilePath.DirectoryName is null) if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null)
continue; continue;
if (notNineCollection is not null && notNineCollection.Contains(mapping.MappingFromItem.Id)) if (!splatNineIdentifiersKeys.Contains(mapping.MappingFromItem.Id))
continue; continue;
if (mapping.MappingFromItem.Keywords is not null && mapping.MappingFromItem.Keywords.Any(l => validKeyWordsToIgnoreInRandom.Contains(l))) if (mapping.MappingFromItem.Keywords is not null && mapping.MappingFromItem.Keywords.Any(l => validKeyWordsToIgnoreInRandom.Contains(l)))
continue; continue;
relativePaths.Add(mapping.MappingFromItem.RelativePath); if (immichAssetsCountIsZero)
relativePaths.Add(mapping.MappingFromItem.RelativePath);
else
{
if (!immichAssets.TryGetValue($"{immichRoot}{mapping.MappingFromItem.RelativePath}", out immichAsset))
continue;
if (!immichAsset.Path.Contains(immichOwnerId))
continue;
relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]);
}
distinctCollection.Add(mapping.MappingFromItem.Id); distinctCollection.Add(mapping.MappingFromItem.Id);
} }
if (relativePaths.Count > 0) if (relativePaths.Count > 0)

1
Map/.vscode/format-report.json vendored Normal file
View File

@ -0,0 +1 @@
[]

42
Map/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Format",
"command": "dotnet",
"type": "process",
"args": [
"format",
"--report",
".vscode",
"--verbosity",
"detailed",
"--severity",
"warn"
],
"problemMatcher": "$msCompile"
},
{
"label": "Format-Whitespaces",
"command": "dotnet",
"type": "process",
"args": [
"format",
"whitespace"
],
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Map.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Map</PackageId> <PackageId>Phares.View.by.Distance.Map</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -36,8 +36,8 @@
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -1,6 +1,8 @@
namespace View_by_Distance.Map.Models; namespace View_by_Distance.Map.Models;
public record Configuration(bool DeletePossibleDuplicates, public record Configuration(Shared.Models.Methods.IDistanceLimits DistanceLimits,
Shared.Models.Properties.IPropertyConfiguration PropertyConfiguration,
bool DeletePossibleDuplicates,
bool DistanceMoveUnableToMatch, bool DistanceMoveUnableToMatch,
bool DistanceRenameToMatch, bool DistanceRenameToMatch,
int FaceConfidencePercent, int FaceConfidencePercent,

View File

@ -23,6 +23,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
long? Ticks, long? Ticks,
string? PersonDirectory); string? PersonDirectory);
internal record FilteredOriginalImage(int Id,
FilePath FilePath,
int ApproximateYears,
string PersonKeyFormatted,
string Directory,
string PersonDirectory,
string CheckFile);
public void SaveContainers(int? updated, List<SaveContainer> saveContainers) public void SaveContainers(int? updated, List<SaveContainer> saveContainers)
{ {
if (_Configuration is null) if (_Configuration is null)
@ -137,7 +145,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
} }
} }
private List<SaveShortcutsForOutputResolutions> GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection) private List<SaveShortcutsForOutputResolutions> GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
List<SaveShortcutsForOutputResolutions> results = []; List<SaveShortcutsForOutputResolutions> results = [];
if (_Configuration is null) if (_Configuration is null)
@ -153,7 +161,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
string personKeyFormatted; string personKeyFormatted;
Calendar calendar = new CultureInfo("en-US").Calendar; Calendar calendar = new CultureInfo("en-US").Calendar;
ReadOnlyDictionary<int, List<long>> idToPersonKeys = IMapLogic.GetIdToPersonKeys(personKeyToIds); ReadOnlyDictionary<int, List<long>> idToPersonKeys = IMapLogic.GetIdToPersonKeys(personKeyToIds);
foreach (Mapping mapping in mappingCollection) foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(); dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey; description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey;
@ -162,9 +170,9 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Year}.{season}-MM{dateTime.Month:00}-WW{weekOfYear}"); directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Year}.{season}-MM{dateTime.Month:00}-WW{weekOfYear}");
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false)); results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
if (mapping.MappingFromItem.FilePath.DirectoryName is null) if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null)
continue; continue;
directoryName = Path.GetFileName(mapping.MappingFromItem.FilePath.DirectoryName); directoryName = Path.GetFileName(mapping.MappingFromItem.FilePath.DirectoryFullPath);
if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim())) if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim()))
{ {
// Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 " // Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 "
@ -181,12 +189,12 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey); personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey);
directory = Path.Combine($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName); directory = Path.Combine($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName);
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
if (IPerson.IsDefaultName(mapping.MappingFromPerson)) if (IPerson.IsDefaultName(mapping.MappingFromPerson))
continue; continue;
directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName); directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName);
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false)); results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
} }
return results; return results;
} }
@ -230,7 +238,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
ReadOnlyDictionary<long, int> readOnlyPersonKeyToCount; ReadOnlyDictionary<long, int> readOnlyPersonKeyToCount;
Dictionary<int, List<(string, int)>> skipCollection = []; Dictionary<int, List<(string, int)>> skipCollection = [];
Dictionary<int, List<(string, int)>> skipNotSkipCollection = []; Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
ReadOnlyDictionary<int, List<(string, int)>> readOnlyskipCollection; ReadOnlyDictionary<int, List<(string, int)>> readOnlySkipCollection;
string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory); string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, ticks.ToString()); string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, ticks.ToString());
ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> idThenWholePercentagesToPersonContainers; ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> idThenWholePercentagesToPersonContainers;
@ -256,7 +264,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
{ {
List<string> personKeyFormattedCollection = []; List<string> personKeyFormattedCollection = [];
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = []; Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
Stateless.MapLogic.SetPersonCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection); Stateless.MapLogic.SetPersonCollectionsAfterSetSkipCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection); readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection);
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted); readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted);
} }
@ -297,7 +305,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
skipCollection, skipCollection,
readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyFormattedToPersonContainer,
personKeyFormattedIdThenWholePercentagesCollection); personKeyFormattedIdThenWholePercentagesCollection);
readOnlyskipCollection = new(skipCollection); readOnlySkipCollection = new(skipCollection);
notMappedPersonContainers.AddRange(Stateless.MapLogic.GetNotMappedPersonContainers(configuration, notMappedPersonContainers.AddRange(Stateless.MapLogic.GetNotMappedPersonContainers(configuration,
ticks, ticks,
personContainers, personContainers,
@ -307,7 +315,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
configuration, configuration,
ticks, ticks,
personContainers, personContainers,
readOnlyskipCollection, readOnlySkipCollection,
records)); records));
int lossCount = records.Count - locationContainers.Count; int lossCount = records.Count - locationContainers.Count;
int unableToMatchCount = records.Count - personKeyFormattedIdThenWholePercentagesCollection.Count; int unableToMatchCount = records.Count - personKeyFormattedIdThenWholePercentagesCollection.Count;
@ -452,6 +460,31 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
private (long?, string?) GetDirectory(Configuration configuration, string by, string segmentB)
{
long? ticks = null;
const int zero = 0;
string? directory = null;
string personKeyFormatted;
PersonBirthday personBirthday;
PersonContainer personContainer;
for (int i = _NotMappedPersonContainers.Count - 1; i > 0; i--)
{
if (configuration.SaveIndividually)
break;
personContainer = _NotMappedPersonContainers[i];
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0)
continue;
personBirthday = personContainer.Birthdays[zero];
ticks = personBirthday.Value.Ticks;
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
_NotMappedPersonContainers.RemoveAt(i);
break;
}
return (ticks, directory);
}
private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem) private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem)
{ {
long? ticks = null; long? ticks = null;
@ -504,7 +537,30 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
private Record Get(Configuration configuration, bool saveIndividually, string by, Mapping question, int padLeft) private Record Get(Configuration configuration, string by, long? personKey, string? displayDirectoryName, string segmentB)
{
long? ticks;
string? directory;
string? debugDirectory;
string? personDirectory;
if (personKey is null || string.IsNullOrEmpty(displayDirectoryName))
{
debugDirectory = null;
(ticks, directory) = GetDirectory(configuration, by, segmentB);
personDirectory = directory is null ? null : Path.Combine(directory, $"X+{ticks}");
}
else
{
ticks = null;
string personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey.Value);
debugDirectory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, displayDirectoryName);
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
personDirectory = Path.Combine(directory, displayDirectoryName, "lnk");
}
return new(debugDirectory, directory, ticks, personDirectory);
}
private Record Get(Configuration configuration, bool saveIndividually, int padLeft, string by, Mapping question)
{ {
long? ticks; long? ticks;
string? directory; string? directory;
@ -532,7 +588,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return new(debugDirectory, directory, ticks, personDirectory); return new(debugDirectory, directory, ticks, personDirectory);
} }
private List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyDictionary<long, List<int>> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny) private List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyDictionary<long, List<int>> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
@ -557,7 +613,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
ReadOnlyDictionary<int, Mapping>? wholePercentagesToMapping; ReadOnlyDictionary<int, Mapping>? wholePercentagesToMapping;
int padLeft = _Configuration.FaceDistancePermyriad.ToString().Length; int padLeft = _Configuration.FaceDistancePermyriad.ToString().Length;
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
foreach (Mapping mapping in mappingCollection) foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
if (mapping.MappingFromLocation is null) if (mapping.MappingFromLocation is null)
continue; continue;
@ -586,7 +642,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
if (!PreAndPostContinue(_Configuration, mapping, question)) if (!PreAndPostContinue(_Configuration, mapping, question))
continue; continue;
} }
record = Get(_Configuration, saveIndividually, by, mapping, padLeft); record = Get(_Configuration, saveIndividually, padLeft, by, mapping);
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory)) if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
continue; continue;
directory = record.Directory; directory = record.Directory;
@ -651,7 +707,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return results; return results;
} }
public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping) public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
@ -659,7 +715,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
bool saveMapped = true; bool saveMapped = true;
int? useFiltersCounter = null; int? useFiltersCounter = null;
string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping)); string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping));
List<SaveContainer> saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, saveIndividually: false); List<SaveContainer> saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, distinctValidImageMappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, saveIndividually: false);
SaveContainers(updated, saveContainers); SaveContainers(updated, saveContainers);
if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory)) if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory))
Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory); Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory);
@ -753,7 +809,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
keyToCount.Add(key, new()); keyToCount.Add(key, new());
_ = keyToCount.TryAdd(key, 0); _ = keyToCount.TryAdd(key, 0);
keyToCount[key]++; keyToCount[key]++;
if (!_Configuration.SaveIndividually && keyToCount[key] < _Configuration.SortingMaximumPerKey) if (!_Configuration.SaveIndividually && keyToCount[key] <= _Configuration.SortingMaximumPerKey)
segmentC = null; segmentC = null;
else else
segmentC = sortingContainer.Sorting.DistancePermyriad.ToString(); segmentC = sortingContainer.Sorting.DistancePermyriad.ToString();
@ -764,6 +820,95 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
private string? GetDisplayDirectoryName(string? displayDirectoryName, LocationContainer locationContainer, ReadOnlyDictionary<long, PersonContainer> personKeyToPersonContainer)
{
string? result = displayDirectoryName;
if (personKeyToPersonContainer.Count != 0)
{
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers = GetWholePercentagesToPersonContainers(locationContainer.Id);
if (wholePercentagesToPersonContainers is not null)
{
foreach (KeyValuePair<int, ReadOnlyCollection<PersonContainer>> keyValuePair in wholePercentagesToPersonContainers)
{
if (keyValuePair.Key != locationContainer.WholePercentages)
continue;
if (keyValuePair.Value.Count != 1)
continue;
result = keyValuePair.Value[0].DisplayDirectoryName;
}
}
}
return result;
}
public List<SaveContainer> GetSaveContainers(string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, Shared.Models.Methods.IDistanceLimits distanceLimits, ReadOnlyDictionary<string, LocationContainer> onlyOne, ReadOnlyDictionary<long, PersonContainer> personKeyToPersonContainer)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<SaveContainer> results = [];
string by;
Record record;
string segmentB;
bool isBySorting;
string checkFile;
string? directory;
string shortcutFile;
string facesDirectory;
bool isCounterPersonYear;
string facePartsDirectory;
FileHolder? faceFileHolder;
SaveContainer? saveContainer;
string? displayDirectoryName;
FileHolder? resizedFileHolder;
int? useFiltersCounter = null;
string resizeContentDirectory;
FileHolder? facePartsFileHolder;
FileHolder? hiddenFaceFileHolder;
LocationContainer locationContainer;
bool sortingContainersAny = onlyOne.Count > 0;
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
{
if (_Configuration.SaveIndividually)
break;
locationContainer = keyValuePair.Value;
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
continue;
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
displayDirectoryName = GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer, personKeyToPersonContainer);
isCounterPersonYear = locationContainer.PersonKey is not null && IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKey.Value);
(by, _, isBySorting) = Stateless.MapLogic.Get(useFiltersCounter, _Configuration.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKey, displayDirectoryName);
record = Get(_Configuration, by, locationContainer.PersonKey, displayDirectoryName, segmentB);
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
continue;
directory = record.Directory;
if (!string.IsNullOrEmpty(record.DebugDirectory))
results.Add(new(record.DebugDirectory));
if (locationContainer.PersonKey is null)
{
if (!_Configuration.SaveSortingWithoutPerson)
throw new NotSupportedException();
if (record.Ticks is null)
continue;
}
results.Add(new(record.PersonDirectory));
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
faceFileHolder = IFileHolder.Get(locationContainer.LengthSource.FullName);
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
shortcutFile = Path.Combine(record.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
resizeContentDirectory = Stateless.MapLogic.GetResizeContentDirectory(_PropertyConfiguration, cContentDirectory, locationContainer.LengthSource);
facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectoryX(_PropertyConfiguration, d2FacePartsContentDirectory, locationContainer.LengthSource);
hiddenFaceFileHolder = IFileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacesHiddenFileNameExtension}"));
facePartsFileHolder = IFileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacePartsFileNameExtension}"));
resizedFileHolder = IFileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
results.Add(saveContainer);
}
return results;
}
public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, int? useFiltersCounter, ReadOnlyCollection<SortingContainer> sortingContainers) public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, int? useFiltersCounter, ReadOnlyCollection<SortingContainer> sortingContainers)
{ {
if (_Configuration is null) if (_Configuration is null)
@ -802,7 +947,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
throw new NotSupportedException(); throw new NotSupportedException();
if (question.MappingFromLocation is null) if (question.MappingFromLocation is null)
continue; continue;
record = Get(_Configuration, _Configuration.SaveIndividually, by, question, padLeft); record = Get(_Configuration, _Configuration.SaveIndividually, padLeft, by, question);
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory)) if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
continue; continue;
directory = record.Directory; directory = record.Directory;
@ -1029,7 +1174,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{ids.Count} Face(s)"))); collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{ids.Count} Face(s)")));
foreach ((long personKey, string displayDirectoryName) in collection) foreach ((long personKey, string displayDirectoryName) in collection)
{ {
matches = (from l in personContainers where l.Key == personKey && l.ApproximateYears.HasValue select l).ToArray(); matches = (from l in personContainers where l.Key == personKey select l).ToArray();
if (matches.Length == 0) if (matches.Length == 0)
continue; continue;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personKey); personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personKey);
@ -1044,11 +1189,11 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return results; return results;
} }
private (int, FilePath, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<long, List<int>> personKeyToIds) private FilteredOriginalImage[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<long, List<int>> personKeyToIds)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
(int, FilePath, int, string, string, string, string)[] results; FilteredOriginalImage[] results;
int count = 0; int count = 0;
int group = 65; int group = 65;
string checkFile; string checkFile;
@ -1058,9 +1203,9 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
string personKeyFormatted; string personKeyFormatted;
List<int> distinctCollection = []; List<int> distinctCollection = [];
bool usePersonKeyAndDeterministicHashCodeKey = false; bool usePersonKeyAndDeterministicHashCodeKey = false;
List<FilteredOriginalImage> filteredOriginalImages = [];
List<string> personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleContentDirectory, personContainers, personKeyToIds); List<string> personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleContentDirectory, personContainers, personKeyToIds);
List<(int Id, FilePath FilePath, int ApproximateYears, string PersonKeyFormatted, string CheckFile, string Directory, string PersonDirectory)> collection = []; foreach (Mapping mapping in distinctValidImageMappingCollection)
foreach (Mapping mapping in mappingCollection)
{ {
if (distinctCollection.Contains(mapping.MappingFromItem.Id)) if (distinctCollection.Contains(mapping.MappingFromItem.Id))
continue; continue;
@ -1069,7 +1214,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
throw new NotSupportedException(); throw new NotSupportedException();
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting) if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting)
continue; continue;
if (mapping.MappingFromPerson?.ApproximateYears is null || mapping.MappingFromLocation is null) if (mapping.MappingFromPerson is null || mapping.MappingFromLocation is null)
continue; continue;
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB)) if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
throw new NotSupportedException(); throw new NotSupportedException();
@ -1097,39 +1242,45 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName); personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}"); checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}");
} }
collection.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, mapping.MappingFromPerson.ApproximateYears.Value, personKeyFormatted, directory, personDirectory, checkFile)); if (mapping is null)
continue;
if (mapping.MappingFromPerson.ApproximateYears is null)
filteredOriginalImages.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, -1, personKeyFormatted, directory, personDirectory, checkFile));
else
filteredOriginalImages.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, mapping.MappingFromPerson.ApproximateYears.Value, personKeyFormatted, directory, personDirectory, checkFile));
distinctCollection.Add(mapping.MappingFromItem.Id); distinctCollection.Add(mapping.MappingFromItem.Id);
count += 1; count += 1;
} }
results = (from l in collection orderby l.ApproximateYears descending, l.PersonKeyFormatted descending select l).ToArray(); results = (from l in filteredOriginalImages orderby l.ApproximateYears descending, l.PersonKeyFormatted descending select l).ToArray();
return results; return results;
} }
public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection) public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
int? updated = null;
FileHolder fileHolder; FileHolder fileHolder;
SaveContainer? saveContainer; SaveContainer? saveContainer;
List<SaveContainer> saveContainers = []; List<SaveContainer> saveContainers = [];
(int, FilePath, int, string, string, string, string)[] collection = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, mappingCollection, personKeyToIds); FilteredOriginalImage[] filteredOriginalImages = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, distinctValidImageMappingCollection, personKeyToIds);
foreach ((int id, FilePath filePath, int approximateYears, string personKeyFormatted, string directory, string personDirectory, string checkFile) in collection) foreach (FilteredOriginalImage filteredOriginalImage in filteredOriginalImages)
{ {
fileHolder = FileHolder.Get(filePath); fileHolder = FileHolder.Get(filteredOriginalImage.FilePath);
saveContainer = new(personDirectory); saveContainer = new(filteredOriginalImage.PersonDirectory);
saveContainers.Add(saveContainer); saveContainers.Add(saveContainer);
saveContainer = new(fileHolder, checkFile, directory); saveContainer = new(fileHolder, filteredOriginalImage.CheckFile, filteredOriginalImage.Directory);
saveContainers.Add(saveContainer); saveContainers.Add(saveContainer);
} }
SaveContainers(null, saveContainers); SaveContainers(updated, saveContainers);
} }
public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection) public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
string hiddenFile; string hiddenFile;
WindowsShortcut windowsShortcut; WindowsShortcut windowsShortcut;
List<SaveShortcutsForOutputResolutions> collection = []; List<SaveShortcutsForOutputResolutions> collection = [];
collection = GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, mappingCollection); collection = GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctValidImageMappingCollection);
string[] distinctDirectories = (from l in collection select l.Directory).Distinct().ToArray(); string[] distinctDirectories = (from l in collection select l.Directory).Distinct().ToArray();
foreach (string directory in distinctDirectories) foreach (string directory in distinctDirectories)
{ {
@ -1163,7 +1314,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
} }
} }
private (List<(string, DateTime[])>, List<SaveShortcutsForOutputResolutions>) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Item> filteredItems, ReadOnlyCollection<Mapping> mappingCollection) private (List<(string, DateTime[])>, List<SaveShortcutsForOutputResolutions>) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Item> validImageItems, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
@ -1171,6 +1322,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
string fileName; string fileName;
string fullName; string fullName;
string directory; string directory;
DateTime dateTime;
string facesDirectory; string facesDirectory;
string? directoryName; string? directoryName;
string personDirectory; string personDirectory;
@ -1178,7 +1330,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
List<string> distinct = []; List<string> distinct = [];
List<SaveShortcutsForOutputResolutions> collection = []; List<SaveShortcutsForOutputResolutions> collection = [];
List<(string, DateTime[])> directoriesAndDateTimes = []; List<(string, DateTime[])> directoriesAndDateTimes = [];
foreach (Item item in filteredItems) foreach (Item item in validImageItems)
{ {
if (item.ResizedFileHolder is null) if (item.ResizedFileHolder is null)
continue; continue;
@ -1191,43 +1343,44 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath); directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath);
if (directoryName is null) if (directoryName is null)
throw new NotSupportedException(); throw new NotSupportedException();
if (item.ResizedFileHolder?.DirectoryName is null || !item.ResizedFileHolder.Exists) if (item.ResizedFileHolder?.DirectoryFullPath is null || !item.ResizedFileHolder.Exists)
continue; continue;
directory = Path.Combine(item.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne); directory = Path.Combine(item.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
personDirectory = Path.Combine(directory, "No Faces"); personDirectory = Path.Combine(directory, "No Faces");
fileName = Path.Combine(personDirectory, $"{item.ResizedFileHolder.Name}.lnk"); fileName = Path.Combine(personDirectory, $"{item.ResizedFileHolder.Name}.lnk");
collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, new(item.FilePath.LastWriteTicks), fileName, face.Mapping.MappingFromItem.Id.ToString(), MakeAllHidden: false)); collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, new(item.FilePath.LastWriteTicks), fileName, face.Mapping.MappingFromItem.Id.ToString(), MakeAllHidden: false));
if (face.Mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(item.ResizedFileHolder.DirectoryName)) if (face.Mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(item.ResizedFileHolder.DirectoryFullPath))
{ {
distinct.Add(item.ResizedFileHolder.DirectoryName); distinct.Add(item.ResizedFileHolder.DirectoryFullPath);
directoriesAndDateTimes.Add(new(item.ResizedFileHolder.DirectoryName, face.Mapping.MappingFromItem.ContainerDateTimes)); directoriesAndDateTimes.Add(new(item.ResizedFileHolder.DirectoryFullPath, face.Mapping.MappingFromItem.ContainerDateTimes));
} }
} }
} }
foreach (Mapping mapping in mappingCollection) foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath); directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
if (directoryName is null) if (directoryName is null)
throw new NotSupportedException(); throw new NotSupportedException();
if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists) if (mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath is null || !mapping.MappingFromItem.ResizedFileHolder.Exists)
continue; continue;
dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting || mapping.MappingFromPerson?.ApproximateYears is null) if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting || mapping.MappingFromPerson?.ApproximateYears is null)
{ {
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName)) if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath))
{ {
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName); distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath);
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes)); directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, mapping.MappingFromItem.ContainerDateTimes));
} }
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne); directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
personDirectory = Path.Combine(directory, "Unknown"); personDirectory = Path.Combine(directory, "Unknown");
fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
facesDirectory = Stateless.MapLogic.GetFacesDirectory(_PropertyConfiguration, dFacesContentDirectory, mapping.FilePath, mapping.MappingFromItem); facesDirectory = Stateless.MapLogic.GetFacesDirectory(_PropertyConfiguration, dFacesContentDirectory, mapping.FilePath, mapping.MappingFromItem);
if (mapping.MappingFromLocation is null) if (mapping.MappingFromLocation is null)
continue; continue;
fullName = Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}{_Configuration.FacesFileNameExtension}"); fullName = Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}{_Configuration.FacesFileNameExtension}");
fileName = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ResizedFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}.lnk"); fileName = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ResizedFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}.lnk");
collection.Add(new(fullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true)); collection.Add(new(fullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true));
} }
else else
{ {
@ -1236,32 +1389,32 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName)) if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
throw new NotSupportedException(); throw new NotSupportedException();
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey); personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey);
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName)) if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath))
{ {
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName); distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath);
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes)); directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, mapping.MappingFromItem.ContainerDateTimes));
} }
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted); directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted);
if (!personKeyToIds.TryGetValue(mapping.MappingFromPerson.PersonKey, out ids)) if (!personKeyToIds.TryGetValue(mapping.MappingFromPerson.PersonKey, out ids))
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName); personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
else else
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{ids.Count} Face(s)"); personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{ids.Count} Face(s)");
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk"); fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false)); collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
} }
} }
return new(directoriesAndDateTimes, collection); return new(directoriesAndDateTimes, collection);
} }
public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> mappingCollection) public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
WindowsShortcut windowsShortcut; WindowsShortcut windowsShortcut;
List<(string, DateTime[])> directoriesAndDateTimes; List<(string, DateTime[])> directoriesAndDateTimes;
List<SaveShortcutsForOutputResolutions> collection; List<SaveShortcutsForOutputResolutions> collection;
ReadOnlyCollection<Item> filteredItems = IContainer.GetItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true); ReadOnlyCollection<Item> validImageItems = IContainer.GetValidImageItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true);
(directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, filteredItems, mappingCollection); (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, validImageItems, distinctValidImageMappingCollection);
string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
foreach (string directory in directories) foreach (string directory in directories)
{ {
@ -1305,10 +1458,13 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) => public bool InSkipCollection(int id, int wholePercentages) =>
_SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(mappingFromLocation.WholePercentages); _SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(wholePercentages);
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) =>
InSkipCollection(id, mappingFromLocation.WholePercentages);
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
{ {
bool? result; bool? result;
ReadOnlyCollection<PersonContainer>? personContainers; ReadOnlyCollection<PersonContainer>? personContainers;
@ -1316,7 +1472,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
result = null; result = null;
else if (wholePercentagesToPersonContainers is null) else if (wholePercentagesToPersonContainers is null)
result = null; result = null;
else if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers)) else if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
result = null; result = null;
else else
{ {
@ -1340,37 +1496,46 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
{ {
string[] directories; string[] directories;
string? directoryName; string? directoryName;
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers); List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
LookForAbandoned(propertyConfiguration, distinctFilteredIds); LookForAbandoned(propertyConfiguration, distinctFilteredIds);
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredIds); dlibDotNet.Tick();
List<string> distinctFilteredFileNameFirstSegments = IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
dlibDotNet.Tick();
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
directoryName = Path.GetFileName(directory); directoryName = Path.GetFileName(directory);
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4) if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick();
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
directoryName = Path.GetFileName(directory); directoryName = Path.GetFileName(directory);
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4) if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick();
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
directoryName = Path.GetFileName(directory); directoryName = Path.GetFileName(directory);
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4) if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick();
} }
} }

View File

@ -32,9 +32,23 @@ internal abstract class DecadeLogic
return result; return result;
} }
internal static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) internal static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
{ {
DateTime dateTime; DateTime dateTime;
foreach (LocationContainer locationContainer in locationContainers)
{
dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
if (locationContainer.CreationDateOnly.Year != dateTime.Year || locationContainer.CreationDateOnly.Month != dateTime.Month || locationContainer.CreationDateOnly.Day != dateTime.Day)
{
if (!File.Exists(locationContainer.FilePath.FullName))
continue;
File.SetCreationTime(locationContainer.FilePath.FullName, dateTime);
}
}
}
internal static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
{
string halfDecade; string halfDecade;
string checkDirectory; string checkDirectory;
string? yearDirectory; string? yearDirectory;
@ -44,17 +58,10 @@ internal abstract class DecadeLogic
string? personKeyFormattedDirectoryName; string? personKeyFormattedDirectoryName;
foreach (LocationContainer locationContainer in locationContainers) foreach (LocationContainer locationContainer in locationContainers)
{ {
if (!File.Exists(locationContainer.FilePath.FullName)) if (string.IsNullOrEmpty(locationContainer.FilePath.DirectoryFullPath))
continue; continue;
dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value; personNameDirectoryName = Path.GetFileName(locationContainer.FilePath.DirectoryFullPath);
if (locationContainer.CreationDateOnly.Year != dateTime.Year || locationContainer.CreationDateOnly.Month != dateTime.Month || locationContainer.CreationDateOnly.Day != dateTime.Day) yearDirectory = Path.GetDirectoryName(locationContainer.FilePath.DirectoryFullPath);
File.SetCreationTime(locationContainer.FilePath.FullName, dateTime);
if (!moveToDecade)
continue;
if (string.IsNullOrEmpty(locationContainer.FilePath.DirectoryName))
continue;
personNameDirectoryName = Path.GetFileName(locationContainer.FilePath.DirectoryName);
yearDirectory = Path.GetDirectoryName(locationContainer.FilePath.DirectoryName);
if (string.IsNullOrEmpty(yearDirectory)) if (string.IsNullOrEmpty(yearDirectory))
continue; continue;
yearDirectoryName = Path.GetFileName(yearDirectory); yearDirectoryName = Path.GetFileName(yearDirectory);
@ -68,6 +75,8 @@ internal abstract class DecadeLogic
if (halfDecade == yearDirectoryName) if (halfDecade == yearDirectoryName)
continue; continue;
checkDirectory = Path.Combine(personKeyFormattedDirectory, halfDecade, personNameDirectoryName); checkDirectory = Path.Combine(personKeyFormattedDirectory, halfDecade, personNameDirectoryName);
if (!File.Exists(locationContainer.FilePath.FullName))
continue;
if (!Directory.Exists(checkDirectory)) if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory); _ = Directory.CreateDirectory(checkDirectory);
File.Move(locationContainer.FilePath.FullName, Path.Combine(checkDirectory, locationContainer.FilePath.Name)); File.Move(locationContainer.FilePath.FullName, Path.Combine(checkDirectory, locationContainer.FilePath.Name));

View File

@ -250,14 +250,27 @@ internal abstract class DistanceLogic
return results; return results;
} }
private static void RenameUnknown(string[] files) private static string[] RenameBirth(string[] files)
{ {
List<string> results = [];
string checkFile;
foreach (string file in files) foreach (string file in files)
{ {
if (file.EndsWith(".unk")) if (file.EndsWith(".brt"))
{
results.Add(file);
continue; continue;
File.Move(file, $"{file}.unk"); }
checkFile = $"{file}.brt";
if (File.Exists(checkFile))
{
results.Add(file);
continue;
}
File.Move(file, checkFile);
results.Add(checkFile);
} }
return results.ToArray();
} }
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory) private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
@ -374,7 +387,7 @@ internal abstract class DistanceLogic
} }
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
if (personNameDirectories.Length > 1) if (personNameDirectories.Length > 1)
throw new NotSupportedException(); throw new NotSupportedException("Try deleting *.lnk files!");
foreach (string personNameDirectory in personNameDirectories) foreach (string personNameDirectory in personNameDirectories)
{ {
directoryNumber++; directoryNumber++;
@ -422,7 +435,7 @@ internal abstract class DistanceLogic
if (!isDefault.Value) if (!isDefault.Value)
{ {
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null) if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
RenameUnknown(files); files = RenameBirth(files);
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted) else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
{ {
if (!check) if (!check)

View File

@ -0,0 +1,207 @@
using ShellProgressBar;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Text.Json;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods;
using static View_by_Distance.Map.Models.Stateless.MapLogic;
namespace View_by_Distance.Map.Models.Stateless;
internal abstract class FaceFileLogic
{
private static void MappedParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyDictionary<int, List<(string, int)>> skipCollection, List<LocationContainer> locationContainers, MappedFile mappedFile)
{
int? id;
string checkFile;
DateOnly dateOnly;
FilePath filePath;
string[] fileMatches;
FileHolder fileHolder;
int? wholePercentages;
const string lnk = ".lnk";
ExifDirectory? exifDirectory;
string personDisplayDirectoryName;
const bool fromDistanceContent = true;
List<(string File, int WholePercentages)>? wholePercentagesCollection;
if (!mappedFile.FilePath.Name.EndsWith(lnk))
{
if (mappedFile.FilePath.Id is null)
return;
id = mappedFile.FilePath.Id;
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, mappedFile.FilePath);
}
else
{
fileHolder = IFileHolder.Get(mappedFile.FilePath.FullName[..^4]);
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
if (filePath.Id is null)
return;
id = filePath.Id;
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
}
if (wholePercentages is null)
return;
if (configuration.LinkedAlpha is null && string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory) && skipCollection.TryGetValue(id.Value, out wholePercentagesCollection))
{
fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray();
foreach (string fileMatch in fileMatches)
{
if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch))
continue;
checkFile = $"{fileMatch}.dup";
if (File.Exists(checkFile))
continue;
File.Move(fileMatch, checkFile);
continue;
}
}
dateOnly = DateOnly.FromDateTime(new DateTime(mappedFile.FilePath.CreationTicks));
if (mappedFile.FilePath.Name.EndsWith(lnk) || !File.Exists(mappedFile.FilePath.FullName))
exifDirectory = null;
else
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
LocationContainer locationContainer = new(dateOnly,
exifDirectory,
mappedFile.DirectoryNumber,
personDisplayDirectoryName,
null,
null,
mappedFile.FilePath,
fromDistanceContent,
id.Value,
null,
null,
mappedFile.PersonKey,
rectangle,
wholePercentages.Value);
lock (locationContainers)
locationContainers.Add(locationContainer);
}
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetReadOnly(Dictionary<int, Dictionary<int, LocationContainer>> keyValuePairs)
{
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
foreach (KeyValuePair<int, Dictionary<int, LocationContainer>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, new(keyValuePair.Value));
return new(results);
}
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory)
{
Dictionary<int, Dictionary<int, LocationContainer>> results = [];
List<LocationContainer> locationContainers = [];
List<string> personKeyFormattedCollection = [];
Dictionary<int, LocationContainer>? keyValuePairs;
Dictionary<int, List<(string, int)>> skipCollection = [];
Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
SetSkipCollections(configuration, personContainers, a2PeopleSingletonDirectory, skipCollection, skipNotSkipCollection);
SetPersonCollectionsAfterSetSkipCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
List<Record> records = DistanceLogic.DeleteEmptyDirectoriesAndGetCollection(propertyConfiguration, configuration, ticks, eDistanceContentDirectory, personKeyFormattedToNewestPersonKeyFormatted.AsReadOnly(), personKeyFormattedCollection.AsReadOnly());
List<MappedFile> mappedFiles = GetMappedFiles(propertyConfiguration, configuration, personContainers, records);
if (mappedFiles.Count > 0)
{
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(mappedFiles.Count, message, options);
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
{
progressBar.Tick();
MappedParallelFor(propertyConfiguration, configuration, skipCollection.AsReadOnly(), locationContainers, mappedFiles[i]);
});
}
foreach (LocationContainer locationContainer in locationContainers)
{
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
{
results.Add(locationContainer.Id, []);
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
throw new Exception();
}
if (keyValuePairs.ContainsKey(locationContainer.WholePercentages))
continue;
keyValuePairs.Add(locationContainer.WholePercentages, locationContainer);
}
return GetReadOnly(results);
}
private static void MoveUnableToMatch(FilePath filePath)
{
string checkFile = $"{filePath.FullName}.unk";
if (File.Exists(filePath.FullName) && !File.Exists(checkFile))
File.Move(filePath.FullName, checkFile);
}
private static void AvailableParallelFor(Configuration configuration, IFaceD dFace, List<LocationContainer> locationContainers, FilePath filePath)
{
string? json;
const bool fromDistanceContent = false;
if (filePath.Id is null)
return;
DateOnly dateOnly = DateOnly.FromDateTime(new DateTime(filePath.CreationTicks));
int? wholePercentages = IMapping.GetWholePercentages(dFace.FileNameExtension, filePath);
if (wholePercentages is null)
{
if (configuration.DistanceMoveUnableToMatch)
MoveUnableToMatch(filePath);
return;
}
ExifDirectory exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(exifDirectory);
if (json is null || !json.Contains(nameof(DateTime)))
{
if (configuration.DistanceMoveUnableToMatch)
MoveUnableToMatch(filePath);
return;
}
FaceFile? faceFile = JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
if (faceFile is null || faceFile.Location is null)
{
if (configuration.DistanceMoveUnableToMatch)
MoveUnableToMatch(filePath);
return;
}
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
if (rectangle is null)
return;
LocationContainer locationContainer = new(dateOnly,
exifDirectory,
null,
null,
null,
faceFile,
filePath,
fromDistanceContent,
filePath.Id.Value,
null,
null,
null,
rectangle,
wholePercentages.Value);
lock (locationContainers)
locationContainers.Add(locationContainer);
}
internal static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths)
{
List<LocationContainer> results = [];
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
string message = $") Building Available Face Files Collection - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(filePaths.Count, message, options);
_ = Parallel.For(0, filePaths.Count, parallelOptions, (i, state) =>
{
progressBar.Tick();
AvailableParallelFor(configuration, dFace, results, filePaths[i]);
});
return results;
}
}

View File

@ -6,13 +6,12 @@ namespace View_by_Distance.Map.Models.Stateless;
internal abstract class LookForAbandonedLogic internal abstract class LookForAbandonedLogic
{ {
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds, string directory, string directoryName) internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<string> distinctFilteredFileNameFirstSegments, string directory, string directoryName)
{ {
FilePath filePath; FilePath filePath;
FileHolder fileHolder; FileHolder fileHolder;
string fileNameFirstSegment; string fileNameFirstSegment;
List<string> renameCollection = []; List<string> renameCollection = [];
string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray();
string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (string file in files) foreach (string file in files)
{ {
@ -21,7 +20,7 @@ internal abstract class LookForAbandonedLogic
fileNameFirstSegment = fileHolder.NameWithoutExtension.Split('.')[0]; fileNameFirstSegment = fileHolder.NameWithoutExtension.Split('.')[0];
if (!filePath.IsIntelligentIdFormat && filePath.SortOrder is null) if (!filePath.IsIntelligentIdFormat && filePath.SortOrder is null)
continue; continue;
if (distinctFilteredIdsValues.Contains(fileNameFirstSegment)) if (distinctFilteredFileNameFirstSegments.Contains(fileNameFirstSegment))
continue; continue;
renameCollection.Add(file); renameCollection.Add(file);
} }
@ -36,7 +35,7 @@ internal abstract class LookForAbandonedLogic
} }
} }
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, List<int> distinctFilteredIds) internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, List<string> distinctFilteredFileNameFirstSegments)
{ {
string[] directories = Directory.GetDirectories(bResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); string[] directories = Directory.GetDirectories(bResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
@ -44,7 +43,7 @@ internal abstract class LookForAbandonedLogic
string? directoryName = Path.GetFileName(directory); string? directoryName = Path.GetFileName(directory);
if (string.IsNullOrEmpty(directoryName) || (directoryName.Length != 2 && directoryName.Length != 4)) if (string.IsNullOrEmpty(directoryName) || (directoryName.Length != 2 && directoryName.Length != 4))
continue; continue;
LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName); LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
} }

View File

@ -83,7 +83,7 @@ internal abstract class MapLogic
} }
} }
internal static void SetPersonCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection) internal static void SetPersonCollectionsAfterSetSkipCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection)
{ {
string personKeyFormatted; string personKeyFormatted;
string newestPersonKeyFormatted; string newestPersonKeyFormatted;
@ -106,8 +106,9 @@ internal abstract class MapLogic
internal static string GetMappingSegmentB(long ticks, long personKey, int? approximateYears, MappingFromItem mappingFromItem) internal static string GetMappingSegmentB(long ticks, long personKey, int? approximateYears, MappingFromItem mappingFromItem)
{ {
string result; string result;
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
PersonBirthday personBirthday = IPersonBirthday.GetPersonBirthday(personKey); PersonBirthday personBirthday = IPersonBirthday.GetPersonBirthday(personKey);
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear); result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
return result; return result;
} }
@ -178,7 +179,9 @@ internal abstract class MapLogic
internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem) internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem)
{ {
string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear); string result;
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
return result; return result;
} }
@ -212,21 +215,21 @@ internal abstract class MapLogic
{ {
if (duplicate.Percent is null) if (duplicate.Percent is null)
continue; continue;
_ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryName, "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryFullPath, "\""));
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, duplicate.PersonKey); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, duplicate.PersonKey);
} }
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates) foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
{ {
if (percent is not null && percent.Value == 0) if (percent is not null && percent.Value == 0)
continue; continue;
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryName, "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
} }
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates) foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
{ {
if (percent is not null && percent.Value > 0) if (percent is not null && percent.Value > 0)
continue; continue;
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryName, "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
} }
} }
@ -322,7 +325,7 @@ internal abstract class MapLogic
continue; continue;
} }
if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer)) if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer))
throw new Exception(); continue;
if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo)) if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo))
{ {
results.Add(personKeyFormattedIdThenWholePercentages.Id, []); results.Add(personKeyFormattedIdThenWholePercentages.Id, []);
@ -415,7 +418,7 @@ internal abstract class MapLogic
if (check) if (check)
continue; continue;
personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2)); personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2));
personContainer = new(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey); personContainer = PersonContainer.Get(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey);
results.Add(personContainer); results.Add(personContainer);
if (results.Count > 99) if (results.Count > 99)
break; break;
@ -435,7 +438,7 @@ internal abstract class MapLogic
return result; return result;
} }
private static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records) internal static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
{ {
List<MappedFile> results = []; List<MappedFile> results = [];
long personKey; long personKey;
@ -444,6 +447,9 @@ internal abstract class MapLogic
FileHolder fileHolder; FileHolder fileHolder;
List<string> distinct = []; List<string> distinct = [];
PersonBirthday? personBirthday; PersonBirthday? personBirthday;
PersonContainer? personContainer;
string? personDisplayDirectoryName;
ReadOnlyDictionary<long, PersonContainer> keyValuePairs = PersonContainer.Extract(personContainers);
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, configuration.PersonBirthdayFormat, personContainers)); results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, configuration.PersonBirthdayFormat, personContainers));
foreach (Record record in records) foreach (Record record in records)
{ {
@ -452,9 +458,13 @@ internal abstract class MapLogic
continue; continue;
if (distinct.Contains(record.MappedFaceFilePath.Name)) if (distinct.Contains(record.MappedFaceFilePath.Name))
continue; continue;
distinct.Add(record.MappedFaceFilePath.Name);
personKey = personBirthday.Value.Ticks; personKey = personBirthday.Value.Ticks;
results.Add(new(personKey, record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath)); distinct.Add(record.MappedFaceFilePath.Name);
if (!keyValuePairs.TryGetValue(personKey, out personContainer))
personDisplayDirectoryName = record.PersonDisplayDirectoryName;
else
personDisplayDirectoryName = personContainer.DisplayDirectoryName;
results.Add(new(personKey, record.PersonKeyFormatted, personDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath));
} }
for (int i = results.Count - 1; i > -1; i--) for (int i = results.Count - 1; i > -1; i--)
{ {
@ -464,7 +474,7 @@ internal abstract class MapLogic
results.RemoveAt(i); results.RemoveAt(i);
continue; continue;
} }
if (!filePath.Name.EndsWith(".dup") && !filePath.Name.EndsWith(".unk") && !filePath.Name.EndsWith(".abd")) if (!filePath.Name.EndsWith(".abd") && !filePath.Name.EndsWith(".brt") && !filePath.Name.EndsWith(".dup") && !filePath.Name.EndsWith(".unk"))
continue; continue;
if (!File.Exists(filePath.FullName)) if (!File.Exists(filePath.FullName))
continue; continue;
@ -532,18 +542,22 @@ internal abstract class MapLogic
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath); exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value); RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName; personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
LocationContainer locationContainer = new(dateOnly,
exifDirectory,
mappedFile.DirectoryNumber,
personDisplayDirectoryName,
null,
null,
mappedFile.FilePath,
fromDistanceContent,
id.Value,
null,
null,
mappedFile.PersonKey,
rectangle,
wholePercentages.Value);
lock (locationContainers) lock (locationContainers)
locationContainers.Add(new(dateOnly, locationContainers.Add(locationContainer);
exifDirectory,
mappedFile.DirectoryNumber,
personDisplayDirectoryName,
mappedFile.FilePath,
fromDistanceContent,
id.Value,
null,
mappedFile.PersonKey,
rectangle,
wholePercentages.Value));
} }
private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer> locationContainers) private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer> locationContainers)
@ -558,6 +572,8 @@ internal abstract class MapLogic
Dictionary<string, (FilePath, int)> distinct = []; Dictionary<string, (FilePath, int)> distinct = [];
foreach (LocationContainer locationContainer in locationContainers) foreach (LocationContainer locationContainer in locationContainers)
{ {
if (locationContainer.PersonKey is null)
continue;
key = string.Concat(locationContainer.PersonKey, locationContainer.Id); key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
if (distinct.TryGetValue(key, out item)) if (distinct.TryGetValue(key, out item))
{ {
@ -573,7 +589,7 @@ internal abstract class MapLogic
} }
delete.Add(item.FilePath); delete.Add(item.FilePath);
delete.Add(locationContainer.FilePath); delete.Add(locationContainer.FilePath);
duplicates.Add(new(locationContainer.PersonKey, locationContainer.Id, locationContainer.FilePath, percent)); duplicates.Add(new(locationContainer.PersonKey.Value, locationContainer.Id, locationContainer.FilePath, percent));
continue; continue;
} }
distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages)); distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages));
@ -727,11 +743,11 @@ internal abstract class MapLogic
personDisplayDirectoryName = personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName; personDisplayDirectoryName = personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName;
matches = configuration.PersonCharacters.Where(l => personDisplayDirectoryName.Contains(l)).ToArray(); matches = configuration.PersonCharacters.Where(l => personDisplayDirectoryName.Contains(l)).ToArray();
if (matches.Length == 0) if (matches.Length == 0)
throw new NotSupportedException(); continue;
group = IPerson.GetHourGroup(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour); group = IPerson.GetHourGroup(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
(status, sex, first) = IPerson.GetPersonHour(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour); (status, sex, first) = IPerson.GetPersonHour(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
personDirectory = new(matches.First(), group, status, sex, first); personDirectory = new(matches.First(), group, status, sex, first);
personContainer = new(configuration.PersonCharacters.ToArray(), personBirthday, personDisplayDirectoryName, personDirectory); personContainer = PersonContainer.Get(configuration.PersonCharacters.ToArray(), personBirthday, personDisplayDirectoryName, personDirectory);
personKeyFormattedToPersonContainer.Add(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, personContainer); personKeyFormattedToPersonContainer.Add(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, personContainer);
} }
if (personContainer.Key is null) if (personContainer.Key is null)
@ -831,9 +847,9 @@ internal abstract class MapLogic
continue; continue;
personBirthday = IPersonBirthday.GetPersonBirthday(keyValuePair.Key); personBirthday = IPersonBirthday.GetPersonBirthday(keyValuePair.Key);
if (!personKeyToPersonContainerCollection.TryGetValue(keyValuePair.Key, out collection)) if (!personKeyToPersonContainerCollection.TryGetValue(keyValuePair.Key, out collection))
personContainer = new(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key); personContainer = PersonContainer.Get(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key);
else else
personContainer = new(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key); personContainer = PersonContainer.Get(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key);
personKeyToPersonContainer.Add(keyValuePair.Key, personContainer); personKeyToPersonContainer.Add(keyValuePair.Key, personContainer);
} }
} }
@ -947,7 +963,7 @@ internal abstract class MapLogic
if (distinct.Contains(personContainer.DisplayDirectoryAllFilePaths[i].Name)) if (distinct.Contains(personContainer.DisplayDirectoryAllFilePaths[i].Name))
continue; continue;
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name); distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
directoryName = Path.GetFileName(personContainer.DisplayDirectoryAllFilePaths[i].DirectoryName); directoryName = Path.GetFileName(personContainer.DisplayDirectoryAllFilePaths[i].DirectoryFullPath);
if (directoryName != personContainer.DisplayDirectoryName) if (directoryName != personContainer.DisplayDirectoryName)
continue; continue;
personBirthday = IPersonBirthday.GetPersonBirthday(personContainer.Key.Value); personBirthday = IPersonBirthday.GetPersonBirthday(personContainer.Key.Value);
@ -987,6 +1003,22 @@ internal abstract class MapLogic
return result; return result;
} }
internal static string GetFacePartsDirectoryX(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath)
{
string result;
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension);
return result;
}
internal static string GetResizeContentDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string cContentDirectory, FilePath filePath)
{
string result;
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
result = Path.Combine(cContentDirectory, directoryName);
return result;
}
internal static SaveContainer GetDebugSaveContainer(SortingContainer sortingContainer, string directory, Mapping keyMapping) internal static SaveContainer GetDebugSaveContainer(SortingContainer sortingContainer, string directory, Mapping keyMapping)
{ {
SaveContainer result; SaveContainer result;
@ -1095,11 +1127,11 @@ internal abstract class MapLogic
return new(results); return new(results);
} }
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> mappingCollection) internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
Dictionary<int, Dictionary<int, Mapping>> results = []; Dictionary<int, Dictionary<int, Mapping>> results = [];
Dictionary<int, Mapping>? keyValuePairs; Dictionary<int, Mapping>? keyValuePairs;
foreach (Mapping mapping in mappingCollection) foreach (Mapping mapping in distinctValidImageMappingCollection)
{ {
if (mapping.MappingFromLocation is null) if (mapping.MappingFromLocation is null)
continue; continue;
@ -1168,29 +1200,29 @@ internal abstract class MapLogic
return results; return results;
} }
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
{ {
string by; string byValue;
bool isByMapping; bool isByMapping;
bool isBySorting; bool isBySorting;
if (mapping.By is null) if (by is null)
{ {
isByMapping = false; isByMapping = false;
isBySorting = !sortingContainersAny; isBySorting = !sortingContainersAny;
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null"; byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
} }
else else
{ {
isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping; isByMapping = by == Shared.Models.Stateless.IMapLogic.Mapping;
isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting; isBySorting = by == Shared.Models.Stateless.IMapLogic.Sorting;
bool isDefaultName = mapping.MappingFromPerson is not null && IPerson.IsDefaultName(mapping.MappingFromPerson.DisplayDirectoryName); bool isDefaultName = displayDirectoryName is not null && IPerson.IsDefaultName(displayDirectoryName);
if (isBySorting && mapping.MappingFromPerson is null) if (isBySorting && displayDirectoryName is null)
by = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}"; byValue = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
else if (isBySorting && useFiltersCounter.HasValue) else if (isBySorting && useFiltersCounter.HasValue)
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}"; byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
else else
{ {
by = $"{mapping.By.Value switch byValue = $"{by.Value switch
{ {
Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping), Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping),
Shared.Models.Stateless.IMapLogic.Sorting => saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting), Shared.Models.Stateless.IMapLogic.Sorting => saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting),
@ -1199,9 +1231,15 @@ internal abstract class MapLogic
}}{(!isDefaultName ? "-A" : "-Z")}"; }}{(!isDefaultName ? "-A" : "-Z")}";
} }
} }
return new(by, isByMapping, isBySorting); return new(byValue, isByMapping, isBySorting);
} }
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, long? personKey, string? displayDirectoryName) =>
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKey is null ? null : Shared.Models.Stateless.IMapLogic.Mapping, displayDirectoryName);
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) =>
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, mapping.By, mapping.MappingFromPerson?.DisplayDirectoryName);
internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent) internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent)
{ {
string json; string json;
@ -1269,7 +1307,7 @@ internal abstract class MapLogic
return new(results); return new(results);
} }
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
{ {
bool? result; bool? result;
ReadOnlyCollection<PersonContainer>? personContainers; ReadOnlyCollection<PersonContainer>? personContainers;
@ -1277,7 +1315,7 @@ internal abstract class MapLogic
result = null; result = null;
else else
{ {
if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers)) if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
result = null; result = null;
else else
{ {

View File

@ -1,4 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Map.Models.Stateless.Methods; namespace View_by_Distance.Map.Models.Stateless.Methods;
@ -10,44 +12,64 @@ public interface IMapLogic
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) => static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
MapLogic.GetIdToPersonKeys(personKeyToIds); MapLogic.GetIdToPersonKeys(personKeyToIds);
ReadOnlyCollection<Shared.Models.Face> TestStatic_GetFaces(ReadOnlyCollection<Shared.Models.Item> items) => ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
GetFaces(items); GetFaces(items);
static ReadOnlyCollection<Shared.Models.Face> GetFaces(ReadOnlyCollection<Shared.Models.Item> items) => static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
MapLogic.GetFaces(items); MapLogic.GetFaces(items);
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) => Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
GetSelectedMappingCollection(items); GetSelectedMappingCollection(items);
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) => static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
MapLogic.GetSelectedMappingCollection(items); MapLogic.GetSelectedMappingCollection(items);
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) => Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
GetSelectedMappingCollection(faces); GetSelectedMappingCollection(faces);
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) => static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
MapLogic.GetSelectedMappingCollection(faces); MapLogic.GetSelectedMappingCollection(faces);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) => ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
GetIdToWholePercentagesToFace(mappingCollection); GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) => static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
MapLogic.GetIdToWholePercentagesToFace(mappingCollection); MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) => List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory); GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) => static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory); MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
void TestStatic_SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) => void TestStatic_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers); SetCreationTime(mappingFromItem, locationContainers);
static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) => static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
DecadeLogic.SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers); DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) => void TestStatic_MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
DecadeLogic.MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation); CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) => static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation); MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
string TestStatic_GetDecade(Shared.Models.MappingFromItem mappingFromItem) => bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
GetDecade(mappingFromItem); GetDecade(mappingFromItem);
static string GetDecade(Shared.Models.MappingFromItem mappingFromItem) => static string GetDecade(MappingFromItem mappingFromItem) =>
DecadeLogic.GetDecade(mappingFromItem, null); DecadeLogic.GetDecade(mappingFromItem, null);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> TestStatic_GetMappedFiles(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
FaceFileLogic.GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
List<LocationContainer> TestStatic_GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
FaceFileLogic.GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
} }

View File

@ -17,14 +17,16 @@ internal abstract class RelationLogic
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = []; Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
foreach (LocationContainer locationContainer in locationContainers) foreach (LocationContainer locationContainer in locationContainers)
{ {
if (locationContainer.PersonKey is null)
continue;
if (!locationContainer.FromDistanceContent) if (!locationContainer.FromDistanceContent)
continue; continue;
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern)) if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
continue; continue;
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo)) if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
{ {
personKeyTo.Add(locationContainer.PersonKey, []); personKeyTo.Add(locationContainer.PersonKey.Value, []);
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo)) if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
throw new Exception(); throw new Exception();
} }
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection)) if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
@ -45,6 +47,7 @@ internal abstract class RelationLogic
int lastIndex; int lastIndex;
List<int> years = []; List<int> years = [];
List<int> indices = []; List<int> indices = [];
LocationContainer locationContainer;
List<(int Index, int Year)> sort = []; List<(int Index, int Year)> sort = [];
List<LocationContainer> collection = []; List<LocationContainer> collection = [];
KeyValuePair<int, List<LocationContainer>> keyValue; KeyValuePair<int, List<LocationContainer>> keyValue;
@ -76,7 +79,10 @@ internal abstract class RelationLogic
key = $"{years.Min()}-{keyValue.Key}"; key = $"{years.Min()}-{keyValue.Key}";
if (collection.Count == 0) if (collection.Count == 0)
continue; continue;
results.Add(new(key, collection[0].PersonKey, new(collection))); locationContainer = collection[0];
if (locationContainer.PersonKey is null)
continue;
results.Add(new(key, locationContainer.PersonKey.Value, new(collection)));
collection = []; collection = [];
years.Clear(); years.Clear();
} }
@ -98,7 +104,7 @@ internal abstract class RelationLogic
string? personKeyFormattedDirectory; string? personKeyFormattedDirectory;
foreach ((FileHolder fileHolder, _) in relationContainers) foreach ((FileHolder fileHolder, _) in relationContainers)
{ {
personNameDirectory = fileHolder.DirectoryName; personNameDirectory = fileHolder.DirectoryFullPath;
yearDirectory = Path.GetDirectoryName(personNameDirectory); yearDirectory = Path.GetDirectoryName(personNameDirectory);
personNameDirectoryName = Path.GetFileName(personNameDirectory); personNameDirectoryName = Path.GetFileName(personNameDirectory);
personKeyFormattedDirectory = Path.GetDirectoryName(yearDirectory); personKeyFormattedDirectory = Path.GetDirectoryName(yearDirectory);
@ -254,7 +260,7 @@ internal abstract class RelationLogic
_ = Directory.CreateDirectory(vsCodeDirectory); _ = Directory.CreateDirectory(vsCodeDirectory);
if (displayDirectoryName is not null) if (displayDirectoryName is not null)
File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty); File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty);
json = "{ \"[markdown]\": { \"editor.wordWrap\": \"off\" }, \"foam.links.hover.enable\": false, \"foam.graph.style\": { \"background\": \"#202020\", \"node\": { \"note\": \"#f2cb1d\", \"distance\": \"green\", \"image\": \"orange\", \"placeholder\": \"white\", } } }"; json = /*lang=json*/ """{ "[markdown]": { "editor.wordWrap": "off" }, "foam.links.hover.enable": false, "foam.graph.style": { "background": "#202020", "node": { "note": "#f2cb1d", "distance": "green", "image": "orange", "placeholder": "white", } } }""";
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "settings.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "settings.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
json = string.Concat("{ \"version\": \"2.0.0\", \"tasks\": [ { \"label\": \"MKLink\", \"type\": \"shell\", \"command\": \"New-Item\", \"args\": [ \"-ItemType\", \"Junction\", \"-Path\", \"'", directory.Replace('\\', '/'), "/()'\", \"-Target\", \"'", eDistanceContentDirectory.Replace('\\', '/'), "'\" ], \"problemMatcher\": [] } ] }"); json = string.Concat("{ \"version\": \"2.0.0\", \"tasks\": [ { \"label\": \"MKLink\", \"type\": \"shell\", \"command\": \"New-Item\", \"args\": [ \"-ItemType\", \"Junction\", \"-Path\", \"'", directory.Replace('\\', '/'), "/()'\", \"-Target\", \"'", eDistanceContentDirectory.Replace('\\', '/'), "'\" ], \"problemMatcher\": [] } ] }");
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
@ -422,7 +428,7 @@ internal abstract class RelationLogic
if (!Directory.Exists(directory)) if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory); _ = Directory.CreateDirectory(directory);
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory); WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
relationContainers = distance.GetRelationContainers(configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection); relationContainers = distance.GetRelationContainers(configuration.DistanceLimits, configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers); movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers);
WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles); WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles);
} }

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>f89b7242-dbb0-4349-b950-657eb8cf87ef</UserSecretsId> <UserSecretsId>f89b7242-dbb0-4349-b950-657eb8cf87ef</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Metadata.Query</PackageId> <PackageId>Phares.View.by.Distance.Metadata.Query</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -35,10 +35,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -16,6 +16,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,13 +7,9 @@ namespace View_by_Distance.Metadata.Query.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable public string[]? IgnoreExtensions { get; set; }
public Property.Models.Configuration? PropertyConfiguration { get; set; }
public string[] IgnoreExtensions { get; set; } public string? PersonBirthdayFormat { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; }
public string PersonBirthdayFormat { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -21,16 +17,32 @@ public class Configuration
return result; return result;
} }
private static Models.Configuration Get(Configuration? configuration) private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.IgnoreExtensions is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
result = new( result = new(propertyConfiguration,
configuration.IgnoreExtensions, configuration.IgnoreExtensions,
configuration.PersonBirthdayFormat, configuration.PersonBirthdayFormat);
configuration.PropertyConfiguration);
return result; return result;
} }
@ -39,15 +51,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
result = Get(configuration); PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -13,10 +13,9 @@ public class Configuration
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
[JsonConstructor] [JsonConstructor]
public Configuration( public Configuration(Property.Models.Configuration propertyConfiguration,
string[] ignoreExtensions, string[] ignoreExtensions,
string personBirthdayFormat, string personBirthdayFormat)
Property.Models.Configuration propertyConfiguration)
{ {
IgnoreExtensions = ignoreExtensions; IgnoreExtensions = ignoreExtensions;
PersonBirthdayFormat = personBirthdayFormat; PersonBirthdayFormat = personBirthdayFormat;

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Metadata</PackageId> <PackageId>Phares.View.by.Distance.Metadata</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -34,7 +34,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -16,8 +16,8 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
private readonly bool _PropertiesChangedForMetadata; private readonly bool _PropertiesChangedForMetadata;
private readonly IPropertyConfiguration _PropertyConfiguration; private readonly IPropertyConfiguration _PropertyConfiguration;
private readonly bool _ForceMetadataLastWriteTimeToCreationTime; private readonly bool _ForceMetadataLastWriteTimeToCreationTime;
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _FileGroups;
public B_Metadata(IPropertyConfiguration propertyConfiguration) public B_Metadata(IPropertyConfiguration propertyConfiguration)
{ {

View File

@ -502,12 +502,12 @@ internal abstract class Exif
result = new(aviDirectories, result = new(aviDirectories,
exifBaseDirectories, exifBaseDirectories,
fileMetadataDirectories, fileMetadataDirectories,
filePath,
gifHeaderDirectories, gifHeaderDirectories,
gpsDirectories, gpsDirectories,
size?.Height, size?.Height,
jpegDirectories, jpegDirectories,
makernoteDirectories, makernoteDirectories,
filePath.Name,
photoshopDirectories, photoshopDirectories,
pngDirectories, pngDirectories,
quickTimeMovieHeaderDirectories, quickTimeMovieHeaderDirectories,
@ -519,8 +519,12 @@ internal abstract class Exif
internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath) internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath)
{ {
Shared.Models.ExifDirectory? result; Shared.Models.ExifDirectory result;
System.Drawing.Size? size = Dimensions.GetDimensions(filePath.FullName); System.Drawing.Size? size;
try
{ size = Dimensions.GetDimensions(filePath.FullName); }
catch (Exception)
{ size = null; }
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName); IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
result = Covert(filePath, size, directories); result = Covert(filePath, size, directories);
return result; return result;

View File

@ -35,6 +35,17 @@ internal static class Face
result = pngDirectory.TextualData[artist.Length..]; result = pngDirectory.TextualData[artist.Length..];
break; break;
} }
if (result is null)
{
const string author = "Author:";
foreach (PngDirectory pngDirectory in pngDirectories)
{
if (pngDirectory.TextualData is null || !pngDirectory.TextualData.StartsWith(author))
continue;
result = pngDirectory.TextualData[author.Length..];
break;
}
}
} }
return result; return result;
} }

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>fa06c6db-0226-42ca-8728-68b1e336184d</UserSecretsId> <UserSecretsId>fa06c6db-0226-42ca-8728-68b1e336184d</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Mirror.Length</PackageId> <PackageId>Phares.View.by.Distance.Mirror.Length</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -35,10 +35,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -17,6 +17,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -40,7 +57,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,13 +7,9 @@ namespace View_by_Distance.Mirror.Length.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable public string[]? IgnoreExtensions { get; set; }
public Property.Models.Configuration? PropertyConfiguration { get; set; }
public string[] IgnoreExtensions { get; set; } public string? PersonBirthdayFormat { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; }
public string PersonBirthdayFormat { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -21,16 +17,32 @@ public class Configuration
return result; return result;
} }
private static Models.Configuration Get(Configuration? configuration) private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.IgnoreExtensions is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
result = new( result = new(propertyConfiguration,
configuration.IgnoreExtensions, configuration.IgnoreExtensions,
configuration.PersonBirthdayFormat, configuration.PersonBirthdayFormat);
configuration.PropertyConfiguration);
return result; return result;
} }
@ -39,15 +51,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
result = Get(configuration); PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -13,10 +13,9 @@ public class Configuration
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
[JsonConstructor] [JsonConstructor]
public Configuration( public Configuration(Property.Models.Configuration propertyConfiguration,
string[] ignoreExtensions, string[] ignoreExtensions,
string personBirthdayFormat, string personBirthdayFormat)
Property.Models.Configuration propertyConfiguration)
{ {
IgnoreExtensions = ignoreExtensions; IgnoreExtensions = ignoreExtensions;
PersonBirthdayFormat = personBirthdayFormat; PersonBirthdayFormat = personBirthdayFormat;

View File

@ -23,6 +23,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -44,7 +61,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,13 +7,9 @@ namespace View_by_Distance.Move.By.Id.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable public string[]? IgnoreExtensions { get; set; }
public Property.Models.Configuration? PropertyConfiguration { get; set; }
public string[] IgnoreExtensions { get; set; } public string? PersonBirthdayFormat { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; }
public string PersonBirthdayFormat { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -21,16 +17,32 @@ public class Configuration
return result; return result;
} }
private static Models.Configuration Get(Configuration? configuration) private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.IgnoreExtensions is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
result = new( result = new(propertyConfiguration,
configuration.IgnoreExtensions, configuration.IgnoreExtensions,
configuration.PersonBirthdayFormat, configuration.PersonBirthdayFormat);
configuration.PropertyConfiguration);
return result; return result;
} }
@ -39,15 +51,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
result = Get(configuration); PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -13,10 +13,9 @@ public class Configuration
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
[JsonConstructor] [JsonConstructor]
public Configuration( public Configuration(Property.Models.Configuration propertyConfiguration,
string[] ignoreExtensions, string[] ignoreExtensions,
string personBirthdayFormat, string personBirthdayFormat)
Property.Models.Configuration propertyConfiguration)
{ {
IgnoreExtensions = ignoreExtensions; IgnoreExtensions = ignoreExtensions;
PersonBirthdayFormat = personBirthdayFormat; PersonBirthdayFormat = personBirthdayFormat;

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>ce31220e-ef92-4e68-89c5-91b027a94dca</UserSecretsId> <UserSecretsId>ce31220e-ef92-4e68-89c5-91b027a94dca</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Move.By.Id</PackageId> <PackageId>Phares.View.by.Distance.Move.By.Id</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -35,9 +35,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -115,7 +115,7 @@ public class MoveById
progressBar.Tick(); progressBar.Tick();
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file); fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
filePath = FilePath.Get(_Configuration.PropertyConfiguration, fileHolder, index: null); filePath = FilePath.Get(_Configuration.PropertyConfiguration, fileHolder, index: null);
if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryName is null) if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryFullPath is null)
continue; continue;
if (allFiles.Contains($"{fileHolder.FullName}.id")) if (allFiles.Contains($"{fileHolder.FullName}.id"))
continue; continue;

View File

@ -16,6 +16,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

View File

@ -7,13 +7,9 @@ namespace View_by_Distance.Offset.Date.Time.Original.Models.Binder;
public class Configuration public class Configuration
{ {
#nullable disable public string[]? IgnoreExtensions { get; set; }
public Property.Models.Configuration? PropertyConfiguration { get; set; }
public string[] IgnoreExtensions { get; set; } public string? PersonBirthdayFormat { get; set; }
public Property.Models.Configuration PropertyConfiguration { get; set; }
public string PersonBirthdayFormat { get; set; }
#nullable restore
public override string ToString() public override string ToString()
{ {
@ -21,16 +17,32 @@ public class Configuration
return result; return result;
} }
private static Models.Configuration Get(Configuration? configuration) private static void PreVerify(IConfigurationRoot configurationRoot, Configuration? configuration)
{
if (configuration?.IgnoreExtensions is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
{ {
Models.Configuration result; Models.Configuration result;
if (configuration is null) throw new NullReferenceException(nameof(configuration)); if (configuration is null) throw new NullReferenceException(nameof(configuration));
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
result = new( result = new(propertyConfiguration,
configuration.IgnoreExtensions, configuration.IgnoreExtensions,
configuration.PersonBirthdayFormat, configuration.PersonBirthdayFormat);
configuration.PropertyConfiguration);
return result; return result;
} }
@ -39,15 +51,20 @@ public class Configuration
Models.Configuration result; Models.Configuration result;
Configuration? configuration; Configuration? configuration;
if (isEnvironment is null) if (isEnvironment is null)
#pragma warning disable IL3050, IL2026
configuration = configurationRoot.Get<Configuration>(); configuration = configurationRoot.Get<Configuration>();
#pragma warning restore IL3050, IL2026
else else
{ {
string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment);
string section = string.Concat(environmentName, ":", nameof(Configuration)); string section = string.Concat(environmentName, ":", nameof(Configuration));
IConfigurationSection configurationSection = configurationRoot.GetSection(section); IConfigurationSection configurationSection = configurationRoot.GetSection(section);
#pragma warning disable IL3050, IL2026
configuration = configurationSection.Get<Configuration>(); configuration = configurationSection.Get<Configuration>();
#pragma warning restore IL3050, IL2026
} }
result = Get(configuration); PreVerify(configurationRoot, configuration);
result = Get(configuration, propertyConfiguration);
return result; return result;
} }

View File

@ -13,10 +13,9 @@ public class Configuration
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
[JsonConstructor] [JsonConstructor]
public Configuration( public Configuration(Property.Models.Configuration propertyConfiguration,
string[] ignoreExtensions, string[] ignoreExtensions,
string personBirthdayFormat, string personBirthdayFormat)
Property.Models.Configuration propertyConfiguration)
{ {
IgnoreExtensions = ignoreExtensions; IgnoreExtensions = ignoreExtensions;
PersonBirthdayFormat = personBirthdayFormat; PersonBirthdayFormat = personBirthdayFormat;

View File

@ -4,13 +4,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>ae069946-d0c0-4e4f-94f6-9c526e4ae4e7</UserSecretsId> <UserSecretsId>ae069946-d0c0-4e4f-94f6-9c526e4ae4e7</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Offset.Date.Time.Original</PackageId> <PackageId>Phares.View.by.Distance.Offset.Date.Time.Original</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -35,10 +35,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />

View File

@ -112,7 +112,7 @@ public class OffsetDateTimeOriginal
string checkFile; string checkFile;
PropertyItem? propertyItem; PropertyItem? propertyItem;
string? ticksDirectory = null; string? ticksDirectory = null;
int dateTimeOriginal = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal; const int dateTimeOriginal = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal; // 36867
for (int i = 0; i < int.MaxValue; i++) for (int i = 0; i < int.MaxValue; i++)
{ {
ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString()); ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString());
@ -216,6 +216,17 @@ public class OffsetDateTimeOriginal
{ {
TimeSpan timeSpan = new(targetDateTimeOriginal.Value.Ticks - badDateTimeOriginal.Value.Ticks); TimeSpan timeSpan = new(targetDateTimeOriginal.Value.Ticks - badDateTimeOriginal.Value.Ticks);
DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks); DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks);
// DateTime a = new(2020, 01, 04, 02, 12, 51, 32);
// // DateTime a = new(2020, 01, 05, 18, 17, 15, 97);
// DateTime b = new(2020, 01, 05, 19, 52, 30, 17);
// DateTime c = new(2024, 12, 07, 11, 19, 06, 13);
// // DateTime d = new(2024, 12, 07, 12, 07, 30, 38);
// long e = new DateTime(c.Ticks - b.Ticks).AddMinutes(-5).Ticks;
// if (a != DateTime.MinValue)
// minimumDateTime = a.AddTicks(e).AddHours(-1);
// if (c != DateTime.MinValue)
// maximumDateTime = c;
// DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, e);
} }
} }
} }

View File

@ -169,7 +169,7 @@ public class F_PhotoPrism
} }
} }
public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, ReadOnlyCollection<Face> distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic) public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, ReadOnlyCollection<Face> distinctValidImageFaces, Shared.Models.Methods.IMapLogic mapLogic)
{ {
string file; string file;
string text; string text;
@ -189,7 +189,7 @@ public class F_PhotoPrism
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers; ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection; (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection;
List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)> collection = []; List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)> collection = [];
foreach (Face face in distinctFilteredFaces) foreach (Face face in distinctValidImageFaces)
{ {
collection.Clear(); collection.Clear();
wholePercentages = face.Mapping?.MappingFromLocation?.WholePercentages; wholePercentages = face.Mapping?.MappingFromLocation?.WholePercentages;

View File

@ -4,12 +4,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputType>library</OutputType> <OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.PhotoPrism</PackageId> <PackageId>Phares.View.by.Distance.PhotoPrism</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>8.0.101.1</Version> <Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors> <Authors>Mike Phares</Authors>
<Company>Phares</Company> <Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
@ -36,8 +36,8 @@
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -20,6 +20,23 @@ public class AppSettings
return result; return result;
} }
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
{
if (appSettings?.Company is null)
{
List<string> paths = [];
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
{
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
continue;
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
continue;
paths.Add(physicalFileProvider.Root);
}
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
}
private static Models.AppSettings Get(AppSettings? appSettings) private static Models.AppSettings Get(AppSettings? appSettings)
{ {
Models.AppSettings result; Models.AppSettings result;
@ -36,7 +53,10 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>(); AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
PreVerify(configurationRoot, appSettings);
result = Get(appSettings); result = Get(appSettings);
return result; return result;
} }

Some files were not shown because too many files have changed in this diff Show More