Compare commits
20 Commits
f458af776a
...
Breaking
Author | SHA1 | Date | |
---|---|---|---|
e728838d25 | |||
ac298166e9 | |||
0b793904b3 | |||
e053dd5746 | |||
ee0219f321 | |||
75cfb2a0d9 | |||
17be39bef9 | |||
c085ac3f76 | |||
a6b3318eec | |||
49e9daea8f | |||
e2e6e15ea2 | |||
d8013da912 | |||
4da353d150 | |||
444e7ed71a | |||
99198cc378 | |||
e532c3ef1e | |||
c580c7eaa4 | |||
43b66f01b6 | |||
304b5e2a0e | |||
326e579d5c |
@ -82,33 +82,60 @@ csharp_style_var_elsewhere = false:warning
|
||||
csharp_style_var_for_built_in_types = false:warning
|
||||
csharp_style_var_when_type_is_apparent = false:warning
|
||||
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 = non_public # IDE0060: Remove unused parameter
|
||||
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.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.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.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.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.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.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.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.IDE0004.severity = warning # IDE0004: Cast is redundant.
|
||||
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.IDE0031.severity = warning # Use null propagation (IDE0031)
|
||||
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.IDE0051.severity = error # Private member '' is unused [, ]
|
||||
dotnet_diagnostic.IDE0058.severity = warning # IDE0058: Expression value is never used
|
||||
dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter
|
||||
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.IDE0230.severity = warning # IDE0230: Use UTF-8 string literal
|
||||
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290)
|
||||
dotnet_diagnostic.IDE0300.severity = warning # IDE0300: 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.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.style = pascal_case
|
||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method
|
||||
|
80
.vscode/launch.json
vendored
80
.vscode/launch.json
vendored
@ -10,8 +10,8 @@
|
||||
"name": "Compare",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Compare/bin/Debug/net8.0/win-x64/Compare.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Compare/bin/Debug/net9.0/win-x64/Compare.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -27,8 +27,8 @@
|
||||
"name": "Copy-Distinct",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Copy-Distinct/bin/Debug/net8.0/win-x64/Copy-Distinct.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Copy-Distinct/bin/Debug/net9.0/win-x64/Copy-Distinct.dll",
|
||||
"args": [],
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
@ -42,8 +42,8 @@
|
||||
"name": "Duplicate-Search",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Duplicate-Search/bin/Debug/net8.0/win-x64/Duplicate-Search.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Duplicate-Search/bin/Debug/net9.0/win-x64/Duplicate-Search.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -59,8 +59,8 @@
|
||||
"name": "Date-Group",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Date-Group/bin/Debug/net8.0/win-x64/Date-Group.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Date-Group/bin/Debug/net9.0/win-x64/Date-Group.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -76,8 +76,8 @@
|
||||
"name": "Delete-By-Distinct",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Delete-By-Distinct/bin/Debug/net8.0/win-x64/Delete-By-Distinct.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Delete-By-Distinct/bin/Debug/net9.0/win-x64/Delete-By-Distinct.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -93,8 +93,8 @@
|
||||
"name": "Delete-By-Relative",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Delete-By-Relative/bin/Debug/net8.0/win-x64/Delete-By-Relative.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Delete-By-Relative/bin/Debug/net9.0/win-x64/Delete-By-Relative.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -110,8 +110,8 @@
|
||||
"name": "Drag-Drop",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Drag-Drop/bin/Debug/net8.0-windows/win-x64/Drag-Drop.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Drag-Drop/bin/Debug/net9.0-windows/win-x64/Drag-Drop.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -127,8 +127,8 @@
|
||||
"name": "Drag-Drop-Explorer",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Explorer/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Explorer.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Explorer/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Explorer.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -144,8 +144,8 @@
|
||||
"name": "Drag-Drop-Move",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Move/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Move.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Move/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Move.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -161,8 +161,8 @@
|
||||
"name": "Drag-Drop-Set-Property-Item",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Set-Property-Item/bin/Debug/net8.0-windows/win-x64/Drag-Drop-Set-Property-Item.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Drag-Drop-Set-Property-Item/bin/Debug/net9.0-windows/win-x64/Drag-Drop-Set-Property-Item.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -178,8 +178,8 @@
|
||||
"name": "Instance",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Instance/bin/Debug/net8.0/win-x64/Instance.dll",
|
||||
"preLaunchTask": "buildInstance",
|
||||
"program": "${workspaceFolder}/Instance/bin/Debug/net9.0/win-x64/Instance.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -195,8 +195,8 @@
|
||||
"name": "Mirror-Length",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Mirror-Length/bin/Debug/net8.0/win-x64/Mirror-Length.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Mirror-Length/bin/Debug/net9.0/win-x64/Mirror-Length.dll",
|
||||
"args": [],
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
@ -210,8 +210,8 @@
|
||||
"name": "Metadata-Query",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Metadata-Query/bin/Debug/net8.0/win-x64/Metadata-Query.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Metadata-Query/bin/Debug/net9.0/win-x64/Metadata-Query.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -227,8 +227,8 @@
|
||||
"name": "Move-By-Id",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Move-By-Id/bin/Debug/net8.0/win-x64/Move-By-Id.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Move-By-Id/bin/Debug/net9.0/win-x64/Move-By-Id.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -244,8 +244,8 @@
|
||||
"name": "Not-Copy-Copy",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Not-Copy-Copy/bin/Debug/net8.0/win-x64/Not-Copy-Copy.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Not-Copy-Copy/bin/Debug/net9.0/win-x64/Not-Copy-Copy.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -261,8 +261,8 @@
|
||||
"name": "Offset-Date-Time-Original",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Offset-Date-Time-Original/bin/Debug/net8.0/win-x64/Offset-Date-Time-Original.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Offset-Date-Time-Original/bin/Debug/net9.0/win-x64/Offset-Date-Time-Original.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -278,8 +278,8 @@
|
||||
"name": "PrepareForOld",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/PrepareForOld/bin/Debug/net8.0/win-x64/PrepareForOld.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/PrepareForOld/bin/Debug/net9.0/win-x64/PrepareForOld.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -295,8 +295,8 @@
|
||||
"name": "Person",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Person/bin/Debug/net8.0/Person.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Person/bin/Debug/net9.0/Person.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -312,8 +312,8 @@
|
||||
"name": "Rename",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Rename/bin/Debug/net8.0/win-x64/Rename.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Rename/bin/Debug/net9.0/win-x64/Rename.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
@ -329,8 +329,8 @@
|
||||
"name": "Set-Created-Date",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Set-Created-Date/bin/Debug/net8.0/win-x64/Set-Created-Date.dll",
|
||||
"preLaunchTask": "buildSolution",
|
||||
"program": "${workspaceFolder}/Set-Created-Date/bin/Debug/net9.0/win-x64/Set-Created-Date.dll",
|
||||
"args": [
|
||||
"s"
|
||||
],
|
||||
|
5
.vscode/mklink.md
vendored
5
.vscode/mklink.md
vendored
@ -13,3 +13,8 @@ mklink /J "D:\1-Images-A\Images-4083e56a-Results\A2)People\4083e56a\{}\!" "D:\1-
|
||||
```bash
|
||||
mklink /J "L:\Git\View-by-Distance-MKLink-Console\.Immich" "D:\1-Images-A\Images-c9dbce3b-Results\F)Immich\c9dbce3b\{}"
|
||||
```
|
||||
|
||||
```bash 1740946894364 = 638765436943640000 = 2025-0.Winter = Sun Mar 02 2025 13:21:33 GMT-0700 (Mountain Standard Time)
|
||||
mklink /J "V:\Tmp\Phares\Pictures-Results" "V:\6-Other-Large-Z\Current-Results-Test"
|
||||
mklink /J "V:\1-Images-A\Images-0b793904-Results" "V:\6-Other-Large-Z\Current-Results"
|
||||
```
|
||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -23,6 +23,9 @@
|
||||
"Immich",
|
||||
"jfif",
|
||||
"JOSN",
|
||||
"makernote",
|
||||
"Makernote",
|
||||
"Makernotes",
|
||||
"mmod",
|
||||
"Nicéphore",
|
||||
"Niépce",
|
||||
@ -32,6 +35,8 @@
|
||||
"permyriad",
|
||||
"Phares",
|
||||
"Phgtv",
|
||||
"photoshop",
|
||||
"Photoshop",
|
||||
"RDHC",
|
||||
"Rects",
|
||||
"resnet",
|
||||
|
38
.vscode/tasks.json
vendored
38
.vscode/tasks.json
vendored
@ -53,7 +53,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "build",
|
||||
"label": "buildSolution",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
@ -63,6 +63,42 @@
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>BlurHash.Core</PackageId>
|
||||
@ -18,6 +18,6 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
<PackageReference Include="System.Memory" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@ -24,6 +24,6 @@
|
||||
<ProjectReference Include="..\BlurHash.Core\BlurHash.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.BlurHash</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,8 +33,8 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<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" />
|
||||
|
@ -10,21 +10,29 @@ namespace View_by_Distance.BlurHash.Models;
|
||||
public class C2_BlurHasher : IBlurHasher
|
||||
{
|
||||
|
||||
private readonly Dictionary<string, string[]> _FileGroups;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||
|
||||
public C2_BlurHasher(IPropertyConfiguration propertyConfiguration)
|
||||
{
|
||||
_FileGroups = [];
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_ResultContentFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
}
|
||||
|
||||
public void Update(string resultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
|
||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||
else if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton)
|
||||
_ResultSingletonFileGroups[0] = keyValuePair.Value;
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
string IBlurHasher.Encode(FileHolder fileHolder)
|
||||
@ -40,20 +48,39 @@ public class C2_BlurHasher : IBlurHasher
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
File.Move(checkFile, fullFileName);
|
||||
}
|
||||
}
|
||||
|
||||
string IBlurHasher.GetFile(FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
if (_FileGroups.Count == 0)
|
||||
if (_ResultSingletonFileGroups[0].Count == 0)
|
||||
throw new Exception("Call Update first!");
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
result = Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{filePath.Name}.csv");
|
||||
string fileName = $"{filePath.Name}.csv";
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||
result = Path.Combine(directory, fileName);
|
||||
MoveIf(fileName, cei, directory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
string IBlurHasher.EncodeAndSave(FilePath filePath, FileHolder fileHolder)
|
||||
{
|
||||
string result;
|
||||
if (_FileGroups.Count == 0)
|
||||
if (_ResultSingletonFileGroups[0].Count == 0)
|
||||
throw new Exception("Call Update first!");
|
||||
int actualByte;
|
||||
string extension = ".png";
|
||||
@ -70,15 +97,18 @@ public class C2_BlurHasher : IBlurHasher
|
||||
byte[] blurHashBytes = Encoding.UTF8.GetBytes(result);
|
||||
string joined = string.Join(string.Empty, blurHashBytes.Select(l => l.ToString("000")));
|
||||
string fileNameWithoutExtension = $"{componentsX}x{componentsY}-{outputWidth}x{outputHeight}-{joined}";
|
||||
string fileName = $"{fileNameWithoutExtension}{extension}";
|
||||
string contents = string.Concat(result, Environment.NewLine, fileNameWithoutExtension, Environment.NewLine, extension);
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(file, contents, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
file = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], $"{fileNameWithoutExtension}{extension}");
|
||||
if (!File.Exists(file))
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||
string fullFileName = Path.Combine(directory, fileName);
|
||||
MoveIf(fileName, cei, directory, fullFileName);
|
||||
if (!File.Exists(fullFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
using FileStream fileStream = new(file, FileMode.CreateNew);
|
||||
using FileStream fileStream = new(fullFileName, FileMode.CreateNew);
|
||||
actualImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
|
||||
_ = fileStream.Seek(0, SeekOrigin.Begin);
|
||||
actualByte = fileStream.ReadByte();
|
||||
|
@ -211,7 +211,7 @@ public class Compare
|
||||
}
|
||||
_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);
|
||||
if (!isSilent)
|
||||
{
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Compare</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Map\Map.csproj" />
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>d862524f-2b48-4f47-b4c3-5a8615814ec2</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Copy.Distinct</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -18,8 +18,8 @@ public class CopyDistinct
|
||||
private readonly Configuration _Configuration;
|
||||
private readonly IsEnvironment _IsEnvironment;
|
||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
|
||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<string, 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)
|
||||
{
|
||||
@ -179,8 +179,10 @@ public class CopyDistinct
|
||||
{
|
||||
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());
|
||||
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)
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>8004d966-1a9e-4545-a220-83f32b6a13e9</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Date.Group</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,15 +34,15 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<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" />
|
||||
|
@ -251,11 +251,11 @@ public class DateGroup
|
||||
if (topDirectoryName.Length > 1)
|
||||
_ = destinationDirectoryName.Append(topDirectoryName);
|
||||
if (_Configuration.BySeason)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year} {seasonName}" });
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year} {seasonName}"]);
|
||||
else if (_Configuration.ByDay)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}" });
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}"]);
|
||||
else if (_Configuration.ByWeek)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}" });
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}"]);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
@ -422,7 +422,7 @@ public class DateGroup
|
||||
{
|
||||
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.Dispose();
|
||||
}
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>0589ecff-b296-48be-a3f7-7bf27f453975</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Delete.By.Distinct</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,14 +34,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>ead2e5ee-5f40-4151-bdb6-31d630d94f28</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Delete.By.Relative</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,14 +34,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Distance</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -36,7 +36,7 @@
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -14,24 +14,26 @@ public class DistanceLimits : IDistanceLimits
|
||||
public double FaceDistancePermyriad { init; get; }
|
||||
public int SortingMaximumPerFaceShouldBeHigh { init; get; }
|
||||
public bool RangeDaysDeltaTargetLessThenUpper { init; get; }
|
||||
public double RangeDistanceToleranceUpperLimit { init; get; }
|
||||
|
||||
public DistanceLimits(int faceAreaPermyriad,
|
||||
int faceConfidencePercent,
|
||||
int faceDistancePermyriad,
|
||||
int[] rangeDaysDeltaTolerance,
|
||||
float[] rangeDistanceTolerance,
|
||||
float[] rangeFaceAreaPermyriadTolerance,
|
||||
float[] rangeFaceAreaTolerance,
|
||||
float[] rangeFaceConfidence,
|
||||
int sortingMaximumPerFaceShouldBeHigh,
|
||||
int? useFiltersCounter = null)
|
||||
{
|
||||
RangeDistanceToleranceUpperLimit = rangeDistanceTolerance[2];
|
||||
SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh;
|
||||
RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2];
|
||||
if (useFiltersCounter is null)
|
||||
{
|
||||
RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1];
|
||||
FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1];
|
||||
FaceAreaPermyriad = faceAreaPermyriad * rangeFaceAreaPermyriadTolerance[1];
|
||||
FaceAreaPermyriad = faceAreaPermyriad * rangeFaceAreaTolerance[1];
|
||||
FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1];
|
||||
}
|
||||
else
|
||||
@ -39,7 +41,7 @@ public class DistanceLimits : IDistanceLimits
|
||||
RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[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];
|
||||
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 System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.FaceRecognitionDotNet;
|
||||
using View_by_Distance.Map.Models;
|
||||
using View_by_Distance.Property.Models.Stateless;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Methods;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
namespace View_by_Distance.Distance.Models;
|
||||
|
||||
@ -50,6 +53,7 @@ public partial class E_Distance : IDistance
|
||||
private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> intersectFaces)
|
||||
{
|
||||
FaceDistanceContainer[] results;
|
||||
DateTime dateTime;
|
||||
int wholePercentages;
|
||||
int confidencePercent;
|
||||
FaceDistance faceDistance;
|
||||
@ -61,14 +65,15 @@ public partial class E_Distance : IDistance
|
||||
throw new NotSupportedException();
|
||||
if (face.Mapping?.MappingFromFilterPost is null)
|
||||
throw new NotSupportedException();
|
||||
dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
||||
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);
|
||||
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
|
||||
{
|
||||
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)
|
||||
face.SetFaceDistance(faceDistance);
|
||||
}
|
||||
@ -91,7 +96,7 @@ public partial class E_Distance : IDistance
|
||||
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 = [];
|
||||
Face face;
|
||||
@ -112,6 +117,8 @@ public partial class E_Distance : IDistance
|
||||
{
|
||||
face = intersectFaces[i];
|
||||
faceDistanceLength = faceDistanceLengths[i];
|
||||
if (faceDistanceLength.Length is null || faceDistanceLength.Length > distanceLimits.RangeDistanceToleranceUpperLimit)
|
||||
continue;
|
||||
if (faceDistanceLength.Length is null)
|
||||
throw new NotSupportedException();
|
||||
results.Add(new(face, faceDistanceLength.Length.Value));
|
||||
@ -119,10 +126,10 @@ public partial class E_Distance : IDistance
|
||||
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;
|
||||
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();
|
||||
if (results.Length > 0)
|
||||
{
|
||||
@ -132,11 +139,11 @@ public partial class E_Distance : IDistance
|
||||
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 = [];
|
||||
string check;
|
||||
foreach (Face face in filteredFaces)
|
||||
foreach (Face face in faces)
|
||||
{
|
||||
if (json is null || face.FaceEncoding is null)
|
||||
continue;
|
||||
@ -165,7 +172,7 @@ public partial class E_Distance : IDistance
|
||||
mappedFaceDirectory = Path.GetDirectoryName(file);
|
||||
if (mappedFaceDirectory is null)
|
||||
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}");
|
||||
if (checkFile == file)
|
||||
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[] matches;
|
||||
FileInfo? fileInfo;
|
||||
List<Face> intersectFaces;
|
||||
List<(Face, double?)> checkFaces = [];
|
||||
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();
|
||||
if (filteredFaces.Length != faces.Count)
|
||||
checkFaces.Clear();
|
||||
List<(Face Face, double? Distance)> checkFaces = [];
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
{
|
||||
if (_Renamed.Contains(locationContainer.FilePath.FullName))
|
||||
@ -232,8 +236,8 @@ public partial class E_Distance : IDistance
|
||||
MoveUnableToMatch(locationContainer.FilePath);
|
||||
continue;
|
||||
}
|
||||
if (filteredFaces.Length > 0)
|
||||
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, json));
|
||||
if (faces.Count > 0)
|
||||
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(faces, json));
|
||||
if (checkFaces.Count == 1)
|
||||
_Debug.Add(0);
|
||||
if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json))
|
||||
@ -242,11 +246,11 @@ public partial class E_Distance : IDistance
|
||||
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
|
||||
if (modelsFaceEncoding is null)
|
||||
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)
|
||||
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(mappingFromItem, intersectFaces, modelsFaceEncoding));
|
||||
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(distanceLimits, mappingFromItem, intersectFaces, modelsFaceEncoding));
|
||||
}
|
||||
}
|
||||
if (checkFaces.Count == 0)
|
||||
@ -261,7 +265,7 @@ public partial class E_Distance : IDistance
|
||||
MoveUnableToMatch(locationContainer.FilePath);
|
||||
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 (_DistanceRenameToMatch && fileInfo is not null)
|
||||
@ -275,6 +279,15 @@ public partial class E_Distance : IDistance
|
||||
}
|
||||
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))
|
||||
{
|
||||
lock (_AllMappedFaceFiles)
|
||||
@ -322,10 +335,88 @@ public partial class E_Distance : IDistance
|
||||
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 = [];
|
||||
foreach (Face face in distinctFilteredFaces)
|
||||
foreach (Face face in distinctValidImageFaces)
|
||||
{
|
||||
if (face.Mapping?.MappingFromFilterPre is null)
|
||||
throw new NotSupportedException();
|
||||
@ -335,8 +426,10 @@ public partial class E_Distance : IDistance
|
||||
continue;
|
||||
if (face.Mapping.MappingFromFilterPre.IsFocusRelativePath is not null && !face.Mapping.MappingFromFilterPre.IsFocusRelativePath.Value)
|
||||
continue;
|
||||
if (face.FaceEncoding is not null && face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding _)
|
||||
continue;
|
||||
// if (!configuration.ReMap && face.Mapping.MappingFromPerson is not null)
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
progressBar.Tick();
|
||||
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)
|
||||
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 = [];
|
||||
SortingContainer sortingContainer;
|
||||
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)
|
||||
{
|
||||
if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.WholePercentages is null)
|
||||
@ -389,7 +483,7 @@ public partial class E_Distance : IDistance
|
||||
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<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
|
||||
@ -397,27 +491,45 @@ public partial class E_Distance : IDistance
|
||||
return results;
|
||||
}
|
||||
|
||||
public static ReadOnlyCollection<FaceDistanceContainer> GetFaceDistanceContainers(ReadOnlyCollection<Face> distinctFilteredFaces)
|
||||
public static ReadOnlyCollection<FaceDistanceContainer> GetFaceDistanceContainers(ReadOnlyCollection<Face> distinctValidImageFaces)
|
||||
{
|
||||
ReadOnlyCollection<FaceDistanceContainer> results;
|
||||
DateTime dateTime;
|
||||
FaceDistance faceDistance;
|
||||
FaceDistanceContainer faceDistanceContainer;
|
||||
List<FaceDistanceContainer> collection = [];
|
||||
foreach (Face face in distinctFilteredFaces)
|
||||
foreach (Face face in distinctValidImageFaces)
|
||||
{
|
||||
if (face.Mapping?.MappingFromLocation is null)
|
||||
throw new NotSupportedException();
|
||||
if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding)
|
||||
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);
|
||||
collection.Add(faceDistanceContainer);
|
||||
}
|
||||
results = new(collection.ToArray());
|
||||
results = collection.AsReadOnly();
|
||||
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 = [];
|
||||
foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers)
|
||||
@ -446,7 +558,46 @@ public partial class E_Distance : IDistance
|
||||
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 = [];
|
||||
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)
|
||||
results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(results);
|
||||
results = ISortingContainer.Sort(results);
|
||||
else
|
||||
results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(results);
|
||||
return new(results);
|
||||
results = ISortingContainer.SortUsingDaysDelta(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 = [];
|
||||
string fileName;
|
||||
@ -496,6 +647,7 @@ public partial class E_Distance : IDistance
|
||||
foreach (Record record in records)
|
||||
{
|
||||
mappedRelations = [];
|
||||
FaceDistance faceDistanceLength;
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(record.FilePath.FullName);
|
||||
if (files.Count > 1)
|
||||
{
|
||||
@ -508,20 +660,22 @@ public partial class E_Distance : IDistance
|
||||
fileName = Path.GetFileName(files[i]);
|
||||
if (fileName == fileHolder.Name)
|
||||
continue;
|
||||
FaceDistance faceDistance = faceDistanceLengths[i];
|
||||
if (faceDistance.Length is null || faceDistance.Length.Value > distanceTolerance)
|
||||
faceDistanceLength = faceDistanceLengths[i];
|
||||
if (faceDistanceLength.Length is null || faceDistanceLength.Length > distanceLimits.RangeDistanceToleranceUpperLimit)
|
||||
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 = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList();
|
||||
results.Add(new(fileHolder, new(mappedRelations)));
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
ReadOnlyCollection<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;
|
||||
string? json;
|
||||
@ -539,7 +693,7 @@ public partial class E_Distance : IDistance
|
||||
faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding);
|
||||
records.Add(new(locationContainer.FilePath, faceRecognitionDotNetFaceEncoding));
|
||||
}
|
||||
result = GetRelationCollections(faceDistancePermyriad, locationContainerDistanceTake, locationContainerDistanceTolerance, records);
|
||||
result = GetRelationCollections(distanceLimits, faceDistancePermyriad, locationContainerDistanceTake, locationContainerDistanceTolerance, records);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@ -26,9 +26,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -6,10 +6,8 @@ public class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropExplorer());
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@ -26,9 +26,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -6,10 +6,8 @@ public class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropMove());
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UserSecretsId>7b153e3d-672b-4f7a-888a-cb31645a2439</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
@ -27,9 +27,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -162,8 +162,8 @@ public partial class DragDropSearch : Form
|
||||
{
|
||||
Text = item.FilePath.Name;
|
||||
_TextBox.Text = item.FilePath.FullName;
|
||||
if (!string.IsNullOrEmpty(item.FilePath.DirectoryName))
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", item.FilePath.DirectoryName, "\""));
|
||||
if (!string.IsNullOrEmpty(item.FilePath.DirectoryFullPath))
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", item.FilePath.DirectoryFullPath, "\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,9 @@ public class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropSearch());
|
||||
}
|
||||
|
||||
private static Item[] GetFilterItems(Models.Configuration configuration, Container container)
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UserSecretsId>c64a15ed-0ba3-4378-8f80-0c19d0531747</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
@ -27,9 +27,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
|
@ -6,10 +6,8 @@ public class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropSetPropertyItem());
|
||||
}
|
||||
|
||||
}
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Duplicate-Search</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Phares.Shared;
|
||||
using ShellProgressBar;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.Duplicate.Search.Models;
|
||||
@ -145,11 +146,11 @@ public class DuplicateSearch
|
||||
Dictionary<int, List<MappingFromItem?>> results = [];
|
||||
string directory;
|
||||
const int zero = 0;
|
||||
Item[] filteredItems;
|
||||
FileHolder resizedFileHolder;
|
||||
DateTime[] containerDateTimes;
|
||||
MappingFromItem? mappingFromItem;
|
||||
List<MappingFromItem?>? collection;
|
||||
ReadOnlyCollection<Item> validImageItems;
|
||||
const string duplicates = "-Duplicate(s)";
|
||||
if (containers.Length != 0)
|
||||
{
|
||||
@ -162,11 +163,11 @@ public class DuplicateSearch
|
||||
continue;
|
||||
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(configuration, container);
|
||||
if (filteredItems.Length == 0)
|
||||
validImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container);
|
||||
if (validImageItems.Count == 0)
|
||||
continue;
|
||||
containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
|
||||
foreach (Item item in filteredItems)
|
||||
containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
|
||||
foreach (Item item in validImageItems)
|
||||
{
|
||||
if (item.Property?.Id is null)
|
||||
{
|
||||
@ -188,7 +189,7 @@ public class DuplicateSearch
|
||||
if (mappingFromItem is not null)
|
||||
{
|
||||
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));
|
||||
@ -207,11 +208,11 @@ public class DuplicateSearch
|
||||
{
|
||||
foreach (MappingFromItem? mappingFromItem in keyValuePair.Value)
|
||||
{
|
||||
if (mappingFromItem?.ResizedFileHolder.DirectoryName is null)
|
||||
if (mappingFromItem?.ResizedFileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (mappingFromItem.ResizedFileHolder.Exists)
|
||||
continue;
|
||||
collection.Add(mappingFromItem.ResizedFileHolder.DirectoryName);
|
||||
collection.Add(mappingFromItem.ResizedFileHolder.DirectoryFullPath);
|
||||
results.Add(new(mappingFromItem.FilePath, mappingFromItem.ResizedFileHolder.FullName));
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Face</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,7 +33,7 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -6,19 +6,20 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using View_by_Distance.FaceRecognitionDotNet;
|
||||
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.Stateless;
|
||||
using View_by_Distance.Resize.Models;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
namespace View_by_Distance.Face.Models;
|
||||
|
||||
/// <summary>
|
||||
// List<D_Faces>
|
||||
/// </summary>
|
||||
public class D_Face
|
||||
public class D_Face : IFaceD
|
||||
{
|
||||
|
||||
protected readonly string _FileNameExtension;
|
||||
@ -41,11 +42,12 @@ public class D_Face
|
||||
private readonly int _FaceDistanceHiddenImageFactor;
|
||||
private readonly EncoderParameters _EncoderParameters;
|
||||
private readonly ImageCodecInfo _HiddenImageCodecInfo;
|
||||
private readonly Dictionary<string, string[]> _FileGroups;
|
||||
private readonly bool _ForceFaceLastWriteTimeToCreationTime;
|
||||
private readonly EncoderParameters _HiddenEncoderParameters;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultCollectionFileGroups;
|
||||
|
||||
public D_Face(
|
||||
string argZero,
|
||||
@ -68,7 +70,6 @@ public class D_Face
|
||||
float[] rectangleIntersectMinimums)
|
||||
{
|
||||
_ArgZero = argZero;
|
||||
_FileGroups = [];
|
||||
_ImageCodecInfo = imageCodecInfo;
|
||||
_EncoderParameters = encoderParameters;
|
||||
_FileNameExtension = filenameExtension;
|
||||
@ -83,6 +84,8 @@ public class D_Face
|
||||
_RectangleIntersectMinimum = rectangleIntersectMinimums.Min();
|
||||
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
|
||||
_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;
|
||||
@ -100,10 +103,16 @@ public class D_Face
|
||||
|
||||
public void Update(string dResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||
else if (keyValuePair.Key == _PropertyConfiguration.ResultCollection)
|
||||
_ResultCollectionFileGroups[0] = keyValuePair.Value;
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName)
|
||||
@ -111,8 +120,8 @@ public class D_Face
|
||||
(Model, PredictorModel, ModelParameter) result;
|
||||
Array array;
|
||||
Model? model = null;
|
||||
array = Enum.GetValues<Model>();
|
||||
PredictorModel? predictorModel = null;
|
||||
array = Enum.GetValues(typeof(Model));
|
||||
foreach (Model check in array)
|
||||
{
|
||||
if (modelName.Contains(check.ToString()))
|
||||
@ -124,7 +133,7 @@ public class D_Face
|
||||
if (model is null)
|
||||
throw new Exception("Destination directory must have Model name!");
|
||||
model = model.Value;
|
||||
array = Enum.GetValues(typeof(PredictorModel));
|
||||
array = Enum.GetValues<PredictorModel>();
|
||||
foreach (PredictorModel check in array)
|
||||
{
|
||||
if (predictorModelName.Contains(check.ToString()))
|
||||
@ -149,51 +158,68 @@ public class D_Face
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
private void SaveFaces(FileHolder resizedFileHolder, List<(Shared.Models.Face, FileInfo?, string, bool)> collection)
|
||||
private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
Bitmap bitmap;
|
||||
short type = 2;
|
||||
FaceFile faceFile;
|
||||
Graphics graphics;
|
||||
Location? location;
|
||||
Rectangle rectangle;
|
||||
string locationJson;
|
||||
string faceFileJson;
|
||||
string faceEncodingJson;
|
||||
PropertyItem? propertyItem;
|
||||
string outputResolutionJson;
|
||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||
string? model = IMetadata.GetModel(exifDirectory);
|
||||
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)
|
||||
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 (!save)
|
||||
continue;
|
||||
if (fileInfo is null)
|
||||
if (fileHolder is null)
|
||||
continue;
|
||||
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
|
||||
continue;
|
||||
if (_OverrideForFaceImages && fileHolder.Exists)
|
||||
{
|
||||
IFaceD dFace = this;
|
||||
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
||||
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
|
||||
continue;
|
||||
}
|
||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
||||
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);
|
||||
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||
geoLocation?.ToDmsString(),
|
||||
face.DateTime,
|
||||
null,
|
||||
face.FaceParts,
|
||||
face.Location,
|
||||
maker,
|
||||
null,
|
||||
model,
|
||||
face.OutputResolution);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
using (bitmap = new(width, height))
|
||||
{
|
||||
using (graphics = Graphics.FromImage(bitmap))
|
||||
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson);
|
||||
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson);
|
||||
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||
bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||
}
|
||||
if (File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
@ -213,7 +239,7 @@ public class D_Face
|
||||
}
|
||||
}
|
||||
|
||||
private List<Shared.Models.Face> GetFaces(string outputResolution, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location>? locations)
|
||||
private List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
|
||||
{
|
||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||
@ -222,7 +248,24 @@ public class D_Face
|
||||
List<Shared.Models.Face> results = [];
|
||||
FaceRecognitionDotNet.Image? unknownImage;
|
||||
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)
|
||||
{ unknownImage = null; }
|
||||
if (unknownImage is not null)
|
||||
@ -260,73 +303,37 @@ public class D_Face
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
private static List<LocationContainer> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
List<LocationContainer> results = [];
|
||||
string? json;
|
||||
Location? location;
|
||||
Rectangle? rectangle;
|
||||
List<int> skip = [];
|
||||
OutputResolution? outputResolutionCheck = null;
|
||||
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
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))
|
||||
{
|
||||
if (face.Location is null || face.OutputResolution is null)
|
||||
continue;
|
||||
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution));
|
||||
}
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
if (locationContainer.ExifDirectory is null)
|
||||
continue;
|
||||
if (skip.Contains(locationContainer.WholePercentages))
|
||||
continue;
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.Location is not null && face.OutputResolution is not null)
|
||||
continue;
|
||||
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
||||
if (json is null)
|
||||
continue;
|
||||
outputResolutionCheck = JsonSerializer.Deserialize<OutputResolution>(json);
|
||||
if (outputResolutionCheck is null || outputResolutionCheck.Width != outputResolutionWidth || outputResolutionCheck.Height != outputResolutionHeight)
|
||||
continue;
|
||||
rectangle = Shared.Models.Stateless.Methods.ILocation.GetRectangle(Shared.Models.Stateless.ILocation.Digits, outputResolutionCheck, locationContainer.WholePercentages);
|
||||
if (rectangle is null)
|
||||
continue;
|
||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(outputResolutionHeight, rectangle.Value, outputResolutionWidth);
|
||||
if (location is null)
|
||||
continue;
|
||||
if (!results.Any(l => l.WholePercentages == locationContainer.WholePercentages))
|
||||
results.Add(new(locationContainer.CreationDateOnly,
|
||||
locationContainer.ExifDirectory,
|
||||
locationContainer.DirectoryNumber,
|
||||
locationContainer.DisplayDirectoryName,
|
||||
locationContainer.FilePath,
|
||||
locationContainer.FromDistanceContent,
|
||||
locationContainer.Id,
|
||||
location,
|
||||
locationContainer.PersonKey,
|
||||
rectangle.Value,
|
||||
locationContainer.WholePercentages));
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
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)
|
||||
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;
|
||||
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
|
||||
throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
|
||||
string? json;
|
||||
List<Location>? locations;
|
||||
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"));
|
||||
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);
|
||||
@ -359,18 +366,13 @@ public class D_Face
|
||||
parseExceptions.Add(nameof(D_Face));
|
||||
}
|
||||
}
|
||||
List<LocationContainer> collection;
|
||||
if (results is null || locationContainers is null)
|
||||
collection = [];
|
||||
else
|
||||
collection = GetLocationContainers(outputResolution, locationContainers, outputResolutionToResize, results);
|
||||
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
||||
locations = (from l in collection where l is not null select l.Location).ToList();
|
||||
locations = [];
|
||||
else
|
||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||
if (results is null || (locations is not null && locations.Count > 0))
|
||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||
if (results is null || locations.Count > 0)
|
||||
{
|
||||
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations);
|
||||
results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
|
||||
if (results.Count == 0)
|
||||
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
||||
else
|
||||
@ -394,17 +396,39 @@ public class D_Face
|
||||
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)
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||
{
|
||||
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = [];
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (Directory.Exists(checkFile))
|
||||
{
|
||||
Directory.Move(checkFile, directoryInfo.FullName);
|
||||
directoryInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<(Shared.Models.Face, FileHolder?, string, bool)> SaveFaces(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = [];
|
||||
bool save;
|
||||
FileInfo fileInfo;
|
||||
FileHolder fileHolder;
|
||||
string deterministicHashCodeKey;
|
||||
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();
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
||||
bool directoryExists = Directory.Exists(directory);
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||
DirectoryInfo directoryInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, directoryInfo);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
save = false;
|
||||
@ -414,24 +438,94 @@ public class D_Face
|
||||
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 (!directoryExists)
|
||||
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 (!fileInfo.Exists)
|
||||
else if (!fileHolder.Exists)
|
||||
save = true;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
save = true;
|
||||
results.Add(new(face, fileInfo, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||
results.Add(new(face, fileHolder, Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||
}
|
||||
if (results.Any(l => l.Save))
|
||||
{
|
||||
if (!directoryExists)
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
SaveFaces(mappingFromItem.ResizedFileHolder, results);
|
||||
if (!directoryInfo.Exists)
|
||||
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||
SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
private static (string?, string?) Get(string? json)
|
||||
{
|
||||
string? model;
|
||||
string? maker;
|
||||
FaceFile? faceFile = json is null ? null : JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
|
||||
if (faceFile is null || faceFile.Location is null)
|
||||
(maker, model) = (null, null);
|
||||
else
|
||||
(maker, model) = (faceFile.Maker, faceFile.Model);
|
||||
return (maker, model);
|
||||
}
|
||||
|
||||
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Shared.Models.Face face, bool mappedFile)
|
||||
{
|
||||
FileInfo fileInfo = new(filePath.FullName);
|
||||
if (fileInfo.Exists)
|
||||
{
|
||||
string? json;
|
||||
short type = 2;
|
||||
string? model;
|
||||
string? maker;
|
||||
string checkFile = $"{filePath.FullName}.exif";
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
||||
// const int author = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor; // 40093
|
||||
if (mappedFile)
|
||||
{
|
||||
json = IMetadata.GetOutputResolution(exifDirectory);
|
||||
if (json is not null && json.Contains(nameof(DateTime)))
|
||||
return;
|
||||
(maker, model) = Get(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
maker = IMetadata.GetMaker(exifDirectory);
|
||||
model = IMetadata.GetModel(exifDirectory);
|
||||
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
|
||||
json = IMetadata.GetOutputResolution(faceExifDirectory);
|
||||
if (json is not null && json.Contains(nameof(DateTime)))
|
||||
return;
|
||||
}
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
FaceFile faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||
geoLocation?.ToDmsString(),
|
||||
face.DateTime,
|
||||
null,
|
||||
face.FaceParts,
|
||||
face.Location,
|
||||
maker,
|
||||
null,
|
||||
model,
|
||||
face.OutputResolution);
|
||||
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
||||
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
|
||||
Bitmap bitmap = new(fileInfo.FullName);
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
bitmap.Save(checkFile);
|
||||
bitmap.Dispose();
|
||||
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
|
||||
File.Delete(fileInfo.FullName);
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
}
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.FaceParts</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,7 +33,7 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -2,9 +2,12 @@ using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.Face.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.Stateless;
|
||||
using View_by_Distance.Resize.Models;
|
||||
@ -25,22 +28,23 @@ public class D2_FaceParts
|
||||
|
||||
private readonly ImageCodecInfo _ImageCodecInfo;
|
||||
private readonly bool _CheckDFaceAndUpWriteDates;
|
||||
private readonly ConstructorInfo _ConstructorInfo;
|
||||
private readonly bool _OverrideForFaceLandmarkImages;
|
||||
private readonly EncoderParameters _EncoderParameters;
|
||||
private readonly List<string> _AngleBracketCollection;
|
||||
private readonly Dictionary<string, string[]> _FileGroups;
|
||||
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)
|
||||
{
|
||||
_FileGroups = [];
|
||||
_ImageCodecInfo = imageCodecInfo;
|
||||
_EncoderParameters = encoderParameters;
|
||||
_FileNameExtension = filenameExtension;
|
||||
_AngleBracketCollection = [];
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
|
||||
_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()
|
||||
@ -51,45 +55,14 @@ public class D2_FaceParts
|
||||
|
||||
public void Update(string dResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
public void SetAngleBracketCollection(Configuration configuration, string d2ResultsFullGroupDirectory, string sourceDirectory)
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
_AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(configuration,
|
||||
sourceDirectory,
|
||||
d2ResultsFullGroupDirectory,
|
||||
contentDescription: "n gif file(s) for each face found",
|
||||
singletonDescription: string.Empty,
|
||||
collectionDescription: string.Empty,
|
||||
converted: true));
|
||||
}
|
||||
|
||||
public string GetFacePartsDirectory(Configuration configuration, string dResultsFullGroupDirectory, Item item, bool includeNameWithoutExtension)
|
||||
{
|
||||
string result;
|
||||
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
|
||||
if (!angleBracketCollectionAny)
|
||||
{
|
||||
if (item.FilePath.DirectoryName is null)
|
||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryName));
|
||||
SetAngleBracketCollection(configuration, dResultsFullGroupDirectory, item.FilePath.DirectoryName);
|
||||
}
|
||||
if (includeNameWithoutExtension)
|
||||
result = Path.Combine(_AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), item.FilePath.NameWithoutExtension);
|
||||
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||
else
|
||||
{
|
||||
result = _AngleBracketCollection[0].Replace("<>", $"[{_PropertyConfiguration.ResultContent}]");
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
throw new Exception();
|
||||
}
|
||||
if (!angleBracketCollectionAny)
|
||||
_AngleBracketCollection.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
|
||||
@ -183,54 +156,18 @@ public class D2_FaceParts
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveFaceParts(int pointSize, FileHolder resizedFileHolder, bool saveRotated, List<(Shared.Models.Face, string, string)> collection)
|
||||
private void SaveRotated(MappingFromItem mappingFromItem, List<(Shared.Models.Face, string, string)> collection)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
double? α;
|
||||
int width;
|
||||
int height;
|
||||
Bitmap rotated;
|
||||
foreach ((Shared.Models.Face face, string fileName, string rotatedFileName) in collection)
|
||||
foreach ((Shared.Models.Face face, string _, string rotatedFileName) in collection)
|
||||
{
|
||||
if (face.FaceEncoding is null)
|
||||
if (face.FaceParts is null)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
using (Image image = Image.FromFile(resizedFileHolder.FullName))
|
||||
{
|
||||
using Graphics graphic = Graphics.FromImage(image);
|
||||
if (face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
{
|
||||
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);
|
||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
rotated = RotateBitmap(image, (float)α.Value);
|
||||
if (rotated is not null)
|
||||
{
|
||||
@ -239,28 +176,250 @@ public class D2_FaceParts
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
private string GetSeasonDirectory(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, bool any)
|
||||
{
|
||||
string result;
|
||||
string minimumDateYear = mappingFromItem.MinimumDateTime.ToString("yyyy");
|
||||
DateTime dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
|
||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
string year = mappingFromItem.DateTimeOriginal is null ? $"{minimumDateYear[1..]}{minimumDateYear[0]}" : mappingFromItem.DateTimeOriginal.Value.ToString("yyyy");
|
||||
string directory = Path.Combine(d2ResultsFullGroupDirectory, $"[{_PropertyConfiguration.ResultContent}]", $"{year}.{season} {seasonName}");
|
||||
result = any ? Path.Combine(directory, "---") : Path.Combine(directory, "Complete");
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveImage(MappingFromItem mappingFromItem, string directory, Image image, List<FaceFile> faceFiles)
|
||||
{
|
||||
short type = 2;
|
||||
string faceFileJson;
|
||||
PropertyItem? propertyItem;
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||
string fileName = Path.Combine(directory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
||||
try
|
||||
{
|
||||
foreach (int propertyId in image.PropertyIdList)
|
||||
{
|
||||
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
|
||||
continue;
|
||||
image.RemovePropertyItem(propertyId);
|
||||
}
|
||||
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||
image.SetPropertyItem(propertyItem);
|
||||
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||
if (!string.IsNullOrEmpty(faceFileJson))
|
||||
File.WriteAllText($"{fileName}.json", faceFileJson);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveAllFaceParts(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
int x;
|
||||
int 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);
|
||||
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();
|
||||
string directory = GetSeasonDirectory(d2ResultsFullGroupDirectory, mappingFromItem, any);
|
||||
SaveImage(mappingFromItem, directory, image, faceFiles);
|
||||
}
|
||||
|
||||
private void SaveImage(string fileName, Image image, FaceFile faceFile)
|
||||
{
|
||||
short type = 2;
|
||||
string faceFileJson;
|
||||
PropertyItem? propertyItem;
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||
try
|
||||
{
|
||||
foreach (int propertyId in image.PropertyIdList)
|
||||
{
|
||||
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
|
||||
continue;
|
||||
image.RemovePropertyItem(propertyId);
|
||||
}
|
||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||
image.SetPropertyItem(propertyItem);
|
||||
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
if (!string.IsNullOrEmpty(faceFileJson))
|
||||
File.WriteAllText($"{fileName}.json", faceFileJson);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveFaceParts(MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<(Shared.Models.Face, string, string)> collection)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
Brush brush;
|
||||
int pointSize;
|
||||
FaceFile faceFile;
|
||||
MappingFromPerson? mappingFromPerson;
|
||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||
string? model = IMetadata.GetModel(exifDirectory);
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
foreach ((Shared.Models.Face face, string fileName, string _) in collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetPointSize(Dictionary<FacePart, FacePoint[]> faceParts, int defaultPointSize)
|
||||
{
|
||||
int result;
|
||||
FacePoint[]? facePoints;
|
||||
if (faceParts.TryGetValue(FacePart.LeftEye, out facePoints))
|
||||
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
|
||||
else
|
||||
{
|
||||
if (faceParts.TryGetValue(FacePart.RightEye, out facePoints))
|
||||
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
|
||||
else
|
||||
result = defaultPointSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
public void SaveFaceLandmarkImages(Configuration configuration, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, List<Shared.Models.Face> faces, bool saveRotated)
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (Directory.Exists(checkFile))
|
||||
{
|
||||
Directory.Move(checkFile, directoryInfo.FullName);
|
||||
directoryInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveFaceLandmarkImages(Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, 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 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();
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
||||
bool directoryExists = Directory.Exists(directory);
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||
DirectoryInfo directoryInfo = new(Path.Combine(directory, mappingFromItem.FilePath.NameWithoutExtension));
|
||||
MoveIf(fileName, cei, directory, directoryInfo);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||
@ -269,14 +428,14 @@ public class D2_FaceParts
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||
continue;
|
||||
rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName));
|
||||
if (check)
|
||||
continue;
|
||||
else if (!directoryExists)
|
||||
else if (!directoryInfo.Exists)
|
||||
check = true;
|
||||
else if (_OverrideForFaceLandmarkImages)
|
||||
check = true;
|
||||
@ -294,50 +453,25 @@ public class D2_FaceParts
|
||||
}
|
||||
if (check)
|
||||
{
|
||||
if (!directoryExists)
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
SaveFaceParts(pointSize, mappingFromItem.ResizedFileHolder, saveRotated, collection);
|
||||
if (!directoryInfo.Exists)
|
||||
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||
SaveFaceParts(mappingFromItem, exifDirectory, collection);
|
||||
if (saveRotated)
|
||||
SaveRotated(mappingFromItem, 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)
|
||||
private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileHolder?, string, bool)> faceCollection)
|
||||
{
|
||||
bool results = false;
|
||||
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)
|
||||
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 (File.Exists(checkFile))
|
||||
@ -353,26 +487,25 @@ public class D2_FaceParts
|
||||
if (!results)
|
||||
results = true;
|
||||
if (!File.Exists(checkFile))
|
||||
File.Copy(fileInfo.FullName, checkFile);
|
||||
File.Copy(fileHolder.FullName, checkFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection)
|
||||
public void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection);
|
||||
string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
||||
bool save = faceCollection.Any(l => l.Face.FaceEncoding is not null && l.Face.Location is not null && l.Face.OutputResolution is not null && l.Face.FaceParts is not null && l.Face.FaceParts.Count != 0);
|
||||
FileInfo fileInfo = new(fileName);
|
||||
if (save && (!fileInfo.Exists || new TimeSpan(DateTime.Now.Ticks - fileInfo.LastWriteTime.Ticks).TotalDays > 10))
|
||||
bool any = false;
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
SaveFaceLandmarkImage(mappingFromItem, faceCollection, fileName);
|
||||
fileInfo.Refresh();
|
||||
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
continue;
|
||||
if (!any)
|
||||
any = true;
|
||||
}
|
||||
if (!hasNotMapped && !fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && (fileInfo.Exists || save))
|
||||
File.SetAttributes(fileName, FileAttributes.Hidden);
|
||||
if (any)
|
||||
SaveAllFaceParts(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
||||
}
|
||||
|
||||
}
|
@ -167,7 +167,13 @@ public class FaceRecognition : DisposableObject
|
||||
}
|
||||
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)
|
||||
{
|
||||
DlibDotNet.Rectangle rectangle = new(location.Left, location.Top, location.Right, location.Bottom);
|
||||
@ -197,7 +203,7 @@ public class FaceRecognition : DisposableObject
|
||||
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 = [];
|
||||
if (image is null)
|
||||
@ -206,9 +212,7 @@ public class FaceRecognition : DisposableObject
|
||||
ThrowIfDisposed();
|
||||
if (_PredictorModel == PredictorModel.Custom)
|
||||
throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported.");
|
||||
if (locations is null)
|
||||
locations = GetLocations(image);
|
||||
else if (locations.Count == 0)
|
||||
if (locations.Count == 0)
|
||||
locations.AddRange(GetLocations(image));
|
||||
List<FullObjectDetection> fullObjectDetections = GetFullObjectDetections(image, locations);
|
||||
if (fullObjectDetections.Count != locations.Count)
|
||||
@ -408,22 +412,50 @@ public class FaceRecognition : DisposableObject
|
||||
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)
|
||||
{
|
||||
List<FaceDistance> results = [];
|
||||
if (faceDistances is null)
|
||||
throw new NullReferenceException(nameof(faceDistances));
|
||||
if (faceDistances.Count != 0)
|
||||
{
|
||||
double length;
|
||||
FaceDistance result;
|
||||
if (faceDistanceToCompare is null || faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare)
|
||||
if (faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare)
|
||||
throw new NullReferenceException(nameof(faceDistanceToCompare));
|
||||
faceEncodingToCompare.ThrowIfDisposed();
|
||||
foreach (FaceDistance faceDistance in faceDistances)
|
||||
{
|
||||
#pragma warning disable CA1513
|
||||
if (faceDistance.Encoding is not FaceEncoding faceEncoding || faceEncoding.IsDisposed)
|
||||
throw new ObjectDisposedException($"{nameof(faceDistances)} contains disposed object.");
|
||||
#pragma warning restore CA1513
|
||||
using (Matrix<double> diff = faceEncoding.Encoding - faceEncodingToCompare.Encoding)
|
||||
length = DlibDotNet.Dlib.Length(diff);
|
||||
result = new(faceDistance, length);
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.FaceRecognitionDotNet</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>2999dda1-5329-4d9f-9d68-cccfabe0e47f</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Instance</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,12 +34,12 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
|
@ -9,7 +9,6 @@ public class Configuration
|
||||
|
||||
public bool? CheckDFaceAndUpWriteDates { get; set; }
|
||||
public bool? CheckJsonForDistanceResults { get; set; }
|
||||
public string[]? CopyFacesAndSaveFaceLandmarkForOutputResolutions { get; set; }
|
||||
public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; }
|
||||
public bool? DeletePossibleDuplicates { get; set; }
|
||||
public int? DistanceFactor { get; set; }
|
||||
@ -28,6 +27,8 @@ public class Configuration
|
||||
public bool? ForceResizeLastWriteTimeToCreationTime { 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[]? JLinks { get; set; }
|
||||
public string? LinkedAlpha { get; set; }
|
||||
@ -77,6 +78,7 @@ public class Configuration
|
||||
public string[]? SaveBlurHashForOutputResolutions { get; set; }
|
||||
public string[]? SaveFaceDistancesForOutputResolutions { get; set; }
|
||||
public string[]? SaveFaceLandmarkForOutputResolutions { get; set; }
|
||||
public string[]? SaveFaceLandmarkForOutputResolutionsV2 { get; set; }
|
||||
public string[]? SaveFilteredOriginalImagesFromJLinksForOutputResolutions { get; set; }
|
||||
public bool? SaveFullYearOfRandomFiles { get; set; }
|
||||
public bool? SaveIndividually { get; set; }
|
||||
@ -129,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?.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?.DeletePossibleDuplicates is null) throw new NullReferenceException(nameof(configuration.DeletePossibleDuplicates));
|
||||
if (configuration?.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor));
|
||||
@ -148,6 +149,8 @@ public class Configuration
|
||||
if (configuration?.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime));
|
||||
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?.JLinks is null) throw new NullReferenceException(nameof(configuration.JLinks));
|
||||
// if (configuration?.LinkedAlpha is null) throw new NullReferenceException(nameof(configuration.LinkedAlpha));
|
||||
@ -197,6 +200,7 @@ public class Configuration
|
||||
// if (configuration?.SaveBlurHashForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveBlurHashForOutputResolutions));
|
||||
// if (configuration?.SaveFaceDistancesForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceDistancesForOutputResolutions));
|
||||
// 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?.SaveFullYearOfRandomFiles is null) throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles));
|
||||
if (configuration?.SaveIndividually is null) throw new NullReferenceException(nameof(configuration.SaveIndividually));
|
||||
@ -221,7 +225,6 @@ public class Configuration
|
||||
result = new(propertyConfiguration,
|
||||
configuration.CheckDFaceAndUpWriteDates.Value,
|
||||
configuration.CheckJsonForDistanceResults.Value,
|
||||
configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions ?? [],
|
||||
configuration.CrossDirectoryMaxItemsInDistanceCollection.Value,
|
||||
configuration.DeletePossibleDuplicates.Value,
|
||||
configuration.DistanceFactor.Value,
|
||||
@ -240,6 +243,8 @@ public class Configuration
|
||||
configuration.ForceResizeLastWriteTimeToCreationTime.Value,
|
||||
configuration.GenealogicalDataCommunicationFile,
|
||||
configuration.ImmichAssetsFile,
|
||||
configuration.ImmichOwnerId,
|
||||
configuration.ImmichRoot,
|
||||
configuration.IgnoreExtensions ?? [],
|
||||
configuration.JLinks ?? [],
|
||||
configuration.LinkedAlpha,
|
||||
@ -289,6 +294,7 @@ public class Configuration
|
||||
configuration.SaveBlurHashForOutputResolutions ?? [],
|
||||
configuration.SaveFaceDistancesForOutputResolutions ?? [],
|
||||
configuration.SaveFaceLandmarkForOutputResolutions ?? [],
|
||||
configuration.SaveFaceLandmarkForOutputResolutionsV2 ?? [],
|
||||
configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions ?? [],
|
||||
configuration.SaveFullYearOfRandomFiles.Value,
|
||||
configuration.SaveIndividually.Value,
|
||||
|
@ -54,7 +54,7 @@ public class 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,
|
||||
bool CheckDFaceAndUpWriteDates,
|
||||
bool CheckJsonForDistanceResults,
|
||||
string[] CopyFacesAndSaveFaceLandmarkForOutputResolutions,
|
||||
int CrossDirectoryMaxItemsInDistanceCollection,
|
||||
bool DeletePossibleDuplicates,
|
||||
int DistanceFactor,
|
||||
@ -22,6 +21,8 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
|
||||
bool ForceResizeLastWriteTimeToCreationTime,
|
||||
string GenealogicalDataCommunicationFile,
|
||||
string ImmichAssetsFile,
|
||||
string ImmichOwnerId,
|
||||
string ImmichRoot,
|
||||
string[] IgnoreExtensions,
|
||||
string[] JLinks,
|
||||
string? LinkedAlpha,
|
||||
@ -63,7 +64,7 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
|
||||
int RadomUseBirthdayMinimum,
|
||||
int[] RangeDaysDeltaTolerance,
|
||||
float[] RangeDistanceTolerance,
|
||||
float[] RangeFaceAreaPermyriadTolerance,
|
||||
float[] RangeFaceAreaTolerance,
|
||||
float[] RangeFaceConfidence,
|
||||
float[] RectangleIntersectMinimums,
|
||||
bool ReMap,
|
||||
@ -71,6 +72,7 @@ public record Configuration(Property.Models.Configuration PropertyConfiguration,
|
||||
string[] SaveBlurHashForOutputResolutions,
|
||||
string[] SaveFaceDistancesForOutputResolutions,
|
||||
string[] SaveFaceLandmarkForOutputResolutions,
|
||||
string[] SaveFaceLandmarkForOutputResolutionsV2,
|
||||
string[] SaveFilteredOriginalImagesFromJLinksForOutputResolutions,
|
||||
bool SaveFullYearOfRandomFiles,
|
||||
bool SaveIndividually,
|
||||
|
@ -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.Text.Json;
|
||||
using View_by_Distance.Shared.Models;
|
||||
|
||||
namespace View_by_Distance.Instance.Models;
|
||||
|
||||
@ -24,16 +25,18 @@ internal class F_Random
|
||||
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 = [];
|
||||
string key;
|
||||
DateTime dateTime;
|
||||
List<long>? personKeys;
|
||||
ImmichAsset? immichAsset;
|
||||
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;
|
||||
if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys))
|
||||
continue;
|
||||
@ -49,39 +52,79 @@ internal class F_Random
|
||||
if (!results.TryGetValue(key, out relativePaths))
|
||||
throw new Exception();
|
||||
}
|
||||
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 json;
|
||||
string jsonFile;
|
||||
Random random = new();
|
||||
List<string>? collection;
|
||||
ImmichAsset? immichAsset;
|
||||
string dateFormat = "MM-dd";
|
||||
List<string> relativePaths = [];
|
||||
List<int> distinctCollection = [];
|
||||
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<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[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
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))
|
||||
continue;
|
||||
if (mapping.MappingFromItem.FilePath.DirectoryName is null)
|
||||
if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (notNineCollection is not null && notNineCollection.Contains(mapping.MappingFromItem.Id))
|
||||
if (!splatNineIdentifiersKeys.Contains(mapping.MappingFromItem.Id))
|
||||
continue;
|
||||
if (mapping.MappingFromItem.Keywords is not null && mapping.MappingFromItem.Keywords.Any(l => validKeyWordsToIgnoreInRandom.Contains(l)))
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
if (relativePaths.Count > 0)
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Map</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -37,7 +37,7 @@
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -1,6 +1,8 @@
|
||||
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 DistanceRenameToMatch,
|
||||
int FaceConfidencePercent,
|
||||
|
@ -23,6 +23,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
long? Ticks,
|
||||
string? PersonDirectory);
|
||||
|
||||
internal record FilteredOriginalImage(int Id,
|
||||
FilePath FilePath,
|
||||
int ApproximateYears,
|
||||
string PersonKeyFormatted,
|
||||
string Directory,
|
||||
string PersonDirectory,
|
||||
string CheckFile);
|
||||
|
||||
public void SaveContainers(int? updated, List<SaveContainer> saveContainers)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
@ -137,7 +145,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
}
|
||||
}
|
||||
|
||||
private List<SaveShortcutsForOutputResolutions> GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection)
|
||||
private List<SaveShortcutsForOutputResolutions> GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
List<SaveShortcutsForOutputResolutions> results = [];
|
||||
if (_Configuration is null)
|
||||
@ -153,7 +161,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
string personKeyFormatted;
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
ReadOnlyDictionary<int, List<long>> idToPersonKeys = IMapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||
foreach (Mapping mapping in mappingCollection)
|
||||
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
||||
{
|
||||
dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
||||
description = mapping.MappingFromLocation is null ? mapping.MappingFromItem.Id.ToString() : mapping.MappingFromLocation.DeterministicHashCodeKey;
|
||||
@ -162,9 +170,9 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
directory = Path.Combine($"{eDistanceContentDirectory}---", "Date Shortcuts", $"{dateTime.Year}.{season}-MM{dateTime.Month:00}-WW{weekOfYear}");
|
||||
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
|
||||
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
|
||||
if (mapping.MappingFromItem.FilePath.DirectoryName is null)
|
||||
if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null)
|
||||
continue;
|
||||
directoryName = Path.GetFileName(mapping.MappingFromItem.FilePath.DirectoryName);
|
||||
directoryName = Path.GetFileName(mapping.MappingFromItem.FilePath.DirectoryFullPath);
|
||||
if (!string.IsNullOrEmpty(mapping.MappingFromItem.Model) && !string.IsNullOrEmpty(mapping.MappingFromItem.Model.Trim()))
|
||||
{
|
||||
// Remove-Item -LiteralPath "\\?\D:\Tmp\a\EX-Z70 "
|
||||
@ -181,12 +189,12 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey);
|
||||
directory = Path.Combine($"{eDistanceContentDirectory}---", "Person Key Shortcuts", personKeyFormatted, directoryName);
|
||||
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
|
||||
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false));
|
||||
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
|
||||
if (IPerson.IsDefaultName(mapping.MappingFromPerson))
|
||||
continue;
|
||||
directory = Path.Combine($"{eDistanceContentDirectory}---", "Name Shortcuts", mapping.MappingFromPerson.DisplayDirectoryName, directoryName);
|
||||
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}.lnk");
|
||||
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, description, MakeAllHidden: false));
|
||||
results.Add(new(mapping.MappingFromItem.FilePath.FullName, directory, dateTime, fileName, description, MakeAllHidden: false));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@ -230,7 +238,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
ReadOnlyDictionary<long, int> readOnlyPersonKeyToCount;
|
||||
Dictionary<int, List<(string, int)>> skipCollection = [];
|
||||
Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
|
||||
ReadOnlyDictionary<int, List<(string, int)>> readOnlyskipCollection;
|
||||
ReadOnlyDictionary<int, List<(string, int)>> readOnlySkipCollection;
|
||||
string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory);
|
||||
string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, ticks.ToString());
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> idThenWholePercentagesToPersonContainers;
|
||||
@ -256,7 +264,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
{
|
||||
List<string> personKeyFormattedCollection = [];
|
||||
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
|
||||
Stateless.MapLogic.SetPersonCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
||||
Stateless.MapLogic.SetPersonCollectionsAfterSetSkipCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
||||
readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection);
|
||||
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted);
|
||||
}
|
||||
@ -297,7 +305,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
skipCollection,
|
||||
readOnlyPersonKeyFormattedToPersonContainer,
|
||||
personKeyFormattedIdThenWholePercentagesCollection);
|
||||
readOnlyskipCollection = new(skipCollection);
|
||||
readOnlySkipCollection = new(skipCollection);
|
||||
notMappedPersonContainers.AddRange(Stateless.MapLogic.GetNotMappedPersonContainers(configuration,
|
||||
ticks,
|
||||
personContainers,
|
||||
@ -307,7 +315,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
configuration,
|
||||
ticks,
|
||||
personContainers,
|
||||
readOnlyskipCollection,
|
||||
readOnlySkipCollection,
|
||||
records));
|
||||
int lossCount = records.Count - locationContainers.Count;
|
||||
int unableToMatchCount = records.Count - personKeyFormattedIdThenWholePercentagesCollection.Count;
|
||||
@ -348,7 +356,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
else
|
||||
results = [];
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyDictionary<long, List<int>> GetPersonKeyToIds()
|
||||
@ -385,7 +393,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
}
|
||||
if (shouldMove.Count > 0)
|
||||
throw new Exception(string.Join(Environment.NewLine, shouldMove));
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
(bool, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>?) Shared.Models.Methods.IMapLogic.GetWholePercentagesToPersonContainers(int id)
|
||||
@ -452,6 +460,31 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
private (long?, string?) GetDirectory(Configuration configuration, string by, string segmentB)
|
||||
{
|
||||
long? ticks = null;
|
||||
const int zero = 0;
|
||||
string? directory = null;
|
||||
string personKeyFormatted;
|
||||
PersonBirthday personBirthday;
|
||||
PersonContainer personContainer;
|
||||
for (int i = _NotMappedPersonContainers.Count - 1; i > 0; i--)
|
||||
{
|
||||
if (configuration.SaveIndividually)
|
||||
break;
|
||||
personContainer = _NotMappedPersonContainers[i];
|
||||
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0)
|
||||
continue;
|
||||
personBirthday = personContainer.Birthdays[zero];
|
||||
ticks = personBirthday.Value.Ticks;
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
|
||||
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
|
||||
_NotMappedPersonContainers.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
return (ticks, directory);
|
||||
}
|
||||
|
||||
private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem)
|
||||
{
|
||||
long? ticks = null;
|
||||
@ -504,7 +537,30 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
private Record Get(Configuration configuration, bool saveIndividually, string by, Mapping question, int padLeft)
|
||||
private Record Get(Configuration configuration, string by, long? personKey, string? displayDirectoryName, string segmentB)
|
||||
{
|
||||
long? ticks;
|
||||
string? directory;
|
||||
string? debugDirectory;
|
||||
string? personDirectory;
|
||||
if (personKey is null || string.IsNullOrEmpty(displayDirectoryName))
|
||||
{
|
||||
debugDirectory = null;
|
||||
(ticks, directory) = GetDirectory(configuration, by, segmentB);
|
||||
personDirectory = directory is null ? null : Path.Combine(directory, $"X+{ticks}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ticks = null;
|
||||
string personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey.Value);
|
||||
debugDirectory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, displayDirectoryName);
|
||||
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
|
||||
personDirectory = Path.Combine(directory, displayDirectoryName, "lnk");
|
||||
}
|
||||
return new(debugDirectory, directory, ticks, personDirectory);
|
||||
}
|
||||
|
||||
private Record Get(Configuration configuration, bool saveIndividually, int padLeft, string by, Mapping question)
|
||||
{
|
||||
long? ticks;
|
||||
string? directory;
|
||||
@ -532,7 +588,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return new(debugDirectory, directory, ticks, personDirectory);
|
||||
}
|
||||
|
||||
private List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyDictionary<long, List<int>> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny)
|
||||
private List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyDictionary<long, List<int>> personKeyToIds, int? useFiltersCounter, bool saveMapped, bool saveIndividually, bool sortingContainersAny)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
@ -557,7 +613,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
ReadOnlyDictionary<int, Mapping>? wholePercentagesToMapping;
|
||||
int padLeft = _Configuration.FaceDistancePermyriad.ToString().Length;
|
||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
foreach (Mapping mapping in mappingCollection)
|
||||
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
||||
{
|
||||
if (mapping.MappingFromLocation is null)
|
||||
continue;
|
||||
@ -586,7 +642,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
if (!PreAndPostContinue(_Configuration, mapping, question))
|
||||
continue;
|
||||
}
|
||||
record = Get(_Configuration, saveIndividually, by, mapping, padLeft);
|
||||
record = Get(_Configuration, saveIndividually, padLeft, by, mapping);
|
||||
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||
continue;
|
||||
directory = record.Directory;
|
||||
@ -651,7 +707,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
|
||||
public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
@ -659,7 +715,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
bool saveMapped = true;
|
||||
int? useFiltersCounter = null;
|
||||
string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping));
|
||||
List<SaveContainer> saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, saveIndividually: false);
|
||||
List<SaveContainer> saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, distinctValidImageMappingCollection, idToWholePercentagesToMapping, personKeyToIds, useFiltersCounter, saveMapped, sortingContainersAny: true, saveIndividually: false);
|
||||
SaveContainers(updated, saveContainers);
|
||||
if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory))
|
||||
Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory);
|
||||
@ -753,7 +809,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
keyToCount.Add(key, new());
|
||||
_ = keyToCount.TryAdd(key, 0);
|
||||
keyToCount[key]++;
|
||||
if (!_Configuration.SaveIndividually && keyToCount[key] < _Configuration.SortingMaximumPerKey)
|
||||
if (!_Configuration.SaveIndividually && keyToCount[key] <= _Configuration.SortingMaximumPerKey)
|
||||
segmentC = null;
|
||||
else
|
||||
segmentC = sortingContainer.Sorting.DistancePermyriad.ToString();
|
||||
@ -764,6 +820,95 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
private string? GetDisplayDirectoryName(string? displayDirectoryName, LocationContainer locationContainer, ReadOnlyDictionary<long, PersonContainer> personKeyToPersonContainer)
|
||||
{
|
||||
string? result = displayDirectoryName;
|
||||
if (personKeyToPersonContainer.Count != 0)
|
||||
{
|
||||
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers = GetWholePercentagesToPersonContainers(locationContainer.Id);
|
||||
if (wholePercentagesToPersonContainers is not null)
|
||||
{
|
||||
foreach (KeyValuePair<int, ReadOnlyCollection<PersonContainer>> keyValuePair in wholePercentagesToPersonContainers)
|
||||
{
|
||||
if (keyValuePair.Key != locationContainer.WholePercentages)
|
||||
continue;
|
||||
if (keyValuePair.Value.Count != 1)
|
||||
continue;
|
||||
result = keyValuePair.Value[0].DisplayDirectoryName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<SaveContainer> GetSaveContainers(string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, Shared.Models.Methods.IDistanceLimits distanceLimits, ReadOnlyDictionary<string, LocationContainer> onlyOne, ReadOnlyDictionary<long, PersonContainer> personKeyToPersonContainer)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
List<SaveContainer> results = [];
|
||||
string by;
|
||||
Record record;
|
||||
string segmentB;
|
||||
bool isBySorting;
|
||||
string checkFile;
|
||||
string? directory;
|
||||
string shortcutFile;
|
||||
string facesDirectory;
|
||||
bool isCounterPersonYear;
|
||||
string facePartsDirectory;
|
||||
FileHolder? faceFileHolder;
|
||||
SaveContainer? saveContainer;
|
||||
string? displayDirectoryName;
|
||||
FileHolder? resizedFileHolder;
|
||||
int? useFiltersCounter = null;
|
||||
string resizeContentDirectory;
|
||||
FileHolder? facePartsFileHolder;
|
||||
FileHolder? hiddenFaceFileHolder;
|
||||
LocationContainer locationContainer;
|
||||
bool sortingContainersAny = onlyOne.Count > 0;
|
||||
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
|
||||
{
|
||||
if (_Configuration.SaveIndividually)
|
||||
break;
|
||||
locationContainer = keyValuePair.Value;
|
||||
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
||||
continue;
|
||||
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
||||
displayDirectoryName = GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer, personKeyToPersonContainer);
|
||||
isCounterPersonYear = locationContainer.PersonKey is not null && IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKey.Value);
|
||||
(by, _, isBySorting) = Stateless.MapLogic.Get(useFiltersCounter, _Configuration.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKey, displayDirectoryName);
|
||||
record = Get(_Configuration, by, locationContainer.PersonKey, displayDirectoryName, segmentB);
|
||||
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||
continue;
|
||||
directory = record.Directory;
|
||||
if (!string.IsNullOrEmpty(record.DebugDirectory))
|
||||
results.Add(new(record.DebugDirectory));
|
||||
if (locationContainer.PersonKey is null)
|
||||
{
|
||||
if (!_Configuration.SaveSortingWithoutPerson)
|
||||
throw new NotSupportedException();
|
||||
if (record.Ticks is null)
|
||||
continue;
|
||||
}
|
||||
results.Add(new(record.PersonDirectory));
|
||||
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
|
||||
faceFileHolder = IFileHolder.Get(locationContainer.LengthSource.FullName);
|
||||
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
||||
shortcutFile = Path.Combine(record.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
||||
resizeContentDirectory = Stateless.MapLogic.GetResizeContentDirectory(_PropertyConfiguration, cContentDirectory, locationContainer.LengthSource);
|
||||
facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectoryX(_PropertyConfiguration, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
||||
hiddenFaceFileHolder = IFileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacesHiddenFileNameExtension}"));
|
||||
facePartsFileHolder = IFileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacePartsFileNameExtension}"));
|
||||
resizedFileHolder = IFileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
||||
saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
||||
results.Add(saveContainer);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, int? useFiltersCounter, ReadOnlyCollection<SortingContainer> sortingContainers)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
@ -802,7 +947,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
throw new NotSupportedException();
|
||||
if (question.MappingFromLocation is null)
|
||||
continue;
|
||||
record = Get(_Configuration, _Configuration.SaveIndividually, by, question, padLeft);
|
||||
record = Get(_Configuration, _Configuration.SaveIndividually, padLeft, by, question);
|
||||
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||
continue;
|
||||
directory = record.Directory;
|
||||
@ -944,7 +1089,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
results.Add(new(keyMapping, sortingContainer.Sorting, sortingContainer.Source));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private (string, PersonBirthday?) GetPersonBirthday(string[] directoryNames)
|
||||
@ -1029,7 +1174,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{ids.Count} Face(s)")));
|
||||
foreach ((long personKey, string displayDirectoryName) in collection)
|
||||
{
|
||||
matches = (from l in personContainers where l.Key == personKey && l.ApproximateYears.HasValue select l).ToArray();
|
||||
matches = (from l in personContainers where l.Key == personKey select l).ToArray();
|
||||
if (matches.Length == 0)
|
||||
continue;
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personKey);
|
||||
@ -1044,11 +1189,11 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
private (int, FilePath, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyCollection<Mapping> mappingCollection, ReadOnlyDictionary<long, List<int>> personKeyToIds)
|
||||
private FilteredOriginalImage[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleContentDirectory, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, ReadOnlyDictionary<long, List<int>> personKeyToIds)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
(int, FilePath, int, string, string, string, string)[] results;
|
||||
FilteredOriginalImage[] results;
|
||||
int count = 0;
|
||||
int group = 65;
|
||||
string checkFile;
|
||||
@ -1058,9 +1203,9 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
string personKeyFormatted;
|
||||
List<int> distinctCollection = [];
|
||||
bool usePersonKeyAndDeterministicHashCodeKey = false;
|
||||
List<FilteredOriginalImage> filteredOriginalImages = [];
|
||||
List<string> personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleContentDirectory, personContainers, personKeyToIds);
|
||||
List<(int Id, FilePath FilePath, int ApproximateYears, string PersonKeyFormatted, string CheckFile, string Directory, string PersonDirectory)> collection = [];
|
||||
foreach (Mapping mapping in mappingCollection)
|
||||
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
||||
{
|
||||
if (distinctCollection.Contains(mapping.MappingFromItem.Id))
|
||||
continue;
|
||||
@ -1069,7 +1214,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
throw new NotSupportedException();
|
||||
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting)
|
||||
continue;
|
||||
if (mapping.MappingFromPerson?.ApproximateYears is null || mapping.MappingFromLocation is null)
|
||||
if (mapping.MappingFromPerson is null || mapping.MappingFromLocation is null)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
|
||||
throw new NotSupportedException();
|
||||
@ -1097,39 +1242,45 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
|
||||
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}");
|
||||
}
|
||||
collection.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, mapping.MappingFromPerson.ApproximateYears.Value, personKeyFormatted, directory, personDirectory, checkFile));
|
||||
if (mapping is null)
|
||||
continue;
|
||||
if (mapping.MappingFromPerson.ApproximateYears is null)
|
||||
filteredOriginalImages.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, -1, personKeyFormatted, directory, personDirectory, checkFile));
|
||||
else
|
||||
filteredOriginalImages.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.FilePath, mapping.MappingFromPerson.ApproximateYears.Value, personKeyFormatted, directory, personDirectory, checkFile));
|
||||
distinctCollection.Add(mapping.MappingFromItem.Id);
|
||||
count += 1;
|
||||
}
|
||||
results = (from l in collection orderby l.ApproximateYears descending, l.PersonKeyFormatted descending select l).ToArray();
|
||||
results = (from l in filteredOriginalImages orderby l.ApproximateYears descending, l.PersonKeyFormatted descending select l).ToArray();
|
||||
return results;
|
||||
}
|
||||
|
||||
public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection)
|
||||
public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
int? updated = null;
|
||||
FileHolder fileHolder;
|
||||
SaveContainer? saveContainer;
|
||||
List<SaveContainer> saveContainers = [];
|
||||
(int, FilePath, int, string, string, string, string)[] collection = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, mappingCollection, personKeyToIds);
|
||||
foreach ((int id, FilePath filePath, int approximateYears, string personKeyFormatted, string directory, string personDirectory, string checkFile) in collection)
|
||||
FilteredOriginalImage[] filteredOriginalImages = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleContentDirectory, personContainers, distinctValidImageMappingCollection, personKeyToIds);
|
||||
foreach (FilteredOriginalImage filteredOriginalImage in filteredOriginalImages)
|
||||
{
|
||||
fileHolder = FileHolder.Get(filePath);
|
||||
saveContainer = new(personDirectory);
|
||||
fileHolder = FileHolder.Get(filteredOriginalImage.FilePath);
|
||||
saveContainer = new(filteredOriginalImage.PersonDirectory);
|
||||
saveContainers.Add(saveContainer);
|
||||
saveContainer = new(fileHolder, checkFile, directory);
|
||||
saveContainer = new(fileHolder, filteredOriginalImage.CheckFile, filteredOriginalImage.Directory);
|
||||
saveContainers.Add(saveContainer);
|
||||
}
|
||||
SaveContainers(null, saveContainers);
|
||||
SaveContainers(updated, saveContainers);
|
||||
}
|
||||
|
||||
public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> mappingCollection)
|
||||
public void SaveShortcutsForOutputResolutionsPreMapLogic(string eDistanceContentDirectory, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
string hiddenFile;
|
||||
WindowsShortcut windowsShortcut;
|
||||
List<SaveShortcutsForOutputResolutions> collection = [];
|
||||
collection = GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, mappingCollection);
|
||||
collection = GetCollectionForSaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctValidImageMappingCollection);
|
||||
string[] distinctDirectories = (from l in collection select l.Directory).Distinct().ToArray();
|
||||
foreach (string directory in distinctDirectories)
|
||||
{
|
||||
@ -1163,7 +1314,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
}
|
||||
}
|
||||
|
||||
private (List<(string, DateTime[])>, List<SaveShortcutsForOutputResolutions>) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Item> filteredItems, ReadOnlyCollection<Mapping> mappingCollection)
|
||||
private (List<(string, DateTime[])>, List<SaveShortcutsForOutputResolutions>) GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Item> validImageItems, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
@ -1171,6 +1322,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
string fileName;
|
||||
string fullName;
|
||||
string directory;
|
||||
DateTime dateTime;
|
||||
string facesDirectory;
|
||||
string? directoryName;
|
||||
string personDirectory;
|
||||
@ -1178,7 +1330,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
List<string> distinct = [];
|
||||
List<SaveShortcutsForOutputResolutions> collection = [];
|
||||
List<(string, DateTime[])> directoriesAndDateTimes = [];
|
||||
foreach (Item item in filteredItems)
|
||||
foreach (Item item in validImageItems)
|
||||
{
|
||||
if (item.ResizedFileHolder is null)
|
||||
continue;
|
||||
@ -1191,43 +1343,44 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath);
|
||||
if (directoryName is null)
|
||||
throw new NotSupportedException();
|
||||
if (item.ResizedFileHolder?.DirectoryName is null || !item.ResizedFileHolder.Exists)
|
||||
if (item.ResizedFileHolder?.DirectoryFullPath is null || !item.ResizedFileHolder.Exists)
|
||||
continue;
|
||||
directory = Path.Combine(item.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
|
||||
directory = Path.Combine(item.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
|
||||
personDirectory = Path.Combine(directory, "No Faces");
|
||||
fileName = Path.Combine(personDirectory, $"{item.ResizedFileHolder.Name}.lnk");
|
||||
collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, new(item.FilePath.LastWriteTicks), fileName, face.Mapping.MappingFromItem.Id.ToString(), MakeAllHidden: false));
|
||||
if (face.Mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(item.ResizedFileHolder.DirectoryName))
|
||||
if (face.Mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(item.ResizedFileHolder.DirectoryFullPath))
|
||||
{
|
||||
distinct.Add(item.ResizedFileHolder.DirectoryName);
|
||||
directoriesAndDateTimes.Add(new(item.ResizedFileHolder.DirectoryName, face.Mapping.MappingFromItem.ContainerDateTimes));
|
||||
distinct.Add(item.ResizedFileHolder.DirectoryFullPath);
|
||||
directoriesAndDateTimes.Add(new(item.ResizedFileHolder.DirectoryFullPath, face.Mapping.MappingFromItem.ContainerDateTimes));
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Mapping mapping in mappingCollection)
|
||||
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
||||
{
|
||||
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
|
||||
if (directoryName is null)
|
||||
throw new NotSupportedException();
|
||||
if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists)
|
||||
if (mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath is null || !mapping.MappingFromItem.ResizedFileHolder.Exists)
|
||||
continue;
|
||||
dateTime = mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
||||
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting || mapping.MappingFromPerson?.ApproximateYears is null)
|
||||
{
|
||||
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName))
|
||||
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath))
|
||||
{
|
||||
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName);
|
||||
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes));
|
||||
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath);
|
||||
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, mapping.MappingFromItem.ContainerDateTimes));
|
||||
}
|
||||
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
|
||||
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
|
||||
personDirectory = Path.Combine(directory, "Unknown");
|
||||
fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
|
||||
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
|
||||
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
|
||||
facesDirectory = Stateless.MapLogic.GetFacesDirectory(_PropertyConfiguration, dFacesContentDirectory, mapping.FilePath, mapping.MappingFromItem);
|
||||
if (mapping.MappingFromLocation is null)
|
||||
continue;
|
||||
fullName = Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}{_Configuration.FacesFileNameExtension}");
|
||||
fileName = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ResizedFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}.lnk");
|
||||
collection.Add(new(fullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true));
|
||||
collection.Add(new(fullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey, MakeAllHidden: true));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1236,32 +1389,32 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
|
||||
throw new NotSupportedException();
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonKey);
|
||||
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName))
|
||||
if (mapping.MappingFromItem.ContainerDateTimes.Length > 0 && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath))
|
||||
{
|
||||
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName);
|
||||
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes));
|
||||
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath);
|
||||
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, mapping.MappingFromItem.ContainerDateTimes));
|
||||
}
|
||||
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted);
|
||||
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryFullPath, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted);
|
||||
if (!personKeyToIds.TryGetValue(mapping.MappingFromPerson.PersonKey, out ids))
|
||||
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
|
||||
else
|
||||
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{ids.Count} Face(s)");
|
||||
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
|
||||
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, mapping.MappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
|
||||
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, dateTime, fileName, mapping.MappingFromLocation?.DeterministicHashCodeKey, MakeAllHidden: false));
|
||||
}
|
||||
}
|
||||
return new(directoriesAndDateTimes, collection);
|
||||
}
|
||||
|
||||
public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> mappingCollection)
|
||||
public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
if (_Configuration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration));
|
||||
WindowsShortcut windowsShortcut;
|
||||
List<(string, DateTime[])> directoriesAndDateTimes;
|
||||
List<SaveShortcutsForOutputResolutions> collection;
|
||||
ReadOnlyCollection<Item> filteredItems = IContainer.GetItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true);
|
||||
(directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, filteredItems, mappingCollection);
|
||||
ReadOnlyCollection<Item> validImageItems = IContainer.GetValidImageItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true);
|
||||
(directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, validImageItems, distinctValidImageMappingCollection);
|
||||
string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
@ -1305,10 +1458,13 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) =>
|
||||
_SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(mappingFromLocation.WholePercentages);
|
||||
public bool InSkipCollection(int id, int wholePercentages) =>
|
||||
_SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(wholePercentages);
|
||||
|
||||
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation)
|
||||
public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) =>
|
||||
InSkipCollection(id, mappingFromLocation.WholePercentages);
|
||||
|
||||
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
|
||||
{
|
||||
bool? result;
|
||||
ReadOnlyCollection<PersonContainer>? personContainers;
|
||||
@ -1316,7 +1472,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
result = null;
|
||||
else if (wholePercentagesToPersonContainers is null)
|
||||
result = null;
|
||||
else if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers))
|
||||
else if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
@ -1340,37 +1496,46 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
||||
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||
|
||||
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
||||
{
|
||||
string[] directories;
|
||||
string? directoryName;
|
||||
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredIds);
|
||||
dlibDotNet.Tick();
|
||||
List<string> distinctFilteredFileNameFirstSegments = IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
|
||||
dlibDotNet.Tick();
|
||||
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||
continue;
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||
}
|
||||
dlibDotNet.Tick();
|
||||
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||
continue;
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||
}
|
||||
dlibDotNet.Tick();
|
||||
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||
continue;
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||
}
|
||||
dlibDotNet.Tick();
|
||||
}
|
||||
|
||||
}
|
@ -32,9 +32,23 @@ internal abstract class DecadeLogic
|
||||
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;
|
||||
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 checkDirectory;
|
||||
string? yearDirectory;
|
||||
@ -44,17 +58,10 @@ internal abstract class DecadeLogic
|
||||
string? personKeyFormattedDirectoryName;
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
{
|
||||
if (!File.Exists(locationContainer.FilePath.FullName))
|
||||
if (string.IsNullOrEmpty(locationContainer.FilePath.DirectoryFullPath))
|
||||
continue;
|
||||
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)
|
||||
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);
|
||||
personNameDirectoryName = Path.GetFileName(locationContainer.FilePath.DirectoryFullPath);
|
||||
yearDirectory = Path.GetDirectoryName(locationContainer.FilePath.DirectoryFullPath);
|
||||
if (string.IsNullOrEmpty(yearDirectory))
|
||||
continue;
|
||||
yearDirectoryName = Path.GetFileName(yearDirectory);
|
||||
@ -68,6 +75,8 @@ internal abstract class DecadeLogic
|
||||
if (halfDecade == yearDirectoryName)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(personKeyFormattedDirectory, halfDecade, personNameDirectoryName);
|
||||
if (!File.Exists(locationContainer.FilePath.FullName))
|
||||
continue;
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
File.Move(locationContainer.FilePath.FullName, Path.Combine(checkDirectory, locationContainer.FilePath.Name));
|
||||
|
@ -250,14 +250,27 @@ internal abstract class DistanceLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void RenameUnknown(string[] files)
|
||||
private static string[] RenameBirth(string[] files)
|
||||
{
|
||||
List<string> results = [];
|
||||
string checkFile;
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.EndsWith(".unk"))
|
||||
if (file.EndsWith(".brt"))
|
||||
{
|
||||
results.Add(file);
|
||||
continue;
|
||||
File.Move(file, $"{file}.unk");
|
||||
}
|
||||
checkFile = $"{file}.brt";
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
results.Add(file);
|
||||
continue;
|
||||
}
|
||||
File.Move(file, checkFile);
|
||||
results.Add(checkFile);
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
|
||||
@ -374,7 +387,7 @@ internal abstract class DistanceLogic
|
||||
}
|
||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (personNameDirectories.Length > 1)
|
||||
throw new NotSupportedException();
|
||||
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||
foreach (string personNameDirectory in personNameDirectories)
|
||||
{
|
||||
directoryNumber++;
|
||||
@ -422,7 +435,7 @@ internal abstract class DistanceLogic
|
||||
if (!isDefault.Value)
|
||||
{
|
||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
RenameUnknown(files);
|
||||
files = RenameBirth(files);
|
||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||
{
|
||||
if (!check)
|
||||
|
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 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;
|
||||
FileHolder fileHolder;
|
||||
string fileNameFirstSegment;
|
||||
List<string> renameCollection = [];
|
||||
string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray();
|
||||
string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
@ -21,7 +20,7 @@ internal abstract class LookForAbandonedLogic
|
||||
fileNameFirstSegment = fileHolder.NameWithoutExtension.Split('.')[0];
|
||||
if (!filePath.IsIntelligentIdFormat && filePath.SortOrder is null)
|
||||
continue;
|
||||
if (distinctFilteredIdsValues.Contains(fileNameFirstSegment))
|
||||
if (distinctFilteredFileNameFirstSegments.Contains(fileNameFirstSegment))
|
||||
continue;
|
||||
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);
|
||||
foreach (string directory in directories)
|
||||
@ -44,7 +43,7 @@ internal abstract class LookForAbandonedLogic
|
||||
string? directoryName = Path.GetFileName(directory);
|
||||
if (string.IsNullOrEmpty(directoryName) || (directoryName.Length != 2 && directoryName.Length != 4))
|
||||
continue;
|
||||
LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
||||
LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ internal abstract class MapLogic
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetPersonCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection)
|
||||
internal static void SetPersonCollectionsAfterSetSkipCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection)
|
||||
{
|
||||
string personKeyFormatted;
|
||||
string newestPersonKeyFormatted;
|
||||
@ -106,8 +106,9 @@ internal abstract class MapLogic
|
||||
internal static string GetMappingSegmentB(long ticks, long personKey, int? approximateYears, MappingFromItem mappingFromItem)
|
||||
{
|
||||
string result;
|
||||
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
||||
PersonBirthday personBirthday = IPersonBirthday.GetPersonBirthday(personKey);
|
||||
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear);
|
||||
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -173,12 +174,14 @@ internal abstract class MapLogic
|
||||
results.Add(face);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem)
|
||||
{
|
||||
string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear);
|
||||
string result;
|
||||
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
||||
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -212,30 +215,47 @@ internal abstract class MapLogic
|
||||
{
|
||||
if (duplicate.Percent is null)
|
||||
continue;
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryName, "\""));
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryFullPath, "\""));
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, duplicate.PersonKey);
|
||||
}
|
||||
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
|
||||
{
|
||||
if (percent is not null && percent.Value == 0)
|
||||
continue;
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryName, "\""));
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
|
||||
}
|
||||
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
|
||||
{
|
||||
if (percent is not null && percent.Value > 0)
|
||||
continue;
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryName, "\""));
|
||||
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
File.Move(checkFile, fullFileName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, FilePath filePath, MappingFromItem mappingFromItem)
|
||||
{
|
||||
string result;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(dFacesContentDirectory, directoryName, mappingFromItem.FilePath.NameWithoutExtension);
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(dFacesContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension);
|
||||
MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, dFacesContentDirectory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -322,7 +342,7 @@ internal abstract class MapLogic
|
||||
continue;
|
||||
}
|
||||
if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer))
|
||||
throw new Exception();
|
||||
continue;
|
||||
if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo))
|
||||
{
|
||||
results.Add(personKeyFormattedIdThenWholePercentages.Id, []);
|
||||
@ -366,7 +386,7 @@ internal abstract class MapLogic
|
||||
}
|
||||
results.Add(idTo.Key, new(keyValuePairs));
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetReadOnly(Dictionary<int, Dictionary<int, Mapping>> keyValuePairs)
|
||||
@ -374,7 +394,7 @@ internal abstract class MapLogic
|
||||
Dictionary<int, ReadOnlyDictionary<int, Mapping>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<int, Mapping>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static List<PersonContainer> GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List<long> personKeys, ReadOnlyDictionary<long, int> personKeyToCount)
|
||||
@ -415,7 +435,7 @@ internal abstract class MapLogic
|
||||
if (check)
|
||||
continue;
|
||||
personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2));
|
||||
personContainer = new(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey);
|
||||
personContainer = PersonContainer.Get(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey);
|
||||
results.Add(personContainer);
|
||||
if (results.Count > 99)
|
||||
break;
|
||||
@ -435,7 +455,7 @@ internal abstract class MapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
||||
internal static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
||||
{
|
||||
List<MappedFile> results = [];
|
||||
long personKey;
|
||||
@ -444,6 +464,9 @@ internal abstract class MapLogic
|
||||
FileHolder fileHolder;
|
||||
List<string> distinct = [];
|
||||
PersonBirthday? personBirthday;
|
||||
PersonContainer? personContainer;
|
||||
string? personDisplayDirectoryName;
|
||||
ReadOnlyDictionary<long, PersonContainer> keyValuePairs = PersonContainer.Extract(personContainers);
|
||||
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, configuration.PersonBirthdayFormat, personContainers));
|
||||
foreach (Record record in records)
|
||||
{
|
||||
@ -452,9 +475,13 @@ internal abstract class MapLogic
|
||||
continue;
|
||||
if (distinct.Contains(record.MappedFaceFilePath.Name))
|
||||
continue;
|
||||
distinct.Add(record.MappedFaceFilePath.Name);
|
||||
personKey = personBirthday.Value.Ticks;
|
||||
results.Add(new(personKey, record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath));
|
||||
distinct.Add(record.MappedFaceFilePath.Name);
|
||||
if (!keyValuePairs.TryGetValue(personKey, out personContainer))
|
||||
personDisplayDirectoryName = record.PersonDisplayDirectoryName;
|
||||
else
|
||||
personDisplayDirectoryName = personContainer.DisplayDirectoryName;
|
||||
results.Add(new(personKey, record.PersonKeyFormatted, personDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath));
|
||||
}
|
||||
for (int i = results.Count - 1; i > -1; i--)
|
||||
{
|
||||
@ -464,7 +491,7 @@ internal abstract class MapLogic
|
||||
results.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
if (!filePath.Name.EndsWith(".dup") && !filePath.Name.EndsWith(".unk") && !filePath.Name.EndsWith(".abd"))
|
||||
if (!filePath.Name.EndsWith(".abd") && !filePath.Name.EndsWith(".brt") && !filePath.Name.EndsWith(".dup") && !filePath.Name.EndsWith(".unk"))
|
||||
continue;
|
||||
if (!File.Exists(filePath.FullName))
|
||||
continue;
|
||||
@ -532,18 +559,22 @@ internal abstract class MapLogic
|
||||
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;
|
||||
lock (locationContainers)
|
||||
locationContainers.Add(new(dateOnly,
|
||||
LocationContainer locationContainer = new(dateOnly,
|
||||
exifDirectory,
|
||||
mappedFile.DirectoryNumber,
|
||||
personDisplayDirectoryName,
|
||||
null,
|
||||
null,
|
||||
mappedFile.FilePath,
|
||||
fromDistanceContent,
|
||||
id.Value,
|
||||
null,
|
||||
null,
|
||||
mappedFile.PersonKey,
|
||||
rectangle,
|
||||
wholePercentages.Value));
|
||||
wholePercentages.Value);
|
||||
lock (locationContainers)
|
||||
locationContainers.Add(locationContainer);
|
||||
}
|
||||
|
||||
private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||
@ -558,6 +589,8 @@ internal abstract class MapLogic
|
||||
Dictionary<string, (FilePath, int)> distinct = [];
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
{
|
||||
if (locationContainer.PersonKey is null)
|
||||
continue;
|
||||
key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
|
||||
if (distinct.TryGetValue(key, out item))
|
||||
{
|
||||
@ -573,7 +606,7 @@ internal abstract class MapLogic
|
||||
}
|
||||
delete.Add(item.FilePath);
|
||||
delete.Add(locationContainer.FilePath);
|
||||
duplicates.Add(new(locationContainer.PersonKey, locationContainer.Id, locationContainer.FilePath, percent));
|
||||
duplicates.Add(new(locationContainer.PersonKey.Value, locationContainer.Id, locationContainer.FilePath, percent));
|
||||
continue;
|
||||
}
|
||||
distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages));
|
||||
@ -727,11 +760,11 @@ internal abstract class MapLogic
|
||||
personDisplayDirectoryName = personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName;
|
||||
matches = configuration.PersonCharacters.Where(l => personDisplayDirectoryName.Contains(l)).ToArray();
|
||||
if (matches.Length == 0)
|
||||
throw new NotSupportedException();
|
||||
continue;
|
||||
group = IPerson.GetHourGroup(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
|
||||
(status, sex, first) = IPerson.GetPersonHour(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
|
||||
personDirectory = new(matches.First(), group, status, sex, first);
|
||||
personContainer = new(configuration.PersonCharacters.ToArray(), personBirthday, personDisplayDirectoryName, personDirectory);
|
||||
personContainer = PersonContainer.Get(configuration.PersonCharacters.ToArray(), personBirthday, personDisplayDirectoryName, personDirectory);
|
||||
personKeyFormattedToPersonContainer.Add(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, personContainer);
|
||||
}
|
||||
if (personContainer.Key is null)
|
||||
@ -777,7 +810,7 @@ internal abstract class MapLogic
|
||||
idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value].Add(wholePercentages.Value);
|
||||
results.Add(new(record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.IsDefault, record.LinksCount, record.MappedFaceFilePath, record.MappedFaceFilePath.Id.Value, wholePercentages.Value));
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static List<PersonContainer> GetNotMappedPersonContainers(Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyDictionary<long, int> personKeyToCount)
|
||||
@ -831,9 +864,9 @@ internal abstract class MapLogic
|
||||
continue;
|
||||
personBirthday = IPersonBirthday.GetPersonBirthday(keyValuePair.Key);
|
||||
if (!personKeyToPersonContainerCollection.TryGetValue(keyValuePair.Key, out collection))
|
||||
personContainer = new(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key);
|
||||
personContainer = PersonContainer.Get(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key);
|
||||
else
|
||||
personContainer = new(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key);
|
||||
personContainer = PersonContainer.Get(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key);
|
||||
personKeyToPersonContainer.Add(keyValuePair.Key, personContainer);
|
||||
}
|
||||
}
|
||||
@ -947,7 +980,7 @@ internal abstract class MapLogic
|
||||
if (distinct.Contains(personContainer.DisplayDirectoryAllFilePaths[i].Name))
|
||||
continue;
|
||||
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
|
||||
directoryName = Path.GetFileName(personContainer.DisplayDirectoryAllFilePaths[i].DirectoryName);
|
||||
directoryName = Path.GetFileName(personContainer.DisplayDirectoryAllFilePaths[i].DirectoryFullPath);
|
||||
if (directoryName != personContainer.DisplayDirectoryName)
|
||||
continue;
|
||||
personBirthday = IPersonBirthday.GetPersonBirthday(personContainer.Key.Value);
|
||||
@ -982,8 +1015,26 @@ internal abstract class MapLogic
|
||||
internal static string GetFacePartsDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath, MappingFromItem mappingFromItem)
|
||||
{
|
||||
string result;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, directoryName, mappingFromItem.FilePath.NameWithoutExtension);
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension);
|
||||
MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetFacePartsDirectoryX(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
||||
MoveIf(filePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetResizeContentDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string cContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
result = Path.Combine(cContentDirectory, cei.Combined);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1092,14 +1143,14 @@ internal abstract class MapLogic
|
||||
collection.Add(keyValuePair.Key);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> mappingCollection)
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||
{
|
||||
Dictionary<int, Dictionary<int, Mapping>> results = [];
|
||||
Dictionary<int, Mapping>? keyValuePairs;
|
||||
foreach (Mapping mapping in mappingCollection)
|
||||
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
||||
{
|
||||
if (mapping.MappingFromLocation is null)
|
||||
continue;
|
||||
@ -1168,29 +1219,29 @@ internal abstract class MapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping)
|
||||
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
||||
{
|
||||
string by;
|
||||
string byValue;
|
||||
bool isByMapping;
|
||||
bool isBySorting;
|
||||
if (mapping.By is null)
|
||||
if (by is null)
|
||||
{
|
||||
isByMapping = false;
|
||||
isBySorting = !sortingContainersAny;
|
||||
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
|
||||
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
|
||||
}
|
||||
else
|
||||
{
|
||||
isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping;
|
||||
isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting;
|
||||
bool isDefaultName = mapping.MappingFromPerson is not null && IPerson.IsDefaultName(mapping.MappingFromPerson.DisplayDirectoryName);
|
||||
if (isBySorting && mapping.MappingFromPerson is null)
|
||||
by = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
|
||||
isByMapping = by == Shared.Models.Stateless.IMapLogic.Mapping;
|
||||
isBySorting = by == Shared.Models.Stateless.IMapLogic.Sorting;
|
||||
bool isDefaultName = displayDirectoryName is not null && IPerson.IsDefaultName(displayDirectoryName);
|
||||
if (isBySorting && displayDirectoryName is null)
|
||||
byValue = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
|
||||
else if (isBySorting && useFiltersCounter.HasValue)
|
||||
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
||||
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
||||
else
|
||||
{
|
||||
by = $"{mapping.By.Value switch
|
||||
byValue = $"{by.Value switch
|
||||
{
|
||||
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),
|
||||
@ -1199,9 +1250,15 @@ internal abstract class MapLogic
|
||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||
}
|
||||
}
|
||||
return new(by, isByMapping, isBySorting);
|
||||
return new(byValue, isByMapping, isBySorting);
|
||||
}
|
||||
|
||||
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, long? personKey, string? displayDirectoryName) =>
|
||||
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKey is null ? null : Shared.Models.Stateless.IMapLogic.Mapping, displayDirectoryName);
|
||||
|
||||
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) =>
|
||||
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, mapping.By, mapping.MappingFromPerson?.DisplayDirectoryName);
|
||||
|
||||
internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent)
|
||||
{
|
||||
string json;
|
||||
@ -1236,7 +1293,7 @@ internal abstract class MapLogic
|
||||
foreach ((string _, int wholePercentage) in keyValuePair.Value)
|
||||
wholePercentagesCollection.Add(wholePercentage);
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, List<int>> ConvertSkipNotSkip(Dictionary<int, List<(string, int)>> skipNotSkipCollection)
|
||||
@ -1254,7 +1311,7 @@ internal abstract class MapLogic
|
||||
foreach ((string _, int wholePercentage) in keyValuePair.Value)
|
||||
wholePercentagesCollection.Add(wholePercentage);
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, List<LocationContainer>> ConvertLocationContainers(List<LocationContainer> locationContainers)
|
||||
@ -1266,10 +1323,10 @@ internal abstract class MapLogic
|
||||
results.Add(locationContainer.Id, []);
|
||||
results[locationContainer.Id].Add(locationContainer);
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation)
|
||||
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
|
||||
{
|
||||
bool? result;
|
||||
ReadOnlyCollection<PersonContainer>? personContainers;
|
||||
@ -1277,7 +1334,7 @@ internal abstract class MapLogic
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers))
|
||||
if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
|
@ -1,4 +1,6 @@
|
||||
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;
|
||||
|
||||
@ -10,44 +12,64 @@ public interface IMapLogic
|
||||
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||
|
||||
ReadOnlyCollection<Shared.Models.Face> TestStatic_GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
||||
ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
GetFaces(items);
|
||||
static ReadOnlyCollection<Shared.Models.Face> GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
||||
static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
MapLogic.GetFaces(items);
|
||||
|
||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
||||
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
GetSelectedMappingCollection(items);
|
||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
||||
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
MapLogic.GetSelectedMappingCollection(items);
|
||||
|
||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
||||
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
GetSelectedMappingCollection(faces);
|
||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
||||
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
MapLogic.GetSelectedMappingCollection(faces);
|
||||
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) =>
|
||||
GetIdToWholePercentagesToFace(mappingCollection);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> mappingCollection) =>
|
||||
MapLogic.GetIdToWholePercentagesToFace(mappingCollection);
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||
GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||
MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||
|
||||
List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||
GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
||||
static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||
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) =>
|
||||
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);
|
||||
void TestStatic_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
SetCreationTime(mappingFromItem, locationContainers);
|
||||
static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||
|
||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
||||
void TestStatic_MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||
static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
DecadeLogic.MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||
|
||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||
|
||||
string TestStatic_GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||
|
||||
string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
||||
GetDecade(mappingFromItem);
|
||||
static string GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
||||
static string GetDecade(MappingFromItem mappingFromItem) =>
|
||||
DecadeLogic.GetDecade(mappingFromItem, null);
|
||||
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> TestStatic_GetMappedFiles(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||
GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||
FaceFileLogic.GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||
|
||||
List<LocationContainer> TestStatic_GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||
GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||
static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||
FaceFileLogic.GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||
|
||||
}
|
@ -17,14 +17,16 @@ internal abstract class RelationLogic
|
||||
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, out yearTo))
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||
{
|
||||
personKeyTo.Add(locationContainer.PersonKey, []);
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, 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))
|
||||
@ -45,6 +47,7 @@ internal abstract class RelationLogic
|
||||
int lastIndex;
|
||||
List<int> years = [];
|
||||
List<int> indices = [];
|
||||
LocationContainer locationContainer;
|
||||
List<(int Index, int Year)> sort = [];
|
||||
List<LocationContainer> collection = [];
|
||||
KeyValuePair<int, List<LocationContainer>> keyValue;
|
||||
@ -76,12 +79,15 @@ internal abstract class RelationLogic
|
||||
key = $"{years.Min()}-{keyValue.Key}";
|
||||
if (collection.Count == 0)
|
||||
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 = [];
|
||||
years.Clear();
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, string> MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers, List<List<string>> linked)
|
||||
@ -98,7 +104,7 @@ internal abstract class RelationLogic
|
||||
string? personKeyFormattedDirectory;
|
||||
foreach ((FileHolder fileHolder, _) in relationContainers)
|
||||
{
|
||||
personNameDirectory = fileHolder.DirectoryName;
|
||||
personNameDirectory = fileHolder.DirectoryFullPath;
|
||||
yearDirectory = Path.GetDirectoryName(personNameDirectory);
|
||||
personNameDirectoryName = Path.GetFileName(personNameDirectory);
|
||||
personKeyFormattedDirectory = Path.GetDirectoryName(yearDirectory);
|
||||
@ -196,7 +202,7 @@ internal abstract class RelationLogic
|
||||
_ = 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)
|
||||
@ -254,7 +260,7 @@ internal abstract class RelationLogic
|
||||
_ = 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\", } } }";
|
||||
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);
|
||||
@ -422,7 +428,7 @@ internal abstract class RelationLogic
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
||||
relationContainers = distance.GetRelationContainers(configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
|
||||
relationContainers = distance.GetRelationContainers(configuration.DistanceLimits, configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
|
||||
movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers);
|
||||
WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles);
|
||||
}
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>f89b7242-dbb0-4349-b950-657eb8cf87ef</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Metadata.Query</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Metadata</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,7 +34,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -16,16 +16,24 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
private readonly bool _PropertiesChangedForMetadata;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly bool _ForceMetadataLastWriteTimeToCreationTime;
|
||||
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
|
||||
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||
|
||||
public B_Metadata(IPropertyConfiguration propertyConfiguration)
|
||||
{
|
||||
_PropertiesChangedForMetadata = false;
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_ForceMetadataLastWriteTimeToCreationTime = false;
|
||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]);
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [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();
|
||||
}
|
||||
}
|
||||
|
||||
public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory)
|
||||
@ -33,8 +41,16 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_PropertiesChangedForMetadata = propertiesChangedForMetadata;
|
||||
_ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime;
|
||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
_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();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -43,12 +59,34 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && System.IO.Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ExifDirectory GetMetadataCollection(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem)
|
||||
{
|
||||
ExifDirectory? result = null;
|
||||
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.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"));
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
|
||||
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||
FileInfo fileInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, fileInfo);
|
||||
if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
|
@ -484,7 +484,7 @@ internal abstract class Exif
|
||||
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.AviDirectory[] aviDirectories = GetAviDirectories(directories);
|
||||
@ -502,12 +502,12 @@ internal abstract class Exif
|
||||
result = new(aviDirectories,
|
||||
exifBaseDirectories,
|
||||
fileMetadataDirectories,
|
||||
filePath,
|
||||
gifHeaderDirectories,
|
||||
gpsDirectories,
|
||||
size?.Height,
|
||||
jpegDirectories,
|
||||
makernoteDirectories,
|
||||
filePath.Name,
|
||||
photoshopDirectories,
|
||||
pngDirectories,
|
||||
quickTimeMovieHeaderDirectories,
|
||||
@ -520,13 +520,13 @@ internal abstract class Exif
|
||||
internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath)
|
||||
{
|
||||
Shared.Models.ExifDirectory result;
|
||||
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
||||
System.Drawing.Size? size;
|
||||
try
|
||||
{ size = Dimensions.GetDimensions(filePath.FullName); }
|
||||
catch (Exception)
|
||||
{ size = null; }
|
||||
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
||||
result = Covert(filePath, size, directories);
|
||||
result = Covert(filePath, directories, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>fa06c6db-0226-42ca-8728-68b1e336184d</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Mirror.Length</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -193,6 +193,7 @@ public class MirrorLength
|
||||
{
|
||||
string message = nameof(MirrorLength);
|
||||
List<(string, string, int)> collectionForMarkDown;
|
||||
logger?.LogDebug("{method}", nameof(MirrorLengthFilesInDirectories));
|
||||
bool inPlaceSave = _PropertyConfiguration.RootDirectory.First() == _AppSettings.Destination;
|
||||
if (!inPlaceSave)
|
||||
collectionForMarkDown = [];
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>ce31220e-ef92-4e68-89c5-91b027a94dca</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Move.By.Id</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -115,7 +115,7 @@ public class MoveById
|
||||
progressBar.Tick();
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
|
||||
filePath = FilePath.Get(_Configuration.PropertyConfiguration, fileHolder, index: null);
|
||||
if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryName is null)
|
||||
if (fileHolder.ExtensionLowered == ".id" || fileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (allFiles.Contains($"{fileHolder.FullName}.id"))
|
||||
continue;
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>ae069946-d0c0-4e4f-94f6-9c526e4ae4e7</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Offset.Date.Time.Original</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -216,6 +216,17 @@ public class OffsetDateTimeOriginal
|
||||
{
|
||||
TimeSpan timeSpan = new(targetDateTimeOriginal.Value.Ticks - badDateTimeOriginal.Value.Ticks);
|
||||
DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, timeSpan.Ticks);
|
||||
// DateTime a = new(2020, 01, 04, 02, 12, 51, 32);
|
||||
// // DateTime a = new(2020, 01, 05, 18, 17, 15, 97);
|
||||
// DateTime b = new(2020, 01, 05, 19, 52, 30, 17);
|
||||
// DateTime c = new(2024, 12, 07, 11, 19, 06, 13);
|
||||
// // DateTime d = new(2024, 12, 07, 12, 07, 30, 38);
|
||||
// long e = new DateTime(c.Ticks - b.Ticks).AddMinutes(-5).Ticks;
|
||||
// if (a != DateTime.MinValue)
|
||||
// minimumDateTime = a.AddTicks(e).AddHours(-1);
|
||||
// if (c != DateTime.MinValue)
|
||||
// maximumDateTime = c;
|
||||
// DateFix(sourceDirectory, asciiEncoding, checkDirectory, minimumDateTime, maximumDateTime, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ public class F_PhotoPrism
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, ReadOnlyCollection<Face> distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic)
|
||||
public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, ReadOnlyCollection<Face> distinctValidImageFaces, Shared.Models.Methods.IMapLogic mapLogic)
|
||||
{
|
||||
string file;
|
||||
string text;
|
||||
@ -189,7 +189,7 @@ public class F_PhotoPrism
|
||||
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
|
||||
(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection;
|
||||
List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)> collection = [];
|
||||
foreach (Face face in distinctFilteredFaces)
|
||||
foreach (Face face in distinctValidImageFaces)
|
||||
{
|
||||
collection.Clear();
|
||||
wholePercentages = face.Mapping?.MappingFromLocation?.WholePercentages;
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.PhotoPrism</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -37,7 +37,7 @@
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.PrepareForOld</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Property.Compare</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,8 +34,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<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" />
|
||||
|
@ -22,19 +22,27 @@ public class A_Property
|
||||
private readonly Configuration _Configuration;
|
||||
private readonly List<string> _AngleBracketCollection;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||
|
||||
public A_Property(int maxDegreeOfParallelism, Configuration propertyConfiguration, string outputExtension, bool reverse, string aResultsFullGroupDirectory)
|
||||
{
|
||||
Reverse = reverse;
|
||||
_ExceptionsDirectories = [];
|
||||
_AngleBracketCollection = [];
|
||||
_OutputExtension = outputExtension;
|
||||
_ASCIIEncoding = new ASCIIEncoding();
|
||||
_Configuration = propertyConfiguration;
|
||||
_AngleBracketCollection = [];
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_MaxDegreeOfParallelism = maxDegreeOfParallelism;
|
||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, aResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]);
|
||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, aResultsFullGroupDirectory, [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();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -43,6 +51,25 @@ public class A_Property
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension)
|
||||
{
|
||||
Shared.Models.Property? result;
|
||||
@ -57,8 +84,11 @@ public class A_Property
|
||||
fileInfo = new(Path.Combine(angleBracket.Replace("<>", _PropertyConfiguration.ResultSingleton), $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"));
|
||||
else
|
||||
{
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, item.FilePath);
|
||||
fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"));
|
||||
string fileName = $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json";
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, item.FilePath);
|
||||
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||
fileInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, fileInfo);
|
||||
}
|
||||
List<DateTime> dateTimes = (from l in sourceDirectoryFileTuples where l is not null && changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
@ -168,7 +198,7 @@ public class A_Property
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
if (!anyNullOrNoIsUniqueFileName)
|
||||
_AngleBracketCollection.AddRange(new[] { Path.Combine(aResultsFullGroupDirectory, "<>") });
|
||||
_AngleBracketCollection.AddRange([Path.Combine(aResultsFullGroupDirectory, "<>")]);
|
||||
else
|
||||
_AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration,
|
||||
sourceDirectory,
|
||||
@ -209,7 +239,7 @@ public class A_Property
|
||||
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
}
|
||||
|
||||
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container container, List<Item> items, string message)
|
||||
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container container, ReadOnlyCollection<Item> items, string message)
|
||||
{
|
||||
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
@ -277,9 +307,9 @@ public class A_Property
|
||||
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
|
||||
if (!angleBracketCollectionAny)
|
||||
{
|
||||
if (item.FilePath.DirectoryName is null)
|
||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryName));
|
||||
SetAngleBracketCollection(item.FilePath.DirectoryName, !item.IsUniqueFileName);
|
||||
if (item.FilePath.DirectoryFullPath is null)
|
||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryFullPath));
|
||||
SetAngleBracketCollection(item.FilePath.DirectoryFullPath, !item.IsUniqueFileName);
|
||||
}
|
||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
||||
result = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
||||
|
@ -28,9 +28,11 @@ public class Configuration
|
||||
public int? ResultAllInOneSubdirectoryLength { get; set; }
|
||||
public string? ResultCollection { get; set; }
|
||||
public string? ResultContent { get; set; }
|
||||
public string? ResultContentCollection { get; set; }
|
||||
public string? ResultSingleton { get; set; }
|
||||
public string? RootDirectory { get; set; }
|
||||
public string[]? ValidImageFormatExtensions { get; set; }
|
||||
public string[]? ValidVideoFormatExtensions { get; set; }
|
||||
public string[]? VerifyToSeason { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
@ -81,9 +83,11 @@ public class Configuration
|
||||
if (configuration.ResultAllInOneSubdirectoryLength is null) throw new NullReferenceException(nameof(configuration.ResultAllInOneSubdirectoryLength));
|
||||
if (configuration.ResultCollection is null) throw new NullReferenceException(nameof(configuration.ResultCollection));
|
||||
if (configuration.ResultContent is null) throw new NullReferenceException(nameof(configuration.ResultContent));
|
||||
if (configuration.ResultContentCollection is null) throw new NullReferenceException(nameof(configuration.ResultContentCollection));
|
||||
if (configuration.ResultSingleton is null) throw new NullReferenceException(nameof(configuration.ResultSingleton));
|
||||
if (configuration.RootDirectory is null) throw new NullReferenceException(nameof(configuration.RootDirectory));
|
||||
if (configuration.ValidImageFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidImageFormatExtensions));
|
||||
if (configuration.ValidVideoFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidVideoFormatExtensions));
|
||||
// if (configuration.VerifyToSeason is null) throw new NullReferenceException(nameof(configuration.VerifyToSeason));
|
||||
result = new(configuration.DateGroup,
|
||||
configuration.FileNameDirectorySeparator,
|
||||
@ -106,9 +110,11 @@ public class Configuration
|
||||
configuration.ResultAllInOneSubdirectoryLength.Value,
|
||||
configuration.ResultCollection,
|
||||
configuration.ResultContent,
|
||||
configuration.ResultContentCollection,
|
||||
configuration.ResultSingleton,
|
||||
Path.GetFullPath(configuration.RootDirectory),
|
||||
configuration.ValidImageFormatExtensions,
|
||||
configuration.ValidVideoFormatExtensions,
|
||||
configuration.VerifyToSeason ?? []);
|
||||
return result;
|
||||
}
|
||||
|
@ -31,8 +31,10 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration
|
||||
public int ResultAllInOneSubdirectoryLength { init; get; }
|
||||
public string ResultCollection { init; get; }
|
||||
public string ResultContent { init; get; }
|
||||
public string ResultContentCollection { init; get; }
|
||||
public string ResultSingleton { init; get; }
|
||||
public string[] ValidImageFormatExtensions { init; get; }
|
||||
public string[] ValidVideoFormatExtensions { init; get; }
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(string dateGroup,
|
||||
@ -56,9 +58,11 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration
|
||||
int resultAllInOneSubdirectoryLength,
|
||||
string resultCollection,
|
||||
string resultContent,
|
||||
string resultContentCollection,
|
||||
string resultSingleton,
|
||||
string rootDirectory,
|
||||
string[] validImageFormatExtensions,
|
||||
string[] validVideoFormatExtensions,
|
||||
string[] verifyToSeason)
|
||||
{
|
||||
DateGroup = dateGroup;
|
||||
@ -82,9 +86,11 @@ public class Configuration : Shared.Models.Properties.IPropertyConfiguration
|
||||
ResultAllInOneSubdirectoryLength = resultAllInOneSubdirectoryLength;
|
||||
ResultCollection = resultCollection;
|
||||
ResultContent = resultContent;
|
||||
ResultContentCollection = resultContentCollection;
|
||||
ResultSingleton = resultSingleton;
|
||||
_RootDirectory = rootDirectory;
|
||||
ValidImageFormatExtensions = validImageFormatExtensions;
|
||||
ValidVideoFormatExtensions = validVideoFormatExtensions;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Property</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -40,10 +40,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<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" />
|
||||
|
@ -20,7 +20,7 @@ public class Rename
|
||||
bool IsIgnoreExtension,
|
||||
bool IsValidImageFormatExtension,
|
||||
List<FileHolder> FileHolders,
|
||||
bool FfmpegFilesPresent,
|
||||
bool FastForwardMovingPictureExpertsGroupFilesPresent,
|
||||
DateTime? DateTimeOriginal,
|
||||
DateTime[] DateTimes,
|
||||
int? Id);
|
||||
@ -218,11 +218,11 @@ public class Rename
|
||||
FilePath filePath;
|
||||
DateTime[] dateTimes;
|
||||
FileHolder fileHolder;
|
||||
string[]? ffmpegFiles;
|
||||
bool isIgnoreExtension;
|
||||
DateTime? dateTimeOriginal;
|
||||
bool isValidImageFormatExtension;
|
||||
ASCIIEncoding asciiEncoding = new();
|
||||
string[]? fastForwardMovingPictureExpertsGroupFiles;
|
||||
IReadOnlyList<MetadataExtractor.Directory> directories;
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
@ -234,7 +234,7 @@ public class Rename
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
continue;
|
||||
filePath = FilePath.Get(_Configuration.PropertyConfiguration, fileHolder, index: i);
|
||||
if (fileHolder.ExtensionLowered == ".paddedId" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
|
||||
if (fileHolder.ExtensionLowered == ".paddedId" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (files.Contains($"{fileHolder.FullName}.paddedId"))
|
||||
continue;
|
||||
@ -243,7 +243,7 @@ public class Rename
|
||||
isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered);
|
||||
isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered);
|
||||
if (!isIgnoreExtension && isValidImageFormatExtension)
|
||||
ffmpegFiles = null;
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
else
|
||||
{
|
||||
try
|
||||
@ -251,33 +251,33 @@ public class Rename
|
||||
catch (Exception) { continue; }
|
||||
CommandTask<CommandResult> result = Cli.Wrap("ffmpeg.exe")
|
||||
// .WithArguments(new[] { "-ss", "00:00:00", "-t", "00:00:00", "-i", files[i], "-qscale:v", "2", "-r", "0.01", $"{fileHolder.Name}-%4d.jpg" })
|
||||
.WithArguments(new[] { "-i", files[i], "-vframes", "1", $"{fileHolder.Name}-%4d.jpg" })
|
||||
.WithWorkingDirectory(fileHolder.DirectoryName)
|
||||
.WithArguments(["-i", files[i], "-vframes", "1", $"{fileHolder.Name}-%4d.jpg"])
|
||||
.WithWorkingDirectory(fileHolder.DirectoryFullPath)
|
||||
.ExecuteAsync();
|
||||
result.Task.Wait();
|
||||
ffmpegFiles = Directory.GetFiles(fileHolder.DirectoryName, $"{fileHolder.Name}-*.jpg", SearchOption.TopDirectoryOnly);
|
||||
if (ffmpegFiles.Length == 0)
|
||||
fastForwardMovingPictureExpertsGroupFiles = Directory.GetFiles(fileHolder.DirectoryFullPath, $"{fileHolder.Name}-*.jpg", SearchOption.TopDirectoryOnly);
|
||||
if (fastForwardMovingPictureExpertsGroupFiles.Length == 0)
|
||||
continue;
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(ffmpegFiles.First());
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(fastForwardMovingPictureExpertsGroupFiles.First());
|
||||
if (!fileHolder.Name.EndsWith("-0001.jpg"))
|
||||
throw new Exception();
|
||||
isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered);
|
||||
isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered);
|
||||
if (isIgnoreExtension || !isValidImageFormatExtension)
|
||||
continue;
|
||||
if (fileHolder.DirectoryName is null)
|
||||
if (fileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
}
|
||||
(dateTimeOriginal, dateTimes, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration, _PropertyConfiguration.PopulatePropertyId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
if (ffmpegFiles is not null)
|
||||
if (fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(files[i]);
|
||||
foreach (string ffmpegFile in ffmpegFiles)
|
||||
File.Delete(ffmpegFile);
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (message is not null)
|
||||
throw new Exception(message);
|
||||
results.Add(new(i + offset, isIgnoreExtension, isValidImageFormatExtension, [fileHolder], ffmpegFiles is null, dateTimeOriginal, dateTimes, id));
|
||||
results.Add(new(i + offset, isIgnoreExtension, isValidImageFormatExtension, [fileHolder], fastForwardMovingPictureExpertsGroupFiles is null, dateTimeOriginal, dateTimes, id));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@ -311,7 +311,7 @@ public class Rename
|
||||
fileHolder = record.FileHolders.First();
|
||||
if (!fileHolder.Exists)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(fileHolder.DirectoryName))
|
||||
if (string.IsNullOrEmpty(fileHolder.DirectoryFullPath))
|
||||
continue;
|
||||
dateTimeFromName = record.DateTimes.Length == 0 ? null : record.DateTimes.First();
|
||||
if (fileHolder.ExtensionLowered == jpeg)
|
||||
@ -320,30 +320,30 @@ public class Rename
|
||||
{
|
||||
if (File.Exists($"{fileHolder.FullName}.paddedId"))
|
||||
{
|
||||
checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.paddedId");
|
||||
checkFile = Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension}{jpg}.paddedId");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (distinct.Contains(checkFile))
|
||||
continue;
|
||||
distinct.Add(checkFile);
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName}.paddedId"), fileHolder.DirectoryName, checkFile));
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName}.paddedId"), fileHolder.DirectoryFullPath, checkFile));
|
||||
}
|
||||
checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}");
|
||||
checkFile = Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension}{jpg}");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (distinct.Contains(checkFile))
|
||||
continue;
|
||||
distinct.Add(checkFile);
|
||||
results.Add(new(fileHolder, fileHolder.DirectoryName, checkFile));
|
||||
results.Add(new(fileHolder, fileHolder.DirectoryFullPath, checkFile));
|
||||
if (nefPresent)
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryName, $"{checkFile[..^4]}.tif"));
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryFullPath, $"{checkFile[..^4]}.tif"));
|
||||
if (nefPresent)
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryName, $"{checkFile[..^4]}.nef"));
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryFullPath, $"{checkFile[..^4]}.nef"));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(fileHolder.FullName, checkFile);
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(checkFile);
|
||||
if (fileHolder.DirectoryName is null)
|
||||
if (fileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -361,13 +361,13 @@ public class Rename
|
||||
if (timeSpan is null || timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_AppSettings.DefaultUnknownDirectoryName))
|
||||
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : fileHolder.DirectoryName);
|
||||
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : fileHolder.DirectoryFullPath);
|
||||
else
|
||||
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : Path.Combine(fileHolder.DirectoryName, _AppSettings.DefaultUnknownDirectoryName));
|
||||
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : Path.Combine(fileHolder.DirectoryFullPath, _AppSettings.DefaultUnknownDirectoryName));
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryName = Path.GetFileName(fileHolder.DirectoryName);
|
||||
directoryName = Path.GetFileName(fileHolder.DirectoryFullPath);
|
||||
directoryNameSegments = directoryName.Split(' ');
|
||||
if (dateTimeFromName is null)
|
||||
isWrongYear = null;
|
||||
@ -375,7 +375,7 @@ public class Rename
|
||||
(isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(directoryNameSegments, dateTimeFromName.Value.ToString("yyyy"));
|
||||
dateTime = minimumDateTime.Value.AddTicks(timeSpan.Value.Ticks);
|
||||
(season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
seasonDirectory = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Year}.{season} {seasonName}");
|
||||
seasonDirectory = Path.Combine(fileHolder.DirectoryFullPath, $"{dateTime.Year}.{season} {seasonName}");
|
||||
}
|
||||
if (seasonDirectory is null || (isWrongYear is not null && isWrongYear.Value))
|
||||
{
|
||||
@ -386,23 +386,23 @@ public class Rename
|
||||
if (minimumDateTime is null)
|
||||
continue;
|
||||
checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
|
||||
checkFile = Path.Combine(fileHolder.DirectoryName, $"{minimumDateTime.Value:yyyy-MM-dd}.{minimumDateTime.Value.Ticks}.{fileHolder.Length}{checkFileExtension}");
|
||||
checkFile = Path.Combine(fileHolder.DirectoryFullPath, $"{minimumDateTime.Value:yyyy-MM-dd}.{minimumDateTime.Value.Ticks}.{fileHolder.Length}{checkFileExtension}");
|
||||
if (checkFile == fileHolder.FullName)
|
||||
continue;
|
||||
if (distinct.Contains(checkFile))
|
||||
continue;
|
||||
distinct.Add(checkFile);
|
||||
results.Add(new(fileHolder, fileHolder.DirectoryName, checkFile));
|
||||
results.Add(new(fileHolder, fileHolder.DirectoryFullPath, checkFile));
|
||||
if (nefPresent)
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryName, $"{checkFile[..^4]}.tif"));
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryFullPath, $"{checkFile[..^4]}.tif"));
|
||||
if (nefPresent)
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryName, $"{checkFile[..^4]}.nef"));
|
||||
results.Add(new(Shared.Models.Stateless.Methods.IFileHolder.Get($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryFullPath, $"{checkFile[..^4]}.nef"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (record.Id is null)
|
||||
continue;
|
||||
paddedId = IId.GetPaddedId(_PropertyConfiguration, record.Id.Value, ignore: null, record.Index);
|
||||
paddedId = IId.GetPaddedId(_PropertyConfiguration, record.Id.Value, hasIgnoreKeyword: null, hasDateTimeOriginal: null, record.Index);
|
||||
checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
|
||||
checkFile = Path.Combine(seasonDirectory, $"{paddedId}{checkFileExtension}");
|
||||
if (checkFile == fileHolder.FullName)
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>6e026d2f-9edf-4c6c-a042-162758114e9a</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Rename</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,11 +34,11 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.6.6" />
|
||||
<PackageReference Include="CliWrap" Version="3.8.1" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
|
@ -37,14 +37,13 @@ public class C_Resize
|
||||
private readonly int _OutputResolutionHeightIndex;
|
||||
private readonly EncoderParameters _EncoderParameters;
|
||||
private readonly int _OutputResolutionOrientationIndex;
|
||||
private readonly Dictionary<string, string[]> _FileGroups;
|
||||
private readonly bool _ForceResizeLastWriteTimeToCreationTime;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||
|
||||
public C_Resize(IPropertyConfiguration propertyConfiguration, bool forceResizeLastWriteTimeToCreationTime, bool overrideForResizeImages, bool propertiesChangedForResize, string[] validResolutions, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension)
|
||||
{
|
||||
_FileGroups = [];
|
||||
_Original = "Original";
|
||||
_TempResolutionWidth = 3;
|
||||
_TempResolutionHeight = 4;
|
||||
@ -61,6 +60,7 @@ public class C_Resize
|
||||
_OverrideForResizeImages = overrideForResizeImages;
|
||||
_PropertiesChangedForResize = propertiesChangedForResize;
|
||||
_ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime;
|
||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
||||
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
||||
_ConstructorInfo = constructorInfo;
|
||||
@ -74,10 +74,14 @@ public class C_Resize
|
||||
|
||||
public void Update(string cResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, string[]> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, [_PropertyConfiguration.ResultSingleton]);
|
||||
foreach (KeyValuePair<string, string[]> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, [_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();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAngleBracketCollection(string cResultsFullGroupDirectory, string sourceDirectory)
|
||||
@ -94,11 +98,12 @@ public class C_Resize
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetGifLowQuality()
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetJpegLowQuality()
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
ImageFormat imageFormat = ImageFormat.Gif;
|
||||
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
|
||||
ImageFormat imageFormat = ImageFormat.Jpeg;
|
||||
ImageCodecInfo[] imageCodecInfoCollection = ImageCodecInfo.GetImageEncoders();
|
||||
ImageCodecInfo imageCodecInfo = (from l in imageCodecInfoCollection where l.FormatID == imageFormat.Guid select l).First();
|
||||
EncoderParameters encoderParameters = new(1);
|
||||
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L);
|
||||
if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension))
|
||||
@ -111,7 +116,8 @@ public class C_Resize
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
ImageFormat imageFormat = ImageFormat.Png;
|
||||
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
|
||||
ImageCodecInfo[] imageCodecInfoCollection = ImageCodecInfo.GetImageEncoders();
|
||||
ImageCodecInfo imageCodecInfo = (from l in imageCodecInfoCollection where l.FormatID == imageFormat.Guid select l).First();
|
||||
EncoderParameters encoderParameters = new(1);
|
||||
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L);
|
||||
if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension))
|
||||
@ -135,7 +141,8 @@ public class C_Resize
|
||||
".tiff" => ImageFormat.Tiff,
|
||||
_ => throw new Exception(),
|
||||
};
|
||||
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
|
||||
ImageCodecInfo[] imageCodecInfoCollection = ImageCodecInfo.GetImageEncoders();
|
||||
ImageCodecInfo imageCodecInfo = (from l in imageCodecInfoCollection where l.FormatID == imageFormat.Guid select l).First();
|
||||
EncoderParameters encoderParameters = new(1);
|
||||
// encoderParameters.Param[0] = New EncoderParameter(Encoder.Quality, CType(75L, Int32)) 'Default
|
||||
// encoderParameters.Param[0] = New EncoderParameter(Encoder.Quality, CType(95L, Int32)) 'Paint
|
||||
@ -424,8 +431,8 @@ public class C_Resize
|
||||
result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), fileName));
|
||||
else
|
||||
{
|
||||
(string directoryName, _) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, directoryName, fileName));
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(cResultsFullGroupDirectory, _PropertyConfiguration.ResultContent, cei.Combined, fileName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -436,14 +443,36 @@ public class C_Resize
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, int id) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, $"{id}{item.FilePath.ExtensionLowered}");
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, int[]> GetResizeKeyValuePairs(Configuration configuration, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem)
|
||||
{
|
||||
Dictionary<string, int[]>? results;
|
||||
string json;
|
||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata)];
|
||||
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.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"));
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
|
||||
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||
FileInfo fileInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, fileInfo);
|
||||
if (_ForceResizeLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
|
@ -4,12 +4,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Resize</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,8 +34,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<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" />
|
||||
|
@ -34,17 +34,15 @@ public class Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.Configuration Get(Configuration? configuration)
|
||||
private static Models.Configuration Get(Configuration? configuration, Property.Models.Configuration propertyConfiguration)
|
||||
{
|
||||
Models.Configuration result;
|
||||
if (configuration is null) throw new NullReferenceException(nameof(configuration));
|
||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||
if (configuration.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat));
|
||||
if (configuration.PropertyConfiguration is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration));
|
||||
result = new(
|
||||
result = new(propertyConfiguration,
|
||||
configuration.IgnoreExtensions,
|
||||
configuration.PersonBirthdayFormat,
|
||||
configuration.PropertyConfiguration);
|
||||
configuration.PersonBirthdayFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ public class Configuration
|
||||
#pragma warning restore IL3050, IL2026
|
||||
}
|
||||
PreVerify(configurationRoot, configuration);
|
||||
result = Get(configuration);
|
||||
result = Get(configuration, propertyConfiguration);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public class Configuration
|
||||
public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration;
|
||||
|
||||
[JsonConstructor]
|
||||
public Configuration(
|
||||
public Configuration(Property.Models.Configuration propertyConfiguration,
|
||||
string[] ignoreExtensions,
|
||||
string personBirthdayFormat,
|
||||
Property.Models.Configuration propertyConfiguration)
|
||||
string personBirthdayFormat)
|
||||
{
|
||||
IgnoreExtensions = ignoreExtensions;
|
||||
PersonBirthdayFormat = personBirthdayFormat;
|
||||
|
@ -4,13 +4,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>b3bbcc69-1439-4e86-9bbf-75c8e8839cc0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Set.Created.Date</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>8.0.101.1</Version>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
|
@ -21,8 +21,8 @@ public class SetCreatedDate
|
||||
private readonly Configuration _Configuration;
|
||||
private readonly IsEnvironment _IsEnvironment;
|
||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||
private readonly ReadOnlyDictionary<string, string[]> _FileGroups;
|
||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> _FileGroups;
|
||||
|
||||
public SetCreatedDate(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
|
||||
{
|
||||
@ -78,7 +78,7 @@ public class SetCreatedDate
|
||||
{
|
||||
progressBar.Tick();
|
||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
|
||||
if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
|
||||
if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
|
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record CombinedEnumAndIndex(string Combined,
|
||||
byte Enum,
|
||||
int Index)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, CombinedEnumAndIndexSourceGenerationContext.Default.CombinedEnumAndIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(CombinedEnumAndIndex))]
|
||||
internal partial class CombinedEnumAndIndexSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record Container(string SourceDirectory, List<Item> Items)
|
||||
public record Container(string SourceDirectory, ReadOnlyCollection<Item> Items)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
|
@ -4,7 +4,7 @@ namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record Datum(
|
||||
[property: JsonPropertyName("accessRuleIds")] IReadOnlyList<object> AccessRuleIds,
|
||||
[property: JsonPropertyName("childAssetTypeInfo")] IReadOnlyList<object> ChildAssetTypeInfo,
|
||||
[property: JsonPropertyName("childAssetTyceinfo")] IReadOnlyList<object> ChildAssetTyceinfo,
|
||||
[property: JsonPropertyName("contentProperties")] ContentProperties ContentProperties,
|
||||
[property: JsonPropertyName("createdBy")] string CreatedBy,
|
||||
[property: JsonPropertyName("createdDate")] DateTime CreatedDate,
|
||||
|
@ -6,12 +6,12 @@ namespace View_by_Distance.Shared.Models;
|
||||
public record ExifDirectory(AviDirectory[] AviDirectories,
|
||||
ExifDirectoryBase[] ExifBaseDirectories,
|
||||
FileMetadataDirectory[] FileMetadataDirectories,
|
||||
FilePath FilePath,
|
||||
GifHeaderDirectory[] GifHeaderDirectories,
|
||||
GpsDirectory[] GpsDirectories,
|
||||
int? Height,
|
||||
JpegDirectory[] JpegDirectories,
|
||||
MakernoteDirectory[] MakernoteDirectories,
|
||||
string OriginalFileName,
|
||||
PhotoshopDirectory[] PhotoshopDirectories,
|
||||
PngDirectory[] PngDirectories,
|
||||
QuickTimeMovieHeaderDirectory[] QuickTimeMovieHeaderDirectories,
|
||||
|
@ -40,8 +40,14 @@ public record class FaceDistance : Properties.IFaceDistance
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
string result = JsonSerializer.Serialize(this, FaceDistanceSourceGenerationContext.Default.FaceDistance);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(FaceDistance))]
|
||||
internal partial class FaceDistanceSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -1,27 +1,11 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public class FaceEncoding : Properties.IFaceEncoding
|
||||
public record FaceEncoding(double[] RawEncoding, int Size);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = false)]
|
||||
[JsonSerializable(typeof(FaceEncoding))]
|
||||
public partial class FaceEncodingGenerationContext : JsonSerializerContext
|
||||
{
|
||||
|
||||
protected double[] _RawEncoding;
|
||||
protected int _Size;
|
||||
public double[] RawEncoding => _RawEncoding;
|
||||
public int Size => _Size;
|
||||
|
||||
[JsonConstructor]
|
||||
public FaceEncoding(double[] rawEncoding, int size)
|
||||
{
|
||||
_RawEncoding = rawEncoding;
|
||||
_Size = size;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -4,11 +4,13 @@ namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record FaceFile(int? AreaPermyriad,
|
||||
int? ConfidencePercent,
|
||||
DateTime DateTime,
|
||||
string? DMS,
|
||||
DateTime DateTime,
|
||||
FaceEncoding? FaceEncoding,
|
||||
Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts,
|
||||
Location? Location,
|
||||
string? Maker,
|
||||
MappingFromPerson? MappingFromPerson,
|
||||
string? Model,
|
||||
OutputResolution? OutputResolution);
|
||||
|
||||
@ -17,3 +19,15 @@ public record FaceFile(int? AreaPermyriad,
|
||||
public partial class FaceFileGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[JsonSerializable(typeof(FaceFile[]))]
|
||||
public partial class FaceFileCollectionGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[JsonSerializable(typeof(FaceFile[]))]
|
||||
public partial class FaceFileCollectionWriteIndentedGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -1,58 +1,35 @@
|
||||
using System.Drawing;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public class FacePoint : Properties.IFacePoint
|
||||
[method: JsonConstructor]
|
||||
public class FacePoint(int index, int x, int y) : Properties.IFacePoint
|
||||
{
|
||||
public int Index { get; } = index;
|
||||
public int X { get; } = x;
|
||||
public int Y { get; } = y;
|
||||
|
||||
protected int _Index;
|
||||
protected int _X;
|
||||
protected int _Y;
|
||||
public int Index => _Index;
|
||||
public int X => _X;
|
||||
public int Y => _Y;
|
||||
|
||||
private readonly Point _Point;
|
||||
|
||||
[JsonConstructor]
|
||||
public FacePoint(int index, int x, int y)
|
||||
{
|
||||
_Index = index;
|
||||
_X = x;
|
||||
_Y = y;
|
||||
_Point = new(x, y);
|
||||
}
|
||||
|
||||
public FacePoint(Point point, int index) :
|
||||
this(index, point.X, point.Y)
|
||||
{ }
|
||||
private readonly Point _Point = new(x, y);
|
||||
|
||||
public override bool Equals(object? obj) => obj is FacePoint point && Equals(point);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0070
|
||||
public override int GetHashCode()
|
||||
#pragma warning restore IDE0070
|
||||
{
|
||||
int hashCode = 1861411795;
|
||||
hashCode = hashCode * -1521134295 + _Point.GetHashCode();
|
||||
hashCode = hashCode * -1521134295 + _Index.GetHashCode();
|
||||
hashCode = (hashCode * -1521134295) + _Point.GetHashCode();
|
||||
hashCode = (hashCode * -1521134295) + Index.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public bool Equals(FacePoint? facePoint)
|
||||
{
|
||||
return facePoint is not null
|
||||
&& _X == facePoint.X
|
||||
&& _Y == facePoint.Y
|
||||
&& _Index == facePoint.Index;
|
||||
&& X == facePoint.X
|
||||
&& Y == facePoint.Y
|
||||
&& Index == facePoint.Index;
|
||||
}
|
||||
|
||||
public static bool operator ==(FacePoint point1, FacePoint point2) => point1.Equals(point2);
|
||||
|
@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record FileHolder(DateTime? CreationTime,
|
||||
string? DirectoryName,
|
||||
string? DirectoryFullPath,
|
||||
bool Exists,
|
||||
string ExtensionLowered,
|
||||
string FullName,
|
||||
@ -20,22 +20,8 @@ public record FileHolder(DateTime? CreationTime,
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FileHolder Get(FileInfo fileInfo)
|
||||
{
|
||||
FileHolder result;
|
||||
if (!fileInfo.Exists)
|
||||
result = new(null,
|
||||
fileInfo.DirectoryName,
|
||||
fileInfo.Exists,
|
||||
fileInfo.Extension.ToLower(),
|
||||
fileInfo.FullName,
|
||||
null,
|
||||
null,
|
||||
fileInfo.Name,
|
||||
Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
||||
else
|
||||
{
|
||||
result = new(fileInfo.CreationTime,
|
||||
private static FileHolder GetExisting(FileInfo fileInfo) =>
|
||||
new(fileInfo.CreationTime,
|
||||
fileInfo.DirectoryName,
|
||||
fileInfo.Exists,
|
||||
fileInfo.Extension.ToLower(),
|
||||
@ -44,15 +30,26 @@ public record FileHolder(DateTime? CreationTime,
|
||||
fileInfo.Length,
|
||||
fileInfo.Name,
|
||||
Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static FileHolder GetNonExisting(FileInfo fileInfo) =>
|
||||
new(null,
|
||||
fileInfo.DirectoryName,
|
||||
fileInfo.Exists,
|
||||
fileInfo.Extension.ToLower(),
|
||||
fileInfo.FullName,
|
||||
null,
|
||||
null,
|
||||
fileInfo.Name,
|
||||
Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
||||
|
||||
public static FileHolder Get(FileInfo fileInfo) =>
|
||||
fileInfo.Exists ? GetExisting(fileInfo) : GetNonExisting(fileInfo);
|
||||
|
||||
public static FileHolder Get(FilePath filePath)
|
||||
{
|
||||
FileHolder result;
|
||||
result = new(new(filePath.CreationTicks),
|
||||
filePath.DirectoryName,
|
||||
filePath.DirectoryFullPath,
|
||||
true,
|
||||
filePath.ExtensionLowered,
|
||||
filePath.FullName,
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
@ -5,12 +6,13 @@ using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record FilePath(long CreationTicks,
|
||||
string DirectoryName,
|
||||
string DirectoryFullPath,
|
||||
string ExtensionLowered,
|
||||
string FileNameFirstSegment,
|
||||
string FullName,
|
||||
int? Id,
|
||||
bool? IsIgnore,
|
||||
bool? HasIgnoreKeyword,
|
||||
bool? HasDateTimeOriginal,
|
||||
bool IsIntelligentIdFormat,
|
||||
long LastWriteTicks,
|
||||
long Length,
|
||||
@ -38,11 +40,12 @@ public record FilePath(long CreationTicks,
|
||||
int? sortOder;
|
||||
string fileNameFirstSegment = fileHolder.Name.Split('.')[0];
|
||||
int sortOrderOnlyLengthIndex = propertyConfiguration.Offset.ToString().Length;
|
||||
string fileDirectoryName = fileHolder.DirectoryName ?? throw new NullReferenceException();
|
||||
string fileDirectoryName = fileHolder.DirectoryFullPath ?? throw new NullReferenceException();
|
||||
bool isIntelligentIdFormat = IId.NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
|
||||
bool isPaddedIntelligentIdFormat = IId.NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||
bool fileNameFirstSegmentIsIdFormat = !isPaddedIntelligentIdFormat && !isIntelligentIdFormat && IId.NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder);
|
||||
bool? isIgnore = !isIntelligentIdFormat && !isPaddedIntelligentIdFormat ? null : fileNameFirstSegment[^1] is '2' or '8';
|
||||
bool? hasIgnoreKeyword = !isIntelligentIdFormat && !isPaddedIntelligentIdFormat ? null : fileNameFirstSegment[^1] is '2' or '8';
|
||||
bool? hasDateTimeOriginal = !isIntelligentIdFormat && !isPaddedIntelligentIdFormat ? null : fileNameFirstSegment[^1] is '1' or '9';
|
||||
if (!fileNameFirstSegmentIsIdFormat && !isIntelligentIdFormat && !isPaddedIntelligentIdFormat)
|
||||
(id, sortOder) = (null, null);
|
||||
else if (isIntelligentIdFormat)
|
||||
@ -70,7 +73,8 @@ public record FilePath(long CreationTicks,
|
||||
fileNameFirstSegment,
|
||||
fileHolder.FullName,
|
||||
id,
|
||||
isIgnore,
|
||||
hasIgnoreKeyword,
|
||||
hasDateTimeOriginal,
|
||||
isIntelligentIdFormat,
|
||||
fileHolder.LastWriteTime.Value.Ticks,
|
||||
fileHolder.Length.Value,
|
||||
@ -80,6 +84,33 @@ public record FilePath(long CreationTicks,
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> GetKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
||||
List<FilePath>? collection;
|
||||
Dictionary<int, List<FilePath>> keyValuePairs = [];
|
||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||
{
|
||||
if (filePaths.Count == 0)
|
||||
continue;
|
||||
foreach (FilePath filePath in filePaths)
|
||||
{
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||
{
|
||||
keyValuePairs.Add(filePath.Id.Value, []);
|
||||
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(filePath);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<int, List<FilePath>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user