Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
bd03bba63e | |||
3f7affceef | |||
130e3b6528 | |||
d5fa108f81 | |||
d9d55d9e4c | |||
e728838d25 | |||
ac298166e9 | |||
0b793904b3 | |||
e053dd5746 | |||
ee0219f321 | |||
75cfb2a0d9 | |||
17be39bef9 | |||
c085ac3f76 | |||
a6b3318eec | |||
49e9daea8f | |||
e2e6e15ea2 | |||
d8013da912 | |||
4da353d150 | |||
444e7ed71a | |||
99198cc378 | |||
e532c3ef1e | |||
c580c7eaa4 | |||
43b66f01b6 | |||
304b5e2a0e | |||
326e579d5c | |||
f458af776a | |||
3b63279545 | |||
61d1ae71f6 | |||
368138bb78 |
@ -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
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -468,3 +468,9 @@ globalStorage/
|
|||||||
[Ll]ib/
|
[Ll]ib/
|
||||||
|
|
||||||
Shared/.kanbn
|
Shared/.kanbn
|
||||||
|
|
||||||
|
.Immich/immich-assets.json
|
||||||
|
Tests/.vscode/.UserSecrets/*
|
||||||
|
Instance/.vscode/.UserSecrets/*
|
||||||
|
Drag-Drop-Set-Property-Item/.vscode/.UserSecrets/*
|
||||||
|
TestsWithFaceRecognitionDotNet/.vscode/.UserSecrets/*
|
||||||
|
80
.vscode/launch.json
vendored
80
.vscode/launch.json
vendored
@ -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"
|
||||||
],
|
],
|
||||||
|
19
.vscode/mklink.md
vendored
19
.vscode/mklink.md
vendored
@ -7,8 +7,25 @@ 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\{}"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash 1740946894364 = 638765436943640000 = 2025-0.Winter = Sun Mar 02 2025 13:21:33 GMT-0700 (Mountain Standard Time)
|
||||||
|
mklink /J "V:\Tmp\Phares\Pictures-Results" "V:\6-Other-Large-Z\Current-Results-Test"
|
||||||
|
mklink /J "V:\1-Images-A\Images-0b793904-Results" "V:\6-Other-Large-Z\Current-Results"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash 1742827407172 = 638784242071720000 = 2025-1.Spring = Mon Mar 24 2025 07:43:26 GMT-0700 (Mountain Standard Time)
|
||||||
|
mkdir "L:\Git\View-by-Distance-MKLink-Console\Instance\.vscode"
|
||||||
|
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Instance\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\2999dda1-5329-4d9f-9d68-cccfabe0e47f"
|
||||||
|
mkdir "L:\Git\View-by-Distance-MKLink-Console\Tests\.vscode"
|
||||||
|
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Tests\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\e8c3d25d-9715-4b35-9010-1cdc74840190"
|
||||||
|
mkdir "L:\Git\View-by-Distance-MKLink-Console\TestsWithFaceRecognitionDotNet\.vscode"
|
||||||
|
mklink /J "L:\Git\View-by-Distance-MKLink-Console\TestsWithFaceRecognitionDotNet\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\ecbdc76d-6037-4046-86a4-1a7626a3d342"
|
||||||
|
mkdir "L:\Git\View-by-Distance-MKLink-Console\Drag-Drop-Set-Property-Item\.vscode"
|
||||||
|
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Drag-Drop-Set-Property-Item\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\c64a15ed-0ba3-4378-8f80-0c19d0531747"
|
||||||
```
|
```
|
||||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -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"
|
||||||
|
98
.vscode/tasks.json
vendored
98
.vscode/tasks.json
vendored
@ -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,92 @@
|
|||||||
"/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"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "buildShared",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Shared/View-by-Distance.Shared.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "buildMetadata",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Metadata/Metadata.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "buildTests",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Tests/Tests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "buildTestsWithFaceRecognitionDotNet",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "buildCopyDistinct",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Copy-Distinct/Copy-Distinct.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
||||||
|
"args": [
|
||||||
|
"s",
|
||||||
|
"X",
|
||||||
|
"L:/Git/View-by-Distance-MKLink-Console",
|
||||||
|
"Day-Helper-2025-03-20",
|
||||||
|
"false",
|
||||||
|
"4"
|
||||||
|
],
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -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>
|
@ -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>
|
@ -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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
@ -10,21 +10,29 @@ 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 ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||||
|
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||||
|
|
||||||
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration)
|
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration)
|
||||||
{
|
{
|
||||||
_FileGroups = [];
|
|
||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
|
_ResultContentFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
|
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(string resultsFullGroupDirectory)
|
public void Update(string resultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
_FileGroups.Clear();
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
|
||||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
|
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
{
|
||||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||||
|
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||||
|
else if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton)
|
||||||
|
_ResultSingletonFileGroups[0] = keyValuePair.Value;
|
||||||
|
else
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string IBlurHasher.Encode(FileHolder fileHolder)
|
string IBlurHasher.Encode(FileHolder fileHolder)
|
||||||
@ -40,20 +48,39 @@ public class C2_BlurHasher : IBlurHasher
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
File.Move(checkFile, fullFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string IBlurHasher.GetFile(FilePath filePath)
|
string IBlurHasher.GetFile(FilePath filePath)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
if (_FileGroups.Count == 0)
|
if (_ResultSingletonFileGroups[0].Count == 0)
|
||||||
throw new Exception("Call Update first!");
|
throw new Exception("Call Update first!");
|
||||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
string fileName = $"{filePath.Name}.csv";
|
||||||
result = Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{filePath.Name}.csv");
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
|
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||||
|
result = Path.Combine(directory, fileName);
|
||||||
|
MoveIf(fileName, cei, directory, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
string IBlurHasher.EncodeAndSave(FilePath filePath, FileHolder fileHolder)
|
string IBlurHasher.EncodeAndSave(FilePath filePath, FileHolder fileHolder)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
if (_FileGroups.Count == 0)
|
if (_ResultSingletonFileGroups[0].Count == 0)
|
||||||
throw new Exception("Call Update first!");
|
throw new Exception("Call Update first!");
|
||||||
int actualByte;
|
int actualByte;
|
||||||
string extension = ".png";
|
string extension = ".png";
|
||||||
@ -70,15 +97,18 @@ public class C2_BlurHasher : IBlurHasher
|
|||||||
byte[] blurHashBytes = Encoding.UTF8.GetBytes(result);
|
byte[] blurHashBytes = Encoding.UTF8.GetBytes(result);
|
||||||
string joined = string.Join(string.Empty, blurHashBytes.Select(l => l.ToString("000")));
|
string joined = string.Join(string.Empty, blurHashBytes.Select(l => l.ToString("000")));
|
||||||
string fileNameWithoutExtension = $"{componentsX}x{componentsY}-{outputWidth}x{outputHeight}-{joined}";
|
string fileNameWithoutExtension = $"{componentsX}x{componentsY}-{outputWidth}x{outputHeight}-{joined}";
|
||||||
|
string fileName = $"{fileNameWithoutExtension}{extension}";
|
||||||
string contents = string.Concat(result, Environment.NewLine, fileNameWithoutExtension, Environment.NewLine, extension);
|
string contents = string.Concat(result, Environment.NewLine, fileNameWithoutExtension, Environment.NewLine, extension);
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(file, contents, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(file, contents, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
file = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], $"{fileNameWithoutExtension}{extension}");
|
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||||
if (!File.Exists(file))
|
string fullFileName = Path.Combine(directory, fileName);
|
||||||
|
MoveIf(fileName, cei, directory, fullFileName);
|
||||||
|
if (!File.Exists(fullFileName))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using FileStream fileStream = new(file, FileMode.CreateNew);
|
using FileStream fileStream = new(fullFileName, FileMode.CreateNew);
|
||||||
actualImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
|
actualImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
|
||||||
_ = fileStream.Seek(0, SeekOrigin.Begin);
|
_ = fileStream.Seek(0, SeekOrigin.Begin);
|
||||||
actualByte = fileStream.ReadByte();
|
actualByte = fileStream.ReadByte();
|
||||||
|
@ -160,7 +160,7 @@ public class Compare
|
|||||||
}
|
}
|
||||||
if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId)
|
if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId)
|
||||||
throw new Exception("Copy keyValuePairs-####.json file");
|
throw new Exception("Copy keyValuePairs-####.json file");
|
||||||
(int j, int f, int t, Shared.Models.Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
|
(int j, int f, int t, Shared.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
|
||||||
if (propertyLogic.ExceptionsDirectories.Any())
|
if (propertyLogic.ExceptionsDirectories.Any())
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers))
|
if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers))
|
||||||
@ -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)
|
||||||
{
|
{
|
||||||
@ -242,6 +242,53 @@ public class Compare
|
|||||||
_ = Directory.CreateDirectory(currentYearDirectory);
|
_ = Directory.CreateDirectory(currentYearDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Verify(Models.Configuration configuration)
|
||||||
|
{
|
||||||
|
if (configuration.Spelling is null || !configuration.Spelling.Any())
|
||||||
|
throw new NullReferenceException(nameof(configuration.Spelling));
|
||||||
|
}
|
||||||
|
|
||||||
|
private A_Property GetPropertyLogic(bool reverse, string outputExtension, Map.Models.MapLogic mapLogic)
|
||||||
|
{
|
||||||
|
A_Property result;
|
||||||
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
|
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||||
|
result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse);
|
||||||
|
string fromPrepareForOld = "34720-637858334555170379.tsv";
|
||||||
|
string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld);
|
||||||
|
if (File.Exists(fromPrepareForOldFile))
|
||||||
|
{
|
||||||
|
string[] lines;
|
||||||
|
string[] columns;
|
||||||
|
List<string> debug = new();
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
lines = File.ReadAllLines(fromPrepareForOldFile);
|
||||||
|
string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory}-Results";
|
||||||
|
int[]? zeros = (from l in mapLogic.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray();
|
||||||
|
lines = (from l in mapLogic.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray();
|
||||||
|
if (!Directory.Exists(resultsDirectory))
|
||||||
|
_ = Directory.CreateDirectory(resultsDirectory);
|
||||||
|
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines);
|
||||||
|
string json = JsonSerializer.Serialize(mapLogic.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json);
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
columns = line.Split('\t');
|
||||||
|
// select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}"
|
||||||
|
if (columns.Length != 7)
|
||||||
|
continue;
|
||||||
|
if (!int.TryParse(columns[1], out int propertyId))
|
||||||
|
continue;
|
||||||
|
if (!zeros.Contains(propertyId))
|
||||||
|
debug.Add(line);
|
||||||
|
else
|
||||||
|
debug.Add(propertyId.ToString());
|
||||||
|
}
|
||||||
|
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPrepareForOld}"), debug);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetRename(string renameA)
|
private string GetRename(string renameA)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
@ -376,12 +423,6 @@ public class Compare
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Verify(Models.Configuration configuration)
|
|
||||||
{
|
|
||||||
if (configuration.Spelling is null || !configuration.Spelling.Any())
|
|
||||||
throw new NullReferenceException(nameof(configuration.Spelling));
|
|
||||||
}
|
|
||||||
|
|
||||||
private long LogDelta(long ticks, string? methodName)
|
private long LogDelta(long ticks, string? methodName)
|
||||||
{
|
{
|
||||||
long result;
|
long result;
|
||||||
@ -391,121 +432,6 @@ public class Compare
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private A_Property GetPropertyLogic(bool reverse, string outputExtension, Map.Models.MapLogic mapLogic)
|
|
||||||
{
|
|
||||||
A_Property result;
|
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
|
||||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
|
||||||
result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse);
|
|
||||||
string fromPrepareForOld = "34720-637858334555170379.tsv";
|
|
||||||
string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld);
|
|
||||||
if (File.Exists(fromPrepareForOldFile))
|
|
||||||
{
|
|
||||||
string[] lines;
|
|
||||||
string[] columns;
|
|
||||||
List<string> debug = new();
|
|
||||||
long ticks = DateTime.Now.Ticks;
|
|
||||||
lines = File.ReadAllLines(fromPrepareForOldFile);
|
|
||||||
string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory}-Results";
|
|
||||||
int[]? zeros = (from l in mapLogic.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray();
|
|
||||||
lines = (from l in mapLogic.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray();
|
|
||||||
if (!Directory.Exists(resultsDirectory))
|
|
||||||
_ = Directory.CreateDirectory(resultsDirectory);
|
|
||||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines);
|
|
||||||
string json = JsonSerializer.Serialize(mapLogic.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true });
|
|
||||||
File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json);
|
|
||||||
foreach (string line in lines)
|
|
||||||
{
|
|
||||||
columns = line.Split('\t');
|
|
||||||
// select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}"
|
|
||||||
if (columns.Length != 7)
|
|
||||||
continue;
|
|
||||||
if (!int.TryParse(columns[1], out int propertyId))
|
|
||||||
continue;
|
|
||||||
if (!zeros.Contains(propertyId))
|
|
||||||
debug.Add(line);
|
|
||||||
else
|
|
||||||
debug.Add(propertyId.ToString());
|
|
||||||
}
|
|
||||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPrepareForOld}"), debug);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration)
|
|
||||||
{
|
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
|
||||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
|
||||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
|
||||||
_Logger?.LogInformation(aPropertySingletonDirectory);
|
|
||||||
_Logger?.LogInformation("to");
|
|
||||||
_Logger?.LogInformation(_Configuration.DiffPropertyDirectory);
|
|
||||||
for (int y = 0; y < int.MaxValue; y++)
|
|
||||||
{
|
|
||||||
_Logger?.LogInformation("Press \"Y\" key to continue or close console if compare not needed");
|
|
||||||
if (Console.ReadKey().Key == ConsoleKey.Y)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_Logger?.LogInformation(". . .");
|
|
||||||
int loadLessThan = 7;
|
|
||||||
string diffRootDirectory;
|
|
||||||
ConsoleKey? consoleKey = null;
|
|
||||||
List<PropertyCompare.Models.PropertyCompare>? duplicates = null;
|
|
||||||
PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection;
|
|
||||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory))
|
|
||||||
diffRootDirectory = string.Empty;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_Configuration.DiffPropertyDirectory.EndsWith("{}"))
|
|
||||||
throw new Exception("Invalid directory should end with {}!");
|
|
||||||
diffRootDirectory = Shared.Models.Stateless.Methods.IProperty.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory);
|
|
||||||
}
|
|
||||||
PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory);
|
|
||||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory))
|
|
||||||
diffPropertyCompareCollection = Array.Empty<PropertyCompare.Models.PropertyCompare>();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false);
|
|
||||||
if (!diffPropertyCompareCollection.Any())
|
|
||||||
throw new Exception("Invalid directory!");
|
|
||||||
}
|
|
||||||
string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]");
|
|
||||||
PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false);
|
|
||||||
{
|
|
||||||
long ticks = DateTime.Now.Ticks;
|
|
||||||
string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray();
|
|
||||||
File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines);
|
|
||||||
string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true });
|
|
||||||
File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json);
|
|
||||||
}
|
|
||||||
for (int x = 0; x < int.MaxValue; x++)
|
|
||||||
{
|
|
||||||
_Logger?.LogInformation($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}");
|
|
||||||
_Logger?.LogInformation($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}");
|
|
||||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
|
||||||
consoleKey = Console.ReadKey().Key;
|
|
||||||
if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_Logger?.LogInformation(". . .");
|
|
||||||
if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D)
|
|
||||||
propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection);
|
|
||||||
else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < int.MaxValue; x++)
|
|
||||||
{
|
|
||||||
_Logger?.LogInformation($"Press \"0 - {loadLessThan}\" key when ready to continue");
|
|
||||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
|
||||||
consoleKey = Console.ReadKey().Key;
|
|
||||||
if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_Logger?.LogInformation(". . .");
|
|
||||||
int i = int.Parse(consoleKey.Value.ToString()[1..]);
|
|
||||||
propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory)
|
private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory)
|
||||||
{
|
{
|
||||||
string searchPattern = "*.delete";
|
string searchPattern = "*.delete";
|
||||||
@ -524,227 +450,6 @@ public class Compare
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool PossiblyRename(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string replaceFile;
|
|
||||||
string replaceDirectory;
|
|
||||||
int remainingDirectories = 0;
|
|
||||||
IEnumerable<(string Find, string Replace)>? found;
|
|
||||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
|
||||||
{
|
|
||||||
if (!topDirectories.Any())
|
|
||||||
continue;
|
|
||||||
found = from l in _RenameFindReplace where sourceDirectory == l.Find select l;
|
|
||||||
if (!found.Any())
|
|
||||||
continue;
|
|
||||||
if (!result)
|
|
||||||
result = true;
|
|
||||||
replaceDirectory = found.First().Replace;
|
|
||||||
if (!Directory.Exists(replaceDirectory))
|
|
||||||
Directory.Move(sourceDirectory, replaceDirectory);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Directory.EnumerateDirectories(sourceDirectory).Any())
|
|
||||||
remainingDirectories += 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
|
||||||
{
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
{
|
|
||||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
|
||||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
|
||||||
}
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
continue;
|
|
||||||
File.Move(sourceDirectoryFile, replaceFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool PossiblyRenameB(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string replaceFile;
|
|
||||||
string replaceDirectory;
|
|
||||||
IEnumerable<(string Find, string Replace)>? found;
|
|
||||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
|
||||||
{
|
|
||||||
if (!topDirectories.Any())
|
|
||||||
continue;
|
|
||||||
found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l;
|
|
||||||
if (!found.Any())
|
|
||||||
continue;
|
|
||||||
if (!result)
|
|
||||||
result = true;
|
|
||||||
replaceDirectory = found.First().Replace;
|
|
||||||
if (!Directory.Exists(replaceDirectory))
|
|
||||||
_ = Directory.CreateDirectory(replaceDirectory);
|
|
||||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
|
||||||
{
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
{
|
|
||||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
|
||||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
|
||||||
}
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
continue;
|
|
||||||
File.Move(sourceDirectoryFile, replaceFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool PossiblyRenameC(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string replaceFile;
|
|
||||||
string replaceDirectory;
|
|
||||||
IEnumerable<(string Find, string Replace)>? found;
|
|
||||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
|
||||||
{
|
|
||||||
if (!topDirectories.Any())
|
|
||||||
continue;
|
|
||||||
found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l;
|
|
||||||
if (!found.Any())
|
|
||||||
continue;
|
|
||||||
if (!result)
|
|
||||||
result = true;
|
|
||||||
replaceDirectory = found.First().Replace;
|
|
||||||
if (!Directory.Exists(replaceDirectory))
|
|
||||||
_ = Directory.CreateDirectory(replaceDirectory);
|
|
||||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
|
||||||
{
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
{
|
|
||||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
|
||||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
|
||||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
|
||||||
}
|
|
||||||
if (File.Exists(replaceFile))
|
|
||||||
continue;
|
|
||||||
File.Move(sourceDirectoryFile, replaceFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool PossiblyCorrect(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
|
||||||
{
|
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
|
||||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
|
||||||
bool result = false;
|
|
||||||
string corrected;
|
|
||||||
string correctedMoveTo;
|
|
||||||
string? correctedDirectory;
|
|
||||||
string filteredSourceDirectoryFile;
|
|
||||||
string[] filteredSourceDirectoryFiles;
|
|
||||||
(string Find, string Replace) findReplace;
|
|
||||||
IEnumerable<(string Find, string Replace)>? found;
|
|
||||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
|
||||||
{
|
|
||||||
if (!topDirectories.Any())
|
|
||||||
continue;
|
|
||||||
filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray();
|
|
||||||
if (!filteredSourceDirectoryFiles.Any())
|
|
||||||
continue;
|
|
||||||
for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++)
|
|
||||||
{
|
|
||||||
found = null;
|
|
||||||
for (int z = 0; z < int.MaxValue; z++)
|
|
||||||
{
|
|
||||||
filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i];
|
|
||||||
found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l;
|
|
||||||
if (!found.Any())
|
|
||||||
break;
|
|
||||||
findReplace = found.First();
|
|
||||||
corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace);
|
|
||||||
correctedDirectory = Path.GetDirectoryName(corrected);
|
|
||||||
if (string.IsNullOrEmpty(correctedDirectory))
|
|
||||||
break;
|
|
||||||
correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected));
|
|
||||||
if (File.Exists(correctedMoveTo))
|
|
||||||
break;
|
|
||||||
if (!Directory.Exists(correctedDirectory))
|
|
||||||
_ = Directory.CreateDirectory(correctedDirectory);
|
|
||||||
if (!result)
|
|
||||||
result = true;
|
|
||||||
File.Move(filteredSourceDirectoryFile, correctedMoveTo);
|
|
||||||
filteredSourceDirectoryFiles[i] = corrected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<string> GetMissingVerifyToSeasonCollection(List<string> _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
|
||||||
{
|
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
|
||||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
|
||||||
List<string> results = new();
|
|
||||||
string check;
|
|
||||||
foreach ((int _, string sourceDirectory, string[] _) in groupCollection)
|
|
||||||
{
|
|
||||||
if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory)
|
|
||||||
continue;
|
|
||||||
check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..];
|
|
||||||
if (check[0] is '=' || check.StartsWith("zzz ="))
|
|
||||||
{
|
|
||||||
if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check))
|
|
||||||
results.Add(check);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll)
|
|
||||||
{
|
|
||||||
int z = 0;
|
|
||||||
string fileName;
|
|
||||||
WindowsShortcut windowsShortcut;
|
|
||||||
foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection)
|
|
||||||
{
|
|
||||||
z += 1;
|
|
||||||
if (z % 1000 == 0)
|
|
||||||
_Log.Debug($"{z}) Loop {propertyDirectory}");
|
|
||||||
if (!keepAll)
|
|
||||||
{
|
|
||||||
fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk");
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileName = string.Empty;
|
|
||||||
for (short c = 65; c < short.MaxValue; c++)
|
|
||||||
{
|
|
||||||
if (c > 95)
|
|
||||||
break;
|
|
||||||
fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk");
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(fileName))
|
|
||||||
continue;
|
|
||||||
windowsShortcut = new() { Path = filteredSourceDirectoryFile };
|
|
||||||
windowsShortcut.Save(fileName);
|
|
||||||
windowsShortcut.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThirdPassToMove(Property.Models.Configuration configuration, Map.Models.MapLogic mapLogic, A_Property propertyLogic, Shared.Models.Container[] containers, string aPropertyContentCollectionDirectory)
|
private void ThirdPassToMove(Property.Models.Configuration configuration, Map.Models.MapLogic mapLogic, A_Property propertyLogic, Shared.Models.Container[] containers, string aPropertyContentCollectionDirectory)
|
||||||
{
|
{
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
@ -865,4 +570,299 @@ public class Compare
|
|||||||
CreateWindowsShortcuts(collection, keepAll);
|
CreateWindowsShortcuts(collection, keepAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll)
|
||||||
|
{
|
||||||
|
int z = 0;
|
||||||
|
string fileName;
|
||||||
|
WindowsShortcut windowsShortcut;
|
||||||
|
foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection)
|
||||||
|
{
|
||||||
|
z += 1;
|
||||||
|
if (z % 1000 == 0)
|
||||||
|
_Log.Debug($"{z}) Loop {propertyDirectory}");
|
||||||
|
if (!keepAll)
|
||||||
|
{
|
||||||
|
fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk");
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileName = string.Empty;
|
||||||
|
for (short c = 65; c < short.MaxValue; c++)
|
||||||
|
{
|
||||||
|
if (c > 95)
|
||||||
|
break;
|
||||||
|
fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk");
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(fileName))
|
||||||
|
continue;
|
||||||
|
windowsShortcut = new() { Path = filteredSourceDirectoryFile };
|
||||||
|
windowsShortcut.Save(fileName);
|
||||||
|
windowsShortcut.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration)
|
||||||
|
{
|
||||||
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
|
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||||
|
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||||
|
_Logger?.LogInformation(aPropertySingletonDirectory);
|
||||||
|
_Logger?.LogInformation("to");
|
||||||
|
_Logger?.LogInformation(_Configuration.DiffPropertyDirectory);
|
||||||
|
for (int y = 0; y < int.MaxValue; y++)
|
||||||
|
{
|
||||||
|
_Logger?.LogInformation("Press \"Y\" key to continue or close console if compare not needed");
|
||||||
|
if (Console.ReadKey().Key == ConsoleKey.Y)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_Logger?.LogInformation(". . .");
|
||||||
|
int loadLessThan = 7;
|
||||||
|
string diffRootDirectory;
|
||||||
|
ConsoleKey? consoleKey = null;
|
||||||
|
List<PropertyCompare.Models.PropertyCompare>? duplicates = null;
|
||||||
|
PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection;
|
||||||
|
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory))
|
||||||
|
diffRootDirectory = string.Empty;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_Configuration.DiffPropertyDirectory.EndsWith("{}"))
|
||||||
|
throw new Exception("Invalid directory should end with {}!");
|
||||||
|
diffRootDirectory = Shared.Models.Stateless.Methods.IProperty.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory);
|
||||||
|
}
|
||||||
|
PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory);
|
||||||
|
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory))
|
||||||
|
diffPropertyCompareCollection = Array.Empty<PropertyCompare.Models.PropertyCompare>();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||||
|
if (!diffPropertyCompareCollection.Any())
|
||||||
|
throw new Exception("Invalid directory!");
|
||||||
|
}
|
||||||
|
string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]");
|
||||||
|
PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||||
|
{
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray();
|
||||||
|
File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines);
|
||||||
|
string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json);
|
||||||
|
}
|
||||||
|
for (int x = 0; x < int.MaxValue; x++)
|
||||||
|
{
|
||||||
|
_Logger?.LogInformation($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}");
|
||||||
|
_Logger?.LogInformation($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}");
|
||||||
|
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||||
|
consoleKey = Console.ReadKey().Key;
|
||||||
|
if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_Logger?.LogInformation(". . .");
|
||||||
|
if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D)
|
||||||
|
propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection);
|
||||||
|
else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < int.MaxValue; x++)
|
||||||
|
{
|
||||||
|
_Logger?.LogInformation($"Press \"0 - {loadLessThan}\" key when ready to continue");
|
||||||
|
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||||
|
consoleKey = Console.ReadKey().Key;
|
||||||
|
if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_Logger?.LogInformation(". . .");
|
||||||
|
int i = int.Parse(consoleKey.Value.ToString()[1..]);
|
||||||
|
propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PossiblyRename(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string replaceFile;
|
||||||
|
string replaceDirectory;
|
||||||
|
int remainingDirectories = 0;
|
||||||
|
IEnumerable<(string Find, string Replace)>? found;
|
||||||
|
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||||
|
{
|
||||||
|
if (!topDirectories.Any())
|
||||||
|
continue;
|
||||||
|
found = from l in _RenameFindReplace where sourceDirectory == l.Find select l;
|
||||||
|
if (!found.Any())
|
||||||
|
continue;
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
replaceDirectory = found.First().Replace;
|
||||||
|
if (!Directory.Exists(replaceDirectory))
|
||||||
|
Directory.Move(sourceDirectory, replaceDirectory);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Directory.EnumerateDirectories(sourceDirectory).Any())
|
||||||
|
remainingDirectories += 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||||
|
{
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
{
|
||||||
|
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||||
|
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||||
|
}
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
continue;
|
||||||
|
File.Move(sourceDirectoryFile, replaceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PossiblyCorrect(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||||
|
{
|
||||||
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
|
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||||
|
bool result = false;
|
||||||
|
string corrected;
|
||||||
|
string correctedMoveTo;
|
||||||
|
string? correctedDirectory;
|
||||||
|
string filteredSourceDirectoryFile;
|
||||||
|
string[] filteredSourceDirectoryFiles;
|
||||||
|
(string Find, string Replace) findReplace;
|
||||||
|
IEnumerable<(string Find, string Replace)>? found;
|
||||||
|
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||||
|
{
|
||||||
|
if (!topDirectories.Any())
|
||||||
|
continue;
|
||||||
|
filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray();
|
||||||
|
if (!filteredSourceDirectoryFiles.Any())
|
||||||
|
continue;
|
||||||
|
for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++)
|
||||||
|
{
|
||||||
|
found = null;
|
||||||
|
for (int z = 0; z < int.MaxValue; z++)
|
||||||
|
{
|
||||||
|
filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i];
|
||||||
|
found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l;
|
||||||
|
if (!found.Any())
|
||||||
|
break;
|
||||||
|
findReplace = found.First();
|
||||||
|
corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace);
|
||||||
|
correctedDirectory = Path.GetDirectoryName(corrected);
|
||||||
|
if (string.IsNullOrEmpty(correctedDirectory))
|
||||||
|
break;
|
||||||
|
correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected));
|
||||||
|
if (File.Exists(correctedMoveTo))
|
||||||
|
break;
|
||||||
|
if (!Directory.Exists(correctedDirectory))
|
||||||
|
_ = Directory.CreateDirectory(correctedDirectory);
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
File.Move(filteredSourceDirectoryFile, correctedMoveTo);
|
||||||
|
filteredSourceDirectoryFiles[i] = corrected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PossiblyRenameB(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string replaceFile;
|
||||||
|
string replaceDirectory;
|
||||||
|
IEnumerable<(string Find, string Replace)>? found;
|
||||||
|
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||||
|
{
|
||||||
|
if (!topDirectories.Any())
|
||||||
|
continue;
|
||||||
|
found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l;
|
||||||
|
if (!found.Any())
|
||||||
|
continue;
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
replaceDirectory = found.First().Replace;
|
||||||
|
if (!Directory.Exists(replaceDirectory))
|
||||||
|
_ = Directory.CreateDirectory(replaceDirectory);
|
||||||
|
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||||
|
{
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
{
|
||||||
|
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||||
|
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||||
|
}
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
continue;
|
||||||
|
File.Move(sourceDirectoryFile, replaceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PossiblyRenameC(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string replaceFile;
|
||||||
|
string replaceDirectory;
|
||||||
|
IEnumerable<(string Find, string Replace)>? found;
|
||||||
|
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||||
|
{
|
||||||
|
if (!topDirectories.Any())
|
||||||
|
continue;
|
||||||
|
found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l;
|
||||||
|
if (!found.Any())
|
||||||
|
continue;
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
replaceDirectory = found.First().Replace;
|
||||||
|
if (!Directory.Exists(replaceDirectory))
|
||||||
|
_ = Directory.CreateDirectory(replaceDirectory);
|
||||||
|
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||||
|
{
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
{
|
||||||
|
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||||
|
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||||
|
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||||
|
}
|
||||||
|
if (File.Exists(replaceFile))
|
||||||
|
continue;
|
||||||
|
File.Move(sourceDirectoryFile, replaceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetMissingVerifyToSeasonCollection(List<string> _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||||
|
{
|
||||||
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
|
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||||
|
List<string> results = new();
|
||||||
|
string check;
|
||||||
|
foreach ((int _, string sourceDirectory, string[] _) in groupCollection)
|
||||||
|
{
|
||||||
|
if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory)
|
||||||
|
continue;
|
||||||
|
check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..];
|
||||||
|
if (check[0] is '=' || check.StartsWith("zzz ="))
|
||||||
|
{
|
||||||
|
if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check))
|
||||||
|
results.Add(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Map\Map.csproj" />
|
<ProjectReference Include="..\Map\Map.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 });
|
||||||
|
1
Container/.vscode/format-report.json
vendored
Normal file
1
Container/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
8
Container/.vscode/settings.json
vendored
Normal file
8
Container/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"dlib",
|
||||||
|
"Exif",
|
||||||
|
"nosj",
|
||||||
|
"Serilog"
|
||||||
|
]
|
||||||
|
}
|
51
Container/Container.csproj
Normal file
51
Container/Container.csproj
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<OutputType>library</OutputType>
|
||||||
|
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>Phares.View.by.Distance.Container</PackageId>
|
||||||
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
|
<Version>9.0.100.1</Version>
|
||||||
|
<Authors>Mike Phares</Authors>
|
||||||
|
<Company>Phares</Company>
|
||||||
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">
|
||||||
|
true
|
||||||
|
</IsWindows>
|
||||||
|
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">
|
||||||
|
true
|
||||||
|
</IsOSX>
|
||||||
|
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">
|
||||||
|
true
|
||||||
|
</IsLinux>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(IsWindows)'=='true'">
|
||||||
|
<DefineConstants>Windows</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(IsOSX)'=='true'">
|
||||||
|
<DefineConstants>OSX</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(IsLinux)'=='true'">
|
||||||
|
<DefineConstants>Linux</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
|
||||||
|
<SupportedPlatform Include="browser" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
|
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||||
|
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -1,8 +1,10 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Container.Models;
|
||||||
|
|
||||||
public record Container(string SourceDirectory, List<Item> Items)
|
public record Container(string SourceDirectory, ReadOnlyCollection<Item> Items)
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
501
Container/Models/Stateless/Methods/Container.cs
Normal file
501
Container/Models/Stateless/Methods/Container.cs
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Text.Json;
|
||||||
|
using View_by_Distance.Shared.Models;
|
||||||
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Container.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
internal abstract class Container
|
||||||
|
{
|
||||||
|
|
||||||
|
private record FilePair(bool IsUnique,
|
||||||
|
List<FilePath> Collection,
|
||||||
|
FilePath FilePath,
|
||||||
|
Item Item);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container)
|
||||||
|
{
|
||||||
|
List<Item> results = [];
|
||||||
|
foreach (Item item in container.Items)
|
||||||
|
{
|
||||||
|
if (!item.IsValidImageFormatExtension || propertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered))
|
||||||
|
continue;
|
||||||
|
results.Add(item);
|
||||||
|
}
|
||||||
|
return container.Items.Count == results.Count ? container.Items : results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items)
|
||||||
|
{
|
||||||
|
DateTime[] results;
|
||||||
|
long containerMinimumTicks = (from l in items select l.FilePath.LastWriteTicks).Min();
|
||||||
|
long containerMaximumTicks = (from l in items select l.FilePath.LastWriteTicks).Max();
|
||||||
|
results = [new(containerMinimumTicks), new(containerMaximumTicks)];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||||
|
{
|
||||||
|
List<int> results = [];
|
||||||
|
ReadOnlyCollection<Item> filteredItems;
|
||||||
|
foreach (Models.Container container in readOnlyContainers)
|
||||||
|
{
|
||||||
|
if (container.Items.Count == 0)
|
||||||
|
continue;
|
||||||
|
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||||
|
if (filteredItems.Count == 0)
|
||||||
|
continue;
|
||||||
|
foreach (Item item in filteredItems)
|
||||||
|
{
|
||||||
|
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||||
|
continue;
|
||||||
|
if (results.Contains(item.Property.Id.Value))
|
||||||
|
continue;
|
||||||
|
results.Add(item.Property.Id.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string _)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
Models.Container[] results;
|
||||||
|
bool useIgnoreExtensions = true;
|
||||||
|
const bool useCeilingAverage = true;
|
||||||
|
const string fileSearchFilter = "*";
|
||||||
|
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
||||||
|
const string directorySearchFilter = "*";
|
||||||
|
ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById = null;
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
|
||||||
|
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
|
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
|
return (count, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IDlibDotNet GetDlibDotNet() =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
private static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||||
|
{
|
||||||
|
List<Models.Container> results = [];
|
||||||
|
string directory;
|
||||||
|
List<Item>? items;
|
||||||
|
Models.Container container;
|
||||||
|
List<string> directories = [];
|
||||||
|
Dictionary<string, List<Item>> directoryToItems = [];
|
||||||
|
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||||
|
{
|
||||||
|
if (filePaths.Count == 0)
|
||||||
|
continue;
|
||||||
|
directory = filePaths[0].DirectoryFullPath;
|
||||||
|
if (directory is null)
|
||||||
|
continue;
|
||||||
|
if (!directories.Contains(directory))
|
||||||
|
directories.Add(directory);
|
||||||
|
if (!directoryToItems.TryGetValue(directory, out items))
|
||||||
|
{
|
||||||
|
directoryToItems.Add(directory, []);
|
||||||
|
if (!directoryToItems.TryGetValue(directory, out items))
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
|
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||||
|
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
|
foreach (FilePair filePair in filePairs)
|
||||||
|
{
|
||||||
|
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||||
|
{
|
||||||
|
directoryToItems.Add(filePair.FilePath.DirectoryFullPath, []);
|
||||||
|
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
items.Add(filePair.Item);
|
||||||
|
}
|
||||||
|
foreach (KeyValuePair<string, List<Item>> keyValuePair in directoryToItems)
|
||||||
|
{
|
||||||
|
if (keyValuePair.Value.Count == 0)
|
||||||
|
continue;
|
||||||
|
container = new(keyValuePair.Key, new(keyValuePair.Value));
|
||||||
|
results.Add(container);
|
||||||
|
}
|
||||||
|
return (filePairs.Count, results.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||||
|
{
|
||||||
|
List<FilePair> results = [];
|
||||||
|
const string extension = ".json";
|
||||||
|
ReadOnlyCollection<Shared.Models.FilePair> filePairs;
|
||||||
|
string jsonGroupDirectory = aPropertySingletonDirectory;
|
||||||
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
|
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
|
filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
|
||||||
|
ParallelFor(dlibDotNet, propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, exifDirectoriesById, filePairs[i], results));
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParallelFor(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, int rootDirectoryLength, ReadOnlyDictionary<int, ExifDirectory>? __, Shared.Models.FilePair filePair, List<FilePair> results)
|
||||||
|
{
|
||||||
|
dlibDotNet?.Tick();
|
||||||
|
bool abandoned = false;
|
||||||
|
FileHolder sourceDirectoryFileHolder;
|
||||||
|
Property? property = GetProperty(filePair);
|
||||||
|
bool? fileSizeChanged = property is not null ? property.FileSize != filePair.FilePath.Length : null;
|
||||||
|
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePair.FilePath.ExtensionLowered);
|
||||||
|
bool? shouldIgnore = property is null || property.Keywords is null ? null : propertyConfiguration.IgnoreRulesKeyWords.Any(l => property.Keywords.Contains(l));
|
||||||
|
bool? isArchive = filePair.FilePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePair.FilePath.Id.Value, out Identifier? identifier);
|
||||||
|
if (property is not null && filePair.FilePath.Id is not null && filePair.FilePath.HasIgnoreKeyword is not null && filePair.FilePath.HasDateTimeOriginal is not null)
|
||||||
|
{
|
||||||
|
char? change;
|
||||||
|
ReadOnlyCollection<FilePath>? filePaths = null;
|
||||||
|
char hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePair.FilePath).ToString()[0];
|
||||||
|
char hasDateTimeOriginal = IId.GetHasDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||||
|
char missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||||
|
if (shouldIgnore is not null && shouldIgnore.Value)
|
||||||
|
{
|
||||||
|
if (filePair.FilePath.FileNameFirstSegment[^1] == hasIgnoreKeyword)
|
||||||
|
change = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
change = hasIgnoreKeyword;
|
||||||
|
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((shouldIgnore is null || !shouldIgnore.Value) && property.DateTimeOriginal is null)
|
||||||
|
{
|
||||||
|
if (filePair.FilePath.FileNameFirstSegment[^1] == missingDateTimeOriginal)
|
||||||
|
change = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
change = missingDateTimeOriginal;
|
||||||
|
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (filePair.FilePath.FileNameFirstSegment[^1] != hasDateTimeOriginal)
|
||||||
|
{
|
||||||
|
change = hasDateTimeOriginal;
|
||||||
|
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
change = null;
|
||||||
|
if (filePaths is not null && change is not null)
|
||||||
|
RenameFile(filePair, filePair.FilePath, change.Value, filePaths);
|
||||||
|
}
|
||||||
|
string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.FilePath.FullName, rootDirectoryLength, forceExtensionToLower: true);
|
||||||
|
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime.Ticks != filePair.FilePath.LastWriteTicks : null;
|
||||||
|
if (filePair.Match is not null)
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
||||||
|
else if (!filePair.IsUnique)
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string fileName = Path.GetFileName(filePair.FilePath.FullName);
|
||||||
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePair.FilePath);
|
||||||
|
string directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
||||||
|
string jsonFileName = $"{fileName}{extension}";
|
||||||
|
string fullFileName = Path.Combine(directory, jsonFileName);
|
||||||
|
MoveIf(jsonFileName, cei, directory, fullFileName);
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
|
||||||
|
}
|
||||||
|
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
||||||
|
{
|
||||||
|
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePair.FilePath.LastWriteTicks));
|
||||||
|
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
||||||
|
}
|
||||||
|
Item item = Item.Get(filePair.FilePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
||||||
|
lock (results)
|
||||||
|
results.Add(new(filePair.IsUnique, filePair.Collection, filePair.FilePath, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Property? GetProperty(Shared.Models.FilePair filePair)
|
||||||
|
{
|
||||||
|
Property? result;
|
||||||
|
if (filePair.Match is null)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(filePair.Match.FullName);
|
||||||
|
if (string.IsNullOrEmpty(json))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RenameFile(Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
||||||
|
{
|
||||||
|
string checkFile;
|
||||||
|
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
|
||||||
|
File.Delete(filePath.FullName);
|
||||||
|
if (filePair.Match is not null)
|
||||||
|
{
|
||||||
|
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(filePair.Match.NameWithoutExtension);
|
||||||
|
string extensionSecond = Path.GetExtension(filePair.Match.Name);
|
||||||
|
checkFile = Path.Combine(filePair.Match.DirectoryFullPath, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{filePair.Match.ExtensionLowered}");
|
||||||
|
if (!File.Exists(checkFile))
|
||||||
|
File.Move(filePair.Match.FullName, checkFile);
|
||||||
|
}
|
||||||
|
foreach (FilePath f in filePaths)
|
||||||
|
{
|
||||||
|
checkFile = Path.Combine(f.DirectoryFullPath, $"{f.NameWithoutExtension[..^1]}{change}{f.ExtensionLowered}");
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(f.FullName, checkFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
File.Move(checkFile, fullFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
ReadOnlyCollection<Item> filteredItems;
|
||||||
|
foreach (Models.Container container in readOnlyContainers)
|
||||||
|
{
|
||||||
|
if (container.Items.Count == 0)
|
||||||
|
continue;
|
||||||
|
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||||
|
if (filteredItems.Count == 0)
|
||||||
|
continue;
|
||||||
|
foreach (Item item in filteredItems)
|
||||||
|
{
|
||||||
|
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||||
|
continue;
|
||||||
|
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
||||||
|
continue;
|
||||||
|
results.Add(item.FilePath.FileNameFirstSegment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
|
||||||
|
{
|
||||||
|
List<Item> results = [];
|
||||||
|
List<int> distinct = [];
|
||||||
|
ReadOnlyCollection<Item> filteredItems;
|
||||||
|
foreach (Models.Container container in containers)
|
||||||
|
{
|
||||||
|
if (container.Items.Count == 0)
|
||||||
|
continue;
|
||||||
|
if (!filterItems)
|
||||||
|
filteredItems = container.Items;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||||
|
if (filteredItems.Count == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (Item item in filteredItems)
|
||||||
|
{
|
||||||
|
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||||
|
continue;
|
||||||
|
if (distinctItems)
|
||||||
|
{
|
||||||
|
if (distinct.Contains(item.Property.Id.Value))
|
||||||
|
continue;
|
||||||
|
distinct.Add(item.Property.Id.Value);
|
||||||
|
}
|
||||||
|
results.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById)
|
||||||
|
{
|
||||||
|
Models.Container[] results;
|
||||||
|
const string directorySearchFilter = "*";
|
||||||
|
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
|
if (keyValuePairs is not null)
|
||||||
|
DoGetFilePairsForRemaining(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, directorySearchFilter);
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DoGetFilePairsForRemaining(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
|
||||||
|
{
|
||||||
|
const string extension = ".json";
|
||||||
|
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
|
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||||
|
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(bMetaSingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
||||||
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||||
|
(string cResultsFullGroupDirectory, _, string dResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories("Original");
|
||||||
|
string cResizeSingletonDirectory = Path.Combine(cResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(cResizeSingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(cResizeSingletonDirectory);
|
||||||
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||||
|
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
|
if (!Directory.Exists(dFaceCollectionDirectory))
|
||||||
|
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
||||||
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection, fileNamesToFiles);
|
||||||
|
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
||||||
|
if (!Directory.Exists(dFaceContentDirectory))
|
||||||
|
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
||||||
|
AnyMovedFace(propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, fileNamesToFiles, dFaceContentDirectory);
|
||||||
|
AnyMovedDistance(propertyConfiguration, facesFileNameExtension, fileNamesToFiles, eDistanceContentDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, string extension, string hiddenExtension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
||||||
|
{
|
||||||
|
string directory;
|
||||||
|
string checkFile;
|
||||||
|
string directoryName;
|
||||||
|
List<string> files = [];
|
||||||
|
string[] fileNameSegments;
|
||||||
|
List<string> directories = [];
|
||||||
|
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories));
|
||||||
|
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{hiddenExtension}", SearchOption.AllDirectories));
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
directory = Path.GetDirectoryName(file) ?? throw new Exception();
|
||||||
|
if (!directories.Contains(directory))
|
||||||
|
directories.Add(directory);
|
||||||
|
directoryName = Path.GetFileName(directory);
|
||||||
|
fileNameSegments = Path.GetFileName(file).Split('.');
|
||||||
|
if (fileNameSegments[0] != directoryName)
|
||||||
|
{
|
||||||
|
fileNameSegments[0] = string.Empty;
|
||||||
|
checkFile = Path.Combine(directory, $"{directoryName}{string.Join('.', fileNameSegments)}");
|
||||||
|
if (!File.Exists(checkFile))
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
|
||||||
|
File.Delete(file);
|
||||||
|
else
|
||||||
|
File.Move(file, checkFile, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (directories.Count > 0)
|
||||||
|
AnyMovedFace(propertyConfiguration, fileNamesToFiles, directories);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, List<string> directories)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string checkFile;
|
||||||
|
FilePath filePath;
|
||||||
|
string subDirectory;
|
||||||
|
string directoryName;
|
||||||
|
string checkDirectory;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
string directoryNameWith;
|
||||||
|
List<FilePath>? collection;
|
||||||
|
List<string> directoryNames = [];
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
fileHolder = IFileHolder.Get(Path.GetFileName(directory));
|
||||||
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||||
|
throw new Exception();
|
||||||
|
directoryNames.Clear();
|
||||||
|
foreach (FilePath f in collection)
|
||||||
|
directoryNames.Add(Path.GetFileName(f.DirectoryFullPath) ?? throw new Exception());
|
||||||
|
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
|
||||||
|
continue;
|
||||||
|
directoryName = Path.GetFileName(Path.GetDirectoryName(directory)) ?? throw new Exception();
|
||||||
|
if (directoryName != directoryNames[0])
|
||||||
|
{
|
||||||
|
subDirectory = Path.GetDirectoryName(Path.GetDirectoryName(directory)) ?? throw new Exception();
|
||||||
|
checkDirectory = Path.Combine(subDirectory, directoryNames[0]);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
directoryNameWith = collection.Count > 1 ? directoryName : $"{collection[0].NameWithoutExtension}";
|
||||||
|
checkFile = Path.Combine(checkDirectory, directoryNameWith);
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
if (!Directory.Exists(checkFile))
|
||||||
|
Directory.Move(directory, checkFile);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new DirectoryInfo(directory).LastWriteTime > new DirectoryInfo(checkFile).LastWriteTime)
|
||||||
|
Directory.Delete(directory, recursive: true);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Directory.Delete(checkFile, recursive: true);
|
||||||
|
Directory.Move(directory, checkFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMovedDistance(IPropertyConfiguration propertyConfiguration, string extension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string checkFile;
|
||||||
|
string directory;
|
||||||
|
FilePath filePath;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
string[] fileNameSegments;
|
||||||
|
List<FilePath>? collection;
|
||||||
|
List<string> fileNames = [];
|
||||||
|
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
fileHolder = IFileHolder.Get(file);
|
||||||
|
if (!fileHolder.Exists)
|
||||||
|
continue;
|
||||||
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
fileNameSegments = filePath.Name.Split('.');
|
||||||
|
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||||
|
continue;
|
||||||
|
fileNames.Clear();
|
||||||
|
foreach (FilePath f in collection)
|
||||||
|
fileNames.Add(f.NameWithoutExtension ?? throw new Exception());
|
||||||
|
if (fileNames.Count == 0 || fileNames.Distinct().Count() != 1)
|
||||||
|
continue;
|
||||||
|
if (filePath.FileNameFirstSegment != fileNames[0])
|
||||||
|
{
|
||||||
|
fileNameSegments[0] = string.Empty;
|
||||||
|
directory = Path.GetDirectoryName(file) ?? throw new Exception();
|
||||||
|
checkFile = Path.Combine(directory, $"{fileNames[0]}{string.Join('.', fileNameSegments)}");
|
||||||
|
if (!result)
|
||||||
|
result = true;
|
||||||
|
if (!File.Exists(checkFile))
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
|
||||||
|
File.Delete(file);
|
||||||
|
else
|
||||||
|
File.Move(file, checkFile, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
Container/Models/Stateless/Methods/IContainer.cs
Normal file
59
Container/Models/Stateless/Methods/IContainer.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using View_by_Distance.Shared.Models;
|
||||||
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Container.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
public interface IContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||||
|
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||||
|
|
||||||
|
public static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||||
|
Container.GetContainerDateTimes(items);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||||
|
Container.GetValidImageItems(propertyConfiguration, container);
|
||||||
|
|
||||||
|
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||||
|
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
|
||||||
|
|
||||||
|
public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
|
public static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
|
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||||
|
Container.GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||||
|
|
||||||
|
internal DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||||
|
GetContainerDateTimes(items);
|
||||||
|
|
||||||
|
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||||
|
GetValidImageItems(propertyConfiguration, container);
|
||||||
|
|
||||||
|
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||||
|
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||||
|
|
||||||
|
internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
|
internal List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
|
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
|
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||||
|
|
||||||
|
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||||
|
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||||
|
|
||||||
|
internal ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||||
|
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||||
|
|
||||||
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Phares.Shared;
|
using Phares.Shared;
|
||||||
using ShellProgressBar;
|
using ShellProgressBar;
|
||||||
@ -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<byte, 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)
|
||||||
{
|
{
|
||||||
@ -37,7 +37,9 @@ public class CopyDistinct
|
|||||||
_Configuration = configuration;
|
_Configuration = configuration;
|
||||||
logger?.LogInformation(propertyConfiguration.RootDirectory);
|
logger?.LogInformation(propertyConfiguration.RootDirectory);
|
||||||
(bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack) = Verify();
|
(bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack) = Verify();
|
||||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs =
|
||||||
|
Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
||||||
|
_FileGroups = keyValuePairs[appSettings.ResultDirectoryKey];
|
||||||
List<string> lines = CopyDistinctFilesInDirectories(logger, move, filesCollection, anyLenFiles, moveBack);
|
List<string> lines = CopyDistinctFilesInDirectories(logger, move, filesCollection, anyLenFiles, moveBack);
|
||||||
if (lines.Count != 0)
|
if (lines.Count != 0)
|
||||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||||
@ -93,6 +95,76 @@ public class CopyDistinct
|
|||||||
return (move, new(filesCollection), anyLenFiles, moveBack);
|
return (move, new(filesCollection), anyLenFiles, moveBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
ProgressBar progressBar;
|
||||||
|
string[] distinctDirectories;
|
||||||
|
ConsoleKey? consoleKey = null;
|
||||||
|
string message = nameof(CopyDistinct);
|
||||||
|
List<(FilePath, string)> toDoCollection;
|
||||||
|
int count = filesCollection.Select(l => l.Length).Sum();
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
if (moveBack)
|
||||||
|
{
|
||||||
|
if (!anyLenFiles)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressBar = new(count, message, options);
|
||||||
|
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
||||||
|
if (key != _PropertyConfiguration.ResultContent)
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
foreach (string distinctDirectory in distinctDirectories)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(distinctDirectory))
|
||||||
|
_ = Directory.CreateDirectory(distinctDirectory);
|
||||||
|
}
|
||||||
|
if (move)
|
||||||
|
logger?.LogInformation($"Ready to Move {toDoCollection.Count} file(s)?");
|
||||||
|
else if (!moveBack)
|
||||||
|
logger?.LogInformation($"Ready to Copy {toDoCollection.Count} file(s)?");
|
||||||
|
else
|
||||||
|
logger?.LogInformation($"Ready to Move back {toDoCollection.Count} file(s)?");
|
||||||
|
for (int y = 0; y < int.MaxValue; y++)
|
||||||
|
{
|
||||||
|
if (move)
|
||||||
|
logger?.LogInformation("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files");
|
||||||
|
else if (!moveBack)
|
||||||
|
logger?.LogInformation("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files");
|
||||||
|
else
|
||||||
|
logger?.LogInformation("Press \"Y\" key to move back file(s), \"N\" key to log file(s) or close console to not move back files");
|
||||||
|
consoleKey = System.Console.ReadKey().Key;
|
||||||
|
if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logger?.LogInformation(". . .");
|
||||||
|
if (consoleKey is null || consoleKey.Value != ConsoleKey.Y)
|
||||||
|
{
|
||||||
|
if (move || moveBack)
|
||||||
|
logger?.LogInformation("Nothing moved!");
|
||||||
|
else
|
||||||
|
logger?.LogInformation("Nothing copied!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressBar = new(count, message, options);
|
||||||
|
results.AddRange(IDirectory.CopyOrMove(toDoCollection, move, moveBack, () => progressBar.Tick()));
|
||||||
|
progressBar.Dispose();
|
||||||
|
if (move || moveBack)
|
||||||
|
logger?.LogInformation("Done moving");
|
||||||
|
else
|
||||||
|
logger?.LogInformation("Done copying");
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private static (string[], List<(FilePath, string)>) GetMoveBackToDoCollection(Property.Models.Configuration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
private static (string[], List<(FilePath, string)>) GetMoveBackToDoCollection(Property.Models.Configuration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||||
{
|
{
|
||||||
List<(FilePath, string)> results = [];
|
List<(FilePath, string)> results = [];
|
||||||
@ -159,72 +231,4 @@ public class CopyDistinct
|
|||||||
return (distinctDirectories.ToArray(), results);
|
return (distinctDirectories.ToArray(), results);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
|
||||||
{
|
|
||||||
List<string> results = [];
|
|
||||||
ProgressBar progressBar;
|
|
||||||
string[] distinctDirectories;
|
|
||||||
ConsoleKey? consoleKey = null;
|
|
||||||
string message = nameof(CopyDistinct);
|
|
||||||
List<(FilePath, string)> toDoCollection;
|
|
||||||
int count = filesCollection.Select(l => l.Length).Sum();
|
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
if (moveBack)
|
|
||||||
{
|
|
||||||
if (!anyLenFiles)
|
|
||||||
throw new NotSupportedException();
|
|
||||||
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
progressBar = new(count, message, options);
|
|
||||||
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
|
||||||
string[] directories = _FileGroups[key];
|
|
||||||
(distinctDirectories, toDoCollection) = IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filesCollection, directories, () => progressBar.Tick());
|
|
||||||
progressBar.Dispose();
|
|
||||||
}
|
|
||||||
foreach (string distinctDirectory in distinctDirectories)
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(distinctDirectory))
|
|
||||||
_ = Directory.CreateDirectory(distinctDirectory);
|
|
||||||
}
|
|
||||||
if (move)
|
|
||||||
logger?.LogInformation($"Ready to Move {toDoCollection.Count} file(s)?");
|
|
||||||
else if (!moveBack)
|
|
||||||
logger?.LogInformation($"Ready to Copy {toDoCollection.Count} file(s)?");
|
|
||||||
else
|
|
||||||
logger?.LogInformation($"Ready to Move back {toDoCollection.Count} file(s)?");
|
|
||||||
for (int y = 0; y < int.MaxValue; y++)
|
|
||||||
{
|
|
||||||
if (move)
|
|
||||||
logger?.LogInformation("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files");
|
|
||||||
else if (!moveBack)
|
|
||||||
logger?.LogInformation("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files");
|
|
||||||
else
|
|
||||||
logger?.LogInformation("Press \"Y\" key to move back file(s), \"N\" key to log file(s) or close console to not move back files");
|
|
||||||
consoleKey = System.Console.ReadKey().Key;
|
|
||||||
if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
logger?.LogInformation(". . .");
|
|
||||||
if (consoleKey is null || consoleKey.Value != ConsoleKey.Y)
|
|
||||||
{
|
|
||||||
if (move || moveBack)
|
|
||||||
logger?.LogInformation("Nothing moved!");
|
|
||||||
else
|
|
||||||
logger?.LogInformation("Nothing copied!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
progressBar = new(count, message, options);
|
|
||||||
results.AddRange(IDirectory.CopyOrMove(toDoCollection, move, moveBack, () => progressBar.Tick()));
|
|
||||||
progressBar.Dispose();
|
|
||||||
if (move || moveBack)
|
|
||||||
logger?.LogInformation("Done moving");
|
|
||||||
else
|
|
||||||
logger?.LogInformation("Done copying");
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
@ -57,11 +57,11 @@ public class DateGroup
|
|||||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||||
(int t, Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
(int t, Container.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory, aResultsFullGroupDirectory);
|
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory, aResultsFullGroupDirectory);
|
||||||
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers))
|
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Property.Models.Stateless.IProperty.Any(containers))
|
||||||
{
|
{
|
||||||
propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers);
|
propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers);
|
||||||
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
||||||
@ -251,11 +251,11 @@ public class DateGroup
|
|||||||
if (topDirectoryName.Length > 1)
|
if (topDirectoryName.Length > 1)
|
||||||
_ = destinationDirectoryName.Append(topDirectoryName);
|
_ = destinationDirectoryName.Append(topDirectoryName);
|
||||||
if (_Configuration.BySeason)
|
if (_Configuration.BySeason)
|
||||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year} {seasonName}" });
|
directoryNames.AddRange([$"{destinationDirectoryName} {year} {seasonName}"]);
|
||||||
else if (_Configuration.ByDay)
|
else if (_Configuration.ByDay)
|
||||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}" });
|
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}"]);
|
||||||
else if (_Configuration.ByWeek)
|
else if (_Configuration.ByWeek)
|
||||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}" });
|
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}"]);
|
||||||
else
|
else
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
@ -302,7 +302,7 @@ public class DateGroup
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Item[] GetFilterItems(Container container)
|
private static Item[] GetFilterItems(Container.Models.Container container)
|
||||||
{
|
{
|
||||||
List<Item> results = [];
|
List<Item> results = [];
|
||||||
foreach (Item item in container.Items)
|
foreach (Item item in container.Items)
|
||||||
@ -313,7 +313,7 @@ public class DateGroup
|
|||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container[] containers)
|
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
||||||
Item[] filteredItems;
|
Item[] filteredItems;
|
||||||
@ -322,7 +322,7 @@ public class DateGroup
|
|||||||
string destinationDirectory;
|
string destinationDirectory;
|
||||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
|
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
|
||||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
|
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
|
||||||
foreach (Container container in containers)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -352,7 +352,7 @@ public class DateGroup
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container[] containers)
|
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
string checkDirectory;
|
string checkDirectory;
|
||||||
bool hasDuplicate;
|
bool hasDuplicate;
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ public class DateGroup
|
|||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
|
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container[] containers)
|
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
string path;
|
string path;
|
||||||
string fileName;
|
string fileName;
|
||||||
@ -468,17 +468,17 @@ public class DateGroup
|
|||||||
WindowsShortcut windowsShortcut;
|
WindowsShortcut windowsShortcut;
|
||||||
TimeSpan threeStandardDeviationHigh;
|
TimeSpan threeStandardDeviationHigh;
|
||||||
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
|
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
|
||||||
foreach (Container container in containers)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
selectedTotal = 0;
|
selectedTotal = 0;
|
||||||
threeStandardDeviationHigh = Shared.Models.Stateless.Methods.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
threeStandardDeviationHigh = Property.Models.Stateless.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
||||||
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
||||||
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
||||||
for (int i = 0; i < container.Items.Count; i++)
|
for (int i = 0; i < container.Items.Count; i++)
|
||||||
{
|
{
|
||||||
(i, dateTimes, selectedItems) = Shared.Models.Stateless.Methods.IProperty.Get(container, threeStandardDeviationHigh, i);
|
(i, dateTimes, selectedItems) = Property.Models.Stateless.IProperty.Get(container, threeStandardDeviationHigh, i);
|
||||||
selectedTotal += selectedItems.Count;
|
selectedTotal += selectedItems.Count;
|
||||||
foreach (Item item in selectedItems)
|
foreach (Item item in selectedItems)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
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,27 +491,45 @@ 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);
|
||||||
}
|
}
|
||||||
results = new(collection.ToArray());
|
results = collection.AsReadOnly();
|
||||||
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 results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
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,20 +660,22 @@ 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]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mappedRelations = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList();
|
mappedRelations = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList();
|
||||||
results.Add(new(fileHolder, new(mappedRelations)));
|
results.Add(new(fileHolder, new(mappedRelations)));
|
||||||
}
|
}
|
||||||
return new(results);
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,8 @@ 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());
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
<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" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,8 @@ 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());
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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,13 +27,14 @@
|
|||||||
</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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
|
<ProjectReference Include="..\Container\Container.csproj" />
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
@ -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,11 +105,11 @@ public partial class DragDropSearch : Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
Container[] containers;
|
Container.Models.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), "{}");
|
||||||
(_, containers) = IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
|
(_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
|
||||||
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
||||||
foreach (Item item in collection)
|
foreach (Item item in collection)
|
||||||
{
|
{
|
||||||
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,11 @@ 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());
|
||||||
}
|
|
||||||
|
|
||||||
private static Item[] GetFilterItems(Models.Configuration configuration, Container container)
|
private static Item[] GetFilterItems(Models.Configuration configuration, Container.Models.Container container)
|
||||||
{
|
{
|
||||||
List<Item> results = [];
|
List<Item> results = [];
|
||||||
foreach (Item item in container.Items)
|
foreach (Item item in container.Items)
|
||||||
@ -26,11 +24,11 @@ public class Program
|
|||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Item> GetItemCollection(Models.Configuration configuration, Container[] containers)
|
public static List<Item> GetItemCollection(Models.Configuration configuration, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
List<Item> results = [];
|
List<Item> results = [];
|
||||||
Item[] filteredItems;
|
Item[] filteredItems;
|
||||||
foreach (Container container in containers)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,8 @@ 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());
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -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;
|
||||||
@ -29,7 +30,7 @@ public class DuplicateSearch
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Configuration.Verify(configuration, requireExist: false);
|
Configuration.Verify(configuration, requireExist: false);
|
||||||
Container[] containers = GetContainers(ticks, configuration);
|
Container.Models.Container[] containers = GetContainers(ticks, configuration);
|
||||||
string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(configuration.RootDirectory);
|
string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(configuration.RootDirectory);
|
||||||
bool argZeroIsConfigurationRootDirectory = configuration.RootDirectory == argZero;
|
bool argZeroIsConfigurationRootDirectory = configuration.RootDirectory == argZero;
|
||||||
string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved");
|
string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved");
|
||||||
@ -124,10 +125,10 @@ public class DuplicateSearch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Container[] GetContainers(long ticks, Configuration configuration)
|
private static Container.Models.Container[] GetContainers(long ticks, Configuration configuration)
|
||||||
{
|
{
|
||||||
int f;
|
int f;
|
||||||
Container[] containers;
|
Container.Models.Container[] containers;
|
||||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
string message = $") Building Container(s) - {totalSeconds} total second(s)";
|
string message = $") Building Container(s) - {totalSeconds} total second(s)";
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
@ -135,38 +136,38 @@ public class DuplicateSearch
|
|||||||
{
|
{
|
||||||
progressBar.Tick();
|
progressBar.Tick();
|
||||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||||
(f, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
|
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
|
||||||
}
|
}
|
||||||
return containers;
|
return containers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container[] containers, string destinationRoot, List<int> preloadIds)
|
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
foreach (int id in preloadIds)
|
foreach (int id in preloadIds)
|
||||||
results.Add(id, [null]);
|
results.Add(id, [null]);
|
||||||
}
|
}
|
||||||
foreach (Container container in containers)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
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 = Container.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 = Container.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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
|
@ -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,12 @@ 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 ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||||
|
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultCollectionFileGroups;
|
||||||
|
|
||||||
public D_Face(
|
public D_Face(
|
||||||
string argZero,
|
string argZero,
|
||||||
@ -68,7 +70,6 @@ public class D_Face
|
|||||||
float[] rectangleIntersectMinimums)
|
float[] rectangleIntersectMinimums)
|
||||||
{
|
{
|
||||||
_ArgZero = argZero;
|
_ArgZero = argZero;
|
||||||
_FileGroups = [];
|
|
||||||
_ImageCodecInfo = imageCodecInfo;
|
_ImageCodecInfo = imageCodecInfo;
|
||||||
_EncoderParameters = encoderParameters;
|
_EncoderParameters = encoderParameters;
|
||||||
_FileNameExtension = filenameExtension;
|
_FileNameExtension = filenameExtension;
|
||||||
@ -83,6 +84,8 @@ public class D_Face
|
|||||||
_RectangleIntersectMinimum = rectangleIntersectMinimums.Min();
|
_RectangleIntersectMinimum = rectangleIntersectMinimums.Min();
|
||||||
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
|
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
|
||||||
_ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime;
|
_ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime;
|
||||||
|
_ResultContentFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
|
_ResultCollectionFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName);
|
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName);
|
||||||
_Model = model;
|
_Model = model;
|
||||||
_PredictorModel = predictorModel;
|
_PredictorModel = predictorModel;
|
||||||
@ -92,6 +95,73 @@ public class D_Face
|
|||||||
_WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
|
_WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
Bitmap bitmap = new(fileInfo.FullName);
|
||||||
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
|
bitmap.Save(checkFile);
|
||||||
|
bitmap.Dispose();
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
|
||||||
|
File.Delete(fileInfo.FullName);
|
||||||
|
File.Move(checkFile, fileInfo.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
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 });
|
||||||
@ -100,120 +170,175 @@ public class D_Face
|
|||||||
|
|
||||||
public void Update(string dResultsFullGroupDirectory)
|
public void Update(string dResultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
_FileGroups.Clear();
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
|
||||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
|
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
{
|
||||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||||
|
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||||
|
else if (keyValuePair.Key == _PropertyConfiguration.ResultCollection)
|
||||||
|
_ResultCollectionFileGroups[0] = keyValuePair.Value;
|
||||||
|
else
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName)
|
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)
|
||||||
{
|
{
|
||||||
(Model, PredictorModel, ModelParameter) result;
|
List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = [];
|
||||||
Array array;
|
bool save;
|
||||||
Model? model = null;
|
FileInfo fileInfo;
|
||||||
PredictorModel? predictorModel = null;
|
FileHolder fileHolder;
|
||||||
array = Enum.GetValues(typeof(Model));
|
string deterministicHashCodeKey;
|
||||||
foreach (Model check in array)
|
string fileName = mappingFromItem.FilePath.NameWithoutExtension;
|
||||||
|
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();
|
||||||
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
|
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||||
|
DirectoryInfo directoryInfo = new(Path.Combine(directory, fileName));
|
||||||
|
MoveIf(fileName, cei, directory, directoryInfo);
|
||||||
|
foreach (Shared.Models.Face face in faces)
|
||||||
{
|
{
|
||||||
if (modelName.Contains(check.ToString()))
|
save = false;
|
||||||
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||||
{
|
{
|
||||||
model = check;
|
results.Add(new(face, null, string.Empty, save));
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||||
|
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||||
|
fileHolder = FileHolder.Get(fileInfo);
|
||||||
|
if (!directoryInfo.Exists)
|
||||||
|
save = true;
|
||||||
|
else if (_OverrideForFaceImages)
|
||||||
|
save = true;
|
||||||
|
else if (!fileHolder.Exists)
|
||||||
|
save = true;
|
||||||
|
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||||
|
save = true;
|
||||||
|
results.Add(new(face, fileHolder, Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||||
}
|
}
|
||||||
if (model is null)
|
if (results.Any(l => l.Save))
|
||||||
throw new Exception("Destination directory must have Model name!");
|
|
||||||
model = model.Value;
|
|
||||||
array = Enum.GetValues(typeof(PredictorModel));
|
|
||||||
foreach (PredictorModel check in array)
|
|
||||||
{
|
{
|
||||||
if (predictorModelName.Contains(check.ToString()))
|
if (!directoryInfo.Exists)
|
||||||
{
|
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||||
predictorModel = check;
|
SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (predictorModel is null)
|
return results;
|
||||||
throw new Exception("Destination directory must have Predictor Model name!");
|
|
||||||
predictorModel = predictorModel.Value;
|
|
||||||
ModelParameter modelParameter = new()
|
|
||||||
{
|
|
||||||
CnnFaceDetectorModel = File.ReadAllBytes(Path.Combine(modelDirectory, "mmod_human_face_detector.dat")),
|
|
||||||
FaceRecognitionModel = File.ReadAllBytes(Path.Combine(modelDirectory, "dlib_face_recognition_resnet_model_v1.dat")),
|
|
||||||
PosePredictor5FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_5_face_landmarks.dat")),
|
|
||||||
PosePredictor68FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_68_face_landmarks.dat"))
|
|
||||||
};
|
|
||||||
result = new(model.Value, predictorModel.Value, modelParameter);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||||
|
|
||||||
private void SaveFaces(FileHolder resizedFileHolder, List<(Shared.Models.Face, FileInfo?, string, bool)> collection)
|
|
||||||
{
|
{
|
||||||
int width;
|
string[] segments = directory.Split(cei.Combined);
|
||||||
int height;
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
Bitmap bitmap;
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
short type = 2;
|
segments.Length == 2 ?
|
||||||
Graphics graphics;
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
Location? location;
|
null;
|
||||||
Rectangle rectangle;
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||||
string locationJson;
|
|
||||||
string faceEncodingJson;
|
|
||||||
PropertyItem? propertyItem;
|
|
||||||
string outputResolutionJson;
|
|
||||||
using Bitmap source = new(resizedFileHolder.FullName);
|
|
||||||
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
|
||||||
int fileSource = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagFileSource;
|
|
||||||
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
|
||||||
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection)
|
|
||||||
{
|
{
|
||||||
if (!save)
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
continue;
|
if (File.Exists(checkFile))
|
||||||
if (fileInfo is null)
|
|
||||||
continue;
|
|
||||||
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
|
|
||||||
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);
|
|
||||||
if (location is null)
|
|
||||||
continue;
|
|
||||||
width = location.Right - location.Left;
|
|
||||||
height = location.Bottom - location.Top;
|
|
||||||
locationJson = JsonSerializer.Serialize(face.Location);
|
|
||||||
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
|
||||||
outputResolutionJson = JsonSerializer.Serialize(face.OutputResolution);
|
|
||||||
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
|
||||||
using (bitmap = new(width, height))
|
|
||||||
{
|
{
|
||||||
using (graphics = Graphics.FromImage(bitmap))
|
File.Move(checkFile, fileInfo.FullName);
|
||||||
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
fileInfo.Refresh();
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson);
|
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson);
|
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
|
||||||
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
|
|
||||||
}
|
}
|
||||||
if (File.Exists(fileName))
|
|
||||||
File.Delete(fileName);
|
|
||||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
|
||||||
if (location is null)
|
|
||||||
continue;
|
|
||||||
width = location.Right - location.Left;
|
|
||||||
height = location.Bottom - location.Top;
|
|
||||||
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
|
||||||
using (bitmap = new(width, height))
|
|
||||||
{
|
|
||||||
using (graphics = Graphics.FromImage(bitmap))
|
|
||||||
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
|
||||||
bitmap.Save(fileName, _HiddenImageCodecInfo, _HiddenEncoderParameters);
|
|
||||||
}
|
|
||||||
File.SetAttributes(fileName, FileAttributes.Hidden);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Shared.Models.Face> GetFaces(string outputResolution, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location>? locations)
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (Directory.Exists(checkFile))
|
||||||
|
{
|
||||||
|
Directory.Move(checkFile, directoryInfo.FullName);
|
||||||
|
directoryInfo.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Shared.Models.Face> 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<Shared.Models.Face>? results;
|
||||||
|
string? json;
|
||||||
|
List<Location> locations;
|
||||||
|
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();
|
||||||
|
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
|
||||||
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
|
string directory = _ResultCollectionFileGroups[0][cei.Enum][cei.Index];
|
||||||
|
FileInfo fileInfo = new(Path.Combine(directory, fileName));
|
||||||
|
MoveIf(fileName, cei, directory, fileInfo);
|
||||||
|
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||||
|
{
|
||||||
|
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
}
|
||||||
|
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||||
|
{
|
||||||
|
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
}
|
||||||
|
if (_PropertiesChangedForFaces)
|
||||||
|
results = null;
|
||||||
|
else if (!fileInfo.Exists)
|
||||||
|
results = null;
|
||||||
|
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||||
|
results = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
results = JsonSerializer.Deserialize<List<Shared.Models.Face>>(json);
|
||||||
|
if (results is null)
|
||||||
|
throw new NullReferenceException(nameof(results));
|
||||||
|
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
results = null;
|
||||||
|
parseExceptions.Add(nameof(D_Face));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
||||||
|
locations = [];
|
||||||
|
else
|
||||||
|
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||||
|
if (results is null || locations.Count > 0)
|
||||||
|
{
|
||||||
|
results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
|
||||||
|
if (results.Count == 0)
|
||||||
|
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool updateDateWhenMatches = dateTimes.Count > 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||||
|
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||||
|
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
|
||||||
|
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
||||||
|
{
|
||||||
|
if (!_ForceFaceLastWriteTimeToCreationTime)
|
||||||
|
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +347,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)
|
||||||
@ -258,180 +400,128 @@ public class D_Face
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName)
|
||||||
|
|
||||||
private static List<LocationContainer> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
|
|
||||||
{
|
{
|
||||||
List<LocationContainer> results = [];
|
(Model, PredictorModel, ModelParameter) result;
|
||||||
string? json;
|
Array array;
|
||||||
|
Model? model = null;
|
||||||
|
array = Enum.GetValues<Model>();
|
||||||
|
PredictorModel? predictorModel = null;
|
||||||
|
foreach (Model check in array)
|
||||||
|
{
|
||||||
|
if (modelName.Contains(check.ToString()))
|
||||||
|
{
|
||||||
|
model = check;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (model is null)
|
||||||
|
throw new Exception("Destination directory must have Model name!");
|
||||||
|
model = model.Value;
|
||||||
|
array = Enum.GetValues<PredictorModel>();
|
||||||
|
foreach (PredictorModel check in array)
|
||||||
|
{
|
||||||
|
if (predictorModelName.Contains(check.ToString()))
|
||||||
|
{
|
||||||
|
predictorModel = check;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (predictorModel is null)
|
||||||
|
throw new Exception("Destination directory must have Predictor Model name!");
|
||||||
|
predictorModel = predictorModel.Value;
|
||||||
|
ModelParameter modelParameter = new()
|
||||||
|
{
|
||||||
|
CnnFaceDetectorModel = File.ReadAllBytes(Path.Combine(modelDirectory, "mmod_human_face_detector.dat")),
|
||||||
|
FaceRecognitionModel = File.ReadAllBytes(Path.Combine(modelDirectory, "dlib_face_recognition_resnet_model_v1.dat")),
|
||||||
|
PosePredictor5FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_5_face_landmarks.dat")),
|
||||||
|
PosePredictor68FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_68_face_landmarks.dat"))
|
||||||
|
};
|
||||||
|
result = new(model.Value, predictorModel.Value, modelParameter);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
Bitmap bitmap;
|
||||||
|
short type = 2;
|
||||||
|
FaceFile faceFile;
|
||||||
|
Graphics graphics;
|
||||||
Location? location;
|
Location? location;
|
||||||
Rectangle? rectangle;
|
Rectangle rectangle;
|
||||||
List<int> skip = [];
|
string faceFileJson;
|
||||||
OutputResolution? outputResolutionCheck = null;
|
string faceEncodingJson;
|
||||||
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
PropertyItem? propertyItem;
|
||||||
foreach (Shared.Models.Face face in faces)
|
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||||
|
string? model = IMetadata.GetModel(exifDirectory);
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
using Bitmap source = new(resizedFileHolder.FullName);
|
||||||
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
|
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||||
|
const int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
||||||
|
foreach ((Shared.Models.Face face, FileHolder? fileHolder, string fileName, bool save) in collection)
|
||||||
{
|
{
|
||||||
if (face.Location is null || face.OutputResolution is null)
|
if (!save)
|
||||||
continue;
|
continue;
|
||||||
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution));
|
if (fileHolder is null)
|
||||||
}
|
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
|
||||||
{
|
|
||||||
if (locationContainer.ExifDirectory is null)
|
|
||||||
continue;
|
continue;
|
||||||
if (skip.Contains(locationContainer.WholePercentages))
|
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
|
||||||
continue;
|
continue;
|
||||||
foreach (Shared.Models.Face face in faces)
|
if (_OverrideForFaceImages && fileHolder.Exists)
|
||||||
{
|
{
|
||||||
if (face.Location is not null && face.OutputResolution is not null)
|
IFaceD dFace = this;
|
||||||
continue;
|
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
||||||
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
|
||||||
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;
|
|
||||||
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
|
|
||||||
throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
|
|
||||||
string? json;
|
|
||||||
List<Location>? locations;
|
|
||||||
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();
|
|
||||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
|
||||||
FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultCollection][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"));
|
|
||||||
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
|
||||||
{
|
|
||||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
}
|
|
||||||
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
|
||||||
{
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
}
|
|
||||||
if (_PropertiesChangedForFaces)
|
|
||||||
results = null;
|
|
||||||
else if (!fileInfo.Exists)
|
|
||||||
results = null;
|
|
||||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
|
||||||
results = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
results = JsonSerializer.Deserialize<List<Shared.Models.Face>>(json);
|
|
||||||
if (results is null)
|
|
||||||
throw new NullReferenceException(nameof(results));
|
|
||||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
results = null;
|
|
||||||
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)
|
|
||||||
locations = (from l in collection where l is not null select l.Location).ToList();
|
|
||||||
else
|
|
||||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
|
||||||
if (results is null || (locations is not null && locations.Count > 0))
|
|
||||||
{
|
|
||||||
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations);
|
|
||||||
if (results.Count == 0)
|
|
||||||
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool updateDateWhenMatches = dateTimes.Count > 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
|
||||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
|
||||||
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
|
|
||||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
|
||||||
{
|
|
||||||
if (!_ForceFaceLastWriteTimeToCreationTime)
|
|
||||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = [];
|
|
||||||
bool save;
|
|
||||||
FileInfo fileInfo;
|
|
||||||
string deterministicHashCodeKey;
|
|
||||||
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();
|
|
||||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
|
||||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
|
||||||
bool directoryExists = Directory.Exists(directory);
|
|
||||||
foreach (Shared.Models.Face face in faces)
|
|
||||||
{
|
|
||||||
save = false;
|
|
||||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
|
||||||
{
|
|
||||||
results.Add(new(face, null, string.Empty, save));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
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);
|
||||||
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
if (location is null)
|
||||||
if (!directoryExists)
|
continue;
|
||||||
save = true;
|
width = location.Right - location.Left;
|
||||||
else if (_OverrideForFaceImages)
|
height = location.Bottom - location.Top;
|
||||||
save = true;
|
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
||||||
else if (!fileInfo.Exists)
|
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
||||||
save = true;
|
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||||
save = true;
|
geoLocation?.ToDmsString(),
|
||||||
results.Add(new(face, fileInfo, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
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 (graphics = Graphics.FromImage(bitmap))
|
||||||
|
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
||||||
|
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||||
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
|
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
||||||
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
|
bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||||
|
}
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
File.Delete(fileName);
|
||||||
|
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
||||||
|
if (location is null)
|
||||||
|
continue;
|
||||||
|
width = location.Right - location.Left;
|
||||||
|
height = location.Bottom - location.Top;
|
||||||
|
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
||||||
|
using (bitmap = new(width, height))
|
||||||
|
{
|
||||||
|
using (graphics = Graphics.FromImage(bitmap))
|
||||||
|
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
||||||
|
bitmap.Save(fileName, _HiddenImageCodecInfo, _HiddenEncoderParameters);
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
File.SetAttributes(fileName, FileAttributes.Hidden);
|
||||||
}
|
}
|
||||||
if (results.Any(l => l.Save))
|
|
||||||
{
|
|
||||||
if (!directoryExists)
|
|
||||||
_ = Directory.CreateDirectory(directory);
|
|
||||||
SaveFaces(mappingFromItem.ResizedFileHolder, results);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
|
@ -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,22 +28,23 @@ 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 ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
_FileGroups = [];
|
|
||||||
_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;
|
||||||
|
_ResultContentFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
|
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()
|
||||||
@ -51,67 +55,241 @@ public class D2_FaceParts
|
|||||||
|
|
||||||
public void Update(string dResultsFullGroupDirectory)
|
public void Update(string dResultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
_FileGroups.Clear();
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
|
||||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
|
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
|
||||||
_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)
|
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryName));
|
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||||
SetAngleBracketCollection(configuration, dResultsFullGroupDirectory, item.FilePath.DirectoryName);
|
else
|
||||||
|
throw new Exception();
|
||||||
}
|
}
|
||||||
if (includeNameWithoutExtension)
|
}
|
||||||
result = Path.Combine(_AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), item.FilePath.NameWithoutExtension);
|
|
||||||
|
public void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||||
|
{
|
||||||
|
bool any = false;
|
||||||
|
foreach (Shared.Models.Face face in faces)
|
||||||
|
{
|
||||||
|
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||||
|
continue;
|
||||||
|
if (!any)
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
if (any)
|
||||||
|
SaveAllFaceParts(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveAllFaceParts(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
Brush brush;
|
||||||
|
int pointSize;
|
||||||
|
bool any = false;
|
||||||
|
FaceFile faceFile;
|
||||||
|
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);
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||||
|
using Graphics graphics = Graphics.FromImage(image);
|
||||||
|
foreach (Shared.Models.Face face in faces)
|
||||||
|
{
|
||||||
|
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||||
|
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();
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
string directory = GetSeasonDirectory(d2ResultsFullGroupDirectory, mappingFromItem, any);
|
||||||
|
SaveImage(mappingFromItem, directory, image, faceFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
result = _AngleBracketCollection[0].Replace("<>", $"[{_PropertyConfiguration.ResultContent}]");
|
if (faceParts.TryGetValue(FacePart.RightEye, out facePoints))
|
||||||
if (!Directory.Exists(result))
|
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
|
||||||
_ = Directory.CreateDirectory(result);
|
else
|
||||||
|
result = defaultPointSize;
|
||||||
}
|
}
|
||||||
if (!angleBracketCollectionAny)
|
|
||||||
_AngleBracketCollection.Clear();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
|
private string GetSeasonDirectory(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, bool any)
|
||||||
{
|
{
|
||||||
xMinimum = points[0].X;
|
string result;
|
||||||
xMaximum = xMinimum;
|
string minimumDateYear = mappingFromItem.MinimumDateTime.ToString("yyyy");
|
||||||
yMinimum = points[0].Y;
|
DateTime dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
|
||||||
yMaximum = yMinimum;
|
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||||
foreach (PointF point in points)
|
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
|
||||||
{
|
{
|
||||||
if (xMinimum > point.X)
|
#pragma warning disable CA1416
|
||||||
xMinimum = point.X;
|
foreach (int propertyId in image.PropertyIdList)
|
||||||
if (xMaximum < point.X)
|
{
|
||||||
xMaximum = point.X;
|
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
|
||||||
if (yMinimum > point.Y)
|
continue;
|
||||||
yMinimum = point.Y;
|
image.RemovePropertyItem(propertyId);
|
||||||
if (yMaximum < point.Y)
|
}
|
||||||
yMaximum = point.Y;
|
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||||
|
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||||
|
image.SetPropertyItem(propertyItem);
|
||||||
|
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
bool check = false;
|
||||||
|
FileInfo rotatedFileInfo;
|
||||||
|
DateTime? dateTime = null;
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
string deterministicHashCodeKey;
|
||||||
|
bool updateDateWhenMatches = false;
|
||||||
|
List<(Shared.Models.Face, string, string)> collection = [];
|
||||||
|
string fileName = mappingFromItem.FilePath.NameWithoutExtension;
|
||||||
|
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face)];
|
||||||
|
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||||
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
|
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||||
|
DirectoryInfo directoryInfo = new(Path.Combine(directory, mappingFromItem.FilePath.NameWithoutExtension));
|
||||||
|
MoveIf(fileName, cei, directory, directoryInfo);
|
||||||
|
foreach (Shared.Models.Face face in faces)
|
||||||
|
{
|
||||||
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||||
|
{
|
||||||
|
collection.Add(new(face, string.Empty, string.Empty));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||||
|
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||||
|
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||||
|
continue;
|
||||||
|
rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||||
|
collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName));
|
||||||
|
if (check)
|
||||||
|
continue;
|
||||||
|
else if (!directoryInfo.Exists)
|
||||||
|
check = true;
|
||||||
|
else if (_OverrideForFaceLandmarkImages)
|
||||||
|
check = true;
|
||||||
|
else if (!fileInfo.Exists)
|
||||||
|
check = true;
|
||||||
|
else if (saveRotated && !rotatedFileInfo.Exists)
|
||||||
|
check = true;
|
||||||
|
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||||
|
check = true;
|
||||||
|
if (check && !updateDateWhenMatches)
|
||||||
|
{
|
||||||
|
updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||||
|
dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
if (!directoryInfo.Exists)
|
||||||
|
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||||
|
SaveFaceParts(mappingFromItem, exifDirectory, collection);
|
||||||
|
if (saveRotated)
|
||||||
|
SaveRotated(mappingFromItem, collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (Directory.Exists(checkFile))
|
||||||
|
{
|
||||||
|
Directory.Move(checkFile, directoryInfo.FullName);
|
||||||
|
directoryInfo.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Bitmap RotateBitmap(Image image, float angle)
|
||||||
|
{
|
||||||
|
Bitmap result;
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
|
Bitmap bitmap = new(image);
|
||||||
|
result = RotateBitmap(bitmap, angle);
|
||||||
|
bitmap?.Dispose();
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static Bitmap RotateBitmap(Bitmap bitmap, float angle)
|
private static Bitmap RotateBitmap(Bitmap bitmap, float angle)
|
||||||
{
|
{
|
||||||
@ -123,6 +301,7 @@ public class D2_FaceParts
|
|||||||
#elif Windows
|
#elif Windows
|
||||||
// Make save Matrix to represent rotation
|
// Make save Matrix to represent rotation
|
||||||
// by this angle.
|
// by this angle.
|
||||||
|
#pragma warning disable CA1416
|
||||||
Matrix rotate_at_origin = new();
|
Matrix rotate_at_origin = new();
|
||||||
rotate_at_origin.Rotate(angle);
|
rotate_at_origin.Rotate(angle);
|
||||||
|
|
||||||
@ -169,175 +348,42 @@ public class D2_FaceParts
|
|||||||
int y = (hgt - bitmap.Height) / 2;
|
int y = (hgt - bitmap.Height) / 2;
|
||||||
gr.DrawImage(bitmap, x, y);
|
gr.DrawImage(bitmap, x, y);
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
#endif
|
#endif
|
||||||
// Return the result bitmap.
|
// Return the result bitmap.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap RotateBitmap(Image image, float angle)
|
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
|
||||||
{
|
{
|
||||||
Bitmap result;
|
xMinimum = points[0].X;
|
||||||
Bitmap bitmap = new(image);
|
xMaximum = xMinimum;
|
||||||
result = RotateBitmap(bitmap, angle);
|
yMinimum = points[0].Y;
|
||||||
bitmap?.Dispose();
|
yMaximum = yMinimum;
|
||||||
return result;
|
foreach (PointF point in points)
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveFaceParts(int pointSize, FileHolder resizedFileHolder, bool saveRotated, List<(Shared.Models.Face, string, string)> collection)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
double? α;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
Bitmap rotated;
|
|
||||||
foreach ((Shared.Models.Face face, string fileName, string rotatedFileName) in collection)
|
|
||||||
{
|
{
|
||||||
if (face.FaceEncoding is null)
|
if (xMinimum > point.X)
|
||||||
continue;
|
xMinimum = point.X;
|
||||||
try
|
if (xMaximum < point.X)
|
||||||
{
|
xMaximum = point.X;
|
||||||
using (Image image = Image.FromFile(resizedFileHolder.FullName))
|
if (yMinimum > point.Y)
|
||||||
{
|
yMinimum = point.Y;
|
||||||
using Graphics graphic = Graphics.FromImage(image);
|
if (yMaximum < point.Y)
|
||||||
if (face.FaceParts is null || face.FaceParts.Count == 0)
|
yMaximum = point.Y;
|
||||||
{
|
|
||||||
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;
|
|
||||||
using Image image = Image.FromFile(resizedFileHolder.FullName);
|
|
||||||
rotated = RotateBitmap(image, (float)α.Value);
|
|
||||||
if (rotated is not null)
|
|
||||||
{
|
|
||||||
rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters);
|
|
||||||
rotated.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileHolder?, string, bool)> faceCollection)
|
||||||
|
|
||||||
public void SaveFaceLandmarkImages(Configuration configuration, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, List<Shared.Models.Face> faces, bool saveRotated)
|
|
||||||
{
|
|
||||||
FileInfo fileInfo;
|
|
||||||
bool check = false;
|
|
||||||
const int pointSize = 2;
|
|
||||||
FileInfo rotatedFileInfo;
|
|
||||||
DateTime? dateTime = null;
|
|
||||||
long ticks = DateTime.Now.Ticks;
|
|
||||||
string deterministicHashCodeKey;
|
|
||||||
bool updateDateWhenMatches = false;
|
|
||||||
List<(Shared.Models.Face, string, string)> collection = [];
|
|
||||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face)];
|
|
||||||
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);
|
|
||||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
|
||||||
bool directoryExists = Directory.Exists(directory);
|
|
||||||
foreach (Shared.Models.Face face in faces)
|
|
||||||
{
|
|
||||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
|
||||||
{
|
|
||||||
collection.Add(new(face, string.Empty, string.Empty));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
|
||||||
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
|
||||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
|
||||||
continue;
|
|
||||||
rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
|
||||||
collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName));
|
|
||||||
if (check)
|
|
||||||
continue;
|
|
||||||
else if (!directoryExists)
|
|
||||||
check = true;
|
|
||||||
else if (_OverrideForFaceLandmarkImages)
|
|
||||||
check = true;
|
|
||||||
else if (!fileInfo.Exists)
|
|
||||||
check = true;
|
|
||||||
else if (saveRotated && !rotatedFileInfo.Exists)
|
|
||||||
check = true;
|
|
||||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
|
||||||
check = true;
|
|
||||||
if (check && !updateDateWhenMatches)
|
|
||||||
{
|
|
||||||
updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
|
||||||
dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (check)
|
|
||||||
{
|
|
||||||
if (!directoryExists)
|
|
||||||
_ = Directory.CreateDirectory(directory);
|
|
||||||
SaveFaceParts(pointSize, mappingFromItem.ResizedFileHolder, saveRotated, collection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
|
||||||
|
|
||||||
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 +399,123 @@ 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)
|
private void SaveImage(string fileName, Image image, FaceFile faceFile)
|
||||||
{
|
{
|
||||||
bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection);
|
short type = 2;
|
||||||
string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
string faceFileJson;
|
||||||
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);
|
PropertyItem? propertyItem;
|
||||||
FileInfo fileInfo = new(fileName);
|
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||||
if (save && (!fileInfo.Exists || new TimeSpan(DateTime.Now.Ticks - fileInfo.LastWriteTime.Ticks).TotalDays > 10))
|
try
|
||||||
{
|
{
|
||||||
SaveFaceLandmarkImage(mappingFromItem, faceCollection, fileName);
|
#pragma warning disable CA1416
|
||||||
fileInfo.Refresh();
|
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);
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
}
|
||||||
|
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 SaveRotated(MappingFromItem mappingFromItem, List<(Shared.Models.Face, string, string)> collection)
|
||||||
|
{
|
||||||
|
double? α;
|
||||||
|
Bitmap rotated;
|
||||||
|
foreach ((Shared.Models.Face face, string _, string rotatedFileName) in collection)
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
SaveImage(fileName, image, faceFile);
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!hasNotMapped && !fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && (fileInfo.Exists || save))
|
|
||||||
File.SetAttributes(fileName, FileAttributes.Hidden);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
5
Instance/.vscode/mklink.md
vendored
Normal 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
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||||
<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.2" />
|
||||||
<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" />
|
||||||
@ -51,6 +51,7 @@
|
|||||||
<ProjectReference Include="..\FaceParts\FaceParts.csproj" />
|
<ProjectReference Include="..\FaceParts\FaceParts.csproj" />
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
<ProjectReference Include="..\Map\Map.csproj" />
|
<ProjectReference Include="..\Map\Map.csproj" />
|
||||||
|
<ProjectReference Include="..\Container\Container.csproj" />
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
|
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
|
||||||
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class Place
|
|||||||
results.Add(Get(place));
|
results.Add(Get(place));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(results);
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
@ -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
|
|
||||||
{
|
|
||||||
}
|
|
@ -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 results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
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
1
Map/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
42
Map/.vscode/tasks.json
vendored
Normal file
42
Map/.vscode/tasks.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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,11 +36,13 @@
|
|||||||
<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.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
<ProjectReference Include="..\Container\Container.csproj" />
|
||||||
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -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,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||||
|
@ -22,62 +22,190 @@ internal abstract class DistanceLogic
|
|||||||
internal record TicksDirectory(DateTime AlternateDirectoryDateTime,
|
internal record TicksDirectory(DateTime AlternateDirectoryDateTime,
|
||||||
string Directory,
|
string Directory,
|
||||||
DateTime DirectoryDateTime,
|
DateTime DirectoryDateTime,
|
||||||
string DirectoryName,
|
|
||||||
bool? IsLocationContainerDebugDirectory,
|
bool? IsLocationContainerDebugDirectory,
|
||||||
float? TotalDays);
|
float? TotalDays);
|
||||||
|
|
||||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
internal static List<Record> DeleteEmptyDirectoriesAndGetCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, string eDistanceContentDirectory, ReadOnlyDictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, ReadOnlyCollection<string> personKeyFormattedCollection)
|
||||||
{
|
|
||||||
string checkFile;
|
|
||||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
|
||||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (facesFileNames.Contains(file))
|
|
||||||
{
|
|
||||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
|
||||||
{
|
{
|
||||||
|
List<Record> results = [];
|
||||||
|
bool check;
|
||||||
|
string message;
|
||||||
string[] files;
|
string[] files;
|
||||||
string checkFile;
|
bool? isDefault;
|
||||||
|
int? linksCount;
|
||||||
|
int totalSeconds;
|
||||||
|
DateTime dateTime;
|
||||||
|
TimeSpan timeSpan;
|
||||||
|
int directoryNumber;
|
||||||
|
List<Record> records;
|
||||||
string? checkDirectory;
|
string? checkDirectory;
|
||||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
ProgressBar progressBar;
|
||||||
foreach (string directory in directories)
|
string[] yearDirectories;
|
||||||
|
string personKeyFormatted;
|
||||||
|
List<string> distinct = [];
|
||||||
|
string? personFirstInitial;
|
||||||
|
bool isReservedDirectoryName;
|
||||||
|
string[] personNameDirectories;
|
||||||
|
string? newestPersonKeyFormatted;
|
||||||
|
string? personDisplayDirectoryName;
|
||||||
|
string[] personNameLinkDirectories;
|
||||||
|
string? personFirstInitialDirectory;
|
||||||
|
List<TicksDirectory> ticksDirectories;
|
||||||
|
string[] personKeyFormattedDirectories;
|
||||||
|
string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
||||||
|
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
for (int i = 1; i < 6; i++)
|
||||||
{
|
{
|
||||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
check = false;
|
||||||
if (!Directory.Exists(checkDirectory))
|
results.Clear();
|
||||||
Directory.Move(directory, checkDirectory);
|
distinct.Clear();
|
||||||
else
|
directoryNumber = 0;
|
||||||
|
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(configuration, eDistanceContentDirectory);
|
||||||
|
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
|
message = $"{i}) {ticksDirectories.Count:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
|
||||||
|
progressBar = new(ticksDirectories.Count, message, options);
|
||||||
|
foreach (TicksDirectory ticksDirectory in ticksDirectories)
|
||||||
{
|
{
|
||||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
progressBar.Tick();
|
||||||
foreach (string file in files)
|
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
||||||
{
|
{
|
||||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
||||||
continue;
|
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy));
|
||||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)))
|
||||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
{
|
||||||
if (checkDirectory is null)
|
Individually(configuration, ticksDirectory, personKeyFormattedDirectory);
|
||||||
continue;
|
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||||
if (File.Exists(checkFile))
|
}
|
||||||
continue;
|
_ = personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
||||||
if (!Directory.Exists(checkDirectory))
|
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
{
|
||||||
File.Move(file, checkFile);
|
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
||||||
|
if (timeSpan.TotalDays > 6)
|
||||||
|
throw new Exception($"{configuration.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
||||||
|
}
|
||||||
|
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string yearDirectory in yearDirectories)
|
||||||
|
{
|
||||||
|
if (check && !Directory.Exists(yearDirectory))
|
||||||
|
continue;
|
||||||
|
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
||||||
|
linksCount = null;
|
||||||
|
else
|
||||||
|
linksCount = GetLinksCount(yearDirectory);
|
||||||
|
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
if (personNameDirectories.Length > 1)
|
||||||
|
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||||
|
foreach (string personNameDirectory in personNameDirectories)
|
||||||
|
{
|
||||||
|
directoryNumber++;
|
||||||
|
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
||||||
|
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||||
|
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
||||||
|
{
|
||||||
|
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||||
|
continue;
|
||||||
|
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
||||||
|
if (Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
Directory.Delete(yearDirectory, recursive: true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Directory.Move(personNameDirectory, checkDirectory);
|
||||||
|
if (!check)
|
||||||
|
check = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
||||||
|
{
|
||||||
|
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
||||||
|
if (checkDirectory is null)
|
||||||
|
continue;
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
||||||
|
if (!check)
|
||||||
|
check = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
if (isReservedDirectoryName && files.Length > 0)
|
||||||
|
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||||
|
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
||||||
|
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
||||||
|
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
||||||
|
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
||||||
|
if (!isDefault.Value)
|
||||||
|
{
|
||||||
|
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||||
|
files = RenameBirth(files);
|
||||||
|
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||||
|
{
|
||||||
|
if (!check)
|
||||||
|
check = true;
|
||||||
|
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length)
|
||||||
|
continue;
|
||||||
|
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !personKeyFormattedCollection.Contains(personKeyFormatted))
|
||||||
|
personFirstInitialDirectory = personNameDirectory;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
personFirstInitial = personDisplayDirectoryName[..1];
|
||||||
|
if (personFirstInitial.All(char.IsDigit))
|
||||||
|
{
|
||||||
|
foreach (string file in files)
|
||||||
|
File.Delete(file);
|
||||||
|
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
File.Delete(file);
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
||||||
|
if (Directory.Exists(personFirstInitialDirectory))
|
||||||
|
throw new Exception("Forgot to ...");
|
||||||
|
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
||||||
|
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
records = GetRecords(propertyConfiguration, configuration, ticksDirectory, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName);
|
||||||
|
if (records.Count > 0)
|
||||||
|
results.AddRange(records);
|
||||||
|
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
||||||
|
{
|
||||||
|
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (!file.EndsWith(".lnk"))
|
||||||
|
continue;
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
||||||
}
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||||
|
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||||
}
|
}
|
||||||
|
progressBar.Dispose();
|
||||||
|
if (check)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(Configuration configuration, string eDistanceContentDirectory)
|
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(Configuration configuration, string eDistanceContentDirectory)
|
||||||
@ -86,53 +214,55 @@ internal abstract class DistanceLogic
|
|||||||
float? totalDays;
|
float? totalDays;
|
||||||
long? next = null;
|
long? next = null;
|
||||||
string? checkDirectory;
|
string? checkDirectory;
|
||||||
string ticksDirectoryName;
|
|
||||||
DateTime directoryDateTime;
|
DateTime directoryDateTime;
|
||||||
DirectoryInfo directoryInfo;
|
DirectoryInfo directoryInfo;
|
||||||
|
TicksDirectory ticksDirectory;
|
||||||
long? lastDirectoryTicks = null;
|
long? lastDirectoryTicks = null;
|
||||||
DateTime dateTime = DateTime.Now;
|
DateTime dateTime = DateTime.Now;
|
||||||
DateTime alternateDirectoryDateTime;
|
DateTime alternateDirectoryDateTime;
|
||||||
|
string ticksDirectoryNameFirstSegment;
|
||||||
bool? isLocationContainerDebugDirectory;
|
bool? isLocationContainerDebugDirectory;
|
||||||
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
||||||
for (int i = 1; i < 5; i++)
|
for (int i = 1; i < 5; i++)
|
||||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||||
if (!Directory.Exists(eDistanceContentDirectory))
|
if (!Directory.Exists(eDistanceContentDirectory))
|
||||||
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
||||||
string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string ticksDirectory in ticksDirectories)
|
foreach (string ticksFullPath in ticksFullPaths)
|
||||||
{
|
{
|
||||||
ticksDirectoryName = Path.GetFileName(ticksDirectory);
|
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
|
||||||
if (ticksDirectoryName.Length < 3)
|
if (ticksDirectoryNameFirstSegment.Length < 3)
|
||||||
continue;
|
continue;
|
||||||
if (!long.TryParse(ticksDirectoryName, out long directoryTicks))
|
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
if (next is null)
|
if (next is null)
|
||||||
next = new DateTime(directoryTicks).Ticks;
|
next = new DateTime(directoryTicks).Ticks;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
next += month;
|
next += month;
|
||||||
checkDirectory = Path.GetDirectoryName(ticksDirectory);
|
checkDirectory = Path.GetDirectoryName(ticksFullPath);
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
continue;
|
continue;
|
||||||
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
|
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
|
||||||
if (ticksDirectory == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern))
|
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern))
|
||||||
continue;
|
continue;
|
||||||
Directory.Move(ticksDirectory, checkDirectory);
|
Directory.Move(ticksFullPath, checkDirectory);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
directoryInfo = new(ticksDirectory);
|
directoryInfo = new(ticksFullPath);
|
||||||
directoryDateTime = new DateTime(directoryTicks);
|
directoryDateTime = new DateTime(directoryTicks);
|
||||||
if (directoryInfo.CreationTime.Ticks != directoryTicks)
|
if (directoryInfo.CreationTime.Ticks != directoryTicks)
|
||||||
Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks));
|
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
|
||||||
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
||||||
Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks));
|
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
|
||||||
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
||||||
isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryName.EndsWith(configuration.LocationContainerDebugDirectory);
|
isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(configuration.LocationContainerDebugDirectory);
|
||||||
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
||||||
results.Add(new(alternateDirectoryDateTime, ticksDirectory, new(directoryTicks), ticksDirectoryName, isLocationContainerDebugDirectory, totalDays));
|
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
|
||||||
|
results.Add(ticksDirectory);
|
||||||
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
||||||
continue;
|
continue;
|
||||||
lastDirectoryTicks = directoryTicks;
|
lastDirectoryTicks = directoryTicks;
|
||||||
@ -216,9 +346,114 @@ internal abstract class DistanceLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||||
|
{
|
||||||
|
string checkFile;
|
||||||
|
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||||
|
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (facesFileNames.Contains(file))
|
||||||
|
{
|
||||||
|
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int? GetLinksCount(string yearDirectory)
|
||||||
|
{
|
||||||
|
int? result;
|
||||||
|
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||||
|
if (yearDirectoryNameSegments.Length != 3)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string lastSegment = yearDirectoryNameSegments[^1];
|
||||||
|
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = lastSegment[0] - 65;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] RenameBirth(string[] files)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
string checkFile;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (file.EndsWith(".brt"))
|
||||||
|
{
|
||||||
|
results.Add(file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
|
||||||
|
if (Directory.Exists(newestPersonKeyDirectory))
|
||||||
|
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
|
||||||
|
else
|
||||||
|
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||||
|
{
|
||||||
|
string[] files;
|
||||||
|
string checkFile;
|
||||||
|
string? checkDirectory;
|
||||||
|
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
Directory.Move(directory, checkDirectory);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||||
|
continue;
|
||||||
|
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||||
|
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||||
|
if (checkDirectory is null)
|
||||||
|
continue;
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||||
{
|
{
|
||||||
List<Record> results = [];
|
List<Record> results = [];
|
||||||
|
string @enum;
|
||||||
|
Record record;
|
||||||
string fileName;
|
string fileName;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
@ -244,244 +479,54 @@ internal abstract class DistanceLogic
|
|||||||
File.Move(file, checkFile);
|
File.Move(file, checkFile);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (file.StartsWith(ticksDirectory.Directory))
|
||||||
|
{
|
||||||
|
@enum = IPath.GetEnum(filePath).ToString();
|
||||||
|
if (!ticksDirectory.Directory.EndsWith(@enum))
|
||||||
|
{
|
||||||
|
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
|
||||||
|
fileHolder = IFileHolder.Get(checkFile);
|
||||||
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
distinct.Add(fileName);
|
distinct.Add(fileName);
|
||||||
results.Add(new(directoryNumber, isDefault, linksCount, filePath, personDisplayDirectoryName, personKeyFormatted));
|
record = new(DirectoryNumber: directoryNumber,
|
||||||
|
IsDefault: isDefault,
|
||||||
|
LinksCount: linksCount,
|
||||||
|
MappedFaceFilePath: filePath,
|
||||||
|
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
||||||
|
PersonKeyFormatted: personKeyFormatted);
|
||||||
|
results.Add(record);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RenameUnknown(string[] files)
|
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
|
||||||
{
|
{
|
||||||
foreach (string file in files)
|
string result;
|
||||||
|
string checkDirectory;
|
||||||
|
string directory = file;
|
||||||
|
List<string> collection = [];
|
||||||
|
for (int i = 0; i < file.Length; i++)
|
||||||
{
|
{
|
||||||
if (file.EndsWith(".unk"))
|
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
|
||||||
continue;
|
if (directory == ticksDirectory.Directory)
|
||||||
File.Move(file, $"{file}.unk");
|
break;
|
||||||
}
|
collection.Add(Path.GetFileName(directory));
|
||||||
}
|
|
||||||
|
|
||||||
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
|
|
||||||
{
|
|
||||||
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
|
|
||||||
if (Directory.Exists(newestPersonKeyDirectory))
|
|
||||||
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
|
|
||||||
else
|
|
||||||
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int? GetLinksCount(string yearDirectory)
|
|
||||||
{
|
|
||||||
int? result;
|
|
||||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
|
||||||
if (yearDirectoryNameSegments.Length != 3)
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string lastSegment = yearDirectoryNameSegments[^1];
|
|
||||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
result = lastSegment[0] - 65;
|
|
||||||
}
|
}
|
||||||
|
collection.Reverse();
|
||||||
|
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
|
||||||
|
foreach (string directoryName in collection)
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
result = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(result))
|
||||||
|
throw new Exception($"File <{fileName}> already exists!");
|
||||||
|
File.Move(file, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Record> DeleteEmptyDirectoriesAndGetCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, string eDistanceContentDirectory, ReadOnlyDictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, ReadOnlyCollection<string> personKeyFormattedCollection)
|
|
||||||
{
|
|
||||||
List<Record> results = [];
|
|
||||||
bool check;
|
|
||||||
string message;
|
|
||||||
string[] files;
|
|
||||||
bool? isDefault;
|
|
||||||
int? linksCount;
|
|
||||||
int totalSeconds;
|
|
||||||
DateTime dateTime;
|
|
||||||
TimeSpan timeSpan;
|
|
||||||
int directoryNumber;
|
|
||||||
string? checkDirectory;
|
|
||||||
ProgressBar progressBar;
|
|
||||||
string[] yearDirectories;
|
|
||||||
string personKeyFormatted;
|
|
||||||
List<string> distinct = [];
|
|
||||||
string? personFirstInitial;
|
|
||||||
bool isReservedDirectoryName;
|
|
||||||
string[] personNameDirectories;
|
|
||||||
string? newestPersonKeyFormatted;
|
|
||||||
string? personDisplayDirectoryName;
|
|
||||||
string[] personNameLinkDirectories;
|
|
||||||
string? personFirstInitialDirectory;
|
|
||||||
List<TicksDirectory> ticksDirectories;
|
|
||||||
string[] personKeyFormattedDirectories;
|
|
||||||
string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
|
||||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
for (int i = 1; i < 6; i++)
|
|
||||||
{
|
|
||||||
check = false;
|
|
||||||
results.Clear();
|
|
||||||
distinct.Clear();
|
|
||||||
directoryNumber = 0;
|
|
||||||
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(configuration, eDistanceContentDirectory);
|
|
||||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
||||||
message = $"{i}) {ticksDirectories.Count:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
|
|
||||||
progressBar = new(ticksDirectories.Count, message, options);
|
|
||||||
foreach (TicksDirectory ticksDirectory in ticksDirectories)
|
|
||||||
{
|
|
||||||
if (i == 1)
|
|
||||||
progressBar.Tick();
|
|
||||||
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
|
||||||
{
|
|
||||||
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
|
||||||
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy));
|
|
||||||
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)))
|
|
||||||
{
|
|
||||||
Individually(configuration, ticksDirectory, personKeyFormattedDirectory);
|
|
||||||
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
|
||||||
}
|
|
||||||
_ = personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
|
||||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
|
||||||
{
|
|
||||||
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
|
||||||
if (timeSpan.TotalDays > 6)
|
|
||||||
throw new Exception($"{configuration.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
|
||||||
}
|
|
||||||
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string yearDirectory in yearDirectories)
|
|
||||||
{
|
|
||||||
if (check && !Directory.Exists(yearDirectory))
|
|
||||||
continue;
|
|
||||||
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
|
||||||
linksCount = null;
|
|
||||||
else
|
|
||||||
linksCount = GetLinksCount(yearDirectory);
|
|
||||||
if (ticksDirectory.DirectoryName != configuration.LocationContainerDebugDirectory)
|
|
||||||
{
|
|
||||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string file in files)
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
if (ticksDirectory.DirectoryName == configuration.LocationContainerDebugDirectory)
|
|
||||||
{
|
|
||||||
isDefault = null;
|
|
||||||
personDisplayDirectoryName = null;
|
|
||||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
|
||||||
files = Directory.GetFiles(yearDirectory, "*.lnk", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
File.Delete(file);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
if (personNameDirectories.Length > 1)
|
|
||||||
throw new NotSupportedException();
|
|
||||||
foreach (string personNameDirectory in personNameDirectories)
|
|
||||||
{
|
|
||||||
directoryNumber++;
|
|
||||||
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
|
||||||
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
|
||||||
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
|
||||||
{
|
|
||||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
|
||||||
continue;
|
|
||||||
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
|
||||||
if (Directory.Exists(checkDirectory))
|
|
||||||
{
|
|
||||||
Directory.Delete(yearDirectory, recursive: true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Directory.Move(personNameDirectory, checkDirectory);
|
|
||||||
if (!check)
|
|
||||||
check = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
|
||||||
{
|
|
||||||
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
|
||||||
if (checkDirectory is null)
|
|
||||||
continue;
|
|
||||||
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
{
|
|
||||||
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
|
||||||
if (!check)
|
|
||||||
check = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
if (isReservedDirectoryName && files.Length > 0)
|
|
||||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
|
||||||
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
|
||||||
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
|
||||||
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
|
||||||
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
|
||||||
if (!isDefault.Value)
|
|
||||||
{
|
|
||||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
|
||||||
RenameUnknown(files);
|
|
||||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
|
||||||
{
|
|
||||||
if (!check)
|
|
||||||
check = true;
|
|
||||||
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length)
|
|
||||||
continue;
|
|
||||||
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !personKeyFormattedCollection.Contains(personKeyFormatted))
|
|
||||||
personFirstInitialDirectory = personNameDirectory;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
personFirstInitial = personDisplayDirectoryName[..1];
|
|
||||||
if (personFirstInitial.All(char.IsDigit))
|
|
||||||
{
|
|
||||||
foreach (string file in files)
|
|
||||||
File.Delete(file);
|
|
||||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
File.Delete(file);
|
|
||||||
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
|
||||||
if (Directory.Exists(personFirstInitialDirectory))
|
|
||||||
throw new Exception("Forgot to ...");
|
|
||||||
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
|
||||||
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
}
|
|
||||||
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
|
||||||
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
|
||||||
{
|
|
||||||
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (!file.EndsWith(".lnk"))
|
|
||||||
continue;
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
|
||||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
|
||||||
}
|
|
||||||
progressBar.Dispose();
|
|
||||||
if (check)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
207
Map/Models/Stateless/FaceFileLogic.cs
Normal file
207
Map/Models/Stateless/FaceFileLogic.cs
Normal 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 results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,53 +1,99 @@
|
|||||||
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;
|
||||||
|
|
||||||
public interface IMapLogic
|
public interface IMapLogic
|
||||||
{
|
{
|
||||||
|
|
||||||
ReadOnlyDictionary<int, List<long>> TestStatic_GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
|
||||||
GetIdToPersonKeys(personKeyToIds);
|
$"{by switch
|
||||||
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
{
|
||||||
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
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.ForceSingleImage => forceSingleImageHumanized,
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||||
|
|
||||||
ReadOnlyCollection<Shared.Models.Face> TestStatic_GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
public static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||||
GetFaces(items);
|
|
||||||
static ReadOnlyCollection<Shared.Models.Face> GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
|
||||||
MapLogic.GetFaces(items);
|
|
||||||
|
|
||||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
|
||||||
GetSelectedMappingCollection(items);
|
|
||||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
|
||||||
MapLogic.GetSelectedMappingCollection(items);
|
MapLogic.GetSelectedMappingCollection(items);
|
||||||
|
|
||||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
public static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||||
GetSelectedMappingCollection(faces);
|
|
||||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
|
||||||
MapLogic.GetSelectedMappingCollection(faces);
|
MapLogic.GetSelectedMappingCollection(faces);
|
||||||
|
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) =>
|
public static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||||
GetIdToWholePercentagesToFace(mappingCollection);
|
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) =>
|
|
||||||
MapLogic.GetIdToWholePercentagesToFace(mappingCollection);
|
|
||||||
|
|
||||||
List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
public static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||||
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);
|
|
||||||
|
|
||||||
void TestStatic_SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
|
public static string GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
|
|
||||||
static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
|
|
||||||
DecadeLogic.SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
|
|
||||||
|
|
||||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
|
||||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
|
||||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
|
||||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
|
||||||
|
|
||||||
string TestStatic_GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
|
||||||
GetDecade(mappingFromItem);
|
|
||||||
static string GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
|
||||||
DecadeLogic.GetDecade(mappingFromItem, null);
|
DecadeLogic.GetDecade(mappingFromItem, null);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
|
||||||
|
MapLogic.GetFaces(items);
|
||||||
|
|
||||||
|
public static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||||
|
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||||
|
|
||||||
|
public static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||||
|
|
||||||
|
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||||
|
MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||||
|
|
||||||
|
public static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||||
|
FaceFileLogic.GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||||
|
|
||||||
|
public static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
DecadeLogic.MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
|
||||||
|
public 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);
|
||||||
|
|
||||||
|
public 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);
|
||||||
|
|
||||||
|
internal string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
|
GetDecade(mappingFromItem);
|
||||||
|
|
||||||
|
internal ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
|
||||||
|
GetFaces(items);
|
||||||
|
|
||||||
|
internal Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||||
|
GetSelectedMappingCollection(items);
|
||||||
|
|
||||||
|
internal Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||||
|
GetSelectedMappingCollection(faces);
|
||||||
|
|
||||||
|
internal ReadOnlyDictionary<int, List<long>> TestStatic_GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||||
|
GetIdToPersonKeys(personKeyToIds);
|
||||||
|
|
||||||
|
internal void TestStatic_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
SetCreationTime(mappingFromItem, locationContainers);
|
||||||
|
|
||||||
|
internal ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||||
|
GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||||
|
|
||||||
|
internal List<LocationContainer> TestStatic_GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||||
|
GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||||
|
|
||||||
|
internal void TestStatic_MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
|
||||||
|
internal bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||||
|
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||||
|
|
||||||
|
internal bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
|
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||||
|
|
||||||
|
internal List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||||
|
GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
||||||
|
|
||||||
|
internal 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);
|
||||||
|
|
||||||
}
|
}
|
@ -8,34 +8,48 @@ namespace View_by_Distance.Map.Models.Stateless;
|
|||||||
internal abstract class RelationLogic
|
internal abstract class RelationLogic
|
||||||
{
|
{
|
||||||
|
|
||||||
internal record Group(string Key, long PersonKey, ReadOnlyCollection<LocationContainer> RelationContainersCollection);
|
internal record Group(string Key,
|
||||||
|
long PersonKey,
|
||||||
|
ReadOnlyCollection<LocationContainer> RelationContainersCollection);
|
||||||
|
|
||||||
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
|
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
|
||||||
{
|
{
|
||||||
List<LocationContainer>? collection;
|
int take;
|
||||||
Dictionary<int, List<LocationContainer>>? yearTo;
|
string directory;
|
||||||
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
bool isCounterPersonYear;
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
string personKeyFormatted;
|
||||||
|
string? displayDirectoryName;
|
||||||
|
Uri uri = new(eDistanceContentDirectory);
|
||||||
|
ReadOnlyDictionary<string, string> movedFiles;
|
||||||
|
ReadOnlyCollection<RelationContainer> relationContainers;
|
||||||
|
ReadOnlyCollection<Group> groups = GetGroups(configuration, locationContainers);
|
||||||
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
|
string message = $") Save Mapped Relations - {totalSeconds} total second(s)";
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
using ProgressBar progressBar = new(groups.Count, message, options);
|
||||||
|
foreach (Group group in groups)
|
||||||
{
|
{
|
||||||
if (!locationContainer.FromDistanceContent)
|
if (configuration.LocationContainerDistanceTolerance is null)
|
||||||
|
break;
|
||||||
|
progressBar.Tick();
|
||||||
|
if (group.RelationContainersCollection.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
take = GetTake(configuration.LocationContainerDistanceTake, group.RelationContainersCollection.Count);
|
||||||
continue;
|
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
||||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo))
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
||||||
{
|
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
||||||
personKeyTo.Add(locationContainer.PersonKey, []);
|
directory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-{configuration.LocationContainerDistanceTolerance.Value}", personKeyFormatted, group.Key);
|
||||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo))
|
if (!Directory.Exists(directory))
|
||||||
throw new Exception();
|
_ = Directory.CreateDirectory(directory);
|
||||||
}
|
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
||||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
relationContainers = distance.GetRelationContainers(configuration.DistanceLimits, configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
|
||||||
{
|
movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers);
|
||||||
yearTo.Add(locationContainer.CreationDateOnly.Year, []);
|
WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles);
|
||||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
collection.Add(locationContainer);
|
|
||||||
}
|
}
|
||||||
return personKeyTo;
|
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
||||||
|
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||||
|
else
|
||||||
|
AddDisplayDirectoryNames(configuration, eDistanceContentDirectory, readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyToPersonContainerCollection, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer> locationContainers)
|
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer> locationContainers)
|
||||||
@ -45,6 +59,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,12 +91,130 @@ 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, collection.AsReadOnly()));
|
||||||
collection = [];
|
collection = [];
|
||||||
years.Clear();
|
years.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(results);
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
|
||||||
|
{
|
||||||
|
List<LocationContainer>? collection;
|
||||||
|
Dictionary<int, List<LocationContainer>>? yearTo;
|
||||||
|
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
||||||
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
|
{
|
||||||
|
if (locationContainer.PersonKey is null)
|
||||||
|
continue;
|
||||||
|
if (!locationContainer.FromDistanceContent)
|
||||||
|
continue;
|
||||||
|
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
||||||
|
continue;
|
||||||
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||||
|
{
|
||||||
|
personKeyTo.Add(locationContainer.PersonKey.Value, []);
|
||||||
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||||
|
{
|
||||||
|
yearTo.Add(locationContainer.CreationDateOnly.Year, []);
|
||||||
|
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
collection.Add(locationContainer);
|
||||||
|
}
|
||||||
|
return personKeyTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetTake(int locationContainerDistanceTake, int count)
|
||||||
|
{
|
||||||
|
int result = locationContainerDistanceTake;
|
||||||
|
int subtract = (int)(locationContainerDistanceTake * .05);
|
||||||
|
if (subtract < 1)
|
||||||
|
subtract = 1;
|
||||||
|
if (count > 9000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 8000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 7000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 6000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 5000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 4000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 3000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 2000)
|
||||||
|
result -= subtract;
|
||||||
|
if (count > 1000)
|
||||||
|
result -= subtract;
|
||||||
|
if (result < 3)
|
||||||
|
result = 3;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetDisplayDirectoryName(ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted)
|
||||||
|
{
|
||||||
|
string? result;
|
||||||
|
PersonContainer? personContainer;
|
||||||
|
List<PersonContainer>? collection;
|
||||||
|
_ = readOnlyPersonKeyToPersonContainerCollection.TryGetValue(personKey, out collection);
|
||||||
|
if (collection is not null)
|
||||||
|
result = collection[0].DisplayDirectoryName;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!readOnlyPersonKeyFormattedToPersonContainer.TryGetValue(personKeyFormatted, out personContainer))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = personContainer.DisplayDirectoryName;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteVsCodeFiles(string eDistanceContentDirectory, string? displayDirectoryName, string directory)
|
||||||
|
{
|
||||||
|
string json;
|
||||||
|
string vsCodeDirectory = Path.Combine(directory, ".vscode");
|
||||||
|
if (!Directory.Exists(vsCodeDirectory))
|
||||||
|
_ = Directory.CreateDirectory(vsCodeDirectory);
|
||||||
|
if (displayDirectoryName is not null)
|
||||||
|
File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyDictionary<string, string> GetMoveFiles(Configuration configuration, string key, int take, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers)
|
||||||
|
{
|
||||||
|
ReadOnlyDictionary<string, string> results;
|
||||||
|
List<List<string>> linked = [];
|
||||||
|
for (int i = 0; i < 25; i++)
|
||||||
|
linked.Add([]);
|
||||||
|
foreach ((FileHolder fileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
||||||
|
{
|
||||||
|
foreach (Relation relation in relations.Take(take))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 25; i++)
|
||||||
|
{
|
||||||
|
if (!linked[i].Contains(relation.File))
|
||||||
|
{
|
||||||
|
linked[i].Add(relation.File);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results = MoveFiles(configuration, key, isCounterPersonYear, displayDirectoryName, relationContainers, linked);
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyDictionary<string, string> MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers, List<List<string>> linked)
|
private static ReadOnlyDictionary<string, string> MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers, List<List<string>> linked)
|
||||||
@ -98,7 +231,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);
|
||||||
@ -196,92 +329,7 @@ internal abstract class RelationLogic
|
|||||||
_ = Directory.CreateDirectory(checkDirectory);
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(results);
|
return results.AsReadOnly();
|
||||||
}
|
|
||||||
|
|
||||||
private static string? GetDisplayDirectoryName(ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted)
|
|
||||||
{
|
|
||||||
string? result;
|
|
||||||
PersonContainer? personContainer;
|
|
||||||
List<PersonContainer>? collection;
|
|
||||||
_ = readOnlyPersonKeyToPersonContainerCollection.TryGetValue(personKey, out collection);
|
|
||||||
if (collection is not null)
|
|
||||||
result = collection[0].DisplayDirectoryName;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!readOnlyPersonKeyFormattedToPersonContainer.TryGetValue(personKeyFormatted, out personContainer))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
result = personContainer.DisplayDirectoryName;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetTake(int locationContainerDistanceTake, int count)
|
|
||||||
{
|
|
||||||
int result = locationContainerDistanceTake;
|
|
||||||
int subtract = (int)(locationContainerDistanceTake * .05);
|
|
||||||
if (subtract < 1)
|
|
||||||
subtract = 1;
|
|
||||||
if (count > 9000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 8000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 7000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 6000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 5000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 4000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 3000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 2000)
|
|
||||||
result -= subtract;
|
|
||||||
if (count > 1000)
|
|
||||||
result -= subtract;
|
|
||||||
if (result < 3)
|
|
||||||
result = 3;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteVsCodeFiles(string eDistanceContentDirectory, string? displayDirectoryName, string directory)
|
|
||||||
{
|
|
||||||
string json;
|
|
||||||
string vsCodeDirectory = Path.Combine(directory, ".vscode");
|
|
||||||
if (!Directory.Exists(vsCodeDirectory))
|
|
||||||
_ = Directory.CreateDirectory(vsCodeDirectory);
|
|
||||||
if (displayDirectoryName is not null)
|
|
||||||
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\", } } }";
|
|
||||||
_ = 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\": [] } ] }");
|
|
||||||
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlyDictionary<string, string> GetMoveFiles(Configuration configuration, string key, int take, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers)
|
|
||||||
{
|
|
||||||
ReadOnlyDictionary<string, string> results;
|
|
||||||
List<List<string>> linked = [];
|
|
||||||
for (int i = 0; i < 25; i++)
|
|
||||||
linked.Add([]);
|
|
||||||
foreach ((FileHolder fileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
|
||||||
{
|
|
||||||
foreach (Relation relation in relations.Take(take))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 25; i++)
|
|
||||||
{
|
|
||||||
if (!linked[i].Contains(relation.File))
|
|
||||||
{
|
|
||||||
linked[i].Add(relation.File);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
results = MoveFiles(configuration, key, isCounterPersonYear, displayDirectoryName, relationContainers, linked);
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteFile(int take, long personKey, bool isCounterPersonYear, string personKeyFormatted, string? displayDirectoryName, string directory, long ticks, Uri uri, ReadOnlyCollection<RelationContainer> relationContainers, ReadOnlyDictionary<string, string> movedFiles)
|
private static void WriteFile(int take, long personKey, bool isCounterPersonYear, string personKeyFormatted, string? displayDirectoryName, string directory, long ticks, Uri uri, ReadOnlyCollection<RelationContainer> relationContainers, ReadOnlyDictionary<string, string> movedFiles)
|
||||||
@ -392,44 +440,4 @@ internal abstract class RelationLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
|
|
||||||
{
|
|
||||||
int take;
|
|
||||||
string directory;
|
|
||||||
bool isCounterPersonYear;
|
|
||||||
string personKeyFormatted;
|
|
||||||
string? displayDirectoryName;
|
|
||||||
Uri uri = new(eDistanceContentDirectory);
|
|
||||||
ReadOnlyDictionary<string, string> movedFiles;
|
|
||||||
ReadOnlyCollection<RelationContainer> relationContainers;
|
|
||||||
ReadOnlyCollection<Group> groups = GetGroups(configuration, locationContainers);
|
|
||||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
||||||
string message = $") Save Mapped Relations - {totalSeconds} total second(s)";
|
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
using ProgressBar progressBar = new(groups.Count, message, options);
|
|
||||||
foreach (Group group in groups)
|
|
||||||
{
|
|
||||||
if (configuration.LocationContainerDistanceTolerance is null)
|
|
||||||
break;
|
|
||||||
progressBar.Tick();
|
|
||||||
if (group.RelationContainersCollection.Count == 0)
|
|
||||||
continue;
|
|
||||||
take = GetTake(configuration.LocationContainerDistanceTake, group.RelationContainersCollection.Count);
|
|
||||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
|
||||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
|
||||||
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
|
||||||
directory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-{configuration.LocationContainerDistanceTolerance.Value}", personKeyFormatted, group.Key);
|
|
||||||
if (!Directory.Exists(directory))
|
|
||||||
_ = Directory.CreateDirectory(directory);
|
|
||||||
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
|
||||||
relationContainers = distance.GetRelationContainers(configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
|
|
||||||
movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers);
|
|
||||||
WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles);
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
|
||||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
|
||||||
else
|
|
||||||
AddDisplayDirectoryNames(configuration, eDistanceContentDirectory, readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyToPersonContainerCollection, groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
<PackageReference Include="System.Text.Json" Version="8.0.0" />
|
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,10 +34,10 @@
|
|||||||
</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="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
|
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -4,6 +4,7 @@ using System.Text.Json;
|
|||||||
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.Properties;
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models;
|
namespace View_by_Distance.Metadata.Models;
|
||||||
|
|
||||||
@ -13,33 +14,103 @@ namespace View_by_Distance.Metadata.Models;
|
|||||||
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public string DateGroupDirectory { get; init; }
|
||||||
|
public ReadOnlyCollection<FilePath> Collection { get; private set; }
|
||||||
|
public ReadOnlyDictionary<int, List<FilePath>> SingletonById { get; private set; }
|
||||||
|
public ReadOnlyDictionary<int, ExifDirectory> ExifDirectoriesById { get; private set; }
|
||||||
|
|
||||||
|
// First
|
||||||
|
// Set DateGroupDirectory
|
||||||
|
// Create a directories for Singleton
|
||||||
|
// Populate Collection
|
||||||
|
// Populate Singleton
|
||||||
|
// Populate existing ExifDirectories
|
||||||
|
// Run similar for resize
|
||||||
|
// Second
|
||||||
|
// Populate needed ExifDirectories Dictionary can't be init only
|
||||||
|
|
||||||
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<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||||
|
|
||||||
public B_Metadata(IPropertyConfiguration propertyConfiguration)
|
public B_Metadata(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, long ticks, string bResultsFullGroupDirectory)
|
||||||
{
|
|
||||||
_PropertiesChangedForMetadata = false;
|
|
||||||
_PropertyConfiguration = propertyConfiguration;
|
|
||||||
_ForceMetadataLastWriteTimeToCreationTime = false;
|
|
||||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
|
||||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory)
|
|
||||||
{
|
{
|
||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
_PropertiesChangedForMetadata = propertiesChangedForMetadata;
|
_PropertiesChangedForMetadata = propertiesChangedForMetadata;
|
||||||
_ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime;
|
_ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime;
|
||||||
|
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
||||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, bResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]);
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, bResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]);
|
||||||
|
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||||
|
{
|
||||||
|
if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton)
|
||||||
|
_ResultSingletonFileGroups[0] = keyValuePair.Value;
|
||||||
|
else
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
List<ExifDirectory> results = [];
|
||||||
|
string jsonGroupDirectory;
|
||||||
|
const string extension = ".json";
|
||||||
|
const string fileSearchFilter = "*";
|
||||||
|
string filesCollectionRootDirectory;
|
||||||
|
const string directorySearchFilter = "*";
|
||||||
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
|
filesCollectionRootDirectory = propertyConfiguration.RootDirectory;
|
||||||
|
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
|
string jsonGroupSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
string jsonGroupCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
|
ReadOnlyCollection<string> directories = new([jsonGroupSingletonDirectory, jsonGroupCollectionDirectory]);
|
||||||
|
Shared.Models.Stateless.Methods.IPath.CreateDirectories(directories);
|
||||||
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
||||||
|
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||||
|
ReadOnlyCollection<FilePair> filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||||
|
string message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||||
|
dlibDotNet.ConstructProgressBar(filePairs.Count, message);
|
||||||
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], results));
|
||||||
|
jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
|
foreach (ExifDirectory exifDirectory in results)
|
||||||
|
{
|
||||||
|
if (exifDirectory.FilePath.Id is null || exifDirectoriesById.ContainsKey(exifDirectory.FilePath.Id.Value))
|
||||||
|
continue;
|
||||||
|
exifDirectoriesById.Add(exifDirectory.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
|
ExifDirectoriesById = new(exifDirectoriesById);
|
||||||
|
DateGroupDirectory = bResultsFullGroupDirectory;
|
||||||
|
SingletonById = fileNamesToFiles;
|
||||||
|
filesCollectionRootDirectory = jsonGroupCollectionDirectory;
|
||||||
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsSingletonCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory,
|
||||||
|
useIgnoreExtensions: false, useCeilingAverage: false);
|
||||||
|
Collection = filePathsSingletonCollection[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
private void ParallelFor(IDlibDotNet dlibDotNet, FilePair filePair, List<ExifDirectory> results)
|
||||||
{
|
{
|
||||||
string result = JsonSerializer.Serialize(this, _WriteIndentedJsonSerializerOptions);
|
dlibDotNet?.Tick();
|
||||||
|
if (filePair.FilePath.Id is null)
|
||||||
|
return;
|
||||||
|
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
||||||
|
if (exifDirectory is null)
|
||||||
|
return;
|
||||||
|
lock (results)
|
||||||
|
results.Add(exifDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExifDirectory? GetExifDirectory(FilePair filePair)
|
||||||
|
{
|
||||||
|
ExifDirectory? result;
|
||||||
|
if (filePair.Match is null)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(filePair.Match.FullName);
|
||||||
|
if (string.IsNullOrEmpty(json))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,8 +118,11 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
{
|
{
|
||||||
ExifDirectory? result = null;
|
ExifDirectory? result = null;
|
||||||
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);
|
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||||
FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"));
|
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
|
||||||
|
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||||
|
FileInfo fileInfo = new(Path.Combine(directory, fileName));
|
||||||
|
MoveIf(fileName, cei, directory, fileInfo);
|
||||||
if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||||
{
|
{
|
||||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||||
@ -104,13 +178,32 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && System.IO.Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
{
|
||||||
|
File.Move(checkFile, fileInfo.FullName);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories)
|
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories)
|
||||||
{
|
{
|
||||||
List<DateTime?> results = [];
|
List<DateTime?> results = [];
|
||||||
DateTime? result = null;
|
DateTime? result = null;
|
||||||
DateTime? dateTime;
|
DateTime? dateTime;
|
||||||
DateTime checkDateTime;
|
DateTime checkDateTime;
|
||||||
string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat();
|
string dateTimeFormat = Stateless.Methods.IMetadata.DateTimeFormat();
|
||||||
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
|
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
|
||||||
results.Add(new DateTime(filePath.CreationTicks));
|
results.Add(new DateTime(filePath.CreationTicks));
|
||||||
results.Add(new DateTime(filePath.LastWriteTicks));
|
results.Add(new DateTime(filePath.LastWriteTicks));
|
||||||
@ -120,7 +213,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
results.Add(checkDateTime);
|
results.Add(checkDateTime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
results.Add(dateTime.Value);
|
results.Add(dateTime.Value);
|
||||||
}
|
}
|
||||||
@ -128,7 +221,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
results.Add(checkDateTime);
|
results.Add(checkDateTime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
results.Add(dateTime.Value);
|
results.Add(dateTime.Value);
|
||||||
}
|
}
|
||||||
@ -139,7 +232,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -157,7 +250,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -175,7 +268,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -193,7 +286,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Globalization;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
||||||
@ -47,4 +48,23 @@ internal static class Base
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
|
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||||
|
{
|
||||||
|
DateTime? result;
|
||||||
|
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
||||||
|
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else
|
||||||
|
result = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
}
|
}
|
@ -484,7 +484,7 @@ internal abstract class Exif
|
|||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Shared.Models.ExifDirectory Covert(Shared.Models.FilePath filePath, System.Drawing.Size? size, IReadOnlyList<MetadataExtractor.Directory> directories)
|
private static Shared.Models.ExifDirectory Covert(Shared.Models.FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories, System.Drawing.Size? size)
|
||||||
{
|
{
|
||||||
Shared.Models.ExifDirectory result;
|
Shared.Models.ExifDirectory result;
|
||||||
Shared.Models.AviDirectory[] aviDirectories = GetAviDirectories(directories);
|
Shared.Models.AviDirectory[] aviDirectories = GetAviDirectories(directories);
|
||||||
@ -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,10 +519,14 @@ 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);
|
|
||||||
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
||||||
result = Covert(filePath, size, directories);
|
System.Drawing.Size? size;
|
||||||
|
try
|
||||||
|
{ size = Dimensions.GetDimensions(filePath.FullName); }
|
||||||
|
catch (Exception)
|
||||||
|
{ size = null; }
|
||||||
|
result = Covert(filePath, directories, size);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -64,4 +64,14 @@ public interface IMetadata
|
|||||||
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
|
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
|
||||||
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
|
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
|
||||||
|
|
||||||
|
string TestStatic_DateTimeFormat() =>
|
||||||
|
DateTimeFormat();
|
||||||
|
static string DateTimeFormat() =>
|
||||||
|
"yyyy:MM:dd HH:mm:ss";
|
||||||
|
|
||||||
|
DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
GetDateTime(dateTimeFormat, value);
|
||||||
|
static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
Base.GetDateTime(dateTimeFormat, value);
|
||||||
|
|
||||||
}
|
}
|
@ -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.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||||
<PackageReference Include="System.Text.Json" Version="8.0.0" />
|
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
<ProjectReference Include="..\Property\Property.csproj" />
|
||||||
|
@ -193,6 +193,7 @@ public class MirrorLength
|
|||||||
{
|
{
|
||||||
string message = nameof(MirrorLength);
|
string message = nameof(MirrorLength);
|
||||||
List<(string, string, int)> collectionForMarkDown;
|
List<(string, string, int)> collectionForMarkDown;
|
||||||
|
logger?.LogDebug("{method}", nameof(MirrorLengthFilesInDirectories));
|
||||||
bool inPlaceSave = _PropertyConfiguration.RootDirectory.First() == _AppSettings.Destination;
|
bool inPlaceSave = _PropertyConfiguration.RootDirectory.First() == _AppSettings.Destination;
|
||||||
if (!inPlaceSave)
|
if (!inPlaceSave)
|
||||||
collectionForMarkDown = [];
|
collectionForMarkDown = [];
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user