Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
c7ded16e50 | |||
3f7affceef | |||
130e3b6528 | |||
d5fa108f81 | |||
d9d55d9e4c | |||
e728838d25 | |||
ac298166e9 | |||
0b793904b3 | |||
e053dd5746 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -470,4 +470,7 @@ globalStorage/
|
||||
Shared/.kanbn
|
||||
|
||||
.Immich/immich-assets.json
|
||||
Tests/.vscode/.UserSecrets/*
|
||||
Instance/.vscode/.UserSecrets/*
|
||||
Drag-Drop-Set-Property-Item/.vscode/.UserSecrets/*
|
||||
TestsWithFaceRecognitionDotNet/.vscode/.UserSecrets/*
|
||||
|
16
.vscode/mklink.md
vendored
16
.vscode/mklink.md
vendored
@ -13,3 +13,19 @@ 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"
|
||||
```
|
||||
|
||||
```bash 1742827407172 = 638784242071720000 = 2025-1.Spring = Mon Mar 24 2025 07:43:26 GMT-0700 (Mountain Standard Time)
|
||||
mkdir "L:\Git\View-by-Distance-MKLink-Console\Instance\.vscode"
|
||||
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Instance\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\2999dda1-5329-4d9f-9d68-cccfabe0e47f"
|
||||
mkdir "L:\Git\View-by-Distance-MKLink-Console\Tests\.vscode"
|
||||
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Tests\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\e8c3d25d-9715-4b35-9010-1cdc74840190"
|
||||
mkdir "L:\Git\View-by-Distance-MKLink-Console\TestsWithFaceRecognitionDotNet\.vscode"
|
||||
mklink /J "L:\Git\View-by-Distance-MKLink-Console\TestsWithFaceRecognitionDotNet\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\ecbdc76d-6037-4046-86a4-1a7626a3d342"
|
||||
mkdir "L:\Git\View-by-Distance-MKLink-Console\Drag-Drop-Set-Property-Item\.vscode"
|
||||
mklink /J "L:\Git\View-by-Distance-MKLink-Console\Drag-Drop-Set-Property-Item\.vscode\.UserSecrets" "C:\Users\mikep\AppData\Roaming\Microsoft\UserSecrets\c64a15ed-0ba3-4378-8f80-0c19d0531747"
|
||||
```
|
||||
|
80
.vscode/tasks.json
vendored
80
.vscode/tasks.json
vendored
@ -72,11 +72,7 @@
|
||||
"build",
|
||||
"${workspaceFolder}/Instance/Instance.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary",
|
||||
"/property:WarningLevel=0",
|
||||
"--verbosity",
|
||||
"quiet",
|
||||
"--no-restore"
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
@ -88,11 +84,7 @@
|
||||
"build",
|
||||
"${workspaceFolder}/Shared/View-by-Distance.Shared.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary",
|
||||
"/property:WarningLevel=0",
|
||||
"--verbosity",
|
||||
"quiet",
|
||||
"--no-restore"
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
@ -104,13 +96,71 @@
|
||||
"build",
|
||||
"${workspaceFolder}/Metadata/Metadata.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary",
|
||||
"/property:WarningLevel=0",
|
||||
"--verbosity",
|
||||
"quiet",
|
||||
"--no-restore"
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "buildTests",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/Tests/Tests.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "buildTestsWithFaceRecognitionDotNet",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "buildCopyDistinct",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/Copy-Distinct/Copy-Distinct.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "buildDragDropSetPropertyItem",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/Drag-Drop-Set-Property-Item/Drag-Drop-Set-Property-Item.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
||||
"type": "shell",
|
||||
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
||||
"args": [
|
||||
"s",
|
||||
"X",
|
||||
"L:/Git/View-by-Distance-MKLink-Console",
|
||||
"Day-Helper-2025-03-20",
|
||||
"false",
|
||||
"4"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -11,20 +11,28 @@ public class C2_BlurHasher : IBlurHasher
|
||||
{
|
||||
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
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, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, resultsFullGroupDirectory, [_PropertyConfiguration.ResultContent, _PropertyConfiguration.ResultSingleton]);
|
||||
foreach (KeyValuePair<string, ReadOnlyCollection<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();
|
||||
|
@ -160,7 +160,7 @@ public class Compare
|
||||
}
|
||||
if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId)
|
||||
throw new Exception("Copy keyValuePairs-####.json file");
|
||||
(int j, int f, int t, Shared.Models.Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
|
||||
(int j, int f, int t, Shared.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
|
||||
if (propertyLogic.ExceptionsDirectories.Any())
|
||||
throw new Exception();
|
||||
if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers))
|
||||
@ -242,6 +242,53 @@ public class Compare
|
||||
_ = Directory.CreateDirectory(currentYearDirectory);
|
||||
}
|
||||
|
||||
private static void Verify(Models.Configuration configuration)
|
||||
{
|
||||
if (configuration.Spelling is null || !configuration.Spelling.Any())
|
||||
throw new NullReferenceException(nameof(configuration.Spelling));
|
||||
}
|
||||
|
||||
private A_Property GetPropertyLogic(bool reverse, string outputExtension, Map.Models.MapLogic mapLogic)
|
||||
{
|
||||
A_Property result;
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse);
|
||||
string fromPrepareForOld = "34720-637858334555170379.tsv";
|
||||
string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld);
|
||||
if (File.Exists(fromPrepareForOldFile))
|
||||
{
|
||||
string[] lines;
|
||||
string[] columns;
|
||||
List<string> debug = new();
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
lines = File.ReadAllLines(fromPrepareForOldFile);
|
||||
string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory}-Results";
|
||||
int[]? zeros = (from l in mapLogic.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray();
|
||||
lines = (from l in mapLogic.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray();
|
||||
if (!Directory.Exists(resultsDirectory))
|
||||
_ = Directory.CreateDirectory(resultsDirectory);
|
||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines);
|
||||
string json = JsonSerializer.Serialize(mapLogic.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
columns = line.Split('\t');
|
||||
// select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}"
|
||||
if (columns.Length != 7)
|
||||
continue;
|
||||
if (!int.TryParse(columns[1], out int propertyId))
|
||||
continue;
|
||||
if (!zeros.Contains(propertyId))
|
||||
debug.Add(line);
|
||||
else
|
||||
debug.Add(propertyId.ToString());
|
||||
}
|
||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPrepareForOld}"), debug);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private string GetRename(string renameA)
|
||||
{
|
||||
string result;
|
||||
@ -376,12 +423,6 @@ public class Compare
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void Verify(Models.Configuration configuration)
|
||||
{
|
||||
if (configuration.Spelling is null || !configuration.Spelling.Any())
|
||||
throw new NullReferenceException(nameof(configuration.Spelling));
|
||||
}
|
||||
|
||||
private long LogDelta(long ticks, string? methodName)
|
||||
{
|
||||
long result;
|
||||
@ -391,121 +432,6 @@ public class Compare
|
||||
return result;
|
||||
}
|
||||
|
||||
private A_Property GetPropertyLogic(bool reverse, string outputExtension, Map.Models.MapLogic mapLogic)
|
||||
{
|
||||
A_Property result;
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse);
|
||||
string fromPrepareForOld = "34720-637858334555170379.tsv";
|
||||
string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld);
|
||||
if (File.Exists(fromPrepareForOldFile))
|
||||
{
|
||||
string[] lines;
|
||||
string[] columns;
|
||||
List<string> debug = new();
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
lines = File.ReadAllLines(fromPrepareForOldFile);
|
||||
string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory}-Results";
|
||||
int[]? zeros = (from l in mapLogic.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray();
|
||||
lines = (from l in mapLogic.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray();
|
||||
if (!Directory.Exists(resultsDirectory))
|
||||
_ = Directory.CreateDirectory(resultsDirectory);
|
||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines);
|
||||
string json = JsonSerializer.Serialize(mapLogic.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
columns = line.Split('\t');
|
||||
// select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}"
|
||||
if (columns.Length != 7)
|
||||
continue;
|
||||
if (!int.TryParse(columns[1], out int propertyId))
|
||||
continue;
|
||||
if (!zeros.Contains(propertyId))
|
||||
debug.Add(line);
|
||||
else
|
||||
debug.Add(propertyId.ToString());
|
||||
}
|
||||
File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPrepareForOld}"), debug);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||
_Logger?.LogInformation(aPropertySingletonDirectory);
|
||||
_Logger?.LogInformation("to");
|
||||
_Logger?.LogInformation(_Configuration.DiffPropertyDirectory);
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
_Logger?.LogInformation("Press \"Y\" key to continue or close console if compare not needed");
|
||||
if (Console.ReadKey().Key == ConsoleKey.Y)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
int loadLessThan = 7;
|
||||
string diffRootDirectory;
|
||||
ConsoleKey? consoleKey = null;
|
||||
List<PropertyCompare.Models.PropertyCompare>? duplicates = null;
|
||||
PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection;
|
||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory))
|
||||
diffRootDirectory = string.Empty;
|
||||
else
|
||||
{
|
||||
if (!_Configuration.DiffPropertyDirectory.EndsWith("{}"))
|
||||
throw new Exception("Invalid directory should end with {}!");
|
||||
diffRootDirectory = Shared.Models.Stateless.Methods.IProperty.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory);
|
||||
}
|
||||
PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory);
|
||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory))
|
||||
diffPropertyCompareCollection = Array.Empty<PropertyCompare.Models.PropertyCompare>();
|
||||
else
|
||||
{
|
||||
diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||
if (!diffPropertyCompareCollection.Any())
|
||||
throw new Exception("Invalid directory!");
|
||||
}
|
||||
string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]");
|
||||
PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray();
|
||||
File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines);
|
||||
string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json);
|
||||
}
|
||||
for (int x = 0; x < int.MaxValue; x++)
|
||||
{
|
||||
_Logger?.LogInformation($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}");
|
||||
_Logger?.LogInformation($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}");
|
||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||
consoleKey = Console.ReadKey().Key;
|
||||
if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D)
|
||||
propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection);
|
||||
else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M)
|
||||
{
|
||||
for (int x = 0; x < int.MaxValue; x++)
|
||||
{
|
||||
_Logger?.LogInformation($"Press \"0 - {loadLessThan}\" key when ready to continue");
|
||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||
consoleKey = Console.ReadKey().Key;
|
||||
if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
int i = int.Parse(consoleKey.Value.ToString()[1..]);
|
||||
propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory)
|
||||
{
|
||||
string searchPattern = "*.delete";
|
||||
@ -524,227 +450,6 @@ public class Compare
|
||||
}
|
||||
}
|
||||
|
||||
private bool PossiblyRename(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
int remainingDirectories = 0;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
Directory.Move(sourceDirectory, replaceDirectory);
|
||||
else
|
||||
{
|
||||
if (Directory.EnumerateDirectories(sourceDirectory).Any())
|
||||
remainingDirectories += 1;
|
||||
else
|
||||
{
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyRenameB(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
_ = Directory.CreateDirectory(replaceDirectory);
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyRenameC(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
_ = Directory.CreateDirectory(replaceDirectory);
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyCorrect(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
bool result = false;
|
||||
string corrected;
|
||||
string correctedMoveTo;
|
||||
string? correctedDirectory;
|
||||
string filteredSourceDirectoryFile;
|
||||
string[] filteredSourceDirectoryFiles;
|
||||
(string Find, string Replace) findReplace;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray();
|
||||
if (!filteredSourceDirectoryFiles.Any())
|
||||
continue;
|
||||
for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++)
|
||||
{
|
||||
found = null;
|
||||
for (int z = 0; z < int.MaxValue; z++)
|
||||
{
|
||||
filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i];
|
||||
found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l;
|
||||
if (!found.Any())
|
||||
break;
|
||||
findReplace = found.First();
|
||||
corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace);
|
||||
correctedDirectory = Path.GetDirectoryName(corrected);
|
||||
if (string.IsNullOrEmpty(correctedDirectory))
|
||||
break;
|
||||
correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected));
|
||||
if (File.Exists(correctedMoveTo))
|
||||
break;
|
||||
if (!Directory.Exists(correctedDirectory))
|
||||
_ = Directory.CreateDirectory(correctedDirectory);
|
||||
if (!result)
|
||||
result = true;
|
||||
File.Move(filteredSourceDirectoryFile, correctedMoveTo);
|
||||
filteredSourceDirectoryFiles[i] = corrected;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<string> GetMissingVerifyToSeasonCollection(List<string> _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
List<string> results = new();
|
||||
string check;
|
||||
foreach ((int _, string sourceDirectory, string[] _) in groupCollection)
|
||||
{
|
||||
if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory)
|
||||
continue;
|
||||
check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..];
|
||||
if (check[0] is '=' || check.StartsWith("zzz ="))
|
||||
{
|
||||
if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check))
|
||||
results.Add(check);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll)
|
||||
{
|
||||
int z = 0;
|
||||
string fileName;
|
||||
WindowsShortcut windowsShortcut;
|
||||
foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection)
|
||||
{
|
||||
z += 1;
|
||||
if (z % 1000 == 0)
|
||||
_Log.Debug($"{z}) Loop {propertyDirectory}");
|
||||
if (!keepAll)
|
||||
{
|
||||
fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = string.Empty;
|
||||
for (short c = 65; c < short.MaxValue; c++)
|
||||
{
|
||||
if (c > 95)
|
||||
break;
|
||||
fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
continue;
|
||||
windowsShortcut = new() { Path = filteredSourceDirectoryFile };
|
||||
windowsShortcut.Save(fileName);
|
||||
windowsShortcut.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThirdPassToMove(Property.Models.Configuration configuration, Map.Models.MapLogic mapLogic, A_Property propertyLogic, Shared.Models.Container[] containers, string aPropertyContentCollectionDirectory)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
@ -865,4 +570,299 @@ public class Compare
|
||||
CreateWindowsShortcuts(collection, keepAll);
|
||||
}
|
||||
|
||||
private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll)
|
||||
{
|
||||
int z = 0;
|
||||
string fileName;
|
||||
WindowsShortcut windowsShortcut;
|
||||
foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection)
|
||||
{
|
||||
z += 1;
|
||||
if (z % 1000 == 0)
|
||||
_Log.Debug($"{z}) Loop {propertyDirectory}");
|
||||
if (!keepAll)
|
||||
{
|
||||
fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = string.Empty;
|
||||
for (short c = 65; c < short.MaxValue; c++)
|
||||
{
|
||||
if (c > 95)
|
||||
break;
|
||||
fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
continue;
|
||||
windowsShortcut = new() { Path = filteredSourceDirectoryFile };
|
||||
windowsShortcut.Save(fileName);
|
||||
windowsShortcut.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||
_Logger?.LogInformation(aPropertySingletonDirectory);
|
||||
_Logger?.LogInformation("to");
|
||||
_Logger?.LogInformation(_Configuration.DiffPropertyDirectory);
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
_Logger?.LogInformation("Press \"Y\" key to continue or close console if compare not needed");
|
||||
if (Console.ReadKey().Key == ConsoleKey.Y)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
int loadLessThan = 7;
|
||||
string diffRootDirectory;
|
||||
ConsoleKey? consoleKey = null;
|
||||
List<PropertyCompare.Models.PropertyCompare>? duplicates = null;
|
||||
PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection;
|
||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory))
|
||||
diffRootDirectory = string.Empty;
|
||||
else
|
||||
{
|
||||
if (!_Configuration.DiffPropertyDirectory.EndsWith("{}"))
|
||||
throw new Exception("Invalid directory should end with {}!");
|
||||
diffRootDirectory = Shared.Models.Stateless.Methods.IProperty.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory);
|
||||
}
|
||||
PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory);
|
||||
if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory))
|
||||
diffPropertyCompareCollection = Array.Empty<PropertyCompare.Models.PropertyCompare>();
|
||||
else
|
||||
{
|
||||
diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||
if (!diffPropertyCompareCollection.Any())
|
||||
throw new Exception("Invalid directory!");
|
||||
}
|
||||
string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]");
|
||||
PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false);
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray();
|
||||
File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines);
|
||||
string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json);
|
||||
}
|
||||
for (int x = 0; x < int.MaxValue; x++)
|
||||
{
|
||||
_Logger?.LogInformation($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}");
|
||||
_Logger?.LogInformation($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}");
|
||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||
consoleKey = Console.ReadKey().Key;
|
||||
if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D)
|
||||
propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection);
|
||||
else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M)
|
||||
{
|
||||
for (int x = 0; x < int.MaxValue; x++)
|
||||
{
|
||||
_Logger?.LogInformation($"Press \"0 - {loadLessThan}\" key when ready to continue");
|
||||
_Logger?.LogInformation("Press \"End\" key when ready to skip");
|
||||
consoleKey = Console.ReadKey().Key;
|
||||
if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End)
|
||||
break;
|
||||
}
|
||||
_Logger?.LogInformation(". . .");
|
||||
int i = int.Parse(consoleKey.Value.ToString()[1..]);
|
||||
propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i);
|
||||
}
|
||||
}
|
||||
|
||||
private bool PossiblyRename(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
int remainingDirectories = 0;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
Directory.Move(sourceDirectory, replaceDirectory);
|
||||
else
|
||||
{
|
||||
if (Directory.EnumerateDirectories(sourceDirectory).Any())
|
||||
remainingDirectories += 1;
|
||||
else
|
||||
{
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyCorrect(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
bool result = false;
|
||||
string corrected;
|
||||
string correctedMoveTo;
|
||||
string? correctedDirectory;
|
||||
string filteredSourceDirectoryFile;
|
||||
string[] filteredSourceDirectoryFiles;
|
||||
(string Find, string Replace) findReplace;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray();
|
||||
if (!filteredSourceDirectoryFiles.Any())
|
||||
continue;
|
||||
for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++)
|
||||
{
|
||||
found = null;
|
||||
for (int z = 0; z < int.MaxValue; z++)
|
||||
{
|
||||
filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i];
|
||||
found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l;
|
||||
if (!found.Any())
|
||||
break;
|
||||
findReplace = found.First();
|
||||
corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace);
|
||||
correctedDirectory = Path.GetDirectoryName(corrected);
|
||||
if (string.IsNullOrEmpty(correctedDirectory))
|
||||
break;
|
||||
correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected));
|
||||
if (File.Exists(correctedMoveTo))
|
||||
break;
|
||||
if (!Directory.Exists(correctedDirectory))
|
||||
_ = Directory.CreateDirectory(correctedDirectory);
|
||||
if (!result)
|
||||
result = true;
|
||||
File.Move(filteredSourceDirectoryFile, correctedMoveTo);
|
||||
filteredSourceDirectoryFiles[i] = corrected;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyRenameB(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
_ = Directory.CreateDirectory(replaceDirectory);
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool PossiblyRenameC(List<string> topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
bool result = false;
|
||||
string replaceFile;
|
||||
string replaceDirectory;
|
||||
IEnumerable<(string Find, string Replace)>? found;
|
||||
foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in groupCollection)
|
||||
{
|
||||
if (!topDirectories.Any())
|
||||
continue;
|
||||
found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l;
|
||||
if (!found.Any())
|
||||
continue;
|
||||
if (!result)
|
||||
result = true;
|
||||
replaceDirectory = found.First().Replace;
|
||||
if (!Directory.Exists(replaceDirectory))
|
||||
_ = Directory.CreateDirectory(replaceDirectory);
|
||||
foreach (string sourceDirectoryFile in sourceDirectoryFiles)
|
||||
{
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile));
|
||||
if (File.Exists(replaceFile))
|
||||
{
|
||||
if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg"));
|
||||
else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture))
|
||||
replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg"));
|
||||
}
|
||||
if (File.Exists(replaceFile))
|
||||
continue;
|
||||
File.Move(sourceDirectoryFile, replaceFile);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<string> GetMissingVerifyToSeasonCollection(List<string> _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> groupCollection)
|
||||
{
|
||||
if (_Configuration?.PropertyConfiguration is null)
|
||||
throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
|
||||
List<string> results = new();
|
||||
string check;
|
||||
foreach ((int _, string sourceDirectory, string[] _) in groupCollection)
|
||||
{
|
||||
if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory)
|
||||
continue;
|
||||
check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..];
|
||||
if (check[0] is '=' || check.StartsWith("zzz ="))
|
||||
{
|
||||
if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check))
|
||||
results.Add(check);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Map\Map.csproj" />
|
||||
|
1
Container/.vscode/format-report.json
vendored
Normal file
1
Container/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
[]
|
8
Container/.vscode/settings.json
vendored
Normal file
8
Container/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"dlib",
|
||||
"Exif",
|
||||
"nosj",
|
||||
"Serilog"
|
||||
]
|
||||
}
|
52
Container/Container.csproj
Normal file
52
Container/Container.csproj
Normal file
@ -0,0 +1,52 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Container</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">
|
||||
true
|
||||
</IsWindows>
|
||||
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">
|
||||
true
|
||||
</IsOSX>
|
||||
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">
|
||||
true
|
||||
</IsLinux>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(IsWindows)'=='true'">
|
||||
<DefineConstants>Windows</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(IsOSX)'=='true'">
|
||||
<DefineConstants>OSX</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(IsLinux)'=='true'">
|
||||
<DefineConstants>Linux</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,7 +1,8 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.Shared.Models;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
namespace View_by_Distance.Container.Models;
|
||||
|
||||
public record Container(string SourceDirectory, ReadOnlyCollection<Item> Items)
|
||||
{
|
487
Container/Models/Stateless/Methods/Container.cs
Normal file
487
Container/Models/Stateless/Methods/Container.cs
Normal file
@ -0,0 +1,487 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
namespace View_by_Distance.Container.Models.Stateless.Methods;
|
||||
|
||||
internal abstract class Container
|
||||
{
|
||||
|
||||
private record FilePair(bool IsUnique,
|
||||
List<FilePath> Collection,
|
||||
FilePath FilePath,
|
||||
Item Item);
|
||||
|
||||
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container)
|
||||
{
|
||||
List<Item> results = [];
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (!item.IsValidImageFormatExtension || propertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered))
|
||||
continue;
|
||||
results.Add(item);
|
||||
}
|
||||
return container.Items.Count == results.Count ? container.Items : results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items)
|
||||
{
|
||||
DateTime[] results;
|
||||
long containerMinimumTicks = (from l in items select l.FilePath.LastWriteTicks).Min();
|
||||
long containerMaximumTicks = (from l in items select l.FilePath.LastWriteTicks).Max();
|
||||
results = [new(containerMinimumTicks), new(containerMaximumTicks)];
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||
{
|
||||
List<int> results = [];
|
||||
ReadOnlyCollection<Item> filteredItems;
|
||||
foreach (Models.Container container in readOnlyContainers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (results.Contains(item.ExifDirectory.FilePath.Id.Value))
|
||||
continue;
|
||||
results.Add(item.ExifDirectory.FilePath.Id.Value);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string _)
|
||||
{
|
||||
int count;
|
||||
Models.Container[] results;
|
||||
bool useIgnoreExtensions = true;
|
||||
const bool useCeilingAverage = true;
|
||||
const string fileSearchFilter = "*";
|
||||
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
||||
const string directorySearchFilter = "*";
|
||||
ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById = null;
|
||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
|
||||
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||
return (count, results);
|
||||
}
|
||||
|
||||
private static IDlibDotNet GetDlibDotNet() =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
private static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||
{
|
||||
List<Models.Container> results = [];
|
||||
string directory;
|
||||
List<Item>? items;
|
||||
Models.Container container;
|
||||
List<string> directories = [];
|
||||
Dictionary<string, List<Item>> directoryToItems = [];
|
||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||
{
|
||||
if (filePaths.Count == 0)
|
||||
continue;
|
||||
directory = filePaths[0].DirectoryFullPath;
|
||||
if (directory is null)
|
||||
continue;
|
||||
if (!directories.Contains(directory))
|
||||
directories.Add(directory);
|
||||
if (!directoryToItems.TryGetValue(directory, out items))
|
||||
{
|
||||
directoryToItems.Add(directory, []);
|
||||
if (!directoryToItems.TryGetValue(directory, out items))
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||
foreach (FilePair filePair in filePairs)
|
||||
{
|
||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||
{
|
||||
directoryToItems.Add(filePair.FilePath.DirectoryFullPath, []);
|
||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||
throw new Exception();
|
||||
}
|
||||
items.Add(filePair.Item);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<Item>> keyValuePair in directoryToItems)
|
||||
{
|
||||
if (keyValuePair.Value.Count == 0)
|
||||
continue;
|
||||
container = new(keyValuePair.Key, new(keyValuePair.Value));
|
||||
results.Add(container);
|
||||
}
|
||||
return (filePairs.Count, results.ToArray());
|
||||
}
|
||||
|
||||
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||
{
|
||||
List<FilePair> results = [];
|
||||
const string extension = ".json";
|
||||
ReadOnlyCollection<Shared.Models.FilePair> filePairs;
|
||||
string jsonGroupDirectory = aPropertySingletonDirectory;
|
||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
|
||||
ParallelFor(dlibDotNet, propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, exifDirectoriesById, filePairs[i], results));
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void ParallelFor(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, int rootDirectoryLength, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, Shared.Models.FilePair filePair, List<FilePair> results)
|
||||
{
|
||||
dlibDotNet?.Tick();
|
||||
bool abandoned = false;
|
||||
FileHolder sourceDirectoryFileHolder;
|
||||
if (exifDirectoriesById is null || filePair.FilePath.Id is null || !exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory))
|
||||
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||
ReadOnlyCollection<string> keywords = IMetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||
bool? shouldIgnore = propertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
||||
bool? fileSizeChanged = exifDirectory is not null ? exifDirectory.FilePath.Length != filePair.FilePath.Length : null;
|
||||
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePair.FilePath.ExtensionLowered);
|
||||
bool? isArchive = filePair.FilePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePair.FilePath.Id.Value, out Identifier? identifier);
|
||||
if (exifDirectory is not null && filePair.FilePath.Id is not null && filePair.FilePath.HasIgnoreKeyword is not null && filePair.FilePath.HasDateTimeOriginal is not null)
|
||||
{
|
||||
char? change;
|
||||
ReadOnlyCollection<FilePath>? filePaths = null;
|
||||
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||
char hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePair.FilePath).ToString()[0];
|
||||
char hasDateTimeOriginal = IId.GetHasDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||
char missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||
if (shouldIgnore is not null && shouldIgnore.Value)
|
||||
{
|
||||
if (filePair.FilePath.FileNameFirstSegment[^1] == hasIgnoreKeyword)
|
||||
change = null;
|
||||
else
|
||||
{
|
||||
change = hasIgnoreKeyword;
|
||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||
}
|
||||
}
|
||||
else if ((shouldIgnore is null || !shouldIgnore.Value) && dateTime is null)
|
||||
{
|
||||
if (filePair.FilePath.FileNameFirstSegment[^1] == missingDateTimeOriginal)
|
||||
change = null;
|
||||
else
|
||||
{
|
||||
change = missingDateTimeOriginal;
|
||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||
}
|
||||
}
|
||||
else if (filePair.FilePath.FileNameFirstSegment[^1] != hasDateTimeOriginal)
|
||||
{
|
||||
change = hasDateTimeOriginal;
|
||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||
}
|
||||
else
|
||||
change = null;
|
||||
if (filePaths is not null && change is not null)
|
||||
RenameFile(filePair, filePair.FilePath, change.Value, filePaths);
|
||||
}
|
||||
string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.FilePath.FullName, rootDirectoryLength, forceExtensionToLower: true);
|
||||
bool? lastWriteTimeChanged = exifDirectory is not null ? propertyConfiguration.PropertiesChangedForProperty || exifDirectory.FilePath.LastWriteTicks != filePair.FilePath.LastWriteTicks : null;
|
||||
if (filePair.Match is not null)
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
||||
else if (!filePair.IsUnique)
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
||||
else
|
||||
{
|
||||
string fileName = Path.GetFileName(filePair.FilePath.FullName);
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePair.FilePath);
|
||||
string directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
||||
string jsonFileName = $"{fileName}{extension}";
|
||||
string fullFileName = Path.Combine(directory, jsonFileName);
|
||||
MoveIf(jsonFileName, cei, directory, fullFileName);
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
|
||||
}
|
||||
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
||||
{
|
||||
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePair.FilePath.LastWriteTicks));
|
||||
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
||||
}
|
||||
Item item = Item.Get(filePair.FilePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, exifDirectory, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
||||
lock (results)
|
||||
results.Add(new(filePair.IsUnique, filePair.Collection, filePair.FilePath, item));
|
||||
}
|
||||
|
||||
private static void RenameFile(Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
||||
{
|
||||
string checkFile;
|
||||
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
|
||||
File.Delete(filePath.FullName);
|
||||
if (filePair.Match is not null)
|
||||
{
|
||||
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(filePair.Match.NameWithoutExtension);
|
||||
string extensionSecond = Path.GetExtension(filePair.Match.Name);
|
||||
checkFile = Path.Combine(filePair.Match.DirectoryFullPath, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{filePair.Match.ExtensionLowered}");
|
||||
if (!File.Exists(checkFile))
|
||||
File.Move(filePair.Match.FullName, checkFile);
|
||||
}
|
||||
foreach (FilePath f in filePaths)
|
||||
{
|
||||
checkFile = Path.Combine(f.DirectoryFullPath, $"{f.NameWithoutExtension[..^1]}{change}{f.ExtensionLowered}");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(f.FullName, checkFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
File.Move(checkFile, fullFileName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||
{
|
||||
List<string> results = [];
|
||||
ReadOnlyCollection<Item> filteredItems;
|
||||
foreach (Models.Container container in readOnlyContainers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
||||
continue;
|
||||
results.Add(item.FilePath.FileNameFirstSegment);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
|
||||
{
|
||||
List<Item> results = [];
|
||||
List<int> distinct = [];
|
||||
ReadOnlyCollection<Item> filteredItems;
|
||||
foreach (Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!filterItems)
|
||||
filteredItems = container.Items;
|
||||
else
|
||||
{
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
}
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (distinctItems)
|
||||
{
|
||||
if (distinct.Contains(item.ExifDirectory.FilePath.Id.Value))
|
||||
continue;
|
||||
distinct.Add(item.ExifDirectory.FilePath.Id.Value);
|
||||
}
|
||||
results.Add(item);
|
||||
}
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById)
|
||||
{
|
||||
Models.Container[] results;
|
||||
const string directorySearchFilter = "*";
|
||||
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||
if (keyValuePairs is not null)
|
||||
DoGetFilePairsForRemaining(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, directorySearchFilter);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static void DoGetFilePairsForRemaining(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
|
||||
{
|
||||
const string extension = ".json";
|
||||
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
if (!Directory.Exists(bMetaSingletonDirectory))
|
||||
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||
(string cResultsFullGroupDirectory, _, string dResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories("Original");
|
||||
string cResizeSingletonDirectory = Path.Combine(cResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
if (!Directory.Exists(cResizeSingletonDirectory))
|
||||
_ = Directory.CreateDirectory(cResizeSingletonDirectory);
|
||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||
if (!Directory.Exists(dFaceCollectionDirectory))
|
||||
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection, fileNamesToFiles);
|
||||
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
||||
if (!Directory.Exists(dFaceContentDirectory))
|
||||
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
||||
AnyMovedFace(propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, fileNamesToFiles, dFaceContentDirectory);
|
||||
AnyMovedDistance(propertyConfiguration, facesFileNameExtension, fileNamesToFiles, eDistanceContentDirectory);
|
||||
}
|
||||
|
||||
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, string extension, string hiddenExtension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
||||
{
|
||||
string directory;
|
||||
string checkFile;
|
||||
string directoryName;
|
||||
List<string> files = [];
|
||||
string[] fileNameSegments;
|
||||
List<string> directories = [];
|
||||
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories));
|
||||
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{hiddenExtension}", SearchOption.AllDirectories));
|
||||
foreach (string file in files)
|
||||
{
|
||||
directory = Path.GetDirectoryName(file) ?? throw new Exception();
|
||||
if (!directories.Contains(directory))
|
||||
directories.Add(directory);
|
||||
directoryName = Path.GetFileName(directory);
|
||||
fileNameSegments = Path.GetFileName(file).Split('.');
|
||||
if (fileNameSegments[0] != directoryName)
|
||||
{
|
||||
fileNameSegments[0] = string.Empty;
|
||||
checkFile = Path.Combine(directory, $"{directoryName}{string.Join('.', fileNameSegments)}");
|
||||
if (!File.Exists(checkFile))
|
||||
File.Move(file, checkFile);
|
||||
else
|
||||
{
|
||||
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
|
||||
File.Delete(file);
|
||||
else
|
||||
File.Move(file, checkFile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (directories.Count > 0)
|
||||
AnyMovedFace(propertyConfiguration, fileNamesToFiles, directories);
|
||||
}
|
||||
|
||||
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, List<string> directories)
|
||||
{
|
||||
bool result = false;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
string subDirectory;
|
||||
string directoryName;
|
||||
string checkDirectory;
|
||||
FileHolder fileHolder;
|
||||
string directoryNameWith;
|
||||
List<FilePath>? collection;
|
||||
List<string> directoryNames = [];
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
fileHolder = IFileHolder.Get(Path.GetFileName(directory));
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||
throw new Exception();
|
||||
directoryNames.Clear();
|
||||
foreach (FilePath f in collection)
|
||||
directoryNames.Add(Path.GetFileName(f.DirectoryFullPath) ?? throw new Exception());
|
||||
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
|
||||
continue;
|
||||
directoryName = Path.GetFileName(Path.GetDirectoryName(directory)) ?? throw new Exception();
|
||||
if (directoryName != directoryNames[0])
|
||||
{
|
||||
subDirectory = Path.GetDirectoryName(Path.GetDirectoryName(directory)) ?? throw new Exception();
|
||||
checkDirectory = Path.Combine(subDirectory, directoryNames[0]);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
directoryNameWith = collection.Count > 1 ? directoryName : $"{collection[0].NameWithoutExtension}";
|
||||
checkFile = Path.Combine(checkDirectory, directoryNameWith);
|
||||
if (!result)
|
||||
result = true;
|
||||
if (!Directory.Exists(checkFile))
|
||||
Directory.Move(directory, checkFile);
|
||||
else
|
||||
{
|
||||
if (new DirectoryInfo(directory).LastWriteTime > new DirectoryInfo(checkFile).LastWriteTime)
|
||||
Directory.Delete(directory, recursive: true);
|
||||
else
|
||||
{
|
||||
Directory.Delete(checkFile, recursive: true);
|
||||
Directory.Move(directory, checkFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AnyMovedDistance(IPropertyConfiguration propertyConfiguration, string extension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
||||
{
|
||||
bool result = false;
|
||||
string checkFile;
|
||||
string directory;
|
||||
FilePath filePath;
|
||||
FileHolder fileHolder;
|
||||
string[] fileNameSegments;
|
||||
List<FilePath>? collection;
|
||||
List<string> fileNames = [];
|
||||
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
if (!fileHolder.Exists)
|
||||
continue;
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
fileNameSegments = filePath.Name.Split('.');
|
||||
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||
continue;
|
||||
fileNames.Clear();
|
||||
foreach (FilePath f in collection)
|
||||
fileNames.Add(f.NameWithoutExtension ?? throw new Exception());
|
||||
if (fileNames.Count == 0 || fileNames.Distinct().Count() != 1)
|
||||
continue;
|
||||
if (filePath.FileNameFirstSegment != fileNames[0])
|
||||
{
|
||||
fileNameSegments[0] = string.Empty;
|
||||
directory = Path.GetDirectoryName(file) ?? throw new Exception();
|
||||
checkFile = Path.Combine(directory, $"{fileNames[0]}{string.Join('.', fileNameSegments)}");
|
||||
if (!result)
|
||||
result = true;
|
||||
if (!File.Exists(checkFile))
|
||||
File.Move(file, checkFile);
|
||||
else
|
||||
{
|
||||
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
|
||||
File.Delete(file);
|
||||
else
|
||||
File.Move(file, checkFile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
59
Container/Models/Stateless/Methods/IContainer.cs
Normal file
59
Container/Models/Stateless/Methods/IContainer.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
namespace View_by_Distance.Container.Models.Stateless.Methods;
|
||||
|
||||
public interface IContainer
|
||||
{
|
||||
|
||||
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||
|
||||
public static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||
Container.GetContainerDateTimes(items);
|
||||
|
||||
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||
Container.GetValidImageItems(propertyConfiguration, container);
|
||||
|
||||
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
|
||||
|
||||
public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
public static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||
|
||||
public static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||
Container.GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||
|
||||
internal DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||
GetContainerDateTimes(items);
|
||||
|
||||
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||
GetValidImageItems(propertyConfiguration, container);
|
||||
|
||||
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||
|
||||
internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
internal List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||
|
||||
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||
|
||||
internal ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||
|
||||
}
|
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Phares.Shared;
|
||||
using ShellProgressBar;
|
||||
@ -19,7 +19,7 @@ public class CopyDistinct
|
||||
private readonly IsEnvironment _IsEnvironment;
|
||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>> _FileGroups;
|
||||
|
||||
public CopyDistinct(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
|
||||
{
|
||||
@ -37,7 +37,9 @@ public class CopyDistinct
|
||||
_Configuration = configuration;
|
||||
logger?.LogInformation(propertyConfiguration.RootDirectory);
|
||||
(bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack) = Verify();
|
||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs =
|
||||
Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
||||
_FileGroups = keyValuePairs[appSettings.ResultDirectoryKey];
|
||||
List<string> lines = CopyDistinctFilesInDirectories(logger, move, filesCollection, anyLenFiles, moveBack);
|
||||
if (lines.Count != 0)
|
||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||
@ -93,6 +95,76 @@ public class CopyDistinct
|
||||
return (move, new(filesCollection), anyLenFiles, moveBack);
|
||||
}
|
||||
|
||||
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
||||
{
|
||||
List<string> results = [];
|
||||
ProgressBar progressBar;
|
||||
string[] distinctDirectories;
|
||||
ConsoleKey? consoleKey = null;
|
||||
string message = nameof(CopyDistinct);
|
||||
List<(FilePath, string)> toDoCollection;
|
||||
int count = filesCollection.Select(l => l.Length).Sum();
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
if (moveBack)
|
||||
{
|
||||
if (!anyLenFiles)
|
||||
throw new NotSupportedException();
|
||||
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar = new(count, message, options);
|
||||
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
||||
if (key != _PropertyConfiguration.ResultContent)
|
||||
throw new NotImplementedException("Changed but didn't update!");
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, filesCollection, useIgnoreExtensions: true);
|
||||
(distinctDirectories, toDoCollection) = IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filePathsCollection, _FileGroups, () => progressBar.Tick());
|
||||
progressBar.Dispose();
|
||||
}
|
||||
foreach (string distinctDirectory in distinctDirectories)
|
||||
{
|
||||
if (!Directory.Exists(distinctDirectory))
|
||||
_ = Directory.CreateDirectory(distinctDirectory);
|
||||
}
|
||||
if (move)
|
||||
logger?.LogInformation($"Ready to Move {toDoCollection.Count} file(s)?");
|
||||
else if (!moveBack)
|
||||
logger?.LogInformation($"Ready to Copy {toDoCollection.Count} file(s)?");
|
||||
else
|
||||
logger?.LogInformation($"Ready to Move back {toDoCollection.Count} file(s)?");
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
if (move)
|
||||
logger?.LogInformation("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files");
|
||||
else if (!moveBack)
|
||||
logger?.LogInformation("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files");
|
||||
else
|
||||
logger?.LogInformation("Press \"Y\" key to move back file(s), \"N\" key to log file(s) or close console to not move back files");
|
||||
consoleKey = System.Console.ReadKey().Key;
|
||||
if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
|
||||
break;
|
||||
}
|
||||
logger?.LogInformation(". . .");
|
||||
if (consoleKey is null || consoleKey.Value != ConsoleKey.Y)
|
||||
{
|
||||
if (move || moveBack)
|
||||
logger?.LogInformation("Nothing moved!");
|
||||
else
|
||||
logger?.LogInformation("Nothing copied!");
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar = new(count, message, options);
|
||||
results.AddRange(IDirectory.CopyOrMove(toDoCollection, move, moveBack, () => progressBar.Tick()));
|
||||
progressBar.Dispose();
|
||||
if (move || moveBack)
|
||||
logger?.LogInformation("Done moving");
|
||||
else
|
||||
logger?.LogInformation("Done copying");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static (string[], List<(FilePath, string)>) GetMoveBackToDoCollection(Property.Models.Configuration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||
{
|
||||
List<(FilePath, string)> results = [];
|
||||
@ -159,74 +231,4 @@ public class CopyDistinct
|
||||
return (distinctDirectories.ToArray(), results);
|
||||
}
|
||||
|
||||
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
||||
{
|
||||
List<string> results = [];
|
||||
ProgressBar progressBar;
|
||||
string[] distinctDirectories;
|
||||
ConsoleKey? consoleKey = null;
|
||||
string message = nameof(CopyDistinct);
|
||||
List<(FilePath, string)> toDoCollection;
|
||||
int count = filesCollection.Select(l => l.Length).Sum();
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
if (moveBack)
|
||||
{
|
||||
if (!anyLenFiles)
|
||||
throw new NotSupportedException();
|
||||
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar = new(count, message, options);
|
||||
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
||||
if (key != _PropertyConfiguration.ResultContent)
|
||||
throw new NotImplementedException("Changed but didn't update!");
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, filesCollection);
|
||||
(distinctDirectories, toDoCollection) = IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filePathsCollection, _FileGroups, () => progressBar.Tick());
|
||||
progressBar.Dispose();
|
||||
}
|
||||
foreach (string distinctDirectory in distinctDirectories)
|
||||
{
|
||||
if (!Directory.Exists(distinctDirectory))
|
||||
_ = Directory.CreateDirectory(distinctDirectory);
|
||||
}
|
||||
if (move)
|
||||
logger?.LogInformation($"Ready to Move {toDoCollection.Count} file(s)?");
|
||||
else if (!moveBack)
|
||||
logger?.LogInformation($"Ready to Copy {toDoCollection.Count} file(s)?");
|
||||
else
|
||||
logger?.LogInformation($"Ready to Move back {toDoCollection.Count} file(s)?");
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
if (move)
|
||||
logger?.LogInformation("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files");
|
||||
else if (!moveBack)
|
||||
logger?.LogInformation("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files");
|
||||
else
|
||||
logger?.LogInformation("Press \"Y\" key to move back file(s), \"N\" key to log file(s) or close console to not move back files");
|
||||
consoleKey = System.Console.ReadKey().Key;
|
||||
if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
|
||||
break;
|
||||
}
|
||||
logger?.LogInformation(". . .");
|
||||
if (consoleKey is null || consoleKey.Value != ConsoleKey.Y)
|
||||
{
|
||||
if (move || moveBack)
|
||||
logger?.LogInformation("Nothing moved!");
|
||||
else
|
||||
logger?.LogInformation("Nothing copied!");
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar = new(count, message, options);
|
||||
results.AddRange(IDirectory.CopyOrMove(toDoCollection, move, moveBack, () => progressBar.Tick()));
|
||||
progressBar.Dispose();
|
||||
if (move || moveBack)
|
||||
logger?.LogInformation("Done moving");
|
||||
else
|
||||
logger?.LogInformation("Done copying");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -34,15 +34,15 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Phares.Shared;
|
||||
using System.Globalization;
|
||||
@ -57,11 +57,11 @@ public class DateGroup
|
||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||
(int t, Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||
(int t, Container.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory, aResultsFullGroupDirectory);
|
||||
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
||||
throw new Exception();
|
||||
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers))
|
||||
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Property.Models.Stateless.IProperty.Any(containers))
|
||||
{
|
||||
propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers);
|
||||
if (propertyLogic.ExceptionsDirectories.Count != 0)
|
||||
@ -96,203 +96,6 @@ public class DateGroup
|
||||
throw new Exception("Change configuration!");
|
||||
}
|
||||
|
||||
private static bool WriteAllText(string path, string contents, bool compareBeforeWrite)
|
||||
{
|
||||
bool result;
|
||||
string text;
|
||||
if (!compareBeforeWrite)
|
||||
result = true;
|
||||
else
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
text = string.Empty;
|
||||
else
|
||||
text = File.ReadAllText(path);
|
||||
result = text != contents;
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
if (path.Contains("()"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
||||
File.WriteAllText(path, contents);
|
||||
else
|
||||
File.WriteAllText(path, contents);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> GetMoveFileCollection(string destinationDirectory, string topDirectory, Item[] filteredItems)
|
||||
{
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> results = [];
|
||||
char flag;
|
||||
string day;
|
||||
int season;
|
||||
string year;
|
||||
string month;
|
||||
string? check;
|
||||
string fileName;
|
||||
string? pathRoot;
|
||||
DateTime dateTime;
|
||||
string seasonName;
|
||||
string weekOfYear;
|
||||
bool? isWrongYear;
|
||||
string seasonValue;
|
||||
string directoryName;
|
||||
string topDirectoryName;
|
||||
List<DateTime> dateTimes;
|
||||
string[]? matches = null;
|
||||
string[] directorySegments;
|
||||
List<string> destinationCollection;
|
||||
List<string> directoryNames = [];
|
||||
List<string> topDirectorySegments = [];
|
||||
StringBuilder destinationDirectoryName = new();
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
for (int z = 1; z < 3; z++)
|
||||
{
|
||||
if (z == 1)
|
||||
{
|
||||
check = Path.Combine(destinationDirectory, ".");
|
||||
pathRoot = Path.GetPathRoot(destinationDirectory);
|
||||
}
|
||||
else if (z == 2)
|
||||
{
|
||||
check = Path.Combine(topDirectory, ".");
|
||||
pathRoot = Path.GetPathRoot(topDirectory);
|
||||
}
|
||||
else
|
||||
throw new Exception();
|
||||
if (string.IsNullOrEmpty(pathRoot))
|
||||
continue;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
check = Path.GetDirectoryName(check);
|
||||
if (string.IsNullOrEmpty(check) || check == pathRoot)
|
||||
break;
|
||||
directoryName = Path.GetFileName(check);
|
||||
directorySegments = directoryName.Split(' ');
|
||||
topDirectorySegments.AddRange(directorySegments);
|
||||
(_, matches) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(directorySegments, string.Empty);
|
||||
if (matches.Length != 0)
|
||||
break;
|
||||
}
|
||||
if (matches is not null && matches.Length != 0)
|
||||
break;
|
||||
}
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
directoryNames.Clear();
|
||||
destinationCollection = [];
|
||||
_ = destinationDirectoryName.Clear();
|
||||
if (item.Property is not null)
|
||||
dateTimes = item.Property.GetDateTimes();
|
||||
else
|
||||
dateTimes = [new(item.FilePath.LastWriteTicks)];
|
||||
if (item.Property is not null && item.Property.DateTimeOriginal is not null)
|
||||
dateTime = item.Property.DateTimeOriginal.Value;
|
||||
else if (item.Property is null)
|
||||
dateTime = new(item.FilePath.LastWriteTicks);
|
||||
else
|
||||
dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
day = dateTime.ToString("MM-dd");
|
||||
month = dateTime.ToString("MMMM");
|
||||
if (item.Property?.Id is null)
|
||||
{
|
||||
flag = '#';
|
||||
isWrongYear = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
(isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(item.FilePath, item.Property.DateTimeOriginal, dateTimes);
|
||||
if (isWrongYear is null)
|
||||
flag = '#';
|
||||
else if (isWrongYear.Value)
|
||||
flag = '~';
|
||||
else
|
||||
{
|
||||
if (item.Property.DateTimeOriginal is not null && dateTime.DayOfYear != item.Property.DateTimeOriginal.Value.DayOfYear && Math.Abs(new TimeSpan(dateTime.Ticks - item.Property.DateTimeOriginal.Value.Ticks).TotalHours) > 8)
|
||||
flag = '^';
|
||||
else
|
||||
flag = '=';
|
||||
}
|
||||
}
|
||||
(season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
if ((from l in topDirectorySegments where l == "Christmas" select true).Any())
|
||||
seasonValue = string.Empty;
|
||||
else
|
||||
seasonValue = $".{season}";
|
||||
if (isWrongYear is null || !isWrongYear.Value)
|
||||
year = $"{flag}{dateTime:yyyy}{seasonValue}";
|
||||
else if (matches is null || matches.Length < 3)
|
||||
year = "----";
|
||||
else
|
||||
{
|
||||
if (matches[0][0] != '~')
|
||||
year = $"{flag}{matches[0].Split('.')[0]}{seasonValue}";
|
||||
else
|
||||
year = $"{flag}{matches[0][1..].Split('.')[0]}{seasonValue}";
|
||||
}
|
||||
topDirectoryName = Path.GetFileName(topDirectory);
|
||||
weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
|
||||
if (_Configuration.ByHash)
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else if (_Configuration.BySeason && topDirectoryName.Length == 1 && topDirectoryName[0] == '_')
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else
|
||||
{
|
||||
if (!_Configuration.KeepFullPath)
|
||||
{
|
||||
if (topDirectoryName.Length > 1)
|
||||
_ = destinationDirectoryName.Append(topDirectoryName);
|
||||
if (_Configuration.BySeason)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year} {seasonName}" });
|
||||
else if (_Configuration.ByDay)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}" });
|
||||
else if (_Configuration.ByWeek)
|
||||
directoryNames.AddRange(new string[] { $"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}" });
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string sourceDirectoryNameSegment in topDirectorySegments)
|
||||
{
|
||||
if (matches is not null && matches.Contains(sourceDirectoryNameSegment))
|
||||
_ = destinationDirectoryName.Append(year);
|
||||
else
|
||||
_ = destinationDirectoryName.Append(sourceDirectoryNameSegment);
|
||||
}
|
||||
if (_Configuration.BySeason)
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else if (_Configuration.ByDay)
|
||||
directoryNames.Add($"{weekOfYear}) {year} {day}");
|
||||
else if (_Configuration.ByWeek)
|
||||
directoryNames.Add($"{weekOfYear}) {month} {year}");
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
if (!_Configuration.ByHash || item.Property?.Id is null)
|
||||
fileName = item.FilePath.Name;
|
||||
else
|
||||
fileName = $"{item.Property.Id.Value}{item.FilePath.ExtensionLowered}";
|
||||
destinationCollection.Add(destinationDirectory);
|
||||
destinationCollection.AddRange(directoryNames);
|
||||
destinationCollection.Add(fileName);
|
||||
if (item.Property is null)
|
||||
results.Add(new(item, item.FilePath.LastWriteTicks, dateTime.Ticks, destinationCollection.ToArray()));
|
||||
else
|
||||
results.Add(new(item, item.Property.LastWriteTime.Ticks, dateTime.Ticks, destinationCollection.ToArray()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private A_Property GetPropertyLogic(bool reverse, string outputExtension, string aResultsFullGroupDirectory)
|
||||
{
|
||||
A_Property result;
|
||||
@ -302,57 +105,67 @@ public class DateGroup
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Item[] GetFilterItems(Container container)
|
||||
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container.Models.Container[] containers)
|
||||
{
|
||||
List<Item> results = [];
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.FilePath is not null)
|
||||
results.Add(item);
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container[] containers)
|
||||
{
|
||||
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
||||
Item[] filteredItems;
|
||||
string? topDirectory;
|
||||
string? checkDirectory;
|
||||
string destinationDirectory;
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
|
||||
foreach (Container container in containers)
|
||||
string path;
|
||||
string fileName;
|
||||
string directory;
|
||||
DateTime dateTime;
|
||||
int selectedTotal;
|
||||
const int minimum = 3;
|
||||
List<DateTime> dateTimes;
|
||||
List<Item> selectedItems;
|
||||
const int maximumHours = 24;
|
||||
string? relativePathDirectory;
|
||||
WindowsShortcut windowsShortcut;
|
||||
TimeSpan threeStandardDeviationHigh;
|
||||
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
|
||||
foreach (Container.Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!_Configuration.KeepFullPath)
|
||||
destinationDirectory = destinationRoot;
|
||||
else
|
||||
destinationDirectory = string.Concat(destinationRoot, container.SourceDirectory[configuration.RootDirectory.Length..]);
|
||||
checkDirectory = Path.GetFullPath(container.SourceDirectory);
|
||||
for (int z = 0; z < int.MaxValue; z++)
|
||||
selectedTotal = 0;
|
||||
threeStandardDeviationHigh = Property.Models.Stateless.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
||||
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
||||
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
||||
for (int i = 0; i < container.Items.Count; i++)
|
||||
{
|
||||
if (checkDirectory == configuration.RootDirectory)
|
||||
break;
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
break;
|
||||
(i, dateTimes, selectedItems) = Property.Models.Stateless.IProperty.Get(container, threeStandardDeviationHigh, i);
|
||||
selectedTotal += selectedItems.Count;
|
||||
foreach (Item item in selectedItems)
|
||||
{
|
||||
if (item.ExifDirectory is null)
|
||||
continue;
|
||||
relativePathDirectory = Path.GetDirectoryName(item.RelativePath);
|
||||
if (string.IsNullOrEmpty(relativePathDirectory))
|
||||
continue;
|
||||
if (item.ExifDirectory is null)
|
||||
dateTime = new(item.FilePath.LastWriteTicks);
|
||||
else if (item.ExifDirectory is not null && item.ExifDirectory.DateTimeOriginal is not null)
|
||||
dateTime = item.ExifDirectory.DateTimeOriginal.Value;
|
||||
else
|
||||
dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.ExifDirectory);
|
||||
path = Path.GetFullPath($"{configuration.RootDirectory}{item.RelativePath[..^5]}");
|
||||
directory = Path.Combine($"{aPropertyContentDirectory}{relativePathDirectory}", $"{dateTimes.Min():yyyy-MM-dd_HH-mm-ss}---{dateTimes.Max():yyyy-MM-dd_HH-mm-ss}");
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
fileName = Path.Combine(directory, $"{Path.GetFileName(item.RelativePath[..^5])}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
windowsShortcut = new() { Path = path };
|
||||
windowsShortcut.Save(fileName);
|
||||
windowsShortcut.Dispose();
|
||||
if (!File.Exists(fileName))
|
||||
continue;
|
||||
File.SetLastWriteTime(fileName, dateTime);
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
if (selectedTotal < container.Items.Count && selectedTotal < (from l in container.Items where l.Property is not null select true).Count())
|
||||
continue;
|
||||
topDirectory = checkDirectory;
|
||||
filteredItems = GetFilterItems(container);
|
||||
if (filteredItems.Length == 0)
|
||||
continue;
|
||||
fileMoveCollectionDirectory = GetMoveFileCollection(destinationDirectory, topDirectory, filteredItems);
|
||||
fileMoveCollection.AddRange(fileMoveCollectionDirectory);
|
||||
}
|
||||
results = (from l in fileMoveCollection orderby l.MinimumDateTimeTicks descending, l.LastWriteTimeTicks descending select l).ToArray();
|
||||
return results;
|
||||
}
|
||||
|
||||
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container[] containers)
|
||||
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||
{
|
||||
string checkDirectory;
|
||||
bool hasDuplicate;
|
||||
@ -453,64 +266,251 @@ public class DateGroup
|
||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
|
||||
}
|
||||
|
||||
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container[] containers)
|
||||
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||
{
|
||||
string path;
|
||||
string fileName;
|
||||
string directory;
|
||||
DateTime dateTime;
|
||||
int selectedTotal;
|
||||
const int minimum = 3;
|
||||
List<DateTime> dateTimes;
|
||||
List<Item> selectedItems;
|
||||
const int maximumHours = 24;
|
||||
string? relativePathDirectory;
|
||||
WindowsShortcut windowsShortcut;
|
||||
TimeSpan threeStandardDeviationHigh;
|
||||
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
|
||||
foreach (Container container in containers)
|
||||
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
||||
Item[] filteredItems;
|
||||
string? topDirectory;
|
||||
string? checkDirectory;
|
||||
string destinationDirectory;
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
|
||||
foreach (Container.Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
selectedTotal = 0;
|
||||
threeStandardDeviationHigh = Shared.Models.Stateless.Methods.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
||||
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
||||
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
||||
for (int i = 0; i < container.Items.Count; i++)
|
||||
if (!_Configuration.KeepFullPath)
|
||||
destinationDirectory = destinationRoot;
|
||||
else
|
||||
destinationDirectory = string.Concat(destinationRoot, container.SourceDirectory[configuration.RootDirectory.Length..]);
|
||||
checkDirectory = Path.GetFullPath(container.SourceDirectory);
|
||||
for (int z = 0; z < int.MaxValue; z++)
|
||||
{
|
||||
(i, dateTimes, selectedItems) = Shared.Models.Stateless.Methods.IProperty.Get(container, threeStandardDeviationHigh, i);
|
||||
selectedTotal += selectedItems.Count;
|
||||
foreach (Item item in selectedItems)
|
||||
if (checkDirectory == configuration.RootDirectory)
|
||||
break;
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
break;
|
||||
}
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
continue;
|
||||
topDirectory = checkDirectory;
|
||||
filteredItems = GetFilterItems(container);
|
||||
if (filteredItems.Length == 0)
|
||||
continue;
|
||||
fileMoveCollectionDirectory = GetMoveFileCollection(destinationDirectory, topDirectory, filteredItems);
|
||||
fileMoveCollection.AddRange(fileMoveCollectionDirectory);
|
||||
}
|
||||
results = (from l in fileMoveCollection orderby l.MinimumDateTimeTicks descending, l.LastWriteTimeTicks descending select l).ToArray();
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Item[] GetFilterItems(Container.Models.Container container)
|
||||
{
|
||||
List<Item> results = [];
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.FilePath is not null)
|
||||
results.Add(item);
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> GetMoveFileCollection(string destinationDirectory, string topDirectory, Item[] filteredItems)
|
||||
{
|
||||
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> results = [];
|
||||
char flag;
|
||||
string day;
|
||||
int season;
|
||||
string year;
|
||||
string month;
|
||||
string? check;
|
||||
string fileName;
|
||||
string? pathRoot;
|
||||
DateTime dateTime;
|
||||
string seasonName;
|
||||
string weekOfYear;
|
||||
bool? isWrongYear;
|
||||
string seasonValue;
|
||||
string directoryName;
|
||||
string topDirectoryName;
|
||||
List<DateTime> dateTimes;
|
||||
string[]? matches = null;
|
||||
string[] directorySegments;
|
||||
List<string> destinationCollection;
|
||||
List<string> directoryNames = [];
|
||||
List<string> topDirectorySegments = [];
|
||||
StringBuilder destinationDirectoryName = new();
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
for (int z = 1; z < 3; z++)
|
||||
{
|
||||
if (z == 1)
|
||||
{
|
||||
check = Path.Combine(destinationDirectory, ".");
|
||||
pathRoot = Path.GetPathRoot(destinationDirectory);
|
||||
}
|
||||
else if (z == 2)
|
||||
{
|
||||
check = Path.Combine(topDirectory, ".");
|
||||
pathRoot = Path.GetPathRoot(topDirectory);
|
||||
}
|
||||
else
|
||||
throw new Exception();
|
||||
if (string.IsNullOrEmpty(pathRoot))
|
||||
continue;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
check = Path.GetDirectoryName(check);
|
||||
if (string.IsNullOrEmpty(check) || check == pathRoot)
|
||||
break;
|
||||
directoryName = Path.GetFileName(check);
|
||||
directorySegments = directoryName.Split(' ');
|
||||
topDirectorySegments.AddRange(directorySegments);
|
||||
(_, matches) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(directorySegments, string.Empty);
|
||||
if (matches.Length != 0)
|
||||
break;
|
||||
}
|
||||
if (matches is not null && matches.Length != 0)
|
||||
break;
|
||||
}
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
directoryNames.Clear();
|
||||
destinationCollection = [];
|
||||
_ = destinationDirectoryName.Clear();
|
||||
if (item.ExifDirectory is not null)
|
||||
dateTimes = item.ExifDirectory.GetDateTimes();
|
||||
else
|
||||
dateTimes = [new(item.FilePath.LastWriteTicks)];
|
||||
if (item.ExifDirectory is not null && item.ExifDirectory.DateTimeOriginal is not null)
|
||||
dateTime = item.ExifDirectory.DateTimeOriginal.Value;
|
||||
else if (item.ExifDirectory is null)
|
||||
dateTime = new(item.FilePath.LastWriteTicks);
|
||||
else
|
||||
dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.ExifDirectory);
|
||||
day = dateTime.ToString("MM-dd");
|
||||
month = dateTime.ToString("MMMM");
|
||||
if (item.ExifDirectory?.FilePath.Id is null)
|
||||
{
|
||||
flag = '#';
|
||||
isWrongYear = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
(isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(item.FilePath, item.ExifDirectory.DateTimeOriginal, dateTimes);
|
||||
if (isWrongYear is null)
|
||||
flag = '#';
|
||||
else if (isWrongYear.Value)
|
||||
flag = '~';
|
||||
else
|
||||
{
|
||||
if (item.Property is null)
|
||||
continue;
|
||||
relativePathDirectory = Path.GetDirectoryName(item.RelativePath);
|
||||
if (string.IsNullOrEmpty(relativePathDirectory))
|
||||
continue;
|
||||
if (item.Property is null)
|
||||
dateTime = new(item.FilePath.LastWriteTicks);
|
||||
else if (item.Property is not null && item.Property.DateTimeOriginal is not null)
|
||||
dateTime = item.Property.DateTimeOriginal.Value;
|
||||
if (item.ExifDirectory.DateTimeOriginal is not null && dateTime.DayOfYear != item.ExifDirectory.DateTimeOriginal.Value.DayOfYear && Math.Abs(new TimeSpan(dateTime.Ticks - item.ExifDirectory.DateTimeOriginal.Value.Ticks).TotalHours) > 8)
|
||||
flag = '^';
|
||||
else
|
||||
dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
path = Path.GetFullPath($"{configuration.RootDirectory}{item.RelativePath[..^5]}");
|
||||
directory = Path.Combine($"{aPropertyContentDirectory}{relativePathDirectory}", $"{dateTimes.Min():yyyy-MM-dd_HH-mm-ss}---{dateTimes.Max():yyyy-MM-dd_HH-mm-ss}");
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
fileName = Path.Combine(directory, $"{Path.GetFileName(item.RelativePath[..^5])}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
windowsShortcut = new() { Path = path };
|
||||
windowsShortcut.Save(fileName);
|
||||
windowsShortcut.Dispose();
|
||||
if (!File.Exists(fileName))
|
||||
continue;
|
||||
File.SetLastWriteTime(fileName, dateTime);
|
||||
flag = '=';
|
||||
}
|
||||
}
|
||||
if (selectedTotal < container.Items.Count && selectedTotal < (from l in container.Items where l.Property is not null select true).Count())
|
||||
continue;
|
||||
(season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
if ((from l in topDirectorySegments where l == "Christmas" select true).Any())
|
||||
seasonValue = string.Empty;
|
||||
else
|
||||
seasonValue = $".{season}";
|
||||
if (isWrongYear is null || !isWrongYear.Value)
|
||||
year = $"{flag}{dateTime:yyyy}{seasonValue}";
|
||||
else if (matches is null || matches.Length < 3)
|
||||
year = "----";
|
||||
else
|
||||
{
|
||||
if (matches[0][0] != '~')
|
||||
year = $"{flag}{matches[0].Split('.')[0]}{seasonValue}";
|
||||
else
|
||||
year = $"{flag}{matches[0][1..].Split('.')[0]}{seasonValue}";
|
||||
}
|
||||
topDirectoryName = Path.GetFileName(topDirectory);
|
||||
weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
|
||||
if (_Configuration.ByHash)
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else if (_Configuration.BySeason && topDirectoryName.Length == 1 && topDirectoryName[0] == '_')
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else
|
||||
{
|
||||
if (!_Configuration.KeepFullPath)
|
||||
{
|
||||
if (topDirectoryName.Length > 1)
|
||||
_ = destinationDirectoryName.Append(topDirectoryName);
|
||||
if (_Configuration.BySeason)
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year} {seasonName}"]);
|
||||
else if (_Configuration.ByDay)
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year}-{day}"]);
|
||||
else if (_Configuration.ByWeek)
|
||||
directoryNames.AddRange([$"{destinationDirectoryName} {year}", $"{weekOfYear}) {year} {month}"]);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string sourceDirectoryNameSegment in topDirectorySegments)
|
||||
{
|
||||
if (matches is not null && matches.Contains(sourceDirectoryNameSegment))
|
||||
_ = destinationDirectoryName.Append(year);
|
||||
else
|
||||
_ = destinationDirectoryName.Append(sourceDirectoryNameSegment);
|
||||
}
|
||||
if (_Configuration.BySeason)
|
||||
directoryNames.Add($"{year} {seasonName}");
|
||||
else if (_Configuration.ByDay)
|
||||
directoryNames.Add($"{weekOfYear}) {year} {day}");
|
||||
else if (_Configuration.ByWeek)
|
||||
directoryNames.Add($"{weekOfYear}) {month} {year}");
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
if (!_Configuration.ByHash || item.ExifDirectory?.FilePath.Id is null)
|
||||
fileName = item.FilePath.Name;
|
||||
else
|
||||
fileName = $"{item.ExifDirectory.FilePath.Id.Value}{item.FilePath.ExtensionLowered}";
|
||||
destinationCollection.Add(destinationDirectory);
|
||||
destinationCollection.AddRange(directoryNames);
|
||||
destinationCollection.Add(fileName);
|
||||
if (item.ExifDirectory is null)
|
||||
results.Add(new(item, item.FilePath.LastWriteTicks, dateTime.Ticks, destinationCollection.ToArray()));
|
||||
else
|
||||
results.Add(new(item, item.ExifDirectory.LastWriteTime.Ticks, dateTime.Ticks, destinationCollection.ToArray()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool WriteAllText(string path, string contents, bool compareBeforeWrite)
|
||||
{
|
||||
bool result;
|
||||
string text;
|
||||
if (!compareBeforeWrite)
|
||||
result = true;
|
||||
else
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
text = string.Empty;
|
||||
else
|
||||
text = File.ReadAllText(path);
|
||||
result = text != contents;
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
if (path.Contains("()"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
||||
File.WriteAllText(path, contents);
|
||||
else
|
||||
File.WriteAllText(path, contents);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -34,14 +34,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -34,14 +34,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -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="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -358,7 +358,7 @@ public partial class E_Distance : IDistance
|
||||
}
|
||||
results.Add(keyValuePair.Key, new(keyValuePairs));
|
||||
}
|
||||
return new(results);
|
||||
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)
|
||||
@ -509,7 +509,7 @@ public partial class E_Distance : IDistance
|
||||
faceDistanceContainer = new(face, faceDistance);
|
||||
collection.Add(faceDistanceContainer);
|
||||
}
|
||||
results = new(collection.ToArray());
|
||||
results = collection.AsReadOnly();
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -568,7 +568,7 @@ public partial class E_Distance : IDistance
|
||||
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
|
||||
results.Add(keyValue.Value);
|
||||
}
|
||||
return new(results);
|
||||
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)
|
||||
@ -624,7 +624,7 @@ public partial class E_Distance : IDistance
|
||||
results = ISortingContainer.Sort(results);
|
||||
else
|
||||
results = ISortingContainer.SortUsingDaysDelta(results);
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<RelationContainer> GetRelationCollections(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float distanceTolerance, List<Record> records)
|
||||
@ -672,7 +672,7 @@ public partial class E_Distance : IDistance
|
||||
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(IDistanceLimits distanceLimits, int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||
|
@ -26,9 +26,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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()
|
||||
{
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropExplorer());
|
||||
}
|
||||
|
||||
}
|
@ -26,9 +26,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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()
|
||||
{
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropMove());
|
||||
}
|
||||
|
||||
}
|
@ -27,13 +27,14 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
<ProjectReference Include="..\Container\Container.csproj" />
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -64,63 +64,6 @@ public partial class DragDropSearch : Form
|
||||
Controls.Add(_TextBox);
|
||||
}
|
||||
|
||||
private void Form1_Load(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
AllowDrop = true;
|
||||
DragDrop += new DragEventHandler(Form1_DragDrop);
|
||||
DragEnter += new DragEventHandler(Form1_DragEnter);
|
||||
_TextBox.LostFocus += new EventHandler(TextBox_LostFocus);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_LostFocus(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_TextBox.Text == "ps")
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void Form1_DragEnter(object? sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Data is not null && e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
Container[] containers;
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}");
|
||||
(_, containers) = IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
|
||||
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
||||
foreach (Item item in collection)
|
||||
{
|
||||
if (item.Property?.Id is null)
|
||||
continue;
|
||||
if (_IdToItem.ContainsKey(item.Property.Id.Value))
|
||||
continue;
|
||||
_IdToItem.Add(item.Property.Id.Value, item);
|
||||
}
|
||||
}
|
||||
|
||||
public static string? GetFaceEncoding(string file)
|
||||
{
|
||||
string? result;
|
||||
@ -147,6 +90,37 @@ public partial class DragDropSearch : Form
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
Container.Models.Container[] containers;
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}");
|
||||
(_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
|
||||
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
||||
foreach (Item item in collection)
|
||||
{
|
||||
if (item.ExifDirectory?.FilePath.Id is null)
|
||||
continue;
|
||||
if (_IdToItem.ContainsKey(item.ExifDirectory.FilePath.Id.Value))
|
||||
continue;
|
||||
_IdToItem.Add(item.ExifDirectory.FilePath.Id.Value, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void Form1_Load(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
AllowDrop = true;
|
||||
DragDrop += new DragEventHandler(Form1_DragDrop);
|
||||
DragEnter += new DragEventHandler(Form1_DragEnter);
|
||||
_TextBox.LostFocus += new EventHandler(TextBox_LostFocus);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetDirectoriesOrDoDragDrop(string[] paths)
|
||||
{
|
||||
string name;
|
||||
@ -168,6 +142,19 @@ public partial class DragDropSearch : Form
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_LostFocus(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_TextBox.Text == "ps")
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void Form1_DragDrop(object? sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
@ -183,4 +170,17 @@ public partial class DragDropSearch : Form
|
||||
}
|
||||
}
|
||||
|
||||
private void Form1_DragEnter(object? sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Data is not null && e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,13 +8,11 @@ public class Program
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropSearch());
|
||||
}
|
||||
|
||||
private static Item[] GetFilterItems(Models.Configuration configuration, Container container)
|
||||
private static Item[] GetFilterItems(Models.Configuration configuration, Container.Models.Container container)
|
||||
{
|
||||
List<Item> results = [];
|
||||
foreach (Item item in container.Items)
|
||||
@ -26,11 +24,11 @@ public class Program
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public static List<Item> GetItemCollection(Models.Configuration configuration, Container[] containers)
|
||||
public static List<Item> GetItemCollection(Models.Configuration configuration, Container.Models.Container[] containers)
|
||||
{
|
||||
List<Item> results = [];
|
||||
Item[] filteredItems;
|
||||
foreach (Container container in containers)
|
||||
foreach (Container.Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
|
@ -27,9 +27,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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()
|
||||
{
|
||||
private static void Main() =>
|
||||
// ApplicationConfiguration.Initialize();
|
||||
Application.Run(new DragDropSetPropertyItem());
|
||||
}
|
||||
|
||||
}
|
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Phares.Shared;
|
||||
using ShellProgressBar;
|
||||
@ -30,7 +30,7 @@ public class DuplicateSearch
|
||||
else
|
||||
{
|
||||
Configuration.Verify(configuration, requireExist: false);
|
||||
Container[] containers = GetContainers(ticks, configuration);
|
||||
Container.Models.Container[] containers = GetContainers(ticks, configuration);
|
||||
string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(configuration.RootDirectory);
|
||||
bool argZeroIsConfigurationRootDirectory = configuration.RootDirectory == argZero;
|
||||
string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved");
|
||||
@ -61,6 +61,144 @@ public class DuplicateSearch
|
||||
File.WriteAllText(Path.Combine(alongSideDirectory, $"{directoryName}-{ticks}.json"), json);
|
||||
}
|
||||
|
||||
private static Container.Models.Container[] GetContainers(long ticks, Configuration configuration)
|
||||
{
|
||||
int f;
|
||||
Container.Models.Container[] containers;
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Building Container(s) - {totalSeconds} total second(s)";
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using (ProgressBar progressBar = new(1, message, options))
|
||||
{
|
||||
progressBar.Tick();
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
private static List<int> GetPreloadIds(string destinationRoot)
|
||||
{
|
||||
List<int> results = [];
|
||||
string[] lines;
|
||||
string preloadDirectory = Path.Combine(destinationRoot, "Preload");
|
||||
if (!Directory.Exists(preloadDirectory))
|
||||
_ = Directory.CreateDirectory(preloadDirectory);
|
||||
string[] files = Directory.GetFiles(preloadDirectory, "*.lsv", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
lines = File.ReadAllLines(file);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line) || !int.TryParse(line, out int id) || id == 0)
|
||||
continue;
|
||||
results.Add(id);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds)
|
||||
{
|
||||
Dictionary<int, List<MappingFromItem?>> results = [];
|
||||
string directory;
|
||||
const int zero = 0;
|
||||
FileHolder resizedFileHolder;
|
||||
DateTime[] containerDateTimes;
|
||||
MappingFromItem? mappingFromItem;
|
||||
List<MappingFromItem?>? collection;
|
||||
ReadOnlyCollection<Item> validImageItems;
|
||||
const string duplicates = "-Duplicate(s)";
|
||||
if (containers.Length != 0)
|
||||
{
|
||||
foreach (int id in preloadIds)
|
||||
results.Add(id, [null]);
|
||||
}
|
||||
foreach (Container.Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
validImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container);
|
||||
if (validImageItems.Count == 0)
|
||||
continue;
|
||||
containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
|
||||
foreach (Item item in validImageItems)
|
||||
{
|
||||
if (item.ExifDirectory?.FilePath.Id is null)
|
||||
{
|
||||
if (int.TryParse(item.FilePath.NameWithoutExtension, out int id))
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
if (!results.TryGetValue(item.ExifDirectory.FilePath.Id.Value, out collection))
|
||||
results.Add(item.ExifDirectory.FilePath.Id.Value, []);
|
||||
if (collection is null && !results.TryGetValue(item.ExifDirectory.FilePath.Id.Value, out collection))
|
||||
continue;
|
||||
if (collection.Count == 0)
|
||||
directory = $"0{duplicates}";
|
||||
else
|
||||
directory = $"{collection.Count + 1}{duplicates}";
|
||||
if (collection.Count == 1)
|
||||
{
|
||||
mappingFromItem = collection[zero];
|
||||
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.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));
|
||||
mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||
collection.Add(mappingFromItem);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void QuestionMove(long ticks, ILogger<Program>? logger, string destinationRoot, Dictionary<int, List<MappingFromItem?>> idToCollection, int duplicates)
|
||||
{
|
||||
int[] ids = (from l in idToCollection orderby l.Key where l.Value.Any(m => m is not null) select l.Key).ToArray();
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(destinationRoot, $"{ticks}-id(s).lsv"), string.Join(Environment.NewLine, ids), updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
string json = JsonSerializer.Serialize(idToCollection, new JsonSerializerOptions { WriteIndented = true });
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(destinationRoot, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
logger?.LogInformation($"Found {duplicates} duplicate file(s)");
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
logger?.LogInformation("Press \"Y\" key to continue or close console to leave them moved");
|
||||
if (System.Console.ReadKey().Key != ConsoleKey.Y)
|
||||
continue;
|
||||
logger?.LogInformation(". . .");
|
||||
List<(FilePath FilePath, string Destination)> collection = GetCollectionAndCreateDirectories(idToCollection);
|
||||
Move(logger, ticks, destinationRoot, collection);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<(FilePath FilePath, string Destination)> GetCollectionAndCreateDirectories(Dictionary<int, List<MappingFromItem?>> idToCollection)
|
||||
{
|
||||
List<(FilePath FilePath, string Destination)> results = [];
|
||||
List<string> collection = [];
|
||||
foreach (KeyValuePair<int, List<MappingFromItem?>> keyValuePair in idToCollection)
|
||||
{
|
||||
foreach (MappingFromItem? mappingFromItem in keyValuePair.Value)
|
||||
{
|
||||
if (mappingFromItem?.ResizedFileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (mappingFromItem.ResizedFileHolder.Exists)
|
||||
continue;
|
||||
collection.Add(mappingFromItem.ResizedFileHolder.DirectoryFullPath);
|
||||
results.Add(new(mappingFromItem.FilePath, mappingFromItem.ResizedFileHolder.FullName));
|
||||
}
|
||||
}
|
||||
foreach (string directory in collection.Distinct())
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void Move(ILogger<Program>? logger, long ticks, string destinationRoot, List<(FilePath FilePath, string Destination)> collection)
|
||||
{
|
||||
StringBuilder stringBuilder = new();
|
||||
@ -107,142 +245,4 @@ public class DuplicateSearch
|
||||
logger?.LogInformation(". . .");
|
||||
}
|
||||
|
||||
private static void QuestionMove(long ticks, ILogger<Program>? logger, string destinationRoot, Dictionary<int, List<MappingFromItem?>> idToCollection, int duplicates)
|
||||
{
|
||||
int[] ids = (from l in idToCollection orderby l.Key where l.Value.Any(m => m is not null) select l.Key).ToArray();
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(destinationRoot, $"{ticks}-id(s).lsv"), string.Join(Environment.NewLine, ids), updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
string json = JsonSerializer.Serialize(idToCollection, new JsonSerializerOptions { WriteIndented = true });
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(destinationRoot, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
logger?.LogInformation($"Found {duplicates} duplicate file(s)");
|
||||
for (int y = 0; y < int.MaxValue; y++)
|
||||
{
|
||||
logger?.LogInformation("Press \"Y\" key to continue or close console to leave them moved");
|
||||
if (System.Console.ReadKey().Key != ConsoleKey.Y)
|
||||
continue;
|
||||
logger?.LogInformation(". . .");
|
||||
List<(FilePath FilePath, string Destination)> collection = GetCollectionAndCreateDirectories(idToCollection);
|
||||
Move(logger, ticks, destinationRoot, collection);
|
||||
}
|
||||
}
|
||||
|
||||
private static Container[] GetContainers(long ticks, Configuration configuration)
|
||||
{
|
||||
int f;
|
||||
Container[] containers;
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Building Container(s) - {totalSeconds} total second(s)";
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using (ProgressBar progressBar = new(1, message, options))
|
||||
{
|
||||
progressBar.Tick();
|
||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
||||
(f, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container[] containers, string destinationRoot, List<int> preloadIds)
|
||||
{
|
||||
Dictionary<int, List<MappingFromItem?>> results = [];
|
||||
string directory;
|
||||
const int zero = 0;
|
||||
FileHolder resizedFileHolder;
|
||||
DateTime[] containerDateTimes;
|
||||
MappingFromItem? mappingFromItem;
|
||||
List<MappingFromItem?>? collection;
|
||||
ReadOnlyCollection<Item> validImageItems;
|
||||
const string duplicates = "-Duplicate(s)";
|
||||
if (containers.Length != 0)
|
||||
{
|
||||
foreach (int id in preloadIds)
|
||||
results.Add(id, [null]);
|
||||
}
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
validImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container);
|
||||
if (validImageItems.Count == 0)
|
||||
continue;
|
||||
containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
|
||||
foreach (Item item in validImageItems)
|
||||
{
|
||||
if (item.Property?.Id is null)
|
||||
{
|
||||
if (int.TryParse(item.FilePath.NameWithoutExtension, out int id))
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
if (!results.TryGetValue(item.Property.Id.Value, out collection))
|
||||
results.Add(item.Property.Id.Value, []);
|
||||
if (collection is null && !results.TryGetValue(item.Property.Id.Value, out collection))
|
||||
continue;
|
||||
if (collection.Count == 0)
|
||||
directory = $"0{duplicates}";
|
||||
else
|
||||
directory = $"{collection.Count + 1}{duplicates}";
|
||||
if (collection.Count == 1)
|
||||
{
|
||||
mappingFromItem = collection[zero];
|
||||
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.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));
|
||||
mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||
collection.Add(mappingFromItem);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<(FilePath FilePath, string Destination)> GetCollectionAndCreateDirectories(Dictionary<int, List<MappingFromItem?>> idToCollection)
|
||||
{
|
||||
List<(FilePath FilePath, string Destination)> results = [];
|
||||
List<string> collection = [];
|
||||
foreach (KeyValuePair<int, List<MappingFromItem?>> keyValuePair in idToCollection)
|
||||
{
|
||||
foreach (MappingFromItem? mappingFromItem in keyValuePair.Value)
|
||||
{
|
||||
if (mappingFromItem?.ResizedFileHolder.DirectoryFullPath is null)
|
||||
continue;
|
||||
if (mappingFromItem.ResizedFileHolder.Exists)
|
||||
continue;
|
||||
collection.Add(mappingFromItem.ResizedFileHolder.DirectoryFullPath);
|
||||
results.Add(new(mappingFromItem.FilePath, mappingFromItem.ResizedFileHolder.FullName));
|
||||
}
|
||||
}
|
||||
foreach (string directory in collection.Distinct())
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<int> GetPreloadIds(string destinationRoot)
|
||||
{
|
||||
List<int> results = [];
|
||||
string[] lines;
|
||||
string preloadDirectory = Path.Combine(destinationRoot, "Preload");
|
||||
if (!Directory.Exists(preloadDirectory))
|
||||
_ = Directory.CreateDirectory(preloadDirectory);
|
||||
string[] files = Directory.GetFiles(preloadDirectory, "*.lsv", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
lines = File.ReadAllLines(file);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line) || !int.TryParse(line, out int id) || id == 0)
|
||||
continue;
|
||||
results.Add(id);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -46,7 +46,8 @@ public class D_Face : IFaceD
|
||||
private readonly EncoderParameters _HiddenEncoderParameters;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
|
||||
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultCollectionFileGroups;
|
||||
|
||||
public D_Face(
|
||||
string argZero,
|
||||
@ -69,7 +70,6 @@ public class D_Face : IFaceD
|
||||
float[] rectangleIntersectMinimums)
|
||||
{
|
||||
_ArgZero = argZero;
|
||||
_FileGroups = [];
|
||||
_ImageCodecInfo = imageCodecInfo;
|
||||
_EncoderParameters = encoderParameters;
|
||||
_FileNameExtension = filenameExtension;
|
||||
@ -84,6 +84,8 @@ public class D_Face : IFaceD
|
||||
_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;
|
||||
@ -93,6 +95,73 @@ public class D_Face : IFaceD
|
||||
_WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
|
||||
}
|
||||
|
||||
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Shared.Models.Face face, bool mappedFile)
|
||||
{
|
||||
FileInfo fileInfo = new(filePath.FullName);
|
||||
if (fileInfo.Exists)
|
||||
{
|
||||
string? json;
|
||||
short type = 2;
|
||||
string? model;
|
||||
string? maker;
|
||||
string checkFile = $"{filePath.FullName}.exif";
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
||||
// const int author = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor; // 40093
|
||||
if (mappedFile)
|
||||
{
|
||||
json = IMetadata.GetOutputResolution(exifDirectory);
|
||||
if (json is not null && json.Contains(nameof(DateTime)))
|
||||
return;
|
||||
(maker, model) = Get(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
maker = IMetadata.GetMaker(exifDirectory);
|
||||
model = IMetadata.GetModel(exifDirectory);
|
||||
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
|
||||
json = IMetadata.GetOutputResolution(faceExifDirectory);
|
||||
if (json is not null && json.Contains(nameof(DateTime)))
|
||||
return;
|
||||
}
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
FaceFile faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||
geoLocation?.ToDmsString(),
|
||||
face.DateTime,
|
||||
null,
|
||||
face.FaceParts,
|
||||
face.Location,
|
||||
maker,
|
||||
null,
|
||||
model,
|
||||
face.OutputResolution);
|
||||
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
||||
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
|
||||
#pragma warning disable CA1416
|
||||
Bitmap bitmap = new(fileInfo.FullName);
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
bitmap.Save(checkFile);
|
||||
bitmap.Dispose();
|
||||
#pragma warning restore CA1416
|
||||
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
|
||||
File.Delete(fileInfo.FullName);
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
private static (string?, string?) Get(string? json)
|
||||
{
|
||||
string? model;
|
||||
string? maker;
|
||||
FaceFile? faceFile = json is null ? null : JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
|
||||
if (faceFile is null || faceFile.Location is null)
|
||||
(maker, model) = (null, null);
|
||||
else
|
||||
(maker, model) = (faceFile.Maker, faceFile.Model);
|
||||
return (maker, model);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
@ -101,10 +170,234 @@ public class D_Face : IFaceD
|
||||
|
||||
public void Update(string dResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, ReadOnlyCollection<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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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;
|
||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||
{
|
||||
results.Add(new(face, null, string.Empty, save));
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
fileHolder = FileHolder.Get(fileInfo);
|
||||
if (!directoryInfo.Exists)
|
||||
save = true;
|
||||
else if (_OverrideForFaceImages)
|
||||
save = true;
|
||||
else if (!fileHolder.Exists)
|
||||
save = true;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
save = true;
|
||||
results.Add(new(face, fileHolder, Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||
}
|
||||
if (results.Any(l => l.Save))
|
||||
{
|
||||
if (!directoryInfo.Exists)
|
||||
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||
SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
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 static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (Directory.Exists(checkFile))
|
||||
{
|
||||
Directory.Move(checkFile, directoryInfo.FullName);
|
||||
directoryInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, ExifDirectory exifDirectory, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
|
||||
{
|
||||
List<Shared.Models.Face>? results;
|
||||
string? json;
|
||||
List<Location> locations;
|
||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultCollectionFileGroups[0][cei.Enum][cei.Index];
|
||||
FileInfo fileInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, fileInfo);
|
||||
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_PropertiesChangedForFaces)
|
||||
results = null;
|
||||
else if (!fileInfo.Exists)
|
||||
results = null;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
results = JsonSerializer.Deserialize<List<Shared.Models.Face>>(json);
|
||||
if (results is null)
|
||||
throw new NullReferenceException(nameof(results));
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results = null;
|
||||
parseExceptions.Add(nameof(D_Face));
|
||||
}
|
||||
}
|
||||
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
||||
locations = [];
|
||||
else
|
||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||
if (results is null || locations.Count > 0)
|
||||
{
|
||||
results = GetFaces(outputResolution, cResultsFullGroupDirectory, exifDirectory, mappingFromItem, outputResolutionToResize, locations);
|
||||
if (results.Count == 0)
|
||||
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
||||
else
|
||||
{
|
||||
bool updateDateWhenMatches = dateTimes.Count > 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
|
||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
||||
{
|
||||
if (!_ForceFaceLastWriteTimeToCreationTime)
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, ExifDirectory exifDirectory, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
|
||||
{
|
||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
||||
List<Shared.Models.Face> results = [];
|
||||
FaceRecognitionDotNet.Image? unknownImage;
|
||||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
||||
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
||||
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
|
||||
collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
|
||||
if (collection.Count == 0)
|
||||
results.Add(new(exifDirectory, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
|
||||
else
|
||||
{
|
||||
double[] rawEncoding;
|
||||
Shared.Models.Face face;
|
||||
Shared.Models.FaceEncoding convertedFaceEncoding;
|
||||
foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary<FacePart, FacePoint[]>? faceParts) in collection)
|
||||
{
|
||||
face = new(exifDirectory, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location);
|
||||
if (faceEncoding is not null)
|
||||
{
|
||||
rawEncoding = faceEncoding.GetRawEncoding();
|
||||
convertedFaceEncoding = new(rawEncoding, faceEncoding.Size);
|
||||
face.SetFaceEncoding(convertedFaceEncoding);
|
||||
}
|
||||
if (faceParts is not null)
|
||||
face.SetFaceParts(faceParts);
|
||||
results.Add(face);
|
||||
}
|
||||
}
|
||||
unknownImage.Dispose();
|
||||
faceRecognition.Dispose();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName)
|
||||
@ -148,8 +441,6 @@ public class D_Face : IFaceD
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
|
||||
{
|
||||
int width;
|
||||
@ -165,6 +456,7 @@ public class D_Face : IFaceD
|
||||
PropertyItem? propertyItem;
|
||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||
string? model = IMetadata.GetModel(exifDirectory);
|
||||
#pragma warning disable CA1416
|
||||
using Bitmap source = new(resizedFileHolder.FullName);
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||
@ -227,254 +519,9 @@ public class D_Face : IFaceD
|
||||
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
||||
bitmap.Save(fileName, _HiddenImageCodecInfo, _HiddenEncoderParameters);
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
File.SetAttributes(fileName, FileAttributes.Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
||||
List<Shared.Models.Face> results = [];
|
||||
FaceRecognitionDotNet.Image? unknownImage;
|
||||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
||||
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
||||
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
|
||||
collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
|
||||
if (collection.Count == 0)
|
||||
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
|
||||
else
|
||||
{
|
||||
double[] rawEncoding;
|
||||
Shared.Models.Face face;
|
||||
Shared.Models.FaceEncoding convertedFaceEncoding;
|
||||
foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary<FacePart, FacePoint[]>? faceParts) in collection)
|
||||
{
|
||||
face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location);
|
||||
if (faceEncoding is not null)
|
||||
{
|
||||
rawEncoding = faceEncoding.GetRawEncoding();
|
||||
convertedFaceEncoding = new(rawEncoding, faceEncoding.Size);
|
||||
face.SetFaceEncoding(convertedFaceEncoding);
|
||||
}
|
||||
if (faceParts is not null)
|
||||
face.SetFaceParts(faceParts);
|
||||
results.Add(face);
|
||||
}
|
||||
}
|
||||
unknownImage.Dispose();
|
||||
faceRecognition.Dispose();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
public List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
|
||||
{
|
||||
List<Shared.Models.Face>? results;
|
||||
string? json;
|
||||
List<Location> locations;
|
||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultCollection][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json"));
|
||||
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_PropertiesChangedForFaces)
|
||||
results = null;
|
||||
else if (!fileInfo.Exists)
|
||||
results = null;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
results = JsonSerializer.Deserialize<List<Shared.Models.Face>>(json);
|
||||
if (results is null)
|
||||
throw new NullReferenceException(nameof(results));
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results = null;
|
||||
parseExceptions.Add(nameof(D_Face));
|
||||
}
|
||||
}
|
||||
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
||||
locations = [];
|
||||
else
|
||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||
if (results is null || locations.Count > 0)
|
||||
{
|
||||
results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
|
||||
if (results.Count == 0)
|
||||
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
||||
else
|
||||
{
|
||||
bool updateDateWhenMatches = dateTimes.Count > 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
|
||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
||||
{
|
||||
if (!_ForceFaceLastWriteTimeToCreationTime)
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
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[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
||||
bool directoryExists = Directory.Exists(directory);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
save = false;
|
||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||
{
|
||||
results.Add(new(face, null, string.Empty, save));
|
||||
continue;
|
||||
}
|
||||
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}"));
|
||||
fileHolder = FileHolder.Get(fileInfo);
|
||||
if (!directoryExists)
|
||||
save = true;
|
||||
else if (_OverrideForFaceImages)
|
||||
save = true;
|
||||
else if (!fileHolder.Exists)
|
||||
save = true;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
save = true;
|
||||
results.Add(new(face, fileHolder, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||
}
|
||||
if (results.Any(l => l.Save))
|
||||
{
|
||||
if (!directoryExists)
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
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
|
||||
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
|
@ -32,17 +32,17 @@ public class D2_FaceParts
|
||||
private readonly bool _OverrideForFaceLandmarkImages;
|
||||
private readonly EncoderParameters _EncoderParameters;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
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;
|
||||
_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;
|
||||
}
|
||||
@ -55,32 +55,241 @@ public class D2_FaceParts
|
||||
|
||||
public void Update(string dResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultContent]);
|
||||
foreach (KeyValuePair<string, ReadOnlyCollection<string>> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
|
||||
{
|
||||
xMinimum = points[0].X;
|
||||
xMaximum = xMinimum;
|
||||
yMinimum = points[0].Y;
|
||||
yMaximum = yMinimum;
|
||||
foreach (PointF point in points)
|
||||
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)
|
||||
{
|
||||
if (xMinimum > point.X)
|
||||
xMinimum = point.X;
|
||||
if (xMaximum < point.X)
|
||||
xMaximum = point.X;
|
||||
if (yMinimum > point.Y)
|
||||
yMinimum = point.Y;
|
||||
if (yMaximum < point.Y)
|
||||
yMaximum = point.Y;
|
||||
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
|
||||
_ResultContentFileGroups[0] = keyValuePair.Value;
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
bool any = false;
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
continue;
|
||||
if (!any)
|
||||
any = true;
|
||||
}
|
||||
if (any)
|
||||
SaveAllFaceParts(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
||||
}
|
||||
|
||||
private void SaveAllFaceParts(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
Brush brush;
|
||||
int pointSize;
|
||||
bool any = false;
|
||||
FaceFile faceFile;
|
||||
bool? isDefaultName;
|
||||
List<long> personKeys = [];
|
||||
List<FaceFile> faceFiles = [];
|
||||
StringBuilder stringBuilder = new();
|
||||
MappingFromPerson? mappingFromPerson;
|
||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||
string? model = IMetadata.GetModel(exifDirectory);
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
#pragma warning disable CA1416
|
||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
using Graphics graphics = Graphics.FromImage(image);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
continue;
|
||||
if (!any && face.Mapping?.MappingFromPerson is null)
|
||||
any = true;
|
||||
mappingFromPerson = face.Mapping?.MappingFromPerson;
|
||||
brush = mappingFromPerson is null ? Brushes.Red : Brushes.GreenYellow;
|
||||
isDefaultName = mappingFromPerson is null ? null : Shared.Models.Stateless.Methods.IPerson.IsDefaultName(mappingFromPerson);
|
||||
if (mappingFromPerson is not null && isDefaultName is not null && !isDefaultName.Value)
|
||||
personKeys.Add(mappingFromPerson.PersonKey);
|
||||
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||
geoLocation?.ToDmsString(),
|
||||
face.DateTime,
|
||||
face.FaceEncoding,
|
||||
face.FaceParts,
|
||||
face.Location,
|
||||
maker,
|
||||
mappingFromPerson,
|
||||
model,
|
||||
face.OutputResolution);
|
||||
faceFiles.Add(faceFile);
|
||||
pointSize = GetPointSize(face.FaceParts, defaultPointSize: 2);
|
||||
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
|
||||
{
|
||||
foreach (FacePoint facePoint in facePoints)
|
||||
graphics.FillEllipse(brush, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2);
|
||||
if (facePart == FacePart.Chin)
|
||||
continue;
|
||||
if (facePoints.Length < 3)
|
||||
continue;
|
||||
x = (int)(from l in facePoints select l.X).Average();
|
||||
y = (int)(from l in facePoints select l.Y).Average();
|
||||
graphics.FillEllipse(Brushes.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2);
|
||||
}
|
||||
}
|
||||
_ = graphics.Save();
|
||||
#pragma warning restore CA1416
|
||||
string directory = GetSeasonDirectory(d2ResultsFullGroupDirectory, mappingFromItem, any);
|
||||
SaveImage(mappingFromItem, directory, image, faceFiles);
|
||||
}
|
||||
|
||||
private int GetPointSize(Dictionary<FacePart, FacePoint[]> faceParts, int defaultPointSize)
|
||||
{
|
||||
int result;
|
||||
FacePoint[]? facePoints;
|
||||
if (faceParts.TryGetValue(FacePart.LeftEye, out facePoints))
|
||||
result = (int)Math.Ceiling((facePoints.Max(l => l.X) - facePoints.Min(l => l.X)) * .05);
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
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);
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||
if (!string.IsNullOrEmpty(faceFileJson))
|
||||
File.WriteAllText($"{fileName}.json", faceFileJson);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveFaceLandmarkImages(Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces, bool saveRotated)
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
bool check = false;
|
||||
FileInfo rotatedFileInfo;
|
||||
DateTime? dateTime = null;
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
string deterministicHashCodeKey;
|
||||
bool updateDateWhenMatches = false;
|
||||
List<(Shared.Models.Face, string, string)> collection = [];
|
||||
string fileName = mappingFromItem.FilePath.NameWithoutExtension;
|
||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face)];
|
||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
|
||||
DirectoryInfo directoryInfo = new(Path.Combine(directory, mappingFromItem.FilePath.NameWithoutExtension));
|
||||
MoveIf(fileName, cei, directory, directoryInfo);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||
{
|
||||
collection.Add(new(face, string.Empty, string.Empty));
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||
continue;
|
||||
rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName));
|
||||
if (check)
|
||||
continue;
|
||||
else if (!directoryInfo.Exists)
|
||||
check = true;
|
||||
else if (_OverrideForFaceLandmarkImages)
|
||||
check = true;
|
||||
else if (!fileInfo.Exists)
|
||||
check = true;
|
||||
else if (saveRotated && !rotatedFileInfo.Exists)
|
||||
check = true;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
check = true;
|
||||
if (check && !updateDateWhenMatches)
|
||||
{
|
||||
updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
}
|
||||
}
|
||||
if (check)
|
||||
{
|
||||
if (!directoryInfo.Exists)
|
||||
_ = Directory.CreateDirectory(directoryInfo.FullName);
|
||||
SaveFaceParts(mappingFromItem, exifDirectory, collection);
|
||||
if (saveRotated)
|
||||
SaveRotated(mappingFromItem, collection);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
string? checkDirectory = segments.Length == 1 ?
|
||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||
segments.Length == 2 ?
|
||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||
null;
|
||||
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
||||
{
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (Directory.Exists(checkFile))
|
||||
{
|
||||
Directory.Move(checkFile, directoryInfo.FullName);
|
||||
directoryInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap RotateBitmap(Image image, float angle)
|
||||
{
|
||||
Bitmap result;
|
||||
#pragma warning disable CA1416
|
||||
Bitmap bitmap = new(image);
|
||||
result = RotateBitmap(bitmap, angle);
|
||||
bitmap?.Dispose();
|
||||
#pragma warning restore CA1416
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bitmap RotateBitmap(Bitmap bitmap, float angle)
|
||||
{
|
||||
@ -92,6 +301,7 @@ public class D2_FaceParts
|
||||
#elif Windows
|
||||
// Make save Matrix to represent rotation
|
||||
// by this angle.
|
||||
#pragma warning disable CA1416
|
||||
Matrix rotate_at_origin = new();
|
||||
rotate_at_origin.Rotate(angle);
|
||||
|
||||
@ -138,301 +348,28 @@ public class D2_FaceParts
|
||||
int y = (hgt - bitmap.Height) / 2;
|
||||
gr.DrawImage(bitmap, x, y);
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
#endif
|
||||
// Return the result bitmap.
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bitmap RotateBitmap(Image image, float angle)
|
||||
private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum)
|
||||
{
|
||||
Bitmap result;
|
||||
Bitmap bitmap = new(image);
|
||||
result = RotateBitmap(bitmap, angle);
|
||||
bitmap?.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveRotated(MappingFromItem mappingFromItem, List<(Shared.Models.Face, string, string)> collection)
|
||||
{
|
||||
double? α;
|
||||
Bitmap rotated;
|
||||
foreach ((Shared.Models.Face face, string _, string rotatedFileName) in collection)
|
||||
xMinimum = points[0].X;
|
||||
xMaximum = xMinimum;
|
||||
yMinimum = points[0].Y;
|
||||
yMaximum = yMinimum;
|
||||
foreach (PointF point in points)
|
||||
{
|
||||
if (face.FaceParts is null)
|
||||
continue;
|
||||
(_, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts);
|
||||
if (α is null)
|
||||
continue;
|
||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
rotated = RotateBitmap(image, (float)α.Value);
|
||||
if (rotated is not null)
|
||||
{
|
||||
rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters);
|
||||
rotated.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetSeasonDirectory(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, bool any)
|
||||
{
|
||||
string result;
|
||||
string minimumDateYear = mappingFromItem.MinimumDateTime.ToString("yyyy");
|
||||
DateTime dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
|
||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
string year = mappingFromItem.DateTimeOriginal is null ? $"{minimumDateYear[1..]}{minimumDateYear[0]}" : mappingFromItem.DateTimeOriginal.Value.ToString("yyyy");
|
||||
string directory = Path.Combine(d2ResultsFullGroupDirectory, $"[{_PropertyConfiguration.ResultContent}]", $"{year}.{season} {seasonName}");
|
||||
result = any ? Path.Combine(directory, "---") : Path.Combine(directory, "Complete");
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveImage(MappingFromItem mappingFromItem, string directory, Image image, List<FaceFile> faceFiles)
|
||||
{
|
||||
short type = 2;
|
||||
string faceFileJson;
|
||||
PropertyItem? propertyItem;
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||
string fileName = Path.Combine(directory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
||||
try
|
||||
{
|
||||
foreach (int propertyId in image.PropertyIdList)
|
||||
{
|
||||
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
|
||||
continue;
|
||||
image.RemovePropertyItem(propertyId);
|
||||
}
|
||||
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||
image.SetPropertyItem(propertyItem);
|
||||
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFiles.ToArray(), FaceFileCollectionGenerationContext.Default.FaceFileArray);
|
||||
if (!string.IsNullOrEmpty(faceFileJson))
|
||||
File.WriteAllText($"{fileName}.json", faceFileJson);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveAllFaceParts(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
{
|
||||
int x;
|
||||
int 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, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces, bool saveRotated)
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
bool check = false;
|
||||
FileInfo rotatedFileInfo;
|
||||
DateTime? dateTime = null;
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
string deterministicHashCodeKey;
|
||||
bool updateDateWhenMatches = false;
|
||||
List<(Shared.Models.Face, string, string)> collection = [];
|
||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face)];
|
||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||
string directory = Path.Combine(_FileGroups[_PropertyConfiguration.ResultContent][directoryIndex], mappingFromItem.FilePath.NameWithoutExtension);
|
||||
bool directoryExists = Directory.Exists(directory);
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
{
|
||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||
{
|
||||
collection.Add(new(face, string.Empty, string.Empty));
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||
continue;
|
||||
rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||
collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName));
|
||||
if (check)
|
||||
continue;
|
||||
else if (!directoryExists)
|
||||
check = true;
|
||||
else if (_OverrideForFaceLandmarkImages)
|
||||
check = true;
|
||||
else if (!fileInfo.Exists)
|
||||
check = true;
|
||||
else if (saveRotated && !rotatedFileInfo.Exists)
|
||||
check = true;
|
||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
check = true;
|
||||
if (check && !updateDateWhenMatches)
|
||||
{
|
||||
updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
}
|
||||
}
|
||||
if (check)
|
||||
{
|
||||
if (!directoryExists)
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
SaveFaceParts(mappingFromItem, exifDirectory, collection);
|
||||
if (saveRotated)
|
||||
SaveRotated(mappingFromItem, collection);
|
||||
if (xMinimum > point.X)
|
||||
xMinimum = point.X;
|
||||
if (xMaximum < point.X)
|
||||
xMaximum = point.X;
|
||||
if (yMinimum > point.Y)
|
||||
yMinimum = point.Y;
|
||||
if (yMaximum < point.Y)
|
||||
yMaximum = point.Y;
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,18 +406,116 @@ public class D2_FaceParts
|
||||
return results;
|
||||
}
|
||||
|
||||
public void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||
private void SaveImage(string fileName, Image image, FaceFile faceFile)
|
||||
{
|
||||
bool any = false;
|
||||
foreach (Shared.Models.Face face in faces)
|
||||
short type = 2;
|
||||
string faceFileJson;
|
||||
PropertyItem? propertyItem;
|
||||
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||
try
|
||||
{
|
||||
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
continue;
|
||||
if (!any)
|
||||
any = true;
|
||||
#pragma warning disable CA1416
|
||||
foreach (int propertyId in image.PropertyIdList)
|
||||
{
|
||||
if (propertyId == MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation)
|
||||
continue;
|
||||
image.RemovePropertyItem(propertyId);
|
||||
}
|
||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||
image.SetPropertyItem(propertyItem);
|
||||
image.Save(fileName, _ImageCodecInfo, _EncoderParameters);
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not null && !string.IsNullOrEmpty(fileName) && File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||
if (!string.IsNullOrEmpty(faceFileJson))
|
||||
File.WriteAllText($"{fileName}.json", faceFileJson);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveRotated(MappingFromItem mappingFromItem, List<(Shared.Models.Face, string, string)> collection)
|
||||
{
|
||||
double? α;
|
||||
Bitmap rotated;
|
||||
foreach ((Shared.Models.Face face, string _, string rotatedFileName) in collection)
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
if (face.FaceParts is null)
|
||||
continue;
|
||||
(_, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts);
|
||||
if (α is null)
|
||||
continue;
|
||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
rotated = RotateBitmap(image, (float)α.Value);
|
||||
if (rotated is not null)
|
||||
{
|
||||
rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters);
|
||||
rotated.Dispose();
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveFaceParts(MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<(Shared.Models.Face, string, string)> collection)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
Brush brush;
|
||||
int pointSize;
|
||||
FaceFile faceFile;
|
||||
MappingFromPerson? mappingFromPerson;
|
||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||
string? model = IMetadata.GetModel(exifDirectory);
|
||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||
foreach ((Shared.Models.Face face, string fileName, string _) in collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
if (face.Location is null || face.FaceEncoding is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||
continue;
|
||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||
mappingFromPerson = face.Mapping?.MappingFromPerson;
|
||||
brush = mappingFromPerson is null ? Brushes.Red : Brushes.GreenYellow;
|
||||
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||
geoLocation?.ToDmsString(),
|
||||
face.DateTime,
|
||||
face.FaceEncoding,
|
||||
face.FaceParts,
|
||||
face.Location,
|
||||
maker,
|
||||
mappingFromPerson,
|
||||
model,
|
||||
face.OutputResolution);
|
||||
using Graphics graphics = Graphics.FromImage(image);
|
||||
pointSize = GetPointSize(face.FaceParts, defaultPointSize: 2);
|
||||
foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts)
|
||||
{
|
||||
foreach (FacePoint facePoint in facePoints)
|
||||
graphics.FillEllipse(brush, facePoint.X - pointSize, facePoint.Y - pointSize, pointSize * 2, pointSize * 2);
|
||||
if (facePart == FacePart.Chin)
|
||||
continue;
|
||||
if (facePoints.Length < 3)
|
||||
continue;
|
||||
x = (int)(from l in facePoints select l.X).Average();
|
||||
y = (int)(from l in facePoints select l.Y).Average();
|
||||
graphics.FillEllipse(Brushes.Purple, x - pointSize, y - pointSize, pointSize * 2, pointSize * 2);
|
||||
}
|
||||
_ = graphics.Save();
|
||||
SaveImage(fileName, image, faceFile);
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
}
|
||||
}
|
||||
if (any)
|
||||
SaveAllFaceParts(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -34,12 +34,12 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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.0" />
|
||||
<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" />
|
||||
@ -51,10 +51,10 @@
|
||||
<ProjectReference Include="..\FaceParts\FaceParts.csproj" />
|
||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||
<ProjectReference Include="..\Map\Map.csproj" />
|
||||
<ProjectReference Include="..\Container\Container.csproj" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
|
||||
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -54,7 +54,7 @@ public class Place
|
||||
results.Add(Get(place));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ internal class F_Random
|
||||
relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static Dictionary<string, ImmichAsset> GetImmichAssets(string immichAssetsFile)
|
||||
|
@ -37,10 +37,12 @@
|
||||
<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="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
<ProjectReference Include="..\Container\Container.csproj" />
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
File diff suppressed because it is too large
Load Diff
@ -22,62 +22,190 @@ internal abstract class DistanceLogic
|
||||
internal record TicksDirectory(DateTime AlternateDirectoryDateTime,
|
||||
string Directory,
|
||||
DateTime DirectoryDateTime,
|
||||
string DirectoryName,
|
||||
bool? IsLocationContainerDebugDirectory,
|
||||
float? TotalDays);
|
||||
|
||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||
{
|
||||
string checkFile;
|
||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (facesFileNames.Contains(file))
|
||||
{
|
||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||
internal static List<Record> DeleteEmptyDirectoriesAndGetCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, string eDistanceContentDirectory, ReadOnlyDictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, ReadOnlyCollection<string> personKeyFormattedCollection)
|
||||
{
|
||||
List<Record> results = [];
|
||||
bool check;
|
||||
string message;
|
||||
string[] files;
|
||||
string checkFile;
|
||||
bool? isDefault;
|
||||
int? linksCount;
|
||||
int totalSeconds;
|
||||
DateTime dateTime;
|
||||
TimeSpan timeSpan;
|
||||
int directoryNumber;
|
||||
List<Record> records;
|
||||
string? checkDirectory;
|
||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
ProgressBar progressBar;
|
||||
string[] yearDirectories;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
string? personFirstInitial;
|
||||
bool isReservedDirectoryName;
|
||||
string[] personNameDirectories;
|
||||
string? newestPersonKeyFormatted;
|
||||
string? personDisplayDirectoryName;
|
||||
string[] personNameLinkDirectories;
|
||||
string? personFirstInitialDirectory;
|
||||
List<TicksDirectory> ticksDirectories;
|
||||
string[] personKeyFormattedDirectories;
|
||||
string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
Directory.Move(directory, checkDirectory);
|
||||
else
|
||||
check = false;
|
||||
results.Clear();
|
||||
distinct.Clear();
|
||||
directoryNumber = 0;
|
||||
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(configuration, eDistanceContentDirectory);
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{i}) {ticksDirectories.Count:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
|
||||
progressBar = new(ticksDirectories.Count, message, options);
|
||||
foreach (TicksDirectory ticksDirectory in ticksDirectories)
|
||||
{
|
||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
progressBar.Tick();
|
||||
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
||||
{
|
||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||
continue;
|
||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
File.Move(file, checkFile);
|
||||
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
||||
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy));
|
||||
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)))
|
||||
{
|
||||
Individually(configuration, ticksDirectory, personKeyFormattedDirectory);
|
||||
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
}
|
||||
_ = personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
{
|
||||
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
||||
if (timeSpan.TotalDays > 6)
|
||||
throw new Exception($"{configuration.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
||||
}
|
||||
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string yearDirectory in yearDirectories)
|
||||
{
|
||||
if (check && !Directory.Exists(yearDirectory))
|
||||
continue;
|
||||
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
||||
linksCount = null;
|
||||
else
|
||||
linksCount = GetLinksCount(yearDirectory);
|
||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (personNameDirectories.Length > 1)
|
||||
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||
foreach (string personNameDirectory in personNameDirectories)
|
||||
{
|
||||
directoryNumber++;
|
||||
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
||||
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
||||
{
|
||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Delete(yearDirectory, recursive: true);
|
||||
continue;
|
||||
}
|
||||
Directory.Move(personNameDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
continue;
|
||||
}
|
||||
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (isReservedDirectoryName && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
||||
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
||||
if (!isDefault.Value)
|
||||
{
|
||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
files = RenameBirth(files);
|
||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||
{
|
||||
if (!check)
|
||||
check = true;
|
||||
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length)
|
||||
continue;
|
||||
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !personKeyFormattedCollection.Contains(personKeyFormatted))
|
||||
personFirstInitialDirectory = personNameDirectory;
|
||||
else
|
||||
{
|
||||
personFirstInitial = personDisplayDirectoryName[..1];
|
||||
if (personFirstInitial.All(char.IsDigit))
|
||||
{
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
||||
continue;
|
||||
}
|
||||
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
||||
if (Directory.Exists(personFirstInitialDirectory))
|
||||
throw new Exception("Forgot to ...");
|
||||
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
||||
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
records = GetRecords(propertyConfiguration, configuration, ticksDirectory, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName);
|
||||
if (records.Count > 0)
|
||||
results.AddRange(records);
|
||||
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
||||
{
|
||||
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith(".lnk"))
|
||||
continue;
|
||||
File.Delete(file);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
}
|
||||
progressBar.Dispose();
|
||||
if (check)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(Configuration configuration, string eDistanceContentDirectory)
|
||||
@ -86,53 +214,55 @@ internal abstract class DistanceLogic
|
||||
float? totalDays;
|
||||
long? next = null;
|
||||
string? checkDirectory;
|
||||
string ticksDirectoryName;
|
||||
DateTime directoryDateTime;
|
||||
DirectoryInfo directoryInfo;
|
||||
TicksDirectory ticksDirectory;
|
||||
long? lastDirectoryTicks = null;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
DateTime alternateDirectoryDateTime;
|
||||
string ticksDirectoryNameFirstSegment;
|
||||
bool? isLocationContainerDebugDirectory;
|
||||
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
||||
for (int i = 1; i < 5; i++)
|
||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||
if (!Directory.Exists(eDistanceContentDirectory))
|
||||
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
||||
string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string ticksDirectory in ticksDirectories)
|
||||
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string ticksFullPath in ticksFullPaths)
|
||||
{
|
||||
ticksDirectoryName = Path.GetFileName(ticksDirectory);
|
||||
if (ticksDirectoryName.Length < 3)
|
||||
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
|
||||
if (ticksDirectoryNameFirstSegment.Length < 3)
|
||||
continue;
|
||||
if (!long.TryParse(ticksDirectoryName, out long directoryTicks))
|
||||
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
|
||||
throw new NotSupportedException();
|
||||
if (next is null)
|
||||
next = new DateTime(directoryTicks).Ticks;
|
||||
else
|
||||
{
|
||||
next += month;
|
||||
checkDirectory = Path.GetDirectoryName(ticksDirectory);
|
||||
checkDirectory = Path.GetDirectoryName(ticksFullPath);
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
{
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
|
||||
if (ticksDirectory == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern))
|
||||
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern))
|
||||
continue;
|
||||
Directory.Move(ticksDirectory, checkDirectory);
|
||||
Directory.Move(ticksFullPath, checkDirectory);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
directoryInfo = new(ticksDirectory);
|
||||
directoryInfo = new(ticksFullPath);
|
||||
directoryDateTime = new DateTime(directoryTicks);
|
||||
if (directoryInfo.CreationTime.Ticks != directoryTicks)
|
||||
Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks));
|
||||
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
|
||||
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
||||
Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks));
|
||||
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
|
||||
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
||||
isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryName.EndsWith(configuration.LocationContainerDebugDirectory);
|
||||
isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(configuration.LocationContainerDebugDirectory);
|
||||
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
||||
results.Add(new(alternateDirectoryDateTime, ticksDirectory, new(directoryTicks), ticksDirectoryName, isLocationContainerDebugDirectory, totalDays));
|
||||
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
|
||||
results.Add(ticksDirectory);
|
||||
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
||||
continue;
|
||||
lastDirectoryTicks = directoryTicks;
|
||||
@ -216,38 +346,42 @@ internal abstract class DistanceLogic
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||
{
|
||||
List<Record> results = [];
|
||||
string fileName;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
FileHolder fileHolder;
|
||||
int? wholePercentages;
|
||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.EndsWith(".lnk"))
|
||||
continue;
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
||||
if (wholePercentages is null)
|
||||
continue;
|
||||
fileName = Path.GetFileName(file);
|
||||
if (distinct.Contains(fileName))
|
||||
if (facesFileNames.Contains(file))
|
||||
{
|
||||
checkFile = $"{file}.dup";
|
||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
distinct.Add(fileName);
|
||||
results.Add(new(directoryNumber, isDefault, linksCount, filePath, personDisplayDirectoryName, personKeyFormatted));
|
||||
File.Delete(file);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static int? GetLinksCount(string yearDirectory)
|
||||
{
|
||||
int? result;
|
||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||
if (yearDirectoryNameSegments.Length != 3)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
string lastSegment = yearDirectoryNameSegments[^1];
|
||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||
result = null;
|
||||
else
|
||||
result = lastSegment[0] - 65;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string[] RenameBirth(string[] files)
|
||||
@ -282,219 +416,117 @@ internal abstract class DistanceLogic
|
||||
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
||||
}
|
||||
|
||||
private static int? GetLinksCount(string yearDirectory)
|
||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||
{
|
||||
int? result;
|
||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||
if (yearDirectoryNameSegments.Length != 3)
|
||||
result = null;
|
||||
else
|
||||
string[] files;
|
||||
string checkFile;
|
||||
string? checkDirectory;
|
||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
string lastSegment = yearDirectoryNameSegments[^1];
|
||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||
result = null;
|
||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
Directory.Move(directory, checkDirectory);
|
||||
else
|
||||
result = lastSegment[0] - 65;
|
||||
{
|
||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||
continue;
|
||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
File.Move(file, checkFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||
}
|
||||
|
||||
internal static List<Record> DeleteEmptyDirectoriesAndGetCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, string eDistanceContentDirectory, ReadOnlyDictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, ReadOnlyCollection<string> personKeyFormattedCollection)
|
||||
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||
{
|
||||
List<Record> results = [];
|
||||
bool check;
|
||||
string message;
|
||||
string[] files;
|
||||
bool? isDefault;
|
||||
int? linksCount;
|
||||
int totalSeconds;
|
||||
DateTime dateTime;
|
||||
TimeSpan timeSpan;
|
||||
int directoryNumber;
|
||||
string? checkDirectory;
|
||||
ProgressBar progressBar;
|
||||
string[] yearDirectories;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
string? personFirstInitial;
|
||||
bool isReservedDirectoryName;
|
||||
string[] personNameDirectories;
|
||||
string? newestPersonKeyFormatted;
|
||||
string? personDisplayDirectoryName;
|
||||
string[] personNameLinkDirectories;
|
||||
string? personFirstInitialDirectory;
|
||||
List<TicksDirectory> ticksDirectories;
|
||||
string[] personKeyFormattedDirectories;
|
||||
string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
for (int i = 1; i < 6; i++)
|
||||
string @enum;
|
||||
Record record;
|
||||
string fileName;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
FileHolder fileHolder;
|
||||
int? wholePercentages;
|
||||
foreach (string file in files)
|
||||
{
|
||||
check = false;
|
||||
results.Clear();
|
||||
distinct.Clear();
|
||||
directoryNumber = 0;
|
||||
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(configuration, eDistanceContentDirectory);
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{i}) {ticksDirectories.Count:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
|
||||
progressBar = new(ticksDirectories.Count, message, options);
|
||||
foreach (TicksDirectory ticksDirectory in ticksDirectories)
|
||||
{
|
||||
if (i == 1)
|
||||
progressBar.Tick();
|
||||
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
||||
{
|
||||
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
||||
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy));
|
||||
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)))
|
||||
{
|
||||
Individually(configuration, ticksDirectory, personKeyFormattedDirectory);
|
||||
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
}
|
||||
_ = personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
{
|
||||
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
||||
if (timeSpan.TotalDays > 6)
|
||||
throw new Exception($"{configuration.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
||||
}
|
||||
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string yearDirectory in yearDirectories)
|
||||
{
|
||||
if (check && !Directory.Exists(yearDirectory))
|
||||
continue;
|
||||
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
||||
linksCount = null;
|
||||
else
|
||||
linksCount = GetLinksCount(yearDirectory);
|
||||
if (ticksDirectory.DirectoryName != configuration.LocationContainerDebugDirectory)
|
||||
{
|
||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
}
|
||||
if (ticksDirectory.DirectoryName == configuration.LocationContainerDebugDirectory)
|
||||
{
|
||||
isDefault = null;
|
||||
personDisplayDirectoryName = null;
|
||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
||||
files = Directory.GetFiles(yearDirectory, "*.lnk", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
continue;
|
||||
}
|
||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (personNameDirectories.Length > 1)
|
||||
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||
foreach (string personNameDirectory in personNameDirectories)
|
||||
{
|
||||
directoryNumber++;
|
||||
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
||||
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
||||
{
|
||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, configuration.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Delete(yearDirectory, recursive: true);
|
||||
continue;
|
||||
}
|
||||
Directory.Move(personNameDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
continue;
|
||||
}
|
||||
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (isReservedDirectoryName && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
||||
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
||||
if (!isDefault.Value)
|
||||
{
|
||||
if (personKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
files = RenameBirth(files);
|
||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||
{
|
||||
if (!check)
|
||||
check = true;
|
||||
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length)
|
||||
continue;
|
||||
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !personKeyFormattedCollection.Contains(personKeyFormatted))
|
||||
personFirstInitialDirectory = personNameDirectory;
|
||||
else
|
||||
{
|
||||
personFirstInitial = personDisplayDirectoryName[..1];
|
||||
if (personFirstInitial.All(char.IsDigit))
|
||||
{
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
||||
continue;
|
||||
}
|
||||
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
||||
if (Directory.Exists(personFirstInitialDirectory))
|
||||
throw new Exception("Forgot to ...");
|
||||
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
||||
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
||||
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
||||
{
|
||||
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith(".lnk"))
|
||||
continue;
|
||||
File.Delete(file);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
}
|
||||
progressBar.Dispose();
|
||||
if (check)
|
||||
if (file.EndsWith(".lnk"))
|
||||
continue;
|
||||
break;
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
||||
if (wholePercentages is null)
|
||||
continue;
|
||||
fileName = Path.GetFileName(file);
|
||||
if (distinct.Contains(fileName))
|
||||
{
|
||||
checkFile = $"{file}.dup";
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
if (file.StartsWith(ticksDirectory.Directory))
|
||||
{
|
||||
@enum = IPath.GetEnum(filePath).ToString();
|
||||
if (!ticksDirectory.Directory.EndsWith(@enum))
|
||||
{
|
||||
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
|
||||
fileHolder = IFileHolder.Get(checkFile);
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
distinct.Add(fileName);
|
||||
record = new(DirectoryNumber: directoryNumber,
|
||||
IsDefault: isDefault,
|
||||
LinksCount: linksCount,
|
||||
MappedFaceFilePath: filePath,
|
||||
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
||||
PersonKeyFormatted: personKeyFormatted);
|
||||
results.Add(record);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
|
||||
{
|
||||
string result;
|
||||
string checkDirectory;
|
||||
string directory = file;
|
||||
List<string> collection = [];
|
||||
for (int i = 0; i < file.Length; i++)
|
||||
{
|
||||
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
|
||||
if (directory == ticksDirectory.Directory)
|
||||
break;
|
||||
collection.Add(Path.GetFileName(directory));
|
||||
}
|
||||
collection.Reverse();
|
||||
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
|
||||
foreach (string directoryName in collection)
|
||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
result = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(result))
|
||||
throw new Exception($"File <{fileName}> already exists!");
|
||||
File.Move(file, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -87,7 +87,7 @@ internal abstract class FaceFileLogic
|
||||
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<int, LocationContainer>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return new(results);
|
||||
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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,69 +7,93 @@ namespace View_by_Distance.Map.Models.Stateless.Methods;
|
||||
public interface IMapLogic
|
||||
{
|
||||
|
||||
ReadOnlyDictionary<int, List<long>> TestStatic_GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||
GetIdToPersonKeys(personKeyToIds);
|
||||
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||
static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
|
||||
$"{by 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),
|
||||
Shared.Models.Stateless.IMapLogic.ForceSingleImage => forceSingleImageHumanized,
|
||||
_ => throw new NotImplementedException()
|
||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||
|
||||
ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
GetFaces(items);
|
||||
static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
MapLogic.GetFaces(items);
|
||||
|
||||
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
GetSelectedMappingCollection(items);
|
||||
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
public static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
MapLogic.GetSelectedMappingCollection(items);
|
||||
|
||||
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
GetSelectedMappingCollection(faces);
|
||||
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
public static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
MapLogic.GetSelectedMappingCollection(faces);
|
||||
|
||||
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_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
SetCreationTime(mappingFromItem, locationContainers);
|
||||
static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||
|
||||
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<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||
|
||||
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) =>
|
||||
public 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(MappingFromItem mappingFromItem) =>
|
||||
public static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||
|
||||
public 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);
|
||||
public static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
MapLogic.GetFaces(items);
|
||||
|
||||
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) =>
|
||||
public static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||
|
||||
public static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||
|
||||
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||
MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||
|
||||
public static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||
FaceFileLogic.GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||
|
||||
public static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
DecadeLogic.MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||
|
||||
public static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||
MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
||||
|
||||
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||
FaceFileLogic.GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||
|
||||
internal string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
||||
GetDecade(mappingFromItem);
|
||||
|
||||
internal ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
|
||||
GetFaces(items);
|
||||
|
||||
internal Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||
GetSelectedMappingCollection(items);
|
||||
|
||||
internal Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||
GetSelectedMappingCollection(faces);
|
||||
|
||||
internal ReadOnlyDictionary<int, List<long>> TestStatic_GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||
GetIdToPersonKeys(personKeyToIds);
|
||||
|
||||
internal void TestStatic_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
SetCreationTime(mappingFromItem, locationContainers);
|
||||
|
||||
internal ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||
GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||
|
||||
internal List<LocationContainer> TestStatic_GetAvailable(int maxDegreeOfParallelism, Configuration configuration, IFaceD dFace, long ticks, ReadOnlyCollection<FilePath> filePaths) =>
|
||||
GetAvailable(maxDegreeOfParallelism, configuration, dFace, ticks, filePaths);
|
||||
|
||||
internal void TestStatic_MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||
MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||
|
||||
internal bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||
|
||||
internal bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||
|
||||
internal List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||
GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
||||
|
||||
internal ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> TestStatic_GetMappedFiles(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||
GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||
|
||||
}
|
@ -8,36 +8,48 @@ namespace View_by_Distance.Map.Models.Stateless;
|
||||
internal abstract class RelationLogic
|
||||
{
|
||||
|
||||
internal record Group(string Key, long PersonKey, ReadOnlyCollection<LocationContainer> RelationContainersCollection);
|
||||
internal record Group(string Key,
|
||||
long PersonKey,
|
||||
ReadOnlyCollection<LocationContainer> RelationContainersCollection);
|
||||
|
||||
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
|
||||
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
|
||||
{
|
||||
List<LocationContainer>? collection;
|
||||
Dictionary<int, List<LocationContainer>>? yearTo;
|
||||
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
int take;
|
||||
string directory;
|
||||
bool isCounterPersonYear;
|
||||
string personKeyFormatted;
|
||||
string? displayDirectoryName;
|
||||
Uri uri = new(eDistanceContentDirectory);
|
||||
ReadOnlyDictionary<string, string> movedFiles;
|
||||
ReadOnlyCollection<RelationContainer> relationContainers;
|
||||
ReadOnlyCollection<Group> groups = GetGroups(configuration, locationContainers);
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Save Mapped Relations - {totalSeconds} total second(s)";
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using ProgressBar progressBar = new(groups.Count, message, options);
|
||||
foreach (Group group in groups)
|
||||
{
|
||||
if (locationContainer.PersonKey is null)
|
||||
if (configuration.LocationContainerDistanceTolerance is null)
|
||||
break;
|
||||
progressBar.Tick();
|
||||
if (group.RelationContainersCollection.Count == 0)
|
||||
continue;
|
||||
if (!locationContainer.FromDistanceContent)
|
||||
continue;
|
||||
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
||||
continue;
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||
{
|
||||
personKeyTo.Add(locationContainer.PersonKey.Value, []);
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||
throw new Exception();
|
||||
}
|
||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||
{
|
||||
yearTo.Add(locationContainer.CreationDateOnly.Year, []);
|
||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(locationContainer);
|
||||
take = GetTake(configuration.LocationContainerDistanceTake, group.RelationContainersCollection.Count);
|
||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
||||
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
||||
directory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-{configuration.LocationContainerDistanceTolerance.Value}", personKeyFormatted, group.Key);
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
||||
relationContainers = distance.GetRelationContainers(configuration.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);
|
||||
}
|
||||
return personKeyTo;
|
||||
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||
else
|
||||
AddDisplayDirectoryNames(configuration, eDistanceContentDirectory, readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyToPersonContainerCollection, groups);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer> locationContainers)
|
||||
@ -82,12 +94,127 @@ internal abstract class RelationLogic
|
||||
locationContainer = collection[0];
|
||||
if (locationContainer.PersonKey is null)
|
||||
continue;
|
||||
results.Add(new(key, locationContainer.PersonKey.Value, new(collection)));
|
||||
results.Add(new(key, locationContainer.PersonKey.Value, collection.AsReadOnly()));
|
||||
collection = [];
|
||||
years.Clear();
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
|
||||
{
|
||||
List<LocationContainer>? collection;
|
||||
Dictionary<int, List<LocationContainer>>? yearTo;
|
||||
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
||||
foreach (LocationContainer locationContainer in locationContainers)
|
||||
{
|
||||
if (locationContainer.PersonKey is null)
|
||||
continue;
|
||||
if (!locationContainer.FromDistanceContent)
|
||||
continue;
|
||||
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
||||
continue;
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||
{
|
||||
personKeyTo.Add(locationContainer.PersonKey.Value, []);
|
||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||
throw new Exception();
|
||||
}
|
||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||
{
|
||||
yearTo.Add(locationContainer.CreationDateOnly.Year, []);
|
||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(locationContainer);
|
||||
}
|
||||
return personKeyTo;
|
||||
}
|
||||
|
||||
private static int GetTake(int locationContainerDistanceTake, int count)
|
||||
{
|
||||
int result = locationContainerDistanceTake;
|
||||
int subtract = (int)(locationContainerDistanceTake * .05);
|
||||
if (subtract < 1)
|
||||
subtract = 1;
|
||||
if (count > 9000)
|
||||
result -= subtract;
|
||||
if (count > 8000)
|
||||
result -= subtract;
|
||||
if (count > 7000)
|
||||
result -= subtract;
|
||||
if (count > 6000)
|
||||
result -= subtract;
|
||||
if (count > 5000)
|
||||
result -= subtract;
|
||||
if (count > 4000)
|
||||
result -= subtract;
|
||||
if (count > 3000)
|
||||
result -= subtract;
|
||||
if (count > 2000)
|
||||
result -= subtract;
|
||||
if (count > 1000)
|
||||
result -= subtract;
|
||||
if (result < 3)
|
||||
result = 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string? GetDisplayDirectoryName(ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted)
|
||||
{
|
||||
string? result;
|
||||
PersonContainer? personContainer;
|
||||
List<PersonContainer>? collection;
|
||||
_ = readOnlyPersonKeyToPersonContainerCollection.TryGetValue(personKey, out collection);
|
||||
if (collection is not null)
|
||||
result = collection[0].DisplayDirectoryName;
|
||||
else
|
||||
{
|
||||
if (!readOnlyPersonKeyFormattedToPersonContainer.TryGetValue(personKeyFormatted, out personContainer))
|
||||
result = null;
|
||||
else
|
||||
result = personContainer.DisplayDirectoryName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void WriteVsCodeFiles(string eDistanceContentDirectory, string? displayDirectoryName, string directory)
|
||||
{
|
||||
string json;
|
||||
string vsCodeDirectory = Path.Combine(directory, ".vscode");
|
||||
if (!Directory.Exists(vsCodeDirectory))
|
||||
_ = Directory.CreateDirectory(vsCodeDirectory);
|
||||
if (displayDirectoryName is not null)
|
||||
File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty);
|
||||
json = /*lang=json*/ """{ "[markdown]": { "editor.wordWrap": "off" }, "foam.links.hover.enable": false, "foam.graph.style": { "background": "#202020", "node": { "note": "#f2cb1d", "distance": "green", "image": "orange", "placeholder": "white", } } }""";
|
||||
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "settings.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
json = string.Concat("{ \"version\": \"2.0.0\", \"tasks\": [ { \"label\": \"MKLink\", \"type\": \"shell\", \"command\": \"New-Item\", \"args\": [ \"-ItemType\", \"Junction\", \"-Path\", \"'", directory.Replace('\\', '/'), "/()'\", \"-Target\", \"'", eDistanceContentDirectory.Replace('\\', '/'), "'\" ], \"problemMatcher\": [] } ] }");
|
||||
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, string> GetMoveFiles(Configuration configuration, string key, int take, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers)
|
||||
{
|
||||
ReadOnlyDictionary<string, string> results;
|
||||
List<List<string>> linked = [];
|
||||
for (int i = 0; i < 25; i++)
|
||||
linked.Add([]);
|
||||
foreach ((FileHolder fileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
||||
{
|
||||
foreach (Relation relation in relations.Take(take))
|
||||
{
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
if (!linked[i].Contains(relation.File))
|
||||
{
|
||||
linked[i].Add(relation.File);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
results = MoveFiles(configuration, key, isCounterPersonYear, displayDirectoryName, relationContainers, linked);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, string> MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers, List<List<string>> linked)
|
||||
@ -202,92 +329,7 @@ internal abstract class RelationLogic
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string? GetDisplayDirectoryName(ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted)
|
||||
{
|
||||
string? result;
|
||||
PersonContainer? personContainer;
|
||||
List<PersonContainer>? collection;
|
||||
_ = readOnlyPersonKeyToPersonContainerCollection.TryGetValue(personKey, out collection);
|
||||
if (collection is not null)
|
||||
result = collection[0].DisplayDirectoryName;
|
||||
else
|
||||
{
|
||||
if (!readOnlyPersonKeyFormattedToPersonContainer.TryGetValue(personKeyFormatted, out personContainer))
|
||||
result = null;
|
||||
else
|
||||
result = personContainer.DisplayDirectoryName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int GetTake(int locationContainerDistanceTake, int count)
|
||||
{
|
||||
int result = locationContainerDistanceTake;
|
||||
int subtract = (int)(locationContainerDistanceTake * .05);
|
||||
if (subtract < 1)
|
||||
subtract = 1;
|
||||
if (count > 9000)
|
||||
result -= subtract;
|
||||
if (count > 8000)
|
||||
result -= subtract;
|
||||
if (count > 7000)
|
||||
result -= subtract;
|
||||
if (count > 6000)
|
||||
result -= subtract;
|
||||
if (count > 5000)
|
||||
result -= subtract;
|
||||
if (count > 4000)
|
||||
result -= subtract;
|
||||
if (count > 3000)
|
||||
result -= subtract;
|
||||
if (count > 2000)
|
||||
result -= subtract;
|
||||
if (count > 1000)
|
||||
result -= subtract;
|
||||
if (result < 3)
|
||||
result = 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void WriteVsCodeFiles(string eDistanceContentDirectory, string? displayDirectoryName, string directory)
|
||||
{
|
||||
string json;
|
||||
string vsCodeDirectory = Path.Combine(directory, ".vscode");
|
||||
if (!Directory.Exists(vsCodeDirectory))
|
||||
_ = Directory.CreateDirectory(vsCodeDirectory);
|
||||
if (displayDirectoryName is not null)
|
||||
File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty);
|
||||
json = /*lang=json*/ """{ "[markdown]": { "editor.wordWrap": "off" }, "foam.links.hover.enable": false, "foam.graph.style": { "background": "#202020", "node": { "note": "#f2cb1d", "distance": "green", "image": "orange", "placeholder": "white", } } }""";
|
||||
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "settings.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
json = string.Concat("{ \"version\": \"2.0.0\", \"tasks\": [ { \"label\": \"MKLink\", \"type\": \"shell\", \"command\": \"New-Item\", \"args\": [ \"-ItemType\", \"Junction\", \"-Path\", \"'", directory.Replace('\\', '/'), "/()'\", \"-Target\", \"'", eDistanceContentDirectory.Replace('\\', '/'), "'\" ], \"problemMatcher\": [] } ] }");
|
||||
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, string> GetMoveFiles(Configuration configuration, string key, int take, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers)
|
||||
{
|
||||
ReadOnlyDictionary<string, string> results;
|
||||
List<List<string>> linked = [];
|
||||
for (int i = 0; i < 25; i++)
|
||||
linked.Add([]);
|
||||
foreach ((FileHolder fileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
||||
{
|
||||
foreach (Relation relation in relations.Take(take))
|
||||
{
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
if (!linked[i].Contains(relation.File))
|
||||
{
|
||||
linked[i].Add(relation.File);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
results = MoveFiles(configuration, key, isCounterPersonYear, displayDirectoryName, relationContainers, linked);
|
||||
return results;
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static void WriteFile(int take, long personKey, bool isCounterPersonYear, string personKeyFormatted, string? displayDirectoryName, string directory, long ticks, Uri uri, ReadOnlyCollection<RelationContainer> relationContainers, ReadOnlyDictionary<string, string> movedFiles)
|
||||
@ -398,44 +440,4 @@ internal abstract class RelationLogic
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
|
||||
{
|
||||
int take;
|
||||
string directory;
|
||||
bool isCounterPersonYear;
|
||||
string personKeyFormatted;
|
||||
string? displayDirectoryName;
|
||||
Uri uri = new(eDistanceContentDirectory);
|
||||
ReadOnlyDictionary<string, string> movedFiles;
|
||||
ReadOnlyCollection<RelationContainer> relationContainers;
|
||||
ReadOnlyCollection<Group> groups = GetGroups(configuration, locationContainers);
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Save Mapped Relations - {totalSeconds} total second(s)";
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using ProgressBar progressBar = new(groups.Count, message, options);
|
||||
foreach (Group group in groups)
|
||||
{
|
||||
if (configuration.LocationContainerDistanceTolerance is null)
|
||||
break;
|
||||
progressBar.Tick();
|
||||
if (group.RelationContainersCollection.Count == 0)
|
||||
continue;
|
||||
take = GetTake(configuration.LocationContainerDistanceTake, group.RelationContainersCollection.Count);
|
||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
||||
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
||||
directory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-{configuration.LocationContainerDistanceTolerance.Value}", personKeyFormatted, group.Key);
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
||||
relationContainers = distance.GetRelationContainers(configuration.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);
|
||||
}
|
||||
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||
else
|
||||
AddDisplayDirectoryNames(configuration, eDistanceContentDirectory, readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyToPersonContainerCollection, groups);
|
||||
}
|
||||
|
||||
}
|
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.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="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -34,10 +34,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<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" />
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -4,6 +4,7 @@ using System.Text.Json;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Methods;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
namespace View_by_Distance.Metadata.Models;
|
||||
|
||||
@ -13,33 +14,103 @@ namespace View_by_Distance.Metadata.Models;
|
||||
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
{
|
||||
|
||||
public string DateGroupDirectory { get; init; }
|
||||
public ReadOnlyCollection<FilePath> Collection { get; private set; }
|
||||
public ReadOnlyDictionary<int, List<FilePath>> SingletonById { get; private set; }
|
||||
public ReadOnlyDictionary<int, ExifDirectory> ExifDirectoriesById { get; private set; }
|
||||
|
||||
// First
|
||||
// Set DateGroupDirectory
|
||||
// Create a directories for Singleton
|
||||
// Populate Collection
|
||||
// Populate Singleton
|
||||
// Populate existing ExifDirectories
|
||||
// Run similar for resize
|
||||
// Second
|
||||
// Populate needed ExifDirectories Dictionary can't be init only
|
||||
|
||||
private readonly bool _PropertiesChangedForMetadata;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly bool _ForceMetadataLastWriteTimeToCreationTime;
|
||||
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
||||
private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||
|
||||
public B_Metadata(IPropertyConfiguration propertyConfiguration)
|
||||
{
|
||||
_PropertiesChangedForMetadata = false;
|
||||
_PropertyConfiguration = propertyConfiguration;
|
||||
_ForceMetadataLastWriteTimeToCreationTime = false;
|
||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]);
|
||||
}
|
||||
|
||||
public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory)
|
||||
public B_Metadata(IDlibDotNet? dlibDotNet, IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, long ticks, string bResultsFullGroupDirectory)
|
||||
{
|
||||
_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();
|
||||
}
|
||||
List<ExifDirectory> results = [];
|
||||
string jsonGroupDirectory;
|
||||
const string extension = ".json";
|
||||
const string fileSearchFilter = "*";
|
||||
string filesCollectionRootDirectory;
|
||||
const string directorySearchFilter = "*";
|
||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||
filesCollectionRootDirectory = propertyConfiguration.RootDirectory;
|
||||
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
string jsonGroupSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
string jsonGroupCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||
ReadOnlyCollection<string> directories = new([jsonGroupSingletonDirectory, jsonGroupCollectionDirectory]);
|
||||
Shared.Models.Stateless.Methods.IPath.CreateDirectories(directories);
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||
ReadOnlyCollection<FilePair> filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
||||
string message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||
dlibDotNet?.ConstructProgressBar(filePairs.Count, message);
|
||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], results));
|
||||
jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||
foreach (ExifDirectory exifDirectory in results)
|
||||
{
|
||||
if (exifDirectory.FilePath.Id is null || exifDirectoriesById.ContainsKey(exifDirectory.FilePath.Id.Value))
|
||||
continue;
|
||||
exifDirectoriesById.Add(exifDirectory.FilePath.Id.Value, exifDirectory);
|
||||
}
|
||||
ExifDirectoriesById = new(exifDirectoriesById);
|
||||
DateGroupDirectory = bResultsFullGroupDirectory;
|
||||
SingletonById = fileNamesToFiles;
|
||||
filesCollectionRootDirectory = jsonGroupCollectionDirectory;
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsSingletonCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory,
|
||||
useIgnoreExtensions: false, useCeilingAverage: false);
|
||||
Collection = filePathsSingletonCollection[0];
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
private void ParallelFor(IDlibDotNet? dlibDotNet, FilePair filePair, List<ExifDirectory> results)
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, _WriteIndentedJsonSerializerOptions);
|
||||
dlibDotNet?.Tick();
|
||||
if (filePair.FilePath.Id is null)
|
||||
return;
|
||||
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
||||
if (exifDirectory is null)
|
||||
return;
|
||||
lock (results)
|
||||
results.Add(exifDirectory);
|
||||
}
|
||||
|
||||
private static ExifDirectory? GetExifDirectory(FilePair filePair)
|
||||
{
|
||||
ExifDirectory? result;
|
||||
if (filePair.Match is null)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(filePair.Match.FullName);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
result = null;
|
||||
else
|
||||
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -47,8 +118,11 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
{
|
||||
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);
|
||||
@ -104,13 +178,32 @@ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories)
|
||||
{
|
||||
List<DateTime?> results = [];
|
||||
DateTime? result = null;
|
||||
DateTime? dateTime;
|
||||
DateTime checkDateTime;
|
||||
string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat();
|
||||
string dateTimeFormat = Stateless.Methods.IMetadata.DateTimeFormat();
|
||||
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
|
||||
results.Add(new DateTime(filePath.CreationTicks));
|
||||
results.Add(new DateTime(filePath.LastWriteTicks));
|
||||
@ -120,7 +213,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
results.Add(checkDateTime);
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
||||
if (dateTime is not null)
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
@ -128,7 +221,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
results.Add(checkDateTime);
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
||||
if (dateTime is not null)
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
@ -139,7 +232,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
||||
if (dateTime is not null)
|
||||
{
|
||||
result ??= dateTime.Value;
|
||||
@ -157,7 +250,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
||||
if (dateTime is not null)
|
||||
{
|
||||
result ??= dateTime.Value;
|
||||
@ -175,7 +268,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
||||
if (dateTime is not null)
|
||||
{
|
||||
result ??= dateTime.Value;
|
||||
@ -193,7 +286,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
||||
if (dateTime is not null)
|
||||
{
|
||||
result ??= dateTime.Value;
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using View_by_Distance.Shared.Models;
|
||||
|
||||
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
||||
@ -47,4 +48,23 @@ internal static class Base
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||
{
|
||||
DateTime? result;
|
||||
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
||||
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
}
|
@ -484,7 +484,7 @@ internal abstract class Exif
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
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);
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -64,4 +64,14 @@ public interface IMetadata
|
||||
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
|
||||
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
|
||||
|
||||
string TestStatic_DateTimeFormat() =>
|
||||
DateTimeFormat();
|
||||
static string DateTimeFormat() =>
|
||||
"yyyy:MM:dd HH:mm:ss";
|
||||
|
||||
DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||
GetDateTime(dateTimeFormat, value);
|
||||
static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||
Base.GetDateTime(dateTimeFormat, value);
|
||||
|
||||
}
|
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.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="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 = [];
|
||||
|
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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" />
|
||||
|
@ -35,10 +35,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.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="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Property\Property.csproj" />
|
||||
|
@ -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="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -33,14 +33,14 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
||||
<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" />
|
||||
|
@ -35,7 +35,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<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, ReadOnlyCollection<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,117 @@ public class A_Property
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetAngleBracketCollection(string aResultsFullGroupDirectory, string sourceDirectory, bool anyNullOrNoIsUniqueFileName = true)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
if (!anyNullOrNoIsUniqueFileName)
|
||||
_AngleBracketCollection.AddRange([Path.Combine(aResultsFullGroupDirectory, "<>")]);
|
||||
else
|
||||
_AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration,
|
||||
sourceDirectory,
|
||||
aResultsFullGroupDirectory,
|
||||
contentDescription: string.Empty,
|
||||
singletonDescription: "Properties for each image",
|
||||
collectionDescription: string.Empty,
|
||||
converted: false));
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container.Models.Container[] containers)
|
||||
{
|
||||
int total = 0;
|
||||
string message;
|
||||
int totalSeconds;
|
||||
bool anyNullOrNoIsUniqueFileName;
|
||||
List<Exception> exceptions = [];
|
||||
Container.Models.Container container;
|
||||
int containersLength = containers.Length;
|
||||
const string outputResolution = "Original";
|
||||
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
|
||||
string propertyRoot = IResult.GetResultsGroupDirectory(_PropertyConfiguration, nameof(A_Property));
|
||||
for (int i = 0; i < containers.Length; i++)
|
||||
{
|
||||
container = containers[i];
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
sourceDirectoryChanges.Clear();
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName);
|
||||
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
||||
SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message);
|
||||
if (exceptions.Count == container.Items.Count)
|
||||
throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!"));
|
||||
if (exceptions.Count != 0)
|
||||
_ExceptionsDirectories.Add(container.SourceDirectory);
|
||||
total += container.Items.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
string aResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(_PropertyConfiguration,
|
||||
nameof(A_Property),
|
||||
string.Empty,
|
||||
includeResizeGroup: false,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container.Models.Container container, ReadOnlyCollection<Item> items, string message)
|
||||
{
|
||||
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using ProgressBar progressBar = new(items.Count, message, options);
|
||||
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
List<Tuple<string, DateTime>> collection;
|
||||
SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
|
||||
if (i == 0 || sourceDirectoryChanges.Count != 0)
|
||||
progressBar.Tick();
|
||||
lock (sourceDirectoryFileTuples)
|
||||
collection = (from l in sourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList();
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.AddRange(collection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lock (exceptions)
|
||||
exceptions.Add(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
|
||||
{
|
||||
Shared.Models.Property property;
|
||||
List<string> parseExceptions = [];
|
||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
||||
string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}");
|
||||
if (item.IsValidImageFormatExtension && item.FilePath.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.FilePath.FullName != filteredSourceDirectoryFileExtensionLowered)
|
||||
File.Move(item.FilePath.FullName, filteredSourceDirectoryFileExtensionLowered);
|
||||
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.ExifDirectory is null)
|
||||
{
|
||||
property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
||||
lock (item)
|
||||
item.Update(null);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
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 +176,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")))
|
||||
@ -84,8 +206,8 @@ public class A_Property
|
||||
json = File.ReadAllText(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
if (item.Property is not null)
|
||||
result = item.Property;
|
||||
if (item.ExifDirectory is not null)
|
||||
result = null;
|
||||
else
|
||||
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
||||
if (result is not null && json.Contains("WrongYear"))
|
||||
@ -164,113 +286,26 @@ public class A_Property
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetAngleBracketCollection(string aResultsFullGroupDirectory, string sourceDirectory, bool anyNullOrNoIsUniqueFileName = true)
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
if (!anyNullOrNoIsUniqueFileName)
|
||||
_AngleBracketCollection.AddRange(new[] { Path.Combine(aResultsFullGroupDirectory, "<>") });
|
||||
else
|
||||
_AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration,
|
||||
sourceDirectory,
|
||||
aResultsFullGroupDirectory,
|
||||
contentDescription: string.Empty,
|
||||
singletonDescription: "Properties for each image",
|
||||
collectionDescription: string.Empty,
|
||||
converted: false));
|
||||
}
|
||||
|
||||
private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
|
||||
{
|
||||
Shared.Models.Property property;
|
||||
List<string> parseExceptions = [];
|
||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
||||
string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}");
|
||||
if (item.IsValidImageFormatExtension && item.FilePath.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.FilePath.FullName != filteredSourceDirectoryFileExtensionLowered)
|
||||
File.Move(item.FilePath.FullName, filteredSourceDirectoryFileExtensionLowered);
|
||||
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.Property is null)
|
||||
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))
|
||||
{
|
||||
property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
||||
lock (item)
|
||||
item.Update(property);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
string aResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(_PropertyConfiguration,
|
||||
nameof(A_Property),
|
||||
string.Empty,
|
||||
includeResizeGroup: false,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
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, ReadOnlyCollection<Item> items, string message)
|
||||
{
|
||||
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using ProgressBar progressBar = new(items.Count, message, options);
|
||||
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
List<Tuple<string, DateTime>> collection;
|
||||
SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
|
||||
if (i == 0 || sourceDirectoryChanges.Count != 0)
|
||||
progressBar.Tick();
|
||||
lock (sourceDirectoryFileTuples)
|
||||
collection = (from l in sourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList();
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.AddRange(collection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lock (exceptions)
|
||||
exceptions.Add(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container[] containers)
|
||||
{
|
||||
int total = 0;
|
||||
string message;
|
||||
int totalSeconds;
|
||||
Container container;
|
||||
bool anyNullOrNoIsUniqueFileName;
|
||||
List<Exception> exceptions = [];
|
||||
int containersLength = containers.Length;
|
||||
const string outputResolution = "Original";
|
||||
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
|
||||
string propertyRoot = IResult.GetResultsGroupDirectory(_PropertyConfiguration, nameof(A_Property));
|
||||
for (int i = 0; i < containers.Length; i++)
|
||||
{
|
||||
container = containers[i];
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
sourceDirectoryChanges.Clear();
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName);
|
||||
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
||||
SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message);
|
||||
if (exceptions.Count == container.Items.Count)
|
||||
throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!"));
|
||||
if (exceptions.Count != 0)
|
||||
_ExceptionsDirectories.Add(container.SourceDirectory);
|
||||
total += container.Items.Count;
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
public Shared.Models.Property GetProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions)
|
||||
{
|
||||
Shared.Models.Property result;
|
||||
|
@ -10,49 +10,80 @@ namespace View_by_Distance.Property.Models.Stateless;
|
||||
public interface IProperty
|
||||
{
|
||||
|
||||
string TestStatic_DateTimeFormat() =>
|
||||
DateTimeFormat();
|
||||
static string DateTimeFormat() =>
|
||||
"yyyy:MM:dd HH:mm:ss";
|
||||
const string DateTimeFormat = "yyyy:MM:dd HH:mm:ss";
|
||||
|
||||
byte[] TestStatic_GetBytes(string value) =>
|
||||
GetBytes(value);
|
||||
static byte[] GetBytes(string value) =>
|
||||
Property.GetBytes(value);
|
||||
|
||||
DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||
GetDateTime(dateTimeFormat, value);
|
||||
static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||
Property.GetDateTime(dateTimeFormat, value);
|
||||
|
||||
PropertyItem TestStatic_GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) =>
|
||||
GetPropertyItem(constructorInfo, id, type, value);
|
||||
static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) =>
|
||||
Property.GetPropertyItem(constructorInfo, id, type, value);
|
||||
|
||||
(string?, DateTime[], Shared.Models.Property) TestStatic_GetProperty(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) =>
|
||||
GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) =>
|
||||
Property.GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
|
||||
(DateTime?, DateTime[], int?, string?) TestStatic_Get(IPropertyConfiguration propertyConfiguration, bool populateId, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(propertyConfiguration, populateId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, null, FilePath.Get(propertyConfiguration, fileHolder, index: null), isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
(DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(populateId, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
static (DateTime?, DateTime[], int?, string?) Get(bool populateId, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, null, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
(DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(populateId, metadata, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
// public
|
||||
static (DateTime?, DateTime[], int?, string?) Get(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, metadata, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
(DateTime?, DateTime[], int?, string?) TestStatic_Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(propertyConfiguration, populateId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
// public
|
||||
static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, null, FilePath.Get(propertyConfiguration, fileHolder, index: null), isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
public static byte[] GetBytes(string value) =>
|
||||
Property.GetBytes(value);
|
||||
|
||||
public static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||
Property.GetDateTime(dateTimeFormat, value);
|
||||
|
||||
public static double GetStandardDeviation(List<long> values, double average) =>
|
||||
Property.GetStandardDeviation(values, average);
|
||||
|
||||
public static bool Any(Container.Models.Container[] propertyHolderCollections) =>
|
||||
Property.Any(propertyHolderCollections);
|
||||
|
||||
public static TimeSpan GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container) =>
|
||||
Property.GetThreeStandardDeviationHigh(minimum, container);
|
||||
|
||||
public static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) =>
|
||||
Property.GetPropertyItem(constructorInfo, id, type, value);
|
||||
|
||||
public static (int, List<DateTime>, List<Item>) Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
|
||||
Property.Get(container, threeStandardDeviationHigh, i);
|
||||
|
||||
public static (DateTime?, DateTime[], int?, string?) Get(bool populateId, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, null, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
public static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Property.Get(populateId, metadata, FilePath.Get(propertyConfiguration, fileHolder, index: null), isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
public static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) =>
|
||||
Property.GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
|
||||
internal byte[] TestStatic_GetBytes(string value) =>
|
||||
GetBytes(value);
|
||||
|
||||
internal DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||
GetDateTime(dateTimeFormat, value);
|
||||
|
||||
internal double TestStatic_GetStandardDeviation(List<long> values, double average) =>
|
||||
GetStandardDeviation(values, average);
|
||||
|
||||
internal bool TestStatic_Any(Container.Models.Container[] propertyHolderCollections) =>
|
||||
Any(propertyHolderCollections);
|
||||
|
||||
internal TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container) =>
|
||||
GetThreeStandardDeviationHigh(minimum, container);
|
||||
|
||||
internal PropertyItem TestStatic_GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value) =>
|
||||
GetPropertyItem(constructorInfo, id, type, value);
|
||||
|
||||
internal (int, List<DateTime>, List<Item>) TestStatic_Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
|
||||
Get(container, threeStandardDeviationHigh, i);
|
||||
|
||||
internal (DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(populateId, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
internal (DateTime?, DateTime[], int?, string?) TestStatic_Get(IPropertyConfiguration propertyConfiguration, bool populateId, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(propertyConfiguration, populateId, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
internal (DateTime?, DateTime[], int?, string?) TestStatic_Get(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(populateId, metadata, filePath, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
internal (DateTime?, DateTime[], int?, string?) TestStatic_Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
|
||||
Get(propertyConfiguration, populateId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
|
||||
|
||||
internal (string?, DateTime[], Shared.Models.Property) TestStatic_GetProperty(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding) =>
|
||||
GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
|
||||
}
|
@ -3,44 +3,52 @@ namespace View_by_Distance.Property.Models.Stateless;
|
||||
public interface IResult
|
||||
{
|
||||
|
||||
string TestStatic_GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) =>
|
||||
GetRelativePath(propertyConfiguration, path);
|
||||
static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) =>
|
||||
public static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) =>
|
||||
Result.GetRelativePath(propertyConfiguration, path);
|
||||
|
||||
string TestStatic_GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) =>
|
||||
GetResultsGroupDirectory(propertyConfiguration, description, create);
|
||||
static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) =>
|
||||
Result.GetResultsGroupDirectory(propertyConfiguration, description, create);
|
||||
|
||||
string TestStatic_GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
GetResultsGroupDirectory(propertyConfiguration, description);
|
||||
static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
public static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
Result.GetResultsGroupDirectory(propertyConfiguration, description, create: true);
|
||||
|
||||
string TestStatic_GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
GetResultsDateGroupDirectory(propertyConfiguration, description);
|
||||
static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
public static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
Result.GetResultsDateGroupDirectory(propertyConfiguration, description);
|
||||
|
||||
string TestStatic_GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) =>
|
||||
GetResultsDateGroupDirectory(propertyConfiguration, description, jsonGroup);
|
||||
static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) =>
|
||||
public static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) =>
|
||||
Result.GetResultsGroupDirectory(propertyConfiguration, description, create);
|
||||
|
||||
public static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) =>
|
||||
Result.GetResultsDateGroupDirectory(propertyConfiguration, description, jsonGroup);
|
||||
|
||||
List<string> TestStatic_GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) =>
|
||||
GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, dateGroupDirectory, contentDescription, singletonDescription, collectionDescription, converted);
|
||||
static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) =>
|
||||
Result.GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, dateGroupDirectory, contentDescription, singletonDescription, collectionDescription, converted);
|
||||
|
||||
string TestStatic_GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) =>
|
||||
GetResultsFullGroupDirectory(propertyConfiguration, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel);
|
||||
static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) =>
|
||||
public static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) =>
|
||||
Result.GetResultsFullGroupDirectory(propertyConfiguration, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel);
|
||||
|
||||
List<string> TestStatic_GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) =>
|
||||
GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel, contentDescription, singletonDescription, collectionDescription);
|
||||
static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) =>
|
||||
public static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) =>
|
||||
Result.GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, dateGroupDirectory, contentDescription, singletonDescription, collectionDescription, converted);
|
||||
|
||||
public static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) =>
|
||||
Result.GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel, contentDescription, singletonDescription, collectionDescription);
|
||||
|
||||
internal string TestStatic_GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) =>
|
||||
GetRelativePath(propertyConfiguration, path);
|
||||
|
||||
internal string TestStatic_GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
GetResultsGroupDirectory(propertyConfiguration, description);
|
||||
|
||||
internal string TestStatic_GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description) =>
|
||||
GetResultsDateGroupDirectory(propertyConfiguration, description);
|
||||
|
||||
internal string TestStatic_GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) =>
|
||||
GetResultsGroupDirectory(propertyConfiguration, description, create);
|
||||
|
||||
internal string TestStatic_GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup) =>
|
||||
GetResultsDateGroupDirectory(propertyConfiguration, description, jsonGroup);
|
||||
|
||||
internal string TestStatic_GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) =>
|
||||
GetResultsFullGroupDirectory(propertyConfiguration, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel);
|
||||
|
||||
internal List<string> TestStatic_GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) =>
|
||||
GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, dateGroupDirectory, contentDescription, singletonDescription, collectionDescription, converted);
|
||||
|
||||
internal List<string> TestStatic_GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) =>
|
||||
GetDirectoryInfoCollection(propertyConfiguration, sourceDirectory, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel, contentDescription, singletonDescription, collectionDescription);
|
||||
|
||||
}
|
@ -14,56 +14,53 @@ namespace View_by_Distance.Property.Models.Stateless;
|
||||
internal partial class Property
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"\D+")]
|
||||
private static partial Regex Digit();
|
||||
|
||||
private static List<DateTime> GetDateTimes(DateTime dateTimeFromName, DateTime?[] dateTimes)
|
||||
internal static TimeSpan GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container)
|
||||
{
|
||||
List<DateTime> results = [dateTimeFromName];
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
TimeSpan result;
|
||||
DateTime? minimumDateTime;
|
||||
List<long> ticksCollection = [];
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (dateTime is null)
|
||||
if (item.ExifDirectory is null)
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(item.ExifDirectory);
|
||||
if (minimumDateTime is null)
|
||||
continue;
|
||||
ticksCollection.Add(minimumDateTime.Value.Ticks);
|
||||
}
|
||||
return results;
|
||||
long threeStandardDeviationHigh;
|
||||
long min;
|
||||
if (ticksCollection.Count == 0)
|
||||
min = 0;
|
||||
else
|
||||
min = ticksCollection.Min();
|
||||
if (ticksCollection.Count < minimum)
|
||||
threeStandardDeviationHigh = long.MaxValue;
|
||||
else
|
||||
threeStandardDeviationHigh = GetThreeStandardDeviationHigh(ref ticksCollection, min);
|
||||
result = new TimeSpan(threeStandardDeviationHigh - min);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(DateTime?[] dateTimes, DateTime?[] metadataDateTimes)
|
||||
private static long GetThreeStandardDeviationHigh(ref List<long> ticksCollection, long min)
|
||||
{
|
||||
List<DateTime> results = [];
|
||||
foreach (DateTime? dateTime in metadataDateTimes)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
long result;
|
||||
ticksCollection = (from l in ticksCollection select l - min).ToList();
|
||||
double sum = ticksCollection.Sum();
|
||||
double average = sum / ticksCollection.Count;
|
||||
double standardDeviation = GetStandardDeviation(ticksCollection, average);
|
||||
result = (long)Math.Ceiling(average + min + (standardDeviation * 3));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(FilePath filePath, DateTime?[] dateTimes)
|
||||
internal static double GetStandardDeviation(List<long> values, double average)
|
||||
{
|
||||
List<DateTime> results = [];
|
||||
string[] digits = Digit().Split(filePath.FullName);
|
||||
foreach (string digit in digits)
|
||||
{
|
||||
if (digit.Length != 4 || digit[..2] is not "19" and not "20" || !int.TryParse(digit, out int year))
|
||||
continue;
|
||||
results.Add(new(year, 1, 1));
|
||||
}
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
{
|
||||
if (dateTime is null)
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
double result = 0;
|
||||
if (values.Count == 0)
|
||||
throw new Exception("Collection must have at least one value!");
|
||||
double sum = values.Sum(l => (l - average) * (l - average));
|
||||
result = Math.Sqrt(sum / values.Count);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static byte[] GetBytes(string value)
|
||||
@ -111,12 +108,12 @@ internal partial class Property
|
||||
format = dateFormat[1];
|
||||
length = dateFormat[0].Length + dateFormat[1].Length;
|
||||
for (int i = dateFormat[0].Length; i < length; i++)
|
||||
_ = value.Append(filePath.NameWithoutExtension[i]);
|
||||
_ = value.Append(filePath.FileNameFirstSegment[i]);
|
||||
if (value.Length != format.Length)
|
||||
continue;
|
||||
if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
|
||||
{
|
||||
if (filePath.NameWithoutExtension.Length < ticksExample.Length || !long.TryParse(filePath.NameWithoutExtension[^ticksExample.Length..], out long ticks))
|
||||
if (filePath.NameWithoutExtension.Length < ticksExample.Length || !long.TryParse(filePath.FileNameFirstSegment[^ticksExample.Length..], out long ticks))
|
||||
result = checkDateTime;
|
||||
else
|
||||
result = new DateTime(ticks);
|
||||
@ -126,22 +123,40 @@ internal partial class Property
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(DateTime?[] metadataDateTimes)
|
||||
internal static bool Any(Container.Models.Container[] containers)
|
||||
{
|
||||
List<DateTime> results = [];
|
||||
foreach (DateTime? dateTime in metadataDateTimes)
|
||||
bool result = false;
|
||||
foreach (Container.Models.Container container in containers)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
if ((from l in container.Items where l.Any() select true).Any())
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||
{
|
||||
DateTime? result;
|
||||
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
||||
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static PropertyItem GetPropertyItem(ConstructorInfo constructorInfo, int id, short type, string value)
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
PropertyItem result = (PropertyItem)constructorInfo.Invoke(null);
|
||||
int length;
|
||||
byte[] bytes;
|
||||
@ -161,27 +176,65 @@ internal partial class Property
|
||||
result.Len = length;
|
||||
result.Type = type;
|
||||
result.Value = bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||
{
|
||||
DateTime? result;
|
||||
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
||||
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
result = dateTime;
|
||||
else
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
internal static (int, List<DateTime>, List<Item>) Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i)
|
||||
{
|
||||
List<Item> results = [];
|
||||
int j = i;
|
||||
long? ticks;
|
||||
TimeSpan timeSpan;
|
||||
Item item;
|
||||
DateTime? minimumDateTime;
|
||||
Item nextItem;
|
||||
DateTime? nextMinimumDateTime;
|
||||
List<DateTime> dateTimes = [];
|
||||
for (; j < container.Items.Count; j++)
|
||||
{
|
||||
ticks = null;
|
||||
item = container.Items[j];
|
||||
if (item.ExifDirectory is null)
|
||||
continue;
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(item.ExifDirectory);
|
||||
if (minimumDateTime is null)
|
||||
continue;
|
||||
for (int k = j + 1; k < container.Items.Count; k++)
|
||||
{
|
||||
nextItem = container.Items[k];
|
||||
if (nextItem.ExifDirectory is null)
|
||||
continue;
|
||||
nextMinimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(nextItem.ExifDirectory);
|
||||
if (nextMinimumDateTime is null)
|
||||
continue;
|
||||
ticks = nextMinimumDateTime.Value.Ticks;
|
||||
break;
|
||||
}
|
||||
results.Add(item);
|
||||
dateTimes.Add(minimumDateTime.Value);
|
||||
if (ticks.HasValue)
|
||||
{
|
||||
timeSpan = new(ticks.Value - minimumDateTime.Value.Ticks);
|
||||
if (timeSpan > threeStandardDeviationHigh)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new(j, dateTimes, results);
|
||||
}
|
||||
|
||||
internal static (DateTime?, DateTime[], int?, string?) Get(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding)
|
||||
{
|
||||
int? id = null;
|
||||
string? message;
|
||||
DateTime[] dateTimes;
|
||||
Shared.Models.Property? property = null;
|
||||
if (isIgnoreExtension || !isValidImageFormatExtension)
|
||||
(message, dateTimes, property) = (null, [], null);
|
||||
else
|
||||
(message, dateTimes, property) = GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
return new(property?.DateTimeOriginal, dateTimes, property?.Id, message);
|
||||
}
|
||||
|
||||
internal static (string?, DateTime[], Shared.Models.Property) GetProperty(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, Shared.Models.Property? property, bool isIgnoreExtension, bool isValidImageFormatExtension, int? id, ASCIIEncoding asciiEncoding)
|
||||
{
|
||||
@ -225,6 +278,7 @@ internal partial class Property
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
using Image image = Image.FromFile(filePath.FullName);
|
||||
width = image.Width;
|
||||
height = image.Height;
|
||||
@ -240,7 +294,7 @@ internal partial class Property
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
id ??= Shared.Models.Stateless.Methods.IId.GetDeterministicHashCode(bytes);
|
||||
}
|
||||
dateTimeFormat = IProperty.DateTimeFormat();
|
||||
dateTimeFormat = IProperty.DateTimeFormat;
|
||||
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime))
|
||||
{
|
||||
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime);
|
||||
@ -318,6 +372,7 @@ internal partial class Property
|
||||
keywords = Encoding.Unicode.GetString(propertyItem.Value).Trim('\0', ' ').Split(';');
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
message = null;
|
||||
dateTimes = [new(filePath.LastWriteTicks), new(filePath.CreationTicks), dateTime, dateTimeDigitized, dateTimeOriginal, gpsDateStamp];
|
||||
}
|
||||
@ -351,19 +406,68 @@ internal partial class Property
|
||||
return (message, dateTimesByLogic.ToArray(), result);
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
internal static (DateTime?, DateTime[], int?, string?) Get(bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FilePath filePath, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding)
|
||||
private static List<DateTime> GetDateTimes(DateTime?[] metadataDateTimes)
|
||||
{
|
||||
int? id = null;
|
||||
string? message;
|
||||
DateTime[] dateTimes;
|
||||
Shared.Models.Property? property = null;
|
||||
if (isIgnoreExtension || !isValidImageFormatExtension)
|
||||
(message, dateTimes, property) = (null, [], null);
|
||||
else
|
||||
(message, dateTimes, property) = GetProperty(populateId, metadata, filePath, property, isIgnoreExtension, isValidImageFormatExtension, id, asciiEncoding);
|
||||
return new(property?.DateTimeOriginal, dateTimes, property?.Id, message);
|
||||
List<DateTime> results = [];
|
||||
foreach (DateTime? dateTime in metadataDateTimes)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(FilePath filePath, DateTime?[] dateTimes)
|
||||
{
|
||||
List<DateTime> results = [];
|
||||
string[] digits = Digit().Split(filePath.FullName);
|
||||
foreach (string digit in digits)
|
||||
{
|
||||
if (digit.Length != 4 || digit[..2] is not "19" and not "20" || !int.TryParse(digit, out int year))
|
||||
continue;
|
||||
results.Add(new(year, 1, 1));
|
||||
}
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
{
|
||||
if (dateTime is null)
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(DateTime dateTimeFromName, DateTime?[] dateTimes)
|
||||
{
|
||||
List<DateTime> results = [dateTimeFromName];
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
{
|
||||
if (dateTime is null)
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<DateTime> GetDateTimes(DateTime?[] dateTimes, DateTime?[] metadataDateTimes)
|
||||
{
|
||||
List<DateTime> results = [];
|
||||
foreach (DateTime? dateTime in metadataDateTimes)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
foreach (DateTime? dateTime in dateTimes)
|
||||
{
|
||||
if (dateTime is null || results.Contains(dateTime.Value))
|
||||
continue;
|
||||
results.Add(dateTime.Value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"\D+")]
|
||||
private static partial Regex Digit();
|
||||
|
||||
}
|
@ -5,13 +5,8 @@ namespace View_by_Distance.Property.Models.Stateless;
|
||||
internal class Result
|
||||
{
|
||||
|
||||
internal static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup)
|
||||
{
|
||||
string result = Path.Combine(GetResultsDateGroupDirectory(propertyConfiguration, description), jsonGroup);
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
internal static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path) =>
|
||||
Shared.Models.Stateless.Methods.IPath.GetRelativePath(path, propertyConfiguration.RootDirectory.Length);
|
||||
|
||||
internal static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description)
|
||||
{
|
||||
@ -21,12 +16,66 @@ internal class Result
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetRelativePath(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string path)
|
||||
internal static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create)
|
||||
{
|
||||
string result = Shared.Models.Stateless.Methods.IPath.GetRelativePath(path, propertyConfiguration.RootDirectory.Length);
|
||||
string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace('_', ')'));
|
||||
if (create && !Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetResultsDateGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string jsonGroup)
|
||||
{
|
||||
string result = Path.Combine(GetResultsDateGroupDirectory(propertyConfiguration, description), jsonGroup);
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel)
|
||||
{
|
||||
string result = GetResultsDateGroupDirectory(propertyConfiguration, description);
|
||||
if (includeResizeGroup)
|
||||
result = Path.Combine(result, outputResolution);
|
||||
if (includeModel && includePredictorModel)
|
||||
{
|
||||
string modelName;
|
||||
string predictorModelName;
|
||||
if (propertyConfiguration.ModelName is null)
|
||||
modelName = Model.Hog.ToString();
|
||||
else
|
||||
modelName = propertyConfiguration.ModelName;
|
||||
if (propertyConfiguration.PredictorModelName is null)
|
||||
predictorModelName = PredictorModel.Large.ToString();
|
||||
else
|
||||
predictorModelName = propertyConfiguration.PredictorModelName;
|
||||
string dateGroupDirectory = string.Concat(outputResolution.Replace(" ", string.Empty), "-", modelName, "-", predictorModelName, "-", propertyConfiguration.NumberOfJitters, "-", propertyConfiguration.NumberOfTimesToUpsample);
|
||||
result = Path.Combine(result, dateGroupDirectory);
|
||||
}
|
||||
else if (includeModel)
|
||||
throw new Exception();
|
||||
else if (includePredictorModel)
|
||||
throw new Exception();
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted)
|
||||
{
|
||||
List<string> results = [];
|
||||
string sourceDirectorySegment = GetRelativePath(propertyConfiguration, sourceDirectory);
|
||||
string result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment);
|
||||
if (!string.IsNullOrEmpty(contentDescription))
|
||||
CheckContent(propertyConfiguration, dateGroupDirectory, contentDescription, result);
|
||||
if (!string.IsNullOrEmpty(singletonDescription))
|
||||
CheckSingleton(propertyConfiguration, dateGroupDirectory, singletonDescription, converted, result);
|
||||
if (!string.IsNullOrEmpty(collectionDescription))
|
||||
CheckCollection(propertyConfiguration, dateGroupDirectory, collectionDescription, converted, result);
|
||||
results.Add(result);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void CheckContent(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dateGroupDirectory, string contentDescription, string result)
|
||||
{
|
||||
string checkDirectory;
|
||||
@ -74,58 +123,6 @@ internal class Result
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
}
|
||||
|
||||
internal static string GetResultsFullGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel)
|
||||
{
|
||||
string result = GetResultsDateGroupDirectory(propertyConfiguration, description);
|
||||
if (includeResizeGroup)
|
||||
result = Path.Combine(result, outputResolution);
|
||||
if (includeModel && includePredictorModel)
|
||||
{
|
||||
string modelName;
|
||||
string predictorModelName;
|
||||
if (propertyConfiguration.ModelName is null)
|
||||
modelName = Model.Hog.ToString();
|
||||
else
|
||||
modelName = propertyConfiguration.ModelName;
|
||||
if (propertyConfiguration.PredictorModelName is null)
|
||||
predictorModelName = PredictorModel.Large.ToString();
|
||||
else
|
||||
predictorModelName = propertyConfiguration.PredictorModelName;
|
||||
string dateGroupDirectory = string.Concat(outputResolution.Replace(" ", string.Empty), "-", modelName, "-", predictorModelName, "-", propertyConfiguration.NumberOfJitters, "-", propertyConfiguration.NumberOfTimesToUpsample);
|
||||
result = Path.Combine(result, dateGroupDirectory);
|
||||
}
|
||||
else if (includeModel)
|
||||
throw new Exception();
|
||||
else if (includePredictorModel)
|
||||
throw new Exception();
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted)
|
||||
{
|
||||
List<string> results = [];
|
||||
string sourceDirectorySegment = GetRelativePath(propertyConfiguration, sourceDirectory);
|
||||
string result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment);
|
||||
if (!string.IsNullOrEmpty(contentDescription))
|
||||
CheckContent(propertyConfiguration, dateGroupDirectory, contentDescription, result);
|
||||
if (!string.IsNullOrEmpty(singletonDescription))
|
||||
CheckSingleton(propertyConfiguration, dateGroupDirectory, singletonDescription, converted, result);
|
||||
if (!string.IsNullOrEmpty(collectionDescription))
|
||||
CheckCollection(propertyConfiguration, dateGroupDirectory, collectionDescription, converted, result);
|
||||
results.Add(result);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create)
|
||||
{
|
||||
string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace('_', ')'));
|
||||
if (create && !Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectoryInfoCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription)
|
||||
{
|
||||
List<string> results;
|
||||
|
@ -40,12 +40,13 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Container\Container.csproj" />
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -251,7 +251,7 @@ 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" })
|
||||
.WithArguments(["-i", files[i], "-vframes", "1", $"{fileHolder.Name}-%4d.jpg"])
|
||||
.WithWorkingDirectory(fileHolder.DirectoryFullPath)
|
||||
.ExecuteAsync();
|
||||
result.Task.Wait();
|
||||
|
@ -34,11 +34,11 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.7.0" />
|
||||
<PackageReference Include="CliWrap" Version="3.8.1" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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" />
|
||||
|
@ -40,11 +40,10 @@ public class C_Resize
|
||||
private readonly bool _ForceResizeLastWriteTimeToCreationTime;
|
||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
||||
private readonly Dictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
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,56 +60,31 @@ 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;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public static byte[] GetBitmapData(Bitmap bitmap)
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Update(string cResultsFullGroupDirectory)
|
||||
{
|
||||
_FileGroups.Clear();
|
||||
ReadOnlyDictionary<string, ReadOnlyCollection<string>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, [_PropertyConfiguration.ResultSingleton]);
|
||||
foreach (KeyValuePair<string, ReadOnlyCollection<string>> keyValuePair in keyValuePairs)
|
||||
_FileGroups.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
public void SetAngleBracketCollection(string cResultsFullGroupDirectory, string sourceDirectory)
|
||||
{
|
||||
AngleBracketCollection.Clear();
|
||||
AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration,
|
||||
sourceDirectory,
|
||||
cResultsFullGroupDirectory,
|
||||
contentDescription: "Resized image",
|
||||
singletonDescription: "Resize dimensions for each resolution",
|
||||
collectionDescription: string.Empty,
|
||||
converted: true));
|
||||
}
|
||||
|
||||
byte[] results;
|
||||
#pragma warning disable CA1416
|
||||
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetJpegLowQuality()
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
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))
|
||||
throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension));
|
||||
result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]);
|
||||
return result;
|
||||
Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
results = new byte[length];
|
||||
Marshal.Copy(intPtr, results, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
#pragma warning restore CA1416
|
||||
return results;
|
||||
}
|
||||
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetPngLowQuality()
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
#pragma warning disable CA1416
|
||||
ImageFormat imageFormat = ImageFormat.Png;
|
||||
ImageCodecInfo[] imageCodecInfoCollection = ImageCodecInfo.GetImageEncoders();
|
||||
ImageCodecInfo imageCodecInfo = (from l in imageCodecInfoCollection where l.FormatID == imageFormat.Guid select l).First();
|
||||
@ -119,12 +93,30 @@ public class C_Resize
|
||||
if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension))
|
||||
throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension));
|
||||
result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]);
|
||||
#pragma warning restore CA1416
|
||||
return result;
|
||||
}
|
||||
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetJpegLowQuality()
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
#pragma warning disable CA1416
|
||||
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))
|
||||
throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension));
|
||||
result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]);
|
||||
#pragma warning restore CA1416
|
||||
return result;
|
||||
}
|
||||
|
||||
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetTuple(string outputExtension, int outputQuality)
|
||||
{
|
||||
(ImageCodecInfo, EncoderParameters, string) result;
|
||||
#pragma warning disable CA1416
|
||||
ImageFormat imageFormat = outputExtension switch
|
||||
{
|
||||
".gif" => ImageFormat.Gif,
|
||||
@ -146,55 +138,274 @@ public class C_Resize
|
||||
if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension))
|
||||
throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension));
|
||||
result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]);
|
||||
#pragma warning restore CA1416
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] GetBitmapData(Bitmap bitmap)
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, int id) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, $"{id}{item.FilePath.ExtensionLowered}");
|
||||
|
||||
private FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, FilePath filePath, bool outputResolutionHasNumber, string fileName)
|
||||
{
|
||||
byte[] results;
|
||||
Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
results = new byte[length];
|
||||
Marshal.Copy(intPtr, results, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
FileHolder result;
|
||||
if (outputResolutionHasNumber)
|
||||
result = Shared.Models.Stateless.Methods.IFileHolder.Get(Path.Combine(AngleBracketCollection[0].Replace("<>", _PropertyConfiguration.ResultContent), fileName));
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Update(string cResultsFullGroupDirectory)
|
||||
{
|
||||
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)
|
||||
{
|
||||
AngleBracketCollection.Clear();
|
||||
AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_PropertyConfiguration,
|
||||
sourceDirectory,
|
||||
cResultsFullGroupDirectory,
|
||||
contentDescription: "Resized image",
|
||||
singletonDescription: "Resize dimensions for each resolution",
|
||||
collectionDescription: string.Empty,
|
||||
converted: true));
|
||||
}
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, item.FilePath.Name);
|
||||
|
||||
public Dictionary<string, int[]> GetResizeKeyValuePairs(Configuration configuration, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, ExifDirectory exifDirectory, 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();
|
||||
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);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_ForceResizeLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_PropertiesChangedForResize)
|
||||
results = null;
|
||||
else if (!fileInfo.Exists)
|
||||
results = null;
|
||||
else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old"))
|
||||
throw new ArgumentException("must be a *.json file");
|
||||
else if (dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
json = File.ReadAllText(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
results = JsonSerializer.Deserialize<Dictionary<string, int[]>>(json);
|
||||
if (results is null)
|
||||
throw new Exception();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), fileInfo.LastWriteTime));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results = null;
|
||||
parseExceptions.Add(nameof(C_Resize));
|
||||
}
|
||||
}
|
||||
if (results is null)
|
||||
{
|
||||
results = GetImageResizes(exifDirectory);
|
||||
json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions);
|
||||
bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
||||
{
|
||||
if (!_ForceResizeLastWriteTimeToCreationTime)
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void CopyPropertyItems(byte[] bytes, PropertyItem[] propertyItems, Bitmap bitmap)
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
bool hasId = false;
|
||||
int id = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized;
|
||||
int imageWidth = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageWidth;
|
||||
int imageHeight = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageHeight;
|
||||
int orientation = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation;
|
||||
foreach (PropertyItem propertyItem in propertyItems)
|
||||
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 (propertyItem.Id == id)
|
||||
hasId = true;
|
||||
else if (propertyItem.Id == imageWidth)
|
||||
continue;
|
||||
else if (propertyItem.Id == imageHeight)
|
||||
continue;
|
||||
else if (propertyItem.Id == orientation)
|
||||
continue;
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
File.Move(checkFile, fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
}
|
||||
if (!hasId)
|
||||
}
|
||||
|
||||
private Dictionary<string, int[]> GetImageResizes(ExifDirectory exifDirectory)
|
||||
{
|
||||
Dictionary<string, int[]> results = [];
|
||||
int[] desired;
|
||||
int checkWidth;
|
||||
int checkHeight;
|
||||
int desiredWidth;
|
||||
int desiredHeight;
|
||||
int? orientation = Shared.Models.Stateless.Methods.IMetaBase.GetOrientation(exifDirectory.ExifBaseDirectories);
|
||||
if (exifDirectory is null || orientation is null || exifDirectory.Width is null || exifDirectory.Height is null)
|
||||
throw new NotSupportedException();
|
||||
checkWidth = exifDirectory.Width.Value;
|
||||
checkHeight = exifDirectory.Height.Value;
|
||||
if (!_ValidResolutions.Contains(_Original))
|
||||
results.Add(_Original, [checkWidth, checkHeight, orientation.Value]);
|
||||
foreach (string validResolution in _ValidResolutions)
|
||||
{
|
||||
PropertyItem propertyItem = (PropertyItem)_ConstructorInfo.Invoke(null);
|
||||
propertyItem.Id = id;
|
||||
propertyItem.Len = bytes.Length;
|
||||
propertyItem.Type = 2;
|
||||
propertyItem.Value = bytes;
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
if (validResolution == _Original)
|
||||
{
|
||||
desiredWidth = checkWidth;
|
||||
desiredHeight = checkHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
desired = GetCollection(validResolution);
|
||||
desiredWidth = desired[0];
|
||||
desiredHeight = desired[1];
|
||||
}
|
||||
if (checkWidth <= desiredWidth && checkHeight <= desiredHeight)
|
||||
results.Add(validResolution, [checkWidth, checkHeight, orientation.Value]);
|
||||
else
|
||||
{
|
||||
if (desiredWidth != desiredHeight)
|
||||
{
|
||||
if (checkWidth * desiredHeight > desiredWidth * checkHeight)
|
||||
results.Add(validResolution, [desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth), orientation.Value]);
|
||||
else
|
||||
results.Add(validResolution, [Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight, orientation.Value]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (checkWidth * desiredHeight <= desiredWidth * checkHeight)
|
||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation.Value, desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth)]);
|
||||
else
|
||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation.Value, Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static int[] GetCollection(string outputResolution)
|
||||
{
|
||||
List<int> results = [];
|
||||
string[] segments = outputResolution.Split('x');
|
||||
results.Add(int.Parse(segments[0]));
|
||||
results.Add(int.Parse(segments[1]));
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public void SaveResizedSubfile(Configuration configuration, string outputResolution, string cResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, Item item, ExifDirectory exifDirectory, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize)
|
||||
{
|
||||
if (mappingFromItem.ResizedFileHolder is null)
|
||||
throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder));
|
||||
#pragma warning disable CA1854
|
||||
if (!outputResolutionToResize.ContainsKey(_Original))
|
||||
throw new Exception();
|
||||
if (!outputResolutionToResize.ContainsKey(outputResolution))
|
||||
throw new Exception();
|
||||
#pragma warning restore CA1854
|
||||
FileInfo fileInfo = new(mappingFromItem.ResizedFileHolder.FullName);
|
||||
bool check = false;
|
||||
int[] resize = outputResolutionToResize[outputResolution];
|
||||
int outputResolutionWidth = resize[_OutputResolutionWidthIndex];
|
||||
int outputResolutionHeight = resize[_OutputResolutionHeightIndex];
|
||||
int outputResolutionOrientation = resize[_OutputResolutionOrientationIndex];
|
||||
int[] originalCollection = outputResolutionToResize[_Original];
|
||||
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();
|
||||
if (_OverrideForResizeImages)
|
||||
check = true;
|
||||
else if (!fileInfo.Exists)
|
||||
check = true;
|
||||
if (outputResolutionWidth == originalCollection[_OutputResolutionWidthIndex] && outputResolutionHeight == originalCollection[_OutputResolutionHeightIndex] && outputResolutionOrientation == originalCollection[_OutputResolutionOrientationIndex])
|
||||
{
|
||||
if (!check && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.CreationTime.AddDays(1))
|
||||
check = true;
|
||||
if (check)
|
||||
{
|
||||
// if (fileInfo.Exists)
|
||||
// File.Delete(fileInfo.FullName);
|
||||
// File.Copy(mappingFromItem.FilePath.FullName, fileInfo.FullName);
|
||||
// item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
||||
// subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!check && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
check = true;
|
||||
if (check)
|
||||
{
|
||||
SaveResizedSubfile(exifDirectory, mappingFromItem, resize);
|
||||
item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveResizedSubfile(ExifDirectory exifDirectory, MappingFromItem mappingFromItem, int[] resize)
|
||||
{
|
||||
string dateTimeFormat = IProperty.DateTimeFormat;
|
||||
DateTime? dateTime = Shared.Models.Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
||||
dateTime ??= Shared.Models.Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
||||
string dateTimeValue = dateTime.Value.ToString(dateTimeFormat);
|
||||
byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue);
|
||||
if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue)
|
||||
throw new Exception();
|
||||
if (resize.Length == 3)
|
||||
SaveResizedSubfile3(mappingFromItem, resize, bytes);
|
||||
else if (resize.Length == 5)
|
||||
SaveResizedSubfile5(mappingFromItem, resize, bytes);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
private void SaveResizedSubfile3(MappingFromItem mappingFromItem, int[] resize, byte[] bytes)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
#pragma warning disable CA1416
|
||||
int outputResolutionWidth = resize[_OutputResolutionWidthIndex];
|
||||
using Bitmap temp = new(mappingFromItem.FilePath.FullName, useIcm: false);
|
||||
int outputResolutionHeight = resize[_OutputResolutionHeightIndex];
|
||||
@ -234,11 +445,45 @@ public class C_Resize
|
||||
CopyPropertyItems(bytes, propertyItems, bitmap);
|
||||
bitmap.Save(mappingFromItem.ResizedFileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||
bitmap.Dispose();
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
|
||||
private void CopyPropertyItems(byte[] bytes, PropertyItem[] propertyItems, Bitmap bitmap)
|
||||
{
|
||||
bool hasId = false;
|
||||
int id = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized;
|
||||
int imageWidth = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageWidth;
|
||||
int imageHeight = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageHeight;
|
||||
int orientation = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation;
|
||||
#pragma warning disable CA1416
|
||||
foreach (PropertyItem propertyItem in propertyItems)
|
||||
{
|
||||
if (propertyItem.Id == id)
|
||||
hasId = true;
|
||||
else if (propertyItem.Id == imageWidth)
|
||||
continue;
|
||||
else if (propertyItem.Id == imageHeight)
|
||||
continue;
|
||||
else if (propertyItem.Id == orientation)
|
||||
continue;
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
}
|
||||
if (!hasId)
|
||||
{
|
||||
PropertyItem propertyItem = (PropertyItem)_ConstructorInfo.Invoke(null);
|
||||
propertyItem.Id = id;
|
||||
propertyItem.Len = bytes.Length;
|
||||
propertyItem.Type = 2;
|
||||
propertyItem.Value = bytes;
|
||||
bitmap.SetPropertyItem(propertyItem);
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
|
||||
private void SaveResizedSubfile5(MappingFromItem mappingFromItem, int[] resize, byte[] bytes)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
#pragma warning disable CA1416
|
||||
using Bitmap temp = new(mappingFromItem.FilePath.FullName, useIcm: false);
|
||||
PropertyItem[] propertyItems = temp.PropertyItems;
|
||||
int tempResolutionWidth = resize[_TempResolutionWidth];
|
||||
@ -291,215 +536,7 @@ public class C_Resize
|
||||
bitmap.Save(mappingFromItem.ResizedFileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||
}
|
||||
bitmap.Dispose();
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
private void SaveResizedSubfile(Shared.Models.Property property, MappingFromItem mappingFromItem, int[] resize)
|
||||
{
|
||||
string dateTimeFormat = IProperty.DateTimeFormat();
|
||||
DateTime dateTime = property.DateTimeOriginal is not null ? property.DateTimeOriginal.Value : Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property);
|
||||
string dateTimeValue = dateTime.ToString(dateTimeFormat);
|
||||
byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue);
|
||||
if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue)
|
||||
throw new Exception();
|
||||
if (resize.Length == 3)
|
||||
SaveResizedSubfile3(mappingFromItem, resize, bytes);
|
||||
else if (resize.Length == 5)
|
||||
SaveResizedSubfile5(mappingFromItem, resize, bytes);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public void SaveResizedSubfile(Configuration configuration, string outputResolution, string cResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, Item item, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize)
|
||||
{
|
||||
if (mappingFromItem.ResizedFileHolder is null)
|
||||
throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder));
|
||||
#pragma warning disable CA1854
|
||||
if (!outputResolutionToResize.ContainsKey(_Original))
|
||||
throw new Exception();
|
||||
if (!outputResolutionToResize.ContainsKey(outputResolution))
|
||||
throw new Exception();
|
||||
#pragma warning restore CA1854
|
||||
FileInfo fileInfo = new(mappingFromItem.ResizedFileHolder.FullName);
|
||||
bool check = false;
|
||||
int[] resize = outputResolutionToResize[outputResolution];
|
||||
int outputResolutionWidth = resize[_OutputResolutionWidthIndex];
|
||||
int outputResolutionHeight = resize[_OutputResolutionHeightIndex];
|
||||
int outputResolutionOrientation = resize[_OutputResolutionOrientationIndex];
|
||||
int[] originalCollection = outputResolutionToResize[_Original];
|
||||
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();
|
||||
if (_OverrideForResizeImages)
|
||||
check = true;
|
||||
else if (!fileInfo.Exists)
|
||||
check = true;
|
||||
if (outputResolutionWidth == originalCollection[_OutputResolutionWidthIndex] && outputResolutionHeight == originalCollection[_OutputResolutionHeightIndex] && outputResolutionOrientation == originalCollection[_OutputResolutionOrientationIndex])
|
||||
{
|
||||
if (!check && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.CreationTime.AddDays(1))
|
||||
check = true;
|
||||
if (check)
|
||||
{
|
||||
// if (fileInfo.Exists)
|
||||
// File.Delete(fileInfo.FullName);
|
||||
// File.Copy(mappingFromItem.FilePath.FullName, fileInfo.FullName);
|
||||
// item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
||||
// subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!check && dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
check = true;
|
||||
if (check)
|
||||
{
|
||||
SaveResizedSubfile(property, mappingFromItem, resize);
|
||||
item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] GetCollection(string outputResolution)
|
||||
{
|
||||
List<int> results = [];
|
||||
string[] segments = outputResolution.Split('x');
|
||||
results.Add(int.Parse(segments[0]));
|
||||
results.Add(int.Parse(segments[1]));
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private Dictionary<string, int[]> GetImageResizes(Shared.Models.Property property)
|
||||
{
|
||||
Dictionary<string, int[]> results = [];
|
||||
int[] desired;
|
||||
int checkWidth;
|
||||
int checkHeight;
|
||||
int desiredWidth;
|
||||
int desiredHeight;
|
||||
int orientation = property.Orientation is null || string.IsNullOrEmpty(property.Orientation) || !int.TryParse(property.Orientation, out int propertyOrientation) ? 0 : propertyOrientation;
|
||||
if (property is null || property.Width is null || property.Height is null)
|
||||
throw new NotSupportedException();
|
||||
checkWidth = property.Width.Value;
|
||||
checkHeight = property.Height.Value;
|
||||
if (!_ValidResolutions.Contains(_Original))
|
||||
results.Add(_Original, [checkWidth, checkHeight, orientation]);
|
||||
foreach (string validResolution in _ValidResolutions)
|
||||
{
|
||||
if (validResolution == _Original)
|
||||
{
|
||||
desiredWidth = checkWidth;
|
||||
desiredHeight = checkHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
desired = GetCollection(validResolution);
|
||||
desiredWidth = desired[0];
|
||||
desiredHeight = desired[1];
|
||||
}
|
||||
if (checkWidth <= desiredWidth && checkHeight <= desiredHeight)
|
||||
results.Add(validResolution, [checkWidth, checkHeight, orientation]);
|
||||
else
|
||||
{
|
||||
if (desiredWidth != desiredHeight)
|
||||
{
|
||||
if (checkWidth * desiredHeight > desiredWidth * checkHeight)
|
||||
results.Add(validResolution, [desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth), orientation]);
|
||||
else
|
||||
results.Add(validResolution, [Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight, orientation]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (checkWidth * desiredHeight <= desiredWidth * checkHeight)
|
||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation, desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth)]);
|
||||
else
|
||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation, Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, FilePath filePath, bool outputResolutionHasNumber, string fileName)
|
||||
{
|
||||
FileHolder result;
|
||||
if (outputResolutionHasNumber)
|
||||
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));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, item.FilePath.Name);
|
||||
|
||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber, int id) =>
|
||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, $"{id}{item.FilePath.ExtensionLowered}");
|
||||
|
||||
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"));
|
||||
if (_ForceResizeLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_ForceResizeLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_PropertiesChangedForResize)
|
||||
results = null;
|
||||
else if (!fileInfo.Exists)
|
||||
results = null;
|
||||
else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old"))
|
||||
throw new ArgumentException("must be a *.json file");
|
||||
else if (dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||
results = null;
|
||||
else
|
||||
{
|
||||
json = File.ReadAllText(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
results = JsonSerializer.Deserialize<Dictionary<string, int[]>>(json);
|
||||
if (results is null)
|
||||
throw new Exception();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), fileInfo.LastWriteTime));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results = null;
|
||||
parseExceptions.Add(nameof(C_Resize));
|
||||
}
|
||||
}
|
||||
if (results is null)
|
||||
{
|
||||
results = GetImageResizes(property);
|
||||
json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions);
|
||||
bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
|
||||
{
|
||||
if (!_ForceResizeLastWriteTimeToCreationTime)
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -35,7 +35,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -35,9 +35,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.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" />
|
||||
|
@ -22,7 +22,7 @@ public class SetCreatedDate
|
||||
private readonly IsEnvironment _IsEnvironment;
|
||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||
private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _FileGroups;
|
||||
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)
|
||||
{
|
||||
|
34
Shared/Models/C_Resize.cs
Normal file
34
Shared/Models/C_Resize.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record C_ResizeX(ReadOnlyDictionary<int, List<FilePath>> Amazon,
|
||||
ReadOnlyDictionary<int, List<FilePath>> Content,
|
||||
string OutputResolutionDirectory,
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, int[]>> OutputResolutionToResize,
|
||||
ReadOnlyDictionary<int, List<FilePath>> Singleton)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, C_ResizeXSourceGenerationContext.Default.C_ResizeX);
|
||||
return result;
|
||||
}
|
||||
|
||||
// If first
|
||||
// Set OutputResolutionDirectory
|
||||
// Create a directories for Amazon, Content and Singleton
|
||||
// Populate Amazon
|
||||
// Populate Content
|
||||
// Populate Singleton
|
||||
// Populate existing OutputResolutionToResize
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(C_ResizeX))]
|
||||
public partial class C_ResizeXSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
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
|
||||
{
|
||||
}
|
24
Shared/Models/D2_FaceParts.cs
Normal file
24
Shared/Models/D2_FaceParts.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record D2_FacePartsX(Dictionary<int, List<FilePath>> Amazon,
|
||||
List<FilePath> Collection,
|
||||
Dictionary<int, List<FilePath>> Content,
|
||||
string OutputResolutionWithDirectory)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, D2_FacePartsXSourceGenerationContext.Default.D2_FacePartsX);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(D2_FacePartsX))]
|
||||
public partial class D2_FacePartsXSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
24
Shared/Models/D_Face.cs
Normal file
24
Shared/Models/D_Face.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record D_FaceX(Dictionary<int, List<FilePath>> Amazon,
|
||||
Dictionary<int, List<FilePath>> Content,
|
||||
Dictionary<int, List<FilePath>> Collection,
|
||||
string OutputResolutionWithDirectory)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, D_FaceXSourceGenerationContext.Default.D_FaceX);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(D_FaceX))]
|
||||
public partial class D_FaceXSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -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,
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@ -33,13 +34,12 @@ public class Face : Properties.IFace
|
||||
_OutputResolution = outputResolution;
|
||||
}
|
||||
|
||||
public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Location? location) :
|
||||
public Face(ExifDirectory exifDirectory, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Location? location) :
|
||||
this(DateTime.MinValue, null, null, null, location, null, null)
|
||||
{
|
||||
DateTime?[] dateTimes;
|
||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||
dateTimes = [property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp];
|
||||
_DateTime = (from l in dateTimes where l.HasValue select l.Value).Min();
|
||||
ReadOnlyCollection<DateTime> dateTimes = Stateless.Methods.IDate.GetDateTimes(exifDirectory);
|
||||
_DateTime = dateTimes.Min();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -48,12 +48,16 @@ public class Face : Properties.IFace
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetFaceEncoding(FaceEncoding faceEncoding) => _FaceEncoding = faceEncoding;
|
||||
public void SetFaceEncoding(FaceEncoding faceEncoding) =>
|
||||
_FaceEncoding = faceEncoding;
|
||||
|
||||
public void SetFaceParts(Dictionary<Stateless.FacePart, FacePoint[]> faceParts) => _FaceParts = faceParts;
|
||||
public void SetFaceParts(Dictionary<Stateless.FacePart, FacePoint[]> faceParts) =>
|
||||
_FaceParts = faceParts;
|
||||
|
||||
public void SetMapping(Mapping mapping) => _Mapping = mapping;
|
||||
public void SetMapping(Mapping mapping) =>
|
||||
_Mapping = mapping;
|
||||
|
||||
public void SetFaceDistance(FaceDistance? faceDistance) => _FaceDistance = faceDistance;
|
||||
public void SetFaceDistance(FaceDistance? faceDistance) =>
|
||||
_FaceDistance = faceDistance;
|
||||
|
||||
}
|
@ -3,11 +3,11 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
internal record FilePair(string Path,
|
||||
bool IsUnique,
|
||||
bool? IsNotUniqueAndNeedsReview,
|
||||
List<string> Collection,
|
||||
string? Match)
|
||||
public record FilePair(FilePath FilePath,
|
||||
bool IsUnique,
|
||||
bool? IsNotUniqueAndNeedsReview,
|
||||
List<FilePath> Collection,
|
||||
FilePath? Match)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
@ -20,6 +20,6 @@ internal record FilePair(string Path,
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(FilePair))]
|
||||
internal partial class FilePairSourceGenerationContext : JsonSerializerContext
|
||||
public partial class FilePairSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -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;
|
||||
@ -20,12 +21,6 @@ public record FilePath(long CreationTicks,
|
||||
int? SortOrder)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, FilePathSourceGenerationContext.Default.FilePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FilePath Get(Properties.IPropertyConfiguration propertyConfiguration, FileHolder fileHolder, int? index)
|
||||
{
|
||||
if (fileHolder.CreationTime is null)
|
||||
@ -83,6 +78,61 @@ public record FilePath(long CreationTicks,
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ReadOnlyDictionary<int, List<FilePath>> GetFilesKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
Dictionary<int, List<FilePath>> results = [];
|
||||
List<FilePath>? collection;
|
||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||
{
|
||||
foreach (FilePath filePath in filePaths)
|
||||
{
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
{
|
||||
results.Add(filePath.Id.Value, []);
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(filePath);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, FilePathSourceGenerationContext.Default.FilePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
|
@ -6,6 +6,7 @@ namespace View_by_Distance.Shared.Models;
|
||||
public class Item : Properties.IItem
|
||||
{
|
||||
|
||||
protected ExifDirectory? _ExifDirectory;
|
||||
protected List<Face> _Faces;
|
||||
protected readonly bool? _FileSizeChanged;
|
||||
protected readonly FilePath _FilePath;
|
||||
@ -15,10 +16,10 @@ public class Item : Properties.IItem
|
||||
protected bool _IsValidImageFormatExtension;
|
||||
protected bool? _LastWriteTimeChanged;
|
||||
protected bool? _Moved;
|
||||
protected Property? _Property;
|
||||
protected readonly string _RelativePath;
|
||||
protected FileHolder? _ResizedFileHolder;
|
||||
protected readonly FileHolder _SourceDirectoryFileHolder;
|
||||
public ExifDirectory? ExifDirectory => _ExifDirectory;
|
||||
public List<Face> Faces => _Faces;
|
||||
public bool? FileSizeChanged => _FileSizeChanged;
|
||||
public FilePath FilePath => _FilePath;
|
||||
@ -28,13 +29,12 @@ public class Item : Properties.IItem
|
||||
public bool IsValidImageFormatExtension => _IsValidImageFormatExtension;
|
||||
public bool? LastWriteTimeChanged => _LastWriteTimeChanged;
|
||||
public bool? Moved => _Moved;
|
||||
public Property? Property => _Property;
|
||||
public string RelativePath => _RelativePath;
|
||||
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
||||
public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder;
|
||||
|
||||
[JsonConstructor]
|
||||
public Item(List<Face> faces, FilePath filePath, bool? fileSizeChanged, bool? isArchive, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder)
|
||||
public Item(List<Face> faces, FilePath filePath, bool? fileSizeChanged, bool? isArchive, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, ExifDirectory? exifDirectory, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder)
|
||||
{
|
||||
_Faces = faces;
|
||||
_FilePath = filePath;
|
||||
@ -45,25 +45,28 @@ public class Item : Properties.IItem
|
||||
_IsValidImageFormatExtension = isValidImageFormatExtension;
|
||||
_LastWriteTimeChanged = lastWriteTimeChanged;
|
||||
_Moved = moved;
|
||||
_Property = property;
|
||||
_ExifDirectory = exifDirectory;
|
||||
_RelativePath = relativePath;
|
||||
_ResizedFileHolder = resizedFileHolder;
|
||||
_SourceDirectoryFileHolder = sourceDirectoryFileHolder;
|
||||
}
|
||||
|
||||
public static Item Get(FilePath filePath, FileHolder sourceDirectoryFileHolder, string relativePath, bool? isArchive, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged)
|
||||
public static Item Get(FilePath filePath, FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) =>
|
||||
Get(filePath, sourceDirectoryFileHolder, relativePath, null, null, false, isValidImageFormatExtension, null, null, null, null);
|
||||
|
||||
public static Item Get(FilePath filePath, FileHolder sourceDirectoryFileHolder, string relativePath, bool? isArchive, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, ExifDirectory? exifDirectory, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged)
|
||||
{
|
||||
Item result;
|
||||
if (relativePath.EndsWith(".json"))
|
||||
throw new ArgumentException("Can not be a *.json file!");
|
||||
if (filePath.ExtensionLowered is ".json")
|
||||
throw new ArgumentException("Can not be a *.json file!");
|
||||
result = new([], filePath, fileSizeChanged, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder);
|
||||
result = new([], filePath, fileSizeChanged, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, exifDirectory, relativePath, null, sourceDirectoryFileHolder);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Item Get(FilePath filePath, FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) =>
|
||||
Get(filePath, sourceDirectoryFileHolder, relativePath, null, null, false, isValidImageFormatExtension, null, null, null, null);
|
||||
public bool Any() =>
|
||||
!_SourceDirectoryFileHolder.Exists || (_FileSizeChanged.HasValue && _FileSizeChanged.Value) || (_LastWriteTimeChanged.HasValue && _LastWriteTimeChanged.Value) || (_Moved.HasValue && _Moved.Value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@ -71,6 +74,9 @@ public class Item : Properties.IItem
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Update(ExifDirectory exifDirectory) =>
|
||||
_ExifDirectory = exifDirectory;
|
||||
|
||||
public void SetMoved(bool moved) => _Moved = moved;
|
||||
|
||||
public void SetResizedFileHolder(string filenameExtension, FileHolder fileHolder)
|
||||
@ -83,8 +89,4 @@ public class Item : Properties.IItem
|
||||
_ResizedFileHolder = fileHolder;
|
||||
}
|
||||
|
||||
public bool Any() => !_SourceDirectoryFileHolder.Exists || (_FileSizeChanged.HasValue && _FileSizeChanged.Value) || (_LastWriteTimeChanged.HasValue && _LastWriteTimeChanged.Value) || (_Moved.HasValue && _Moved.Value);
|
||||
|
||||
public void Update(Property property) => _Property = property;
|
||||
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record MappingFromItem(DateTime[] ContainerDateTimes,
|
||||
DateTime? DateTimeDigitized,
|
||||
DateTime? DateTimeOriginal,
|
||||
int Id,
|
||||
bool? IsArchive,
|
||||
FilePath FilePath,
|
||||
bool? IsWrongYear,
|
||||
string[] Keywords,
|
||||
ReadOnlyCollection<string> Keywords,
|
||||
DateTime MinimumDateTime,
|
||||
string? Model,
|
||||
string RelativePath,
|
||||
@ -29,14 +29,18 @@ public record MappingFromItem(DateTime[] ContainerDateTimes,
|
||||
internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder)
|
||||
{
|
||||
MappingFromItem result;
|
||||
if (item.Property?.Id is null)
|
||||
if (item.ExifDirectory?.FilePath.Id is null)
|
||||
throw new NotSupportedException();
|
||||
if (resizedFileHolder is null)
|
||||
throw new NotSupportedException();
|
||||
List<DateTime> dateTimes = item.Property.GetDateTimes();
|
||||
DateTime minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
(bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.FilePath, item.Property.DateTimeOriginal, dateTimes);
|
||||
result = new(containerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, item.Property.Id.Value, item.IsArchive, item.FilePath, isWrongYear, item.Property.Keywords ?? [], minimumDateTime, item.Property.Model, item.RelativePath, resizedFileHolder);
|
||||
ExifDirectory exifDirectory = item.ExifDirectory;
|
||||
DateTime minimumDateTime = Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
||||
DateTime? dateTime = Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
||||
string? model = Stateless.Methods.MetaBase.GetModel(exifDirectory.ExifBaseDirectories);
|
||||
ReadOnlyCollection<DateTime> dateTimes = Stateless.Methods.IDate.GetDateTimes(exifDirectory);
|
||||
(bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.FilePath, dateTime, dateTimes.ToList());
|
||||
ReadOnlyCollection<string> keywords = Stateless.Methods.MetaBase.GetKeywords(exifDirectory.ExifBaseDirectories);
|
||||
result = new(containerDateTimes, dateTime, exifDirectory.FilePath.Id.Value, item.IsArchive, item.FilePath, isWrongYear, keywords, minimumDateTime, model, item.RelativePath, resizedFileHolder);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
namespace View_by_Distance.Shared.Models.Methods;
|
||||
|
||||
public interface IContainer : Stateless.Methods.IContainer
|
||||
{ // ...
|
||||
|
||||
//
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace View_by_Distance.Shared.Models.Methods;
|
||||
|
||||
public interface IMetadataFile : Stateless.Methods.IMetadataFile
|
||||
{
|
||||
|
||||
// ...
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ namespace View_by_Distance.Shared.Models.Properties;
|
||||
public interface IItem
|
||||
{
|
||||
|
||||
public ExifDirectory? ExifDirectory { get; }
|
||||
public bool? FileSizeChanged { get; }
|
||||
public List<Face> Faces { get; }
|
||||
public FilePath FilePath { get; }
|
||||
@ -11,7 +12,6 @@ public interface IItem
|
||||
public bool IsUniqueFileName { get; }
|
||||
public bool IsValidImageFormatExtension { get; }
|
||||
public bool? Moved { get; }
|
||||
public Property? Property { get; }
|
||||
public string RelativePath { get; }
|
||||
public FileHolder? ResizedFileHolder { get; }
|
||||
public FileHolder SourceDirectoryFileHolder { get; }
|
||||
|
@ -1,282 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal abstract class Container
|
||||
{
|
||||
|
||||
private record FilePair(bool IsUnique, List<string> Collection, FilePath FilePath, Models.Item Item) { }
|
||||
|
||||
internal static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Models.Item> items)
|
||||
{
|
||||
DateTime[] results;
|
||||
long containerMinimumTicks = (from l in items select l.FilePath.LastWriteTicks).Min();
|
||||
long containerMaximumTicks = (from l in items select l.FilePath.LastWriteTicks).Max();
|
||||
results = [new(containerMinimumTicks), new(containerMaximumTicks)];
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container)
|
||||
{
|
||||
List<Models.Item> results = [];
|
||||
foreach (Models.Item item in container.Items)
|
||||
{
|
||||
if (!item.IsValidImageFormatExtension || propertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered))
|
||||
continue;
|
||||
results.Add(item);
|
||||
}
|
||||
return container.Items.Count == results.Count ? container.Items : new(results);
|
||||
}
|
||||
|
||||
private static List<Models.FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
int renamed;
|
||||
const bool useCeilingAverage = true;
|
||||
List<Models.FilePair>? filePairs = null;
|
||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
|
||||
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = XDirectory.GetFilesKeyValuePairs(filePathsCollection);
|
||||
for (int i = 0; i < short.MaxValue; i++)
|
||||
{
|
||||
renamed = 0;
|
||||
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||
compareFileNamesToFiles = XDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
|
||||
renamed += XDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
|
||||
filePairs = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
|
||||
renamed += XDirectory.MaybeMove(propertyConfiguration, filePairs, aPropertySingletonDirectory, extension);
|
||||
if (renamed == 0)
|
||||
break;
|
||||
if (i > 10)
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
|
||||
throw new NullReferenceException(nameof(filePairs));
|
||||
return filePairs;
|
||||
}
|
||||
|
||||
private static Models.Property? GetProperty(Models.FilePair filePair)
|
||||
{
|
||||
Models.Property? result;
|
||||
if (filePair.Match is null)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(filePair.Match);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
result = null;
|
||||
else
|
||||
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ParallelFor(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int rootDirectoryLength, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, Models.FilePair filePair, List<FilePair> results)
|
||||
{
|
||||
dlibDotNet?.Tick();
|
||||
bool abandoned = false;
|
||||
Models.FileHolder sourceDirectoryFileHolder;
|
||||
Models.Property? property = GetProperty(filePair);
|
||||
Models.FileHolder imageFileHolder = IFileHolder.Get(filePair.Path);
|
||||
FilePath filePath = FilePath.Get(propertyConfiguration, imageFileHolder, index: null);
|
||||
bool? fileSizeChanged = property is not null ? property.FileSize != filePath.Length : null;
|
||||
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||
bool? shouldIgnore = property is null || property.Keywords is null ? null : propertyConfiguration.IgnoreRulesKeyWords.Any(l => property.Keywords.Contains(l));
|
||||
bool? isArchive = filePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePath.Id.Value, out Identifier? identifier);
|
||||
if (shouldIgnore is not null)
|
||||
{
|
||||
if (shouldIgnore.Value)
|
||||
{
|
||||
FileInfo fileInfo = new(filePath.FullName);
|
||||
if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden))
|
||||
File.SetAttributes(imageFileHolder.FullName, FileAttributes.Hidden);
|
||||
}
|
||||
if (filePath.HasIgnoreKeyword is not null && filePath.HasIgnoreKeyword.Value != shouldIgnore.Value)
|
||||
{
|
||||
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
|
||||
File.Delete(filePath.FullName);
|
||||
else
|
||||
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
|
||||
}
|
||||
}
|
||||
string relativePath = IPath.GetRelativePath(filePair.Path, rootDirectoryLength, forceExtensionToLower: true);
|
||||
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime.Ticks != filePath.LastWriteTicks : null;
|
||||
if (filePair.Match is not null)
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
||||
else if (!filePair.IsUnique)
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath, extension)));
|
||||
else
|
||||
{
|
||||
string fileName = Path.GetFileName(filePair.Path);
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(Path.Combine(aPropertySingletonDirectory, directoryName, $"{fileName}{extension}"));
|
||||
}
|
||||
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
||||
{
|
||||
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePath.LastWriteTicks));
|
||||
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
||||
}
|
||||
Models.Item item = Models.Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
||||
lock (results)
|
||||
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
|
||||
}
|
||||
|
||||
private static List<FilePair> GetFilePairs(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
|
||||
{
|
||||
List<FilePair> results = [];
|
||||
const string extension = ".json";
|
||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
List<Models.FilePair> filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filePathsCollection);
|
||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, extension, filesCollectionDirectoryLength, splatNineIdentifiers, filePairs[i], results));
|
||||
return results;
|
||||
}
|
||||
|
||||
private static (int, Models.Container[]) GetContainers(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
|
||||
{
|
||||
List<Models.Container> results = [];
|
||||
string directory;
|
||||
List<Models.Item>? items;
|
||||
Models.Container container;
|
||||
List<string> directories = [];
|
||||
Dictionary<string, List<Models.Item>> directoryToItems = [];
|
||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||
{
|
||||
if (filePaths.Count == 0)
|
||||
continue;
|
||||
directory = filePaths[0].DirectoryFullPath;
|
||||
if (directory is null)
|
||||
continue;
|
||||
if (!directories.Contains(directory))
|
||||
directories.Add(directory);
|
||||
if (!directoryToItems.TryGetValue(directory, out items))
|
||||
{
|
||||
directoryToItems.Add(directory, []);
|
||||
if (!directoryToItems.TryGetValue(directory, out items))
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
|
||||
foreach (FilePair filePair in filePairs)
|
||||
{
|
||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||
{
|
||||
directoryToItems.Add(filePair.FilePath.DirectoryFullPath, []);
|
||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||
throw new Exception();
|
||||
}
|
||||
items.Add(filePair.Item);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<Models.Item>> keyValuePair in directoryToItems)
|
||||
{
|
||||
if (keyValuePair.Value.Count == 0)
|
||||
continue;
|
||||
container = new(keyValuePair.Key, new(keyValuePair.Value));
|
||||
results.Add(container);
|
||||
}
|
||||
return (filePairs.Count, results.ToArray());
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
Models.Container[] results;
|
||||
const string directorySearchFilter = "*";
|
||||
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory)
|
||||
{
|
||||
int count;
|
||||
Models.Container[] results;
|
||||
IDlibDotNet? dlibDotNet = null;
|
||||
const bool useCeilingAverage = true;
|
||||
const string fileSearchFilter = "*";
|
||||
const string directorySearchFilter = "*";
|
||||
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
|
||||
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, propertyConfiguration.RootDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
|
||||
return (count, results);
|
||||
}
|
||||
|
||||
internal static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||
{
|
||||
List<int> results = [];
|
||||
ReadOnlyCollection<Models.Item> filteredItems;
|
||||
foreach (Models.Container container in readOnlyContainers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
foreach (Models.Item item in filteredItems)
|
||||
{
|
||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (results.Contains(item.Property.Id.Value))
|
||||
continue;
|
||||
results.Add(item.Property.Id.Value);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||
{
|
||||
List<string> results = [];
|
||||
ReadOnlyCollection<Models.Item> filteredItems;
|
||||
foreach (Models.Container container in readOnlyContainers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
foreach (Models.Item item in filteredItems)
|
||||
{
|
||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
||||
continue;
|
||||
results.Add(item.FilePath.FileNameFirstSegment);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
|
||||
{
|
||||
List<Models.Item> results = [];
|
||||
List<int> distinct = [];
|
||||
ReadOnlyCollection<Models.Item> filteredItems;
|
||||
foreach (Models.Container container in containers)
|
||||
{
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!filterItems)
|
||||
filteredItems = container.Items;
|
||||
else
|
||||
{
|
||||
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
}
|
||||
foreach (Models.Item item in filteredItems)
|
||||
{
|
||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
if (distinctItems)
|
||||
{
|
||||
if (distinct.Contains(item.Property.Id.Value))
|
||||
continue;
|
||||
distinct.Add(item.Property.Id.Value);
|
||||
}
|
||||
results.Add(item);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
}
|
151
Shared/Models/Stateless/Methods/FilePair.cs
Normal file
151
Shared/Models/Stateless/Methods/FilePair.cs
Normal file
@ -0,0 +1,151 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal abstract class FilePair
|
||||
{
|
||||
|
||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
ReadOnlyCollection<Models.FilePair> results;
|
||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||
results = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles)
|
||||
{
|
||||
List<Models.FilePair>? results = null;
|
||||
int renamed;
|
||||
const bool useCeilingAverage = true;
|
||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||
IReadOnlyDictionary<int, List<FilePath>>? compareFileNamesToFiles = null;
|
||||
for (int i = 0; i < fileNamesToFiles.Count; i++)
|
||||
{
|
||||
renamed = 0;
|
||||
jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, fileNamesToFiles, extension);
|
||||
if (renamed > 0)
|
||||
continue;
|
||||
compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
|
||||
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
renamed += XDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
|
||||
if (renamed == 0)
|
||||
break;
|
||||
if (i > 10)
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (results is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
|
||||
throw new NullReferenceException(nameof(results));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension)
|
||||
{
|
||||
int result;
|
||||
bool check;
|
||||
bool moved = false;
|
||||
List<string> renameCollection = [];
|
||||
foreach (string[] files in jsonFilesCollection)
|
||||
{
|
||||
if (files.Length == 0)
|
||||
continue;
|
||||
check = AnyMoved(propertyConfiguration, fileNamesToFiles, extension, renameCollection, files);
|
||||
if (!moved && check)
|
||||
moved = true;
|
||||
}
|
||||
if (renameCollection.Count > 0)
|
||||
XDirectory.MoveFiles(renameCollection, "{}", "{abd}");
|
||||
result = renameCollection.Count;
|
||||
if (moved && result == 0)
|
||||
result = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
||||
{
|
||||
bool result = false;
|
||||
string checkFile;
|
||||
string directory;
|
||||
FilePath filePath;
|
||||
string fileNameWith;
|
||||
string checkDirectory;
|
||||
string directoryName;
|
||||
List<FilePath>? collection;
|
||||
Models.FileHolder fileHolder;
|
||||
List<string> directoryNames = [];
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith(extension))
|
||||
throw new Exception();
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
if (!fileHolder.Exists)
|
||||
continue;
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||
renameCollection.Add(file);
|
||||
else
|
||||
{
|
||||
directoryNames.Clear();
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath) ?? throw new Exception();
|
||||
foreach (FilePath f in collection)
|
||||
directoryNames.Add(Path.GetFileName(f.DirectoryFullPath) ?? throw new Exception());
|
||||
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
|
||||
continue;
|
||||
if (directoryName != directoryNames[0])
|
||||
{
|
||||
directory = Path.GetDirectoryName(filePath.DirectoryFullPath) ?? throw new Exception();
|
||||
checkDirectory = Path.Combine(directory, directoryNames[0]);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
fileNameWith = collection.Count > 1 ? filePath.Name : $"{collection[0].Name}{extension}";
|
||||
checkFile = Path.Combine(checkDirectory, fileNameWith);
|
||||
if (!result)
|
||||
result = true;
|
||||
if (!File.Exists(checkFile))
|
||||
File.Move(file, checkFile);
|
||||
else
|
||||
{
|
||||
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
|
||||
File.Delete(file);
|
||||
else
|
||||
File.Move(file, checkFile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, List<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||
{
|
||||
Dictionary<int, List<FilePath>> results = [];
|
||||
List<FilePath>? collection;
|
||||
FilePath filePath;
|
||||
Models.FileHolder fileHolder;
|
||||
foreach (string[] files in filesCollection)
|
||||
{
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
if (!fileHolder.Exists)
|
||||
continue;
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
{
|
||||
results.Add(filePath.Id.Value, []);
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(filePath);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IContainer
|
||||
{
|
||||
|
||||
DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Models.Item> items) =>
|
||||
GetContainerDateTimes(items);
|
||||
static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Models.Item> items) =>
|
||||
Container.GetContainerDateTimes(items);
|
||||
|
||||
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||
GetValidImageItems(propertyConfiguration, container);
|
||||
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||
Container.GetValidImageItems(propertyConfiguration, container);
|
||||
|
||||
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
|
||||
|
||||
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
||||
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
||||
|
||||
ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection);
|
||||
static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
Container.GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection);
|
||||
|
||||
List<int> TestStatic_GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||
static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||
static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||
|
||||
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||
|
||||
}
|
38
Shared/Models/Stateless/Methods/IDate.cs
Normal file
38
Shared/Models/Stateless/Methods/IDate.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IDate
|
||||
{
|
||||
|
||||
public static DateTime GetMinimum(ExifDirectory exifDirectory) =>
|
||||
XDate.GetMinimum(exifDirectory);
|
||||
|
||||
public static (int Season, string seasonName) GetSeason(int dayOfYear) =>
|
||||
XDate.GetSeason(dayOfYear);
|
||||
|
||||
public static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) =>
|
||||
XDate.GetDateTimeOriginal(exifDirectory);
|
||||
|
||||
public static ReadOnlyCollection<DateTime> GetDateTimes(ExifDirectory exifDirectory) =>
|
||||
XDate.GetDateTimes(exifDirectory);
|
||||
|
||||
public static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
|
||||
XDate.IsWrongYear(directoryInfo, filePath, exifDirectory);
|
||||
|
||||
internal DateTime TestStatic_GetMinimum(ExifDirectory exifDirectory) =>
|
||||
GetMinimum(exifDirectory);
|
||||
|
||||
internal (int Season, string seasonName) TestStatic_GetSeason(int dayOfYear) =>
|
||||
GetSeason(dayOfYear);
|
||||
|
||||
internal DateTime? TestStatic_GetDateTimeOriginal(ExifDirectory exifDirectory) =>
|
||||
GetDateTimeOriginal(exifDirectory);
|
||||
|
||||
internal ReadOnlyCollection<DateTime> TestStatic_GetDateTimes(ExifDirectory exifDirectory) =>
|
||||
XDate.GetDateTimes(exifDirectory);
|
||||
|
||||
internal (bool?, string[]) TestStatic_IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
|
||||
IsWrongYear(directoryInfo, filePath, exifDirectory);
|
||||
|
||||
}
|
@ -5,49 +5,70 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
public interface IDirectory
|
||||
{
|
||||
|
||||
char TestStatic_GetDirectory(string fileName) =>
|
||||
GetDirectory(fileName);
|
||||
static char GetDirectory(string fileName) =>
|
||||
fileName.Split('-').Length > 2 ? '-' : fileName.Split('.')[0][^1];
|
||||
|
||||
int TestStatic_GetDirectory(char directory) =>
|
||||
GetDirectory(directory);
|
||||
static int GetDirectory(char directory) =>
|
||||
public static int GetDirectory(char directory) =>
|
||||
directory == '-' ? 10 : int.TryParse(directory.ToString(), out int value) ? value : 11;
|
||||
|
||||
ReadOnlyCollection<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||
XDirectory.GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
public static char GetDirectory(string fileName) =>
|
||||
fileName.Split('-').Length > 2 ? '-' : fileName.Split('.')[0][^1];
|
||||
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage) =>
|
||||
GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useCeilingAverage);
|
||||
static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage) =>
|
||||
XDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useCeilingAverage);
|
||||
|
||||
void TestStatic_MoveFiles(List<string> files, string find, string replace) =>
|
||||
MoveFiles(files, find, replace);
|
||||
static void MoveFiles(List<string> files, string find, string replace) =>
|
||||
public static void MoveFiles(List<string> files, string find, string replace) =>
|
||||
XDirectory.MoveFiles(files, find, replace);
|
||||
|
||||
(string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, tick);
|
||||
static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, tick);
|
||||
|
||||
(string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick);
|
||||
static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick);
|
||||
|
||||
List<string> TestStatic_CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||
static List<string> CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
public static List<string> CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
XDirectory.CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) =>
|
||||
GetFilePathCollections(propertyConfiguration, filesCollection);
|
||||
static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) =>
|
||||
XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
|
||||
public static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||
XDirectory.GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
|
||||
public static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<Models.FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
||||
XDirectory.MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
||||
|
||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, bool useIgnoreExtensions) =>
|
||||
XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||
|
||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
||||
XDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||
|
||||
public static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
||||
XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
|
||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, null, tick);
|
||||
|
||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||
|
||||
internal int TestStatic_GetDirectory(char directory) =>
|
||||
GetDirectory(directory);
|
||||
|
||||
internal char TestStatic_GetDirectory(string fileName) =>
|
||||
GetDirectory(fileName);
|
||||
|
||||
internal void TestStatic_MoveFiles(List<string> files, string find, string replace) =>
|
||||
MoveFiles(files, find, replace);
|
||||
|
||||
internal List<string> TestStatic_CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||
CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||
|
||||
internal ReadOnlyCollection<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||
|
||||
internal int TestStatic_MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<Models.FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
||||
MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
||||
|
||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, bool useIgnoreExtensions) =>
|
||||
GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||
|
||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
||||
GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||
|
||||
internal List<Models.FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
||||
GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
|
||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick);
|
||||
|
||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||
|
||||
}
|
@ -4,5 +4,8 @@ public interface IDlibDotNet
|
||||
{
|
||||
|
||||
void Tick();
|
||||
(string, string) GetResultsFullGroupDirectories();
|
||||
void ConstructProgressBar(int maxTicks, string message);
|
||||
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
||||
|
||||
}
|
21
Shared/Models/Stateless/Methods/IFilePair.cs
Normal file
21
Shared/Models/Stateless/Methods/IFilePair.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IFilePair
|
||||
{
|
||||
|
||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||
|
||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
||||
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
|
||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||
|
||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
|
||||
}
|
@ -1,61 +1,75 @@
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IId
|
||||
{ // ...
|
||||
{
|
||||
|
||||
const int DeterministicHashCode = 9876543;
|
||||
|
||||
static bool IsOffsetDeterministicHashCode(Properties.IPropertyConfiguration propertyConfiguration) =>
|
||||
propertyConfiguration.Offset == DeterministicHashCode;
|
||||
|
||||
string TestStatic_GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
Id.GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
|
||||
int TestStatic_GetId(Properties.IPropertyConfiguration propertyConfiguration, string intelligentId) =>
|
||||
GetId(propertyConfiguration, intelligentId);
|
||||
static int GetId(Properties.IPropertyConfiguration propertyConfiguration, string intelligentId) =>
|
||||
Id.GetId(propertyConfiguration, intelligentId);
|
||||
|
||||
string TestStatic_GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
Id.GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
|
||||
string TestStatic_GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
|
||||
GetIgnoreFullPath(filePath, fileHolder);
|
||||
static string GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
|
||||
fileHolder.DirectoryFullPath is null ?
|
||||
throw new NotSupportedException() :
|
||||
filePath.Id > -1 ?
|
||||
fileHolder.NameWithoutExtension[^1] == '9' ?
|
||||
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}8{fileHolder.ExtensionLowered}") :
|
||||
throw new NotSupportedException("High") :
|
||||
fileHolder.NameWithoutExtension[^1] == '1' ?
|
||||
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}2{fileHolder.ExtensionLowered}") :
|
||||
throw new NotSupportedException("Low");
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
|
||||
static bool NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
||||
&& fileNameFirstSegment[^1] is '1' or '2' or '8' or '9'
|
||||
&& fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
|
||||
NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder);
|
||||
static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
|
||||
Id.NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||
|
||||
int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
||||
GetDeterministicHashCode(value);
|
||||
static int GetDeterministicHashCode(byte[] value) =>
|
||||
public static int GetDeterministicHashCode(byte[] value) =>
|
||||
Id.GetDeterministicHashCode(value);
|
||||
|
||||
public static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
Id.GetHasIgnoreKeyword(filePath);
|
||||
|
||||
public static int GetId(IPropertyConfiguration propertyConfiguration, string intelligentId) =>
|
||||
Id.GetId(propertyConfiguration, intelligentId);
|
||||
|
||||
public static bool IsOffsetDeterministicHashCode(IPropertyConfiguration propertyConfiguration) =>
|
||||
propertyConfiguration.Offset == DeterministicHashCode;
|
||||
|
||||
public static byte GetHasDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
Id.GetHasDateTimeOriginal(propertyConfiguration, filePath);
|
||||
|
||||
public static byte GetMissingDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
Id.GetMissingDateTimeOriginal(propertyConfiguration, filePath);
|
||||
|
||||
public static bool NameWithoutExtensionIsIdFormat(IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
|
||||
Id.NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||
|
||||
public static bool NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '0' or '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
public static string GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
Id.GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
|
||||
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
||||
&& fileNameFirstSegment[^1] is '0' or '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
|
||||
&& fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
public static string GetPaddedId(IPropertyConfiguration propertyConfiguration, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
Id.GetPaddedId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
|
||||
internal int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
||||
GetDeterministicHashCode(value);
|
||||
|
||||
internal byte TestStatic_GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
GetHasIgnoreKeyword(filePath);
|
||||
|
||||
internal int TestStatic_GetId(IPropertyConfiguration propertyConfiguration, string intelligentId) =>
|
||||
GetId(propertyConfiguration, intelligentId);
|
||||
|
||||
internal byte TestStatic_GetHasDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
GetHasDateTimeOriginal(propertyConfiguration, filePath);
|
||||
|
||||
internal byte TestStatic_GetMissingDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
GetMissingDateTimeOriginal(propertyConfiguration, filePath);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsIdFormat(IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
|
||||
NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
|
||||
|
||||
internal string TestStatic_GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||
|
||||
internal string TestStatic_GetPaddedId(IPropertyConfiguration propertyConfiguration, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
GetPaddedId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IMappingFromItem
|
||||
{ // ...
|
||||
{
|
||||
|
||||
MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
||||
=> GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||
static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
||||
public static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
||||
=> MappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||
|
||||
MappingFromItem TestStatic_GetMappingFromItem(Models.Item item)
|
||||
=> GetMappingFromItem(item);
|
||||
static MappingFromItem GetMappingFromItem(Models.Item item)
|
||||
public static MappingFromItem GetMappingFromItem(Models.Item item)
|
||||
=> GetMappingFromItem(containerDateTimes: [], item, item.ResizedFileHolder);
|
||||
|
||||
internal MappingFromItem TestStatic_GetMappingFromItem(Models.Item item)
|
||||
=> GetMappingFromItem(item);
|
||||
|
||||
internal MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
||||
=> GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||
|
||||
}
|
32
Shared/Models/Stateless/Methods/IMetaBase.cs
Normal file
32
Shared/Models/Stateless/Methods/IMetaBase.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IMetaBase
|
||||
{
|
||||
|
||||
public static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetMaker(exifBaseDirectories);
|
||||
|
||||
public static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetModel(exifBaseDirectories);
|
||||
|
||||
public static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetOrientation(exifBaseDirectories);
|
||||
|
||||
public static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetKeywords(exifBaseDirectories);
|
||||
|
||||
internal static string? TestStatic_GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetMaker(exifBaseDirectories);
|
||||
|
||||
internal static string? TestStatic_GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetModel(exifBaseDirectories);
|
||||
|
||||
internal static int? TestStatic_GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetOrientation(exifBaseDirectories);
|
||||
|
||||
internal static ReadOnlyCollection<string> TestStatic_GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetKeywords(exifBaseDirectories);
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IMetadataFile
|
||||
{
|
||||
|
||||
// ...
|
||||
|
||||
}
|
@ -4,72 +4,95 @@ using View_by_Distance.Shared.Models.Properties;
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
public interface IPath
|
||||
{ // ...
|
||||
{
|
||||
|
||||
string TestStatic_GetRelativePath(string path, int length) =>
|
||||
GetRelativePath(path, length);
|
||||
static string GetRelativePath(string path, int length) =>
|
||||
XPath.GetRelativePath(path, length, forceExtensionToLower: false);
|
||||
public static byte GetEnum(FilePath filePath) =>
|
||||
XPath.GetEnum(filePath);
|
||||
|
||||
bool TestStatic_DeleteEmptyDirectories(string rootDirectory) =>
|
||||
DeleteEmptyDirectories(rootDirectory);
|
||||
static bool DeleteEmptyDirectories(string rootDirectory) =>
|
||||
XPath.DeleteEmptyDirectories(rootDirectory);
|
||||
|
||||
void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||
ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||
static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||
|
||||
void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||
MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||
static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||
|
||||
void TestStatic_DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
|
||||
DeleteEmptyDirectories(rootDirectory, deletedDirectories);
|
||||
static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
|
||||
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
|
||||
// $dirs = gci "" -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName $dirs | Foreach-Object { Remove-Item $_ }
|
||||
|
||||
string[] TestStatic_GetDirectoryNames(string directory) =>
|
||||
GetDirectoryNames(directory);
|
||||
static string[] GetDirectoryNames(string directory) =>
|
||||
XPath.GetDirectoryNames(directory).ToArray();
|
||||
|
||||
string[] TestStatic_GetDirectories(string directory) =>
|
||||
GetDirectories(directory);
|
||||
static string[] GetDirectories(string directory) =>
|
||||
public static string[] GetDirectories(string directory) =>
|
||||
XPath.GetDirectories(directory).ToArray();
|
||||
|
||||
string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) =>
|
||||
GetRelativePath(path, length, forceExtensionToLower);
|
||||
static string GetRelativePath(string path, int length, bool forceExtensionToLower) =>
|
||||
public static string[] GetDirectoryNames(string directory) =>
|
||||
XPath.GetDirectoryNames(directory).ToArray();
|
||||
|
||||
public static string GetRelativePath(string path, int length) =>
|
||||
XPath.GetRelativePath(path, length, forceExtensionToLower: false);
|
||||
|
||||
public static bool DeleteEmptyDirectories(string rootDirectory) =>
|
||||
XPath.DeleteEmptyDirectories(rootDirectory);
|
||||
|
||||
public static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||
|
||||
public static void CreateDirectories(ReadOnlyCollection<string> directories) =>
|
||||
XPath.CreateDirectories(directories);
|
||||
|
||||
public static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||
|
||||
public static string GetRelativePath(string path, int length, bool forceExtensionToLower) =>
|
||||
XPath.GetRelativePath(path, length, forceExtensionToLower);
|
||||
|
||||
bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
|
||||
WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
|
||||
static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
|
||||
XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
|
||||
|
||||
(int level, List<string> directories) TestStatic_Get(string rootDirectory, string sourceDirectory) =>
|
||||
Get(rootDirectory, sourceDirectory);
|
||||
static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory) =>
|
||||
XPath.Get(rootDirectory, sourceDirectory);
|
||||
|
||||
string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
GetDirectory(sourceDirectory, level, directoryName);
|
||||
static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
public static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
XPath.GetDirectory(sourceDirectory, level, directoryName);
|
||||
|
||||
(string, int) TestStatic_GetDirectoryNameAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||
static (string, int) GetDirectoryNameAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
XPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||
public static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
|
||||
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
|
||||
public static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory) =>
|
||||
XPath.Get(rootDirectory, sourceDirectory);
|
||||
|
||||
ReadOnlyDictionary<string, ReadOnlyCollection<string>> TestStatic_GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups);
|
||||
static ReadOnlyDictionary<string, ReadOnlyCollection<string>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
public static CombinedEnumAndIndex GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
XPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
|
||||
public static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
|
||||
XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
|
||||
|
||||
public static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
XPath.GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups);
|
||||
|
||||
internal byte TestStatic_GetEnum(FilePath filePath) =>
|
||||
GetEnum(filePath);
|
||||
|
||||
internal string[] TestStatic_GetDirectories(string directory) =>
|
||||
GetDirectories(directory);
|
||||
|
||||
internal string[] TestStatic_GetDirectoryNames(string directory) =>
|
||||
GetDirectoryNames(directory);
|
||||
|
||||
internal string TestStatic_GetRelativePath(string path, int length) =>
|
||||
GetRelativePath(path, length);
|
||||
|
||||
internal bool TestStatic_DeleteEmptyDirectories(string rootDirectory) =>
|
||||
DeleteEmptyDirectories(rootDirectory);
|
||||
|
||||
internal void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||
MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||
|
||||
internal void TestStatic_CreateDirectories(ReadOnlyCollection<string> directories) =>
|
||||
CreateDirectories(directories);
|
||||
|
||||
internal void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||
ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||
|
||||
internal string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) =>
|
||||
GetRelativePath(path, length, forceExtensionToLower);
|
||||
|
||||
internal string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
GetDirectory(sourceDirectory, level, directoryName);
|
||||
|
||||
internal void TestStatic_DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
|
||||
DeleteEmptyDirectories(rootDirectory, deletedDirectories);
|
||||
|
||||
internal (int level, List<string> directories) TestStatic_Get(string rootDirectory, string sourceDirectory) =>
|
||||
Get(rootDirectory, sourceDirectory);
|
||||
|
||||
internal CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
||||
|
||||
internal bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
|
||||
WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
|
||||
|
||||
internal ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> TestStatic_GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups);
|
||||
|
||||
}
|
@ -23,11 +23,6 @@ public interface IProperty
|
||||
static string GetDiffRootDirectory(string diffPropertyDirectory) =>
|
||||
Property.GetDiffRootDirectory(diffPropertyDirectory);
|
||||
|
||||
bool TestStatic_Any(Models.Container[] propertyHolderCollections) =>
|
||||
Any(propertyHolderCollections);
|
||||
static bool Any(Models.Container[] propertyHolderCollections) =>
|
||||
Property.Any(propertyHolderCollections);
|
||||
|
||||
(bool?, string[]) TestStatic_IsWrongYear(string[] segments, string year) =>
|
||||
IsWrongYear(segments, year);
|
||||
static (bool?, string[]) IsWrongYear(string[] segments, string year) =>
|
||||
@ -43,21 +38,6 @@ public interface IProperty
|
||||
static List<DateTime> GetDateTimes(Models.Property property) =>
|
||||
Property.GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp);
|
||||
|
||||
double TestStatic_GetStandardDeviation(List<long> values, double average) =>
|
||||
GetStandardDeviation(values, average);
|
||||
static double GetStandardDeviation(List<long> values, double average) =>
|
||||
Property.GetStandardDeviation(values, average);
|
||||
|
||||
TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
|
||||
GetThreeStandardDeviationHigh(minimum, container);
|
||||
static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
|
||||
Property.GetThreeStandardDeviationHigh(minimum, container);
|
||||
|
||||
(int, List<DateTime>, List<Models.Item>) TestStatic_Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
|
||||
Get(container, threeStandardDeviationHigh, i);
|
||||
static (int, List<DateTime>, List<Models.Item>) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
|
||||
Property.Get(container, threeStandardDeviationHigh, i);
|
||||
|
||||
List<DateTime> TestStatic_GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>
|
||||
GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, gpsDateStamp);
|
||||
static List<DateTime> GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>
|
||||
|
@ -5,81 +5,6 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
internal abstract class Id
|
||||
{
|
||||
|
||||
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
||||
{
|
||||
bool result;
|
||||
if (fileNameWithoutExtension.Length < 5 || fileNameWithoutExtension.Length > propertyConfiguration.IntMinValueLength)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
bool skipOneAllAreNumbers = fileNameWithoutExtension[1..].All(char.IsNumber);
|
||||
result = (skipOneAllAreNumbers && fileNameWithoutExtension[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameWithoutExtension[0]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int GetId(Properties.IPropertyConfiguration propertyConfiguration, string intelligentId)
|
||||
{
|
||||
int result;
|
||||
StringBuilder results = new();
|
||||
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
for (int i = intelligentId.Length - (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2); i > -1; i--)
|
||||
_ = results.Append(intelligentId[i]);
|
||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||
result = int.Parse(results.ToString());
|
||||
if (intelligentId[^1] is '1' or '2')
|
||||
result *= -1;
|
||||
else if (intelligentId[^1] is not '9' and not '8')
|
||||
throw new NotSupportedException();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||
{
|
||||
string result;
|
||||
StringBuilder stringBuilder = new();
|
||||
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
if (hasDateTimeOriginal is null)
|
||||
{ }
|
||||
int key;
|
||||
string value;
|
||||
List<char> resultAllInOneSubdirectoryChars = [];
|
||||
if (id > -1)
|
||||
{
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : 9;
|
||||
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : 1;
|
||||
value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||
}
|
||||
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
||||
_ = stringBuilder.Append(value[i]);
|
||||
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength; i < value.Length; i++)
|
||||
resultAllInOneSubdirectoryChars.Add(value[i]);
|
||||
result = $"{stringBuilder}{string.Join(string.Empty, resultAllInOneSubdirectoryChars)}{key}";
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
|
||||
{
|
||||
string result;
|
||||
if (propertyConfiguration.Offset < 0)
|
||||
result = Guid.NewGuid().ToString();
|
||||
else
|
||||
{
|
||||
string intelligentId = GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
int check = GetId(propertyConfiguration, intelligentId);
|
||||
if (check != id)
|
||||
throw new NotSupportedException();
|
||||
result = index is null || propertyConfiguration.Offset == IId.DeterministicHashCode ? intelligentId : $"{propertyConfiguration.Offset + index}{intelligentId}";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int GetDeterministicHashCode(byte[] value)
|
||||
{
|
||||
int result;
|
||||
@ -99,4 +24,97 @@ internal abstract class Id
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
(byte)(filePath.Id > -1 ? 8 : 2);
|
||||
|
||||
internal static int GetId(Properties.IPropertyConfiguration propertyConfiguration, string intelligentId)
|
||||
{
|
||||
int result;
|
||||
StringBuilder results = new();
|
||||
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
for (int i = intelligentId.Length - (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2); i > -1; i--)
|
||||
_ = results.Append(intelligentId[i]);
|
||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||
result = int.Parse(results.ToString());
|
||||
if (intelligentId[^1] is '0' or '1' or '2' or '3' or '4')
|
||||
result *= -1;
|
||||
else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
|
||||
throw new NotSupportedException();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static byte GetHasDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
|
||||
|
||||
internal static byte GetMissingDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : filePath.Id > -1 ? 5 : 0);
|
||||
|
||||
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
||||
{
|
||||
bool result;
|
||||
if (fileNameWithoutExtension.Length < 5 || fileNameWithoutExtension.Length > propertyConfiguration.IntMinValueLength)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
bool skipOneAllAreNumbers = fileNameWithoutExtension[1..].All(char.IsNumber);
|
||||
result = (skipOneAllAreNumbers && fileNameWithoutExtension[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameWithoutExtension[0]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||
{
|
||||
string result;
|
||||
StringBuilder stringBuilder = new();
|
||||
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
int key;
|
||||
string value;
|
||||
List<char> resultAllInOneSubdirectoryChars = [];
|
||||
if (hasDateTimeOriginal is null)
|
||||
{
|
||||
key = 0;
|
||||
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||
}
|
||||
else if (id > -1)
|
||||
{
|
||||
if (!propertyConfiguration.ValidVideoFormatExtensions.Contains(extensionLowered))
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal.Value ? 9 : 7;
|
||||
else
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 6 : 5;
|
||||
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!propertyConfiguration.ValidVideoFormatExtensions.Contains(extensionLowered))
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal.Value ? 1 : 3;
|
||||
else
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 4 : 0;
|
||||
value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||
}
|
||||
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
||||
_ = stringBuilder.Append(value[i]);
|
||||
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength; i < value.Length; i++)
|
||||
resultAllInOneSubdirectoryChars.Add(value[i]);
|
||||
result = $"{stringBuilder}{string.Join(string.Empty, resultAllInOneSubdirectoryChars)}{key}";
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
|
||||
{
|
||||
string result;
|
||||
if (propertyConfiguration.Offset < 0)
|
||||
result = Guid.NewGuid().ToString();
|
||||
else
|
||||
{
|
||||
string intelligentId = GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
int check = GetId(propertyConfiguration, intelligentId);
|
||||
if (check != id)
|
||||
throw new NotSupportedException();
|
||||
result = index is null || propertyConfiguration.Offset == IId.DeterministicHashCode ? intelligentId : $"{propertyConfiguration.Offset + index}{intelligentId}";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
83
Shared/Models/Stateless/Methods/MetaBase.cs
Normal file
83
Shared/Models/Stateless/Methods/MetaBase.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal static class MetaBase
|
||||
{
|
||||
|
||||
internal static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
string? result = null;
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
string value;
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
value = exifDirectoryBase?.Make is null ? string.Empty : exifDirectoryBase.Make.ToString().Trim();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
result = $"{value[0].ToString().ToUpper()}{value[1..].ToLower()}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
string? result = null;
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
string value;
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
value = exifDirectoryBase?.Model is null ? string.Empty : exifDirectoryBase.Model.ToString().Trim();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
result = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
int? result = null;
|
||||
// public const int TagOrientation = 274;
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
result = exifDirectoryBase?.OrientationValue;
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
List<string> results = [];
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
string value;
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
value = exifDirectoryBase?.WinKeywords is null ? string.Empty : exifDirectoryBase.WinKeywords.ToString().Trim();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
continue;
|
||||
results.Add(value);
|
||||
}
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user