Compare commits
4 Commits
4-5-6-Supp
...
07-05-b
Author | SHA1 | Date | |
---|---|---|---|
1ede3ebcdb | |||
30d8a270f9 | |||
c7ded16e50 | |||
3f7affceef |
3
.gitignore
vendored
3
.gitignore
vendored
@ -470,4 +470,7 @@ globalStorage/
|
|||||||
Shared/.kanbn
|
Shared/.kanbn
|
||||||
|
|
||||||
.Immich/immich-assets.json
|
.Immich/immich-assets.json
|
||||||
|
Tests/.vscode/.UserSecrets/*
|
||||||
Instance/.vscode/.UserSecrets/*
|
Instance/.vscode/.UserSecrets/*
|
||||||
|
Drag-Drop-Set-Property-Item/.vscode/.UserSecrets/*
|
||||||
|
TestsWithFaceRecognitionDotNet/.vscode/.UserSecrets/*
|
||||||
|
11
.vscode/mklink.md
vendored
11
.vscode/mklink.md
vendored
@ -18,3 +18,14 @@ mklink /J "L:\Git\View-by-Distance-MKLink-Console\.Immich" "D:\1-Images-A\Images
|
|||||||
mklink /J "V:\Tmp\Phares\Pictures-Results" "V:\6-Other-Large-Z\Current-Results-Test"
|
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"
|
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"
|
||||||
|
```
|
||||||
|
60
.vscode/tasks.json
vendored
60
.vscode/tasks.json
vendored
@ -100,6 +100,66 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": "$msCompile"
|
"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": "buildDuplicateSearch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Duplicate-Search/Duplicate-Search.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
@ -89,10 +89,32 @@
|
|||||||
"PropertiesChangedForProperty": false,
|
"PropertiesChangedForProperty": false,
|
||||||
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
|
".nef",
|
||||||
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"PropertyContentCollectionFiles": [
|
"PropertyContentCollectionFiles": [
|
||||||
"/Images-ec5a909 - Results/A) Property/2022-12-30/[()]/637869381676042455.json",
|
"/Images-ec5a909 - Results/A) Property/2022-12-30/[()]/637869381676042455.json",
|
||||||
@ -117,7 +139,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
],
|
],
|
||||||
"VerifyToSeason": [
|
"VerifyToSeason": [
|
||||||
". 2000",
|
". 2000",
|
||||||
|
@ -90,12 +90,32 @@
|
|||||||
"/zzz Phares Slides/Slides 2015-06-10/Magazine 01"
|
"/zzz Phares Slides/Slides 2015-06-10/Magazine 01"
|
||||||
],
|
],
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"PropertyContentCollectionFiles": [
|
"PropertyContentCollectionFiles": [
|
||||||
"/Images-ec5a909 - Results/A) Property/2022-12-30/[()]/637869381676042455.json",
|
"/Images-ec5a909 - Results/A) Property/2022-12-30/[()]/637869381676042455.json",
|
||||||
@ -120,7 +140,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
],
|
],
|
||||||
"VerifyToSeason": [
|
"VerifyToSeason": [
|
||||||
". 2000",
|
". 2000",
|
||||||
|
@ -47,5 +47,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -9,8 +9,10 @@ namespace View_by_Distance.Container.Models.Stateless.Methods;
|
|||||||
internal abstract class Container
|
internal abstract class Container
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private record Record(string From, string To, char A);
|
||||||
|
|
||||||
private record FilePair(bool IsUnique,
|
private record FilePair(bool IsUnique,
|
||||||
List<string> Collection,
|
ReadOnlyCollection<FilePath> Collection,
|
||||||
FilePath FilePath,
|
FilePath FilePath,
|
||||||
Item Item);
|
Item Item);
|
||||||
|
|
||||||
@ -48,35 +50,37 @@ internal abstract class Container
|
|||||||
continue;
|
continue;
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (results.Contains(item.Property.Id.Value))
|
if (results.Contains(item.ExifDirectory.FilePath.Id.Value))
|
||||||
continue;
|
continue;
|
||||||
results.Add(item.Property.Id.Value);
|
results.Add(item.ExifDirectory.FilePath.Id.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string _)
|
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
Models.Container[] results;
|
Models.Container[] results;
|
||||||
|
bool useIgnoreExtensions = true;
|
||||||
const bool useCeilingAverage = true;
|
const bool useCeilingAverage = true;
|
||||||
const string fileSearchFilter = "*";
|
const string fileSearchFilter = "*";
|
||||||
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
|
ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = new(new Dictionary<int, ExifDirectory>());
|
||||||
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
|
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, idToFilePaths, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
return (count, results);
|
return (count, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IDlibDotNet GetDlibDotNet() =>
|
private static IDlibDotNet GetDlibDotNet() =>
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException(nameof(IDlibDotNet));
|
||||||
|
|
||||||
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, string directorySearchFilter)
|
private static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, string directorySearchFilter)
|
||||||
{
|
{
|
||||||
List<Models.Container> results = [];
|
List<Models.Container> results = [];
|
||||||
string directory;
|
string directory;
|
||||||
@ -100,11 +104,7 @@ internal abstract class Container
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories();
|
ReadOnlyCollection<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, filesCollectionDirectory, idToFilePaths, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
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, directorySearchFilter);
|
|
||||||
foreach (FilePair filePair in filePairs)
|
foreach (FilePair filePair in filePairs)
|
||||||
{
|
{
|
||||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||||
@ -119,474 +119,178 @@ internal abstract class Container
|
|||||||
{
|
{
|
||||||
if (keyValuePair.Value.Count == 0)
|
if (keyValuePair.Value.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
container = new(keyValuePair.Key, new(keyValuePair.Value));
|
container = new(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
results.Add(container);
|
results.Add(container);
|
||||||
}
|
}
|
||||||
return (filePairs.Count, results.ToArray());
|
return (filePairs.Count, results.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
private static ReadOnlyCollection<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, string directorySearchFilter)
|
||||||
{
|
|
||||||
Models.Container[] results;
|
|
||||||
const string directorySearchFilter = "*";
|
|
||||||
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, 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)
|
|
||||||
{
|
{
|
||||||
|
ReadOnlyCollection<FilePair> results;
|
||||||
const string extension = ".json";
|
const string extension = ".json";
|
||||||
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
Dictionary<int, ExifDirectory> keyValuePairs = [];
|
||||||
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = GetFilesKeyValuePairs(filePathsCollection);
|
ReadOnlyCollection<Shared.Models.FilePair> filePairs;
|
||||||
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
|
||||||
if (!Directory.Exists(bMetaSingletonDirectory))
|
|
||||||
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
|
||||||
_ = 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);
|
|
||||||
_ = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
|
||||||
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
|
||||||
if (!Directory.Exists(dFaceCollectionDirectory))
|
|
||||||
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
|
||||||
_ = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection, fileNamesToFiles);
|
|
||||||
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
|
||||||
if (!Directory.Exists(dFaceContentDirectory))
|
|
||||||
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
|
||||||
AnyMovedFace(facesFileNameExtension, facesHiddenFileNameExtension, fileNamesToFiles, dFaceContentDirectory);
|
|
||||||
AnyMovedDistance(facesFileNameExtension, fileNamesToFiles, eDistanceContentDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<string[]> filesCollection)
|
|
||||||
{
|
|
||||||
Dictionary<string, List<string>> results = [];
|
|
||||||
string fileNameWithoutExtension;
|
|
||||||
string fileNameWithoutExtensionSecond;
|
|
||||||
string fileNameWithoutExtensionSecondMinusOne;
|
|
||||||
List<string>? collection;
|
|
||||||
foreach (string[] files in filesCollection)
|
|
||||||
{
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
|
|
||||||
fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(fileNameWithoutExtension);
|
|
||||||
if (string.IsNullOrEmpty(fileNameWithoutExtensionSecond) || fileNameWithoutExtensionSecond == fileNameWithoutExtension)
|
|
||||||
continue;
|
|
||||||
fileNameWithoutExtensionSecondMinusOne = fileNameWithoutExtensionSecond[..^1];
|
|
||||||
if (!results.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
|
|
||||||
{
|
|
||||||
results.Add(fileNameWithoutExtensionSecondMinusOne, []);
|
|
||||||
if (!results.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
collection.Add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
|
||||||
{
|
|
||||||
Dictionary<string, List<string>> results = [];
|
|
||||||
List<string>? collection;
|
|
||||||
string fileNameWithoutExtensionMinusOne;
|
|
||||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
|
||||||
{
|
|
||||||
foreach (FilePath filePath in filePaths)
|
|
||||||
{
|
|
||||||
fileNameWithoutExtensionMinusOne = filePath.NameWithoutExtension[..^1];
|
|
||||||
if (!results.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
|
|
||||||
{
|
|
||||||
results.Add(fileNameWithoutExtensionMinusOne, []);
|
|
||||||
if (!results.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
collection.Add(filePath.FullName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Shared.Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles)
|
|
||||||
{
|
|
||||||
List<Shared.Models.FilePair>? results = null;
|
|
||||||
int renamed;
|
|
||||||
const bool useCeilingAverage = true;
|
|
||||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
|
||||||
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
|
|
||||||
for (int i = 0; i < short.MaxValue; i++)
|
|
||||||
{
|
|
||||||
renamed = 0;
|
|
||||||
jsonFilesCollection = IDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
|
||||||
compareFileNamesToFiles = GetFilesKeyValuePairs(jsonFilesCollection);
|
|
||||||
renamed += LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
|
|
||||||
results = IDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
|
||||||
renamed += IDirectory.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int LookForAbandoned(ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> 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(fileNamesToFiles, extension, renameCollection, files);
|
|
||||||
if (!moved && check)
|
|
||||||
moved = true;
|
|
||||||
}
|
|
||||||
if (renameCollection.Count > 0)
|
|
||||||
IDirectory.MoveFiles(renameCollection, "{}", "{abd}");
|
|
||||||
result = renameCollection.Count;
|
|
||||||
if (moved && result == 0)
|
|
||||||
result = 1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool AnyMoved(IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string checkFile;
|
|
||||||
string directory;
|
|
||||||
string fileNameWith;
|
|
||||||
string checkDirectory;
|
|
||||||
string directoryName;
|
|
||||||
List<string>? collection;
|
|
||||||
string fileNameWithoutExtension;
|
|
||||||
List<string> directoryNames = [];
|
|
||||||
string fileNameWithoutExtensionSecond;
|
|
||||||
string fileNameWithoutExtensionSecondMinusOne;
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (!file.EndsWith(extension))
|
|
||||||
throw new Exception();
|
|
||||||
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
|
|
||||||
fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(fileNameWithoutExtension);
|
|
||||||
if (string.IsNullOrEmpty(fileNameWithoutExtensionSecond) || fileNameWithoutExtensionSecond == fileNameWithoutExtension)
|
|
||||||
continue;
|
|
||||||
fileNameWithoutExtensionSecondMinusOne = fileNameWithoutExtensionSecond[..^1];
|
|
||||||
if (!fileNamesToFiles.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
|
|
||||||
renameCollection.Add(file);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
directoryNames.Clear();
|
|
||||||
directoryName = Path.GetFileName(Path.GetDirectoryName(file)) ?? throw new Exception();
|
|
||||||
foreach (string f in collection)
|
|
||||||
directoryNames.Add(Path.GetFileName(Path.GetDirectoryName(f)) ?? throw new Exception());
|
|
||||||
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
|
|
||||||
continue;
|
|
||||||
if (directoryName != directoryNames[0])
|
|
||||||
{
|
|
||||||
directory = Path.GetDirectoryName(Path.GetDirectoryName(file)) ?? throw new Exception();
|
|
||||||
checkDirectory = Path.Combine(directory, directoryNames[0]);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
fileNameWith = collection.Count > 1 ? Path.GetFileName(file) : $"{Path.GetFileName(collection[0])}{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 void AnyMovedFace(string extension, string hiddenExtension, IReadOnlyDictionary<string, List<string>> 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(fileNamesToFiles, directories);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AnyMovedFace(IReadOnlyDictionary<string, List<string>> fileNamesToFiles, List<string> directories)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string checkFile;
|
|
||||||
string subDirectory;
|
|
||||||
string directoryName;
|
|
||||||
string checkDirectory;
|
|
||||||
List<string>? collection;
|
|
||||||
string directoryNameWith;
|
|
||||||
string directoryNameMinusOne;
|
|
||||||
List<string> directoryNames = [];
|
|
||||||
foreach (string directory in directories)
|
|
||||||
{
|
|
||||||
directoryNameMinusOne = Path.GetFileName(directory)[..^1];
|
|
||||||
if (!fileNamesToFiles.TryGetValue(directoryNameMinusOne, out collection))
|
|
||||||
throw new Exception();
|
|
||||||
directoryNames.Clear();
|
|
||||||
foreach (string f in collection)
|
|
||||||
directoryNames.Add(Path.GetFileName(Path.GetDirectoryName(f)) ?? 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 : $"{Path.GetFileNameWithoutExtension(collection[0])}";
|
|
||||||
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(string extension, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string jsonGroupDirectory)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
string fileName;
|
|
||||||
string checkFile;
|
|
||||||
string directory;
|
|
||||||
List<string>? collection;
|
|
||||||
string[] fileNameSegments;
|
|
||||||
List<string> fileNames = [];
|
|
||||||
string fileNameSegmentsZeroMinusOne;
|
|
||||||
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
fileName = Path.GetFileName(file);
|
|
||||||
fileNameSegments = fileName.Split('.');
|
|
||||||
fileNameSegmentsZeroMinusOne = fileNameSegments[0][..^1];
|
|
||||||
if (!fileNamesToFiles.TryGetValue(fileNameSegmentsZeroMinusOne, out collection))
|
|
||||||
continue;
|
|
||||||
fileNames.Clear();
|
|
||||||
foreach (string f in collection)
|
|
||||||
fileNames.Add(Path.GetFileNameWithoutExtension(f) ?? throw new Exception());
|
|
||||||
if (fileNames.Count == 0 || fileNames.Distinct().Count() != 1)
|
|
||||||
continue;
|
|
||||||
if (fileNameSegments[0] != 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, string directorySearchFilter)
|
|
||||||
{
|
|
||||||
List<FilePair> results = [];
|
|
||||||
const string extension = ".json";
|
|
||||||
List<Shared.Models.FilePair> filePairs;
|
|
||||||
string jsonGroupDirectory = aPropertySingletonDirectory;
|
|
||||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = GetFilesKeyValuePairs(filePathsCollection);
|
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
string jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(jsonGroupDirectory))
|
||||||
|
_ = Directory.CreateDirectory(jsonGroupDirectory);
|
||||||
|
filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
|
string message;
|
||||||
|
message = $") {nameof(Container)} - Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds)} total second(s)";
|
||||||
|
dlibDotNet.ConstructProgressBar(filePairs.Count, message);
|
||||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
|
||||||
ParallelFor(dlibDotNet, propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, filePairs[i], results));
|
ParallelFor(exifDirectoriesById, filePairs[i], keyValuePairs, dlibDotNet.Tick));
|
||||||
|
results = GetFilePairs(propertyConfiguration, idToFilePaths, splatNineIdentifiers, exifDirectoriesById, extension, keyValuePairs, filePairs, jsonGroupDirectory, filesCollectionDirectoryLength);
|
||||||
return 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, Shared.Models.FilePair filePair, List<FilePair> results)
|
private static ReadOnlyCollection<FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, string extension, Dictionary<int, ExifDirectory> keyValuePairs, ReadOnlyCollection<Shared.Models.FilePair> filePairs, string jsonGroupDirectory, int rootDirectoryLength)
|
||||||
{
|
|
||||||
dlibDotNet?.Tick();
|
|
||||||
bool abandoned = false;
|
|
||||||
FileHolder sourceDirectoryFileHolder;
|
|
||||||
Property? property = GetProperty(filePair);
|
|
||||||
FileHolder fileHolder = IFileHolder.Get(filePair.Path);
|
|
||||||
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
|
||||||
FilePath filePath = FilePath.Get(propertyConfiguration, fileHolder, 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 (property is not null && filePath.Id is not null && filePath.HasIgnoreKeyword is not null && filePath.HasDateTimeOriginal is not null)
|
|
||||||
{
|
{
|
||||||
|
List<FilePair> results = [];
|
||||||
|
Item item;
|
||||||
|
string json;
|
||||||
char? change;
|
char? change;
|
||||||
ReadOnlyCollection<FilePath>? filePaths = null;
|
bool abandoned;
|
||||||
char hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePath).ToString()[0];
|
bool? isArchive;
|
||||||
char hasDateTimeOriginal = IId.GetHasDateTimeOriginal(propertyConfiguration, filePath).ToString()[0];
|
string fileName;
|
||||||
char missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePath).ToString()[0];
|
string directory;
|
||||||
|
FileInfo fileInfo;
|
||||||
|
bool? shouldIgnore;
|
||||||
|
DateTime? dateTime;
|
||||||
|
string fullFileName;
|
||||||
|
string jsonFileName;
|
||||||
|
string relativePath;
|
||||||
|
bool? fileSizeChanged;
|
||||||
|
char hasIgnoreKeyword;
|
||||||
|
char hasDateTimeOriginal;
|
||||||
|
CombinedEnumAndIndex cei;
|
||||||
|
List<Record> records = [];
|
||||||
|
bool? lastWriteTimeChanged;
|
||||||
|
char missingDateTimeOriginal;
|
||||||
|
ExifDirectory? exifDirectory;
|
||||||
|
bool isValidImageFormatExtension;
|
||||||
|
ReadOnlyCollection<string> keywords;
|
||||||
|
FileHolder sourceDirectoryFileHolder;
|
||||||
|
ReadOnlyCollection<FilePath>? filePaths;
|
||||||
|
foreach (Shared.Models.FilePair filePair in filePairs)
|
||||||
|
{
|
||||||
|
abandoned = false;
|
||||||
|
if (filePair.FilePath.Id is null || (!exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out exifDirectory) && !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out exifDirectory)))
|
||||||
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||||
|
keywords = IMetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||||
|
shouldIgnore = propertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
||||||
|
fileSizeChanged = exifDirectory?.FilePath is not null ? exifDirectory.FilePath.Length != filePair.FilePath.Length : null;
|
||||||
|
isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePair.FilePath.ExtensionLowered);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
filePaths = null;
|
||||||
|
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
|
hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePair.FilePath).ToString()[0];
|
||||||
|
hasDateTimeOriginal = IId.GetHasDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||||
|
missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
||||||
if (shouldIgnore is not null && shouldIgnore.Value)
|
if (shouldIgnore is not null && shouldIgnore.Value)
|
||||||
{
|
{
|
||||||
if (filePath.NameWithoutExtension[^1] == hasIgnoreKeyword)
|
if (filePair.FilePath.FileNameFirstSegment[^1] == hasIgnoreKeyword)
|
||||||
change = null;
|
change = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
change = hasIgnoreKeyword;
|
change = hasIgnoreKeyword;
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((shouldIgnore is null || !shouldIgnore.Value) && property.DateTimeOriginal is null)
|
else if ((shouldIgnore is null || !shouldIgnore.Value) && dateTime is null)
|
||||||
{
|
{
|
||||||
if (filePath.NameWithoutExtension[^1] == missingDateTimeOriginal)
|
if (filePair.FilePath.FileNameFirstSegment[^1] == missingDateTimeOriginal)
|
||||||
change = null;
|
change = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
change = missingDateTimeOriginal;
|
change = missingDateTimeOriginal;
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (filePath.NameWithoutExtension[^1] != hasDateTimeOriginal)
|
else if (filePair.FilePath.FileNameFirstSegment[^1] != hasDateTimeOriginal)
|
||||||
{
|
{
|
||||||
change = hasDateTimeOriginal;
|
change = hasDateTimeOriginal;
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
change = null;
|
change = null;
|
||||||
if (filePaths is not null && change is not null)
|
if (filePaths is not null && change is not null)
|
||||||
RenameFile(extension, filePair, filePath, change.Value, filePaths);
|
RenameFile(filePair, filePair.FilePath, change.Value, filePaths);
|
||||||
}
|
}
|
||||||
string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.Path, rootDirectoryLength, forceExtensionToLower: true);
|
relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.FilePath.FullName, rootDirectoryLength, forceExtensionToLower: true);
|
||||||
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime.Ticks != filePath.LastWriteTicks : null;
|
lastWriteTimeChanged = exifDirectory?.FilePath is not null ? propertyConfiguration.PropertiesChangedForProperty || exifDirectory.FilePath.LastWriteTicks != filePair.FilePath.LastWriteTicks : null;
|
||||||
if (filePair.Match is not null)
|
if (filePair.Match is not null)
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
||||||
else if (!filePair.IsUnique)
|
else if (!filePair.IsUnique)
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string fileName = Path.GetFileName(filePair.Path);
|
fileName = Path.GetFileName(filePair.FilePath.FullName);
|
||||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePair.FilePath);
|
||||||
string directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
||||||
string jsonFileName = $"{fileName}{extension}";
|
jsonFileName = $"{fileName}{extension}";
|
||||||
string fullFileName = Path.Combine(directory, jsonFileName);
|
fullFileName = Path.Combine(directory, jsonFileName);
|
||||||
MoveIf(jsonFileName, cei, directory, fullFileName);
|
MoveIf(jsonFileName, cei, directory, fullFileName);
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
|
fileInfo = new(fullFileName);
|
||||||
}
|
if (exifDirectory is not null && !fileInfo.Exists)
|
||||||
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
|
||||||
{
|
{
|
||||||
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePath.LastWriteTicks));
|
json = JsonSerializer.Serialize(exifDirectory, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
|
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
}
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(fileInfo);
|
||||||
|
}
|
||||||
|
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);
|
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
||||||
}
|
}
|
||||||
Item item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
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));
|
||||||
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Property? GetProperty(Shared.Models.FilePair filePair)
|
private static void ParallelFor(ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Shared.Models.FilePair filePair, Dictionary<int, ExifDirectory> keyValuePairs, Action? tick)
|
||||||
{
|
{
|
||||||
Property? result;
|
tick?.Invoke();
|
||||||
if (filePair.Match is null)
|
if (filePair.FilePath.Id is not null && (!exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory) || exifDirectory.FilePath?.Id is null))
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
string json = File.ReadAllText(filePair.Match);
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||||
if (string.IsNullOrEmpty(json))
|
lock (keyValuePairs)
|
||||||
result = null;
|
{
|
||||||
else
|
if (!keyValuePairs.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
keyValuePairs.Add(filePair.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExifDirectory? GetExifDirectory(Shared.Models.FilePair filePair)
|
private static void RenameFile(Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
||||||
{
|
|
||||||
ExifDirectory? 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, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RenameFile(string extension, Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
|
||||||
{
|
{
|
||||||
string checkFile;
|
string checkFile;
|
||||||
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
|
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
|
||||||
File.Delete(filePath.FullName);
|
File.Delete(filePath.FullName);
|
||||||
if (!string.IsNullOrEmpty(filePair.Match))
|
if (filePair.Match is not null)
|
||||||
{
|
{
|
||||||
string directory = Path.GetDirectoryName(filePair.Match) ?? throw new Exception();
|
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(filePair.Match.NameWithoutExtension);
|
||||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePair.Match);
|
string extensionSecond = Path.GetExtension(filePair.Match.Name);
|
||||||
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(filePair.Match));
|
checkFile = Path.Combine(filePair.Match.DirectoryFullPath, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{filePair.Match.ExtensionLowered}");
|
||||||
string extensionSecond = Path.GetExtension(fileNameWithoutExtension);
|
if (!File.Exists(checkFile) && File.Exists(filePair.Match.FullName))
|
||||||
checkFile = Path.Combine(directory, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{extension}");
|
File.Move(filePair.Match.FullName, checkFile);
|
||||||
if (!File.Exists(checkFile))
|
|
||||||
File.Move(filePair.Match, checkFile);
|
|
||||||
}
|
}
|
||||||
foreach (FilePath f in filePaths)
|
foreach (FilePath f in filePaths)
|
||||||
{
|
{
|
||||||
checkFile = Path.Combine(f.DirectoryFullPath, $"{f.NameWithoutExtension[..^1]}{change}{f.ExtensionLowered}");
|
checkFile = Path.Combine(f.DirectoryFullPath, $"{f.NameWithoutExtension[..^1]}{change}{f.ExtensionLowered}");
|
||||||
if (File.Exists(checkFile))
|
if (File.Exists(checkFile) || !File.Exists(f.FullName))
|
||||||
continue;
|
continue;
|
||||||
File.Move(f.FullName, checkFile);
|
File.Move(f.FullName, checkFile);
|
||||||
}
|
}
|
||||||
@ -621,7 +325,7 @@ internal abstract class Container
|
|||||||
continue;
|
continue;
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
||||||
continue;
|
continue;
|
||||||
@ -650,13 +354,13 @@ internal abstract class Container
|
|||||||
}
|
}
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (distinctItems)
|
if (distinctItems)
|
||||||
{
|
{
|
||||||
if (distinct.Contains(item.Property.Id.Value))
|
if (distinct.Contains(item.ExifDirectory.FilePath.Id.Value))
|
||||||
continue;
|
continue;
|
||||||
distinct.Add(item.Property.Id.Value);
|
distinct.Add(item.ExifDirectory.FilePath.Id.Value);
|
||||||
}
|
}
|
||||||
results.Add(item);
|
results.Add(item);
|
||||||
}
|
}
|
||||||
@ -664,4 +368,173 @@ internal abstract class Container
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById)
|
||||||
|
{
|
||||||
|
Models.Container[] results;
|
||||||
|
const string directorySearchFilter = "*";
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
|
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, idToFilePaths, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
|
AnyMoved(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, idToFilePaths, directorySearchFilter);
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMoved(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, string directorySearchFilter)
|
||||||
|
{
|
||||||
|
const string extension = ".json";
|
||||||
|
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
|
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(bMetaSingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
||||||
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection);
|
||||||
|
(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);
|
||||||
|
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
|
if (!Directory.Exists(dFaceCollectionDirectory))
|
||||||
|
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
||||||
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection);
|
||||||
|
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
||||||
|
if (!Directory.Exists(dFaceContentDirectory))
|
||||||
|
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
||||||
|
AnyMovedFace(propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, idToFilePaths, dFaceContentDirectory);
|
||||||
|
AnyMovedDistance(propertyConfiguration, facesFileNameExtension, idToFilePaths, eDistanceContentDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, string extension, string hiddenExtension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, 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, idToFilePaths, directories);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, List<string> directories)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string checkFile;
|
||||||
|
FilePath? filePath;
|
||||||
|
string subDirectory;
|
||||||
|
string directoryName;
|
||||||
|
string checkDirectory;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
string directoryNameWith;
|
||||||
|
List<string> directoryNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
fileHolder = IFileHolder.Get(Path.GetFileName(directory));
|
||||||
|
filePath = FilePath.GetNullSafe(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, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, string jsonGroupDirectory)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string checkFile;
|
||||||
|
string directory;
|
||||||
|
FilePath filePath;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
string[] fileNameSegments;
|
||||||
|
List<string> fileNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
|
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 (!idToFilePaths.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,17 +8,14 @@ namespace View_by_Distance.Container.Models.Stateless.Methods;
|
|||||||
public interface IContainer
|
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) =>
|
public static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||||
Container.GetContainerDateTimes(items);
|
Container.GetContainerDateTimes(items);
|
||||||
|
|
||||||
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||||
Container.GetValidImageItems(propertyConfiguration, container);
|
Container.GetValidImageItems(propertyConfiguration, container);
|
||||||
|
|
||||||
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration) =>
|
||||||
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
|
Container.GetContainers(propertyConfiguration, splatNineIdentifiers: null);
|
||||||
|
|
||||||
public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
@ -29,8 +26,8 @@ public interface IContainer
|
|||||||
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, 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) =>
|
public static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||||
Container.GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection);
|
Container.GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||||
|
|
||||||
internal DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
internal DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
|
||||||
GetContainerDateTimes(items);
|
GetContainerDateTimes(items);
|
||||||
@ -38,8 +35,8 @@ public interface IContainer
|
|||||||
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
|
||||||
GetValidImageItems(propertyConfiguration, container);
|
GetValidImageItems(propertyConfiguration, container);
|
||||||
|
|
||||||
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration) =>
|
||||||
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
GetContainers(propertyConfiguration);
|
||||||
|
|
||||||
internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
@ -50,10 +47,10 @@ public interface IContainer
|
|||||||
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||||
|
|
||||||
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
|
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers) =>
|
||||||
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
|
Container.GetContainers(propertyConfiguration, splatNineIdentifiers);
|
||||||
|
|
||||||
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) =>
|
internal ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
||||||
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection);
|
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Phares.Shared;
|
using Phares.Shared;
|
||||||
using ShellProgressBar;
|
using ShellProgressBar;
|
||||||
@ -19,7 +19,7 @@ public class CopyDistinct
|
|||||||
private readonly IsEnvironment _IsEnvironment;
|
private readonly IsEnvironment _IsEnvironment;
|
||||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||||
private readonly ReadOnlyDictionary<string, ReadOnlyDictionary<byte, 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)
|
public CopyDistinct(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
|
||||||
{
|
{
|
||||||
@ -37,7 +37,9 @@ public class CopyDistinct
|
|||||||
_Configuration = configuration;
|
_Configuration = configuration;
|
||||||
logger?.LogInformation(propertyConfiguration.RootDirectory);
|
logger?.LogInformation(propertyConfiguration.RootDirectory);
|
||||||
(bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack) = Verify();
|
(bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack) = Verify();
|
||||||
_FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs =
|
||||||
|
Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, [appSettings.ResultDirectoryKey]);
|
||||||
|
_FileGroups = keyValuePairs[appSettings.ResultDirectoryKey];
|
||||||
List<string> lines = CopyDistinctFilesInDirectories(logger, move, filesCollection, anyLenFiles, moveBack);
|
List<string> lines = CopyDistinctFilesInDirectories(logger, move, filesCollection, anyLenFiles, moveBack);
|
||||||
if (lines.Count != 0)
|
if (lines.Count != 0)
|
||||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||||
@ -93,6 +95,76 @@ public class CopyDistinct
|
|||||||
return (move, new(filesCollection), anyLenFiles, moveBack);
|
return (move, new(filesCollection), anyLenFiles, moveBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
ProgressBar progressBar;
|
||||||
|
string[] distinctDirectories;
|
||||||
|
ConsoleKey? consoleKey = null;
|
||||||
|
string message = nameof(CopyDistinct);
|
||||||
|
List<(FilePath, string)> toDoCollection;
|
||||||
|
int count = filesCollection.Select(l => l.Length).Sum();
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
if (moveBack)
|
||||||
|
{
|
||||||
|
if (!anyLenFiles)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressBar = new(count, message, options);
|
||||||
|
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
||||||
|
if (key != _PropertyConfiguration.ResultContent)
|
||||||
|
throw new NotImplementedException("Changed but didn't update!");
|
||||||
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, filesCollection, 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)
|
private static (string[], List<(FilePath, string)>) GetMoveBackToDoCollection(Property.Models.Configuration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||||
{
|
{
|
||||||
List<(FilePath, string)> results = [];
|
List<(FilePath, string)> results = [];
|
||||||
@ -159,74 +231,4 @@ public class CopyDistinct
|
|||||||
return (distinctDirectories.ToArray(), results);
|
return (distinctDirectories.ToArray(), results);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> CopyDistinctFilesInDirectories(ILogger<Program>? logger, bool move, ReadOnlyCollection<string[]> filesCollection, bool anyLenFiles, bool moveBack)
|
|
||||||
{
|
|
||||||
List<string> results = [];
|
|
||||||
ProgressBar progressBar;
|
|
||||||
string[] distinctDirectories;
|
|
||||||
ConsoleKey? consoleKey = null;
|
|
||||||
string message = nameof(CopyDistinct);
|
|
||||||
List<(FilePath, string)> toDoCollection;
|
|
||||||
int count = filesCollection.Select(l => l.Length).Sum();
|
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
if (moveBack)
|
|
||||||
{
|
|
||||||
if (!anyLenFiles)
|
|
||||||
throw new NotSupportedException();
|
|
||||||
(distinctDirectories, toDoCollection) = GetMoveBackToDoCollection(_PropertyConfiguration, filesCollection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
progressBar = new(count, message, options);
|
|
||||||
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -71,12 +71,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "D:/Images",
|
"RootDirectory": "D:/Images",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -92,7 +112,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,203 +96,6 @@ public class DateGroup
|
|||||||
throw new Exception("Change configuration!");
|
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([$"{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.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)
|
private A_Property GetPropertyLogic(bool reverse, string outputExtension, string aResultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
A_Property result;
|
A_Property result;
|
||||||
@ -302,54 +105,64 @@ public class DateGroup
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Item[] GetFilterItems(Container.Models.Container container)
|
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
List<Item> results = [];
|
string path;
|
||||||
foreach (Item item in container.Items)
|
string fileName;
|
||||||
{
|
string directory;
|
||||||
if (item.FilePath is not null)
|
DateTime dateTime;
|
||||||
results.Add(item);
|
int selectedTotal;
|
||||||
}
|
const int minimum = 3;
|
||||||
return results.ToArray();
|
List<DateTime> dateTimes;
|
||||||
}
|
List<Item> selectedItems;
|
||||||
|
const int maximumHours = 24;
|
||||||
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
string? relativePathDirectory;
|
||||||
{
|
WindowsShortcut windowsShortcut;
|
||||||
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
TimeSpan threeStandardDeviationHigh;
|
||||||
Item[] filteredItems;
|
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
|
||||||
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)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
if (!_Configuration.KeepFullPath)
|
selectedTotal = 0;
|
||||||
destinationDirectory = destinationRoot;
|
threeStandardDeviationHigh = Property.Models.Stateless.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
||||||
else
|
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
||||||
destinationDirectory = string.Concat(destinationRoot, container.SourceDirectory[configuration.RootDirectory.Length..]);
|
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
||||||
checkDirectory = Path.GetFullPath(container.SourceDirectory);
|
for (int i = 0; i < container.Items.Count; i++)
|
||||||
for (int z = 0; z < int.MaxValue; z++)
|
|
||||||
{
|
{
|
||||||
if (checkDirectory == configuration.RootDirectory)
|
(i, dateTimes, selectedItems) = Property.Models.Stateless.IProperty.Get(container, threeStandardDeviationHigh, i);
|
||||||
break;
|
selectedTotal += selectedItems.Count;
|
||||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
foreach (Item item in selectedItems)
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
{
|
||||||
break;
|
if (item.ExifDirectory is null)
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
|
||||||
continue;
|
continue;
|
||||||
topDirectory = checkDirectory;
|
relativePathDirectory = Path.GetDirectoryName(item.RelativePath);
|
||||||
filteredItems = GetFilterItems(container);
|
if (string.IsNullOrEmpty(relativePathDirectory))
|
||||||
if (filteredItems.Length == 0)
|
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 (selectedTotal < container.Items.Count && selectedTotal < (from l in container.Items where l.Property is not null select true).Count())
|
||||||
continue;
|
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.Models.Container[] containers)
|
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||||
@ -453,64 +266,251 @@ public class DateGroup
|
|||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
|
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container.Models.Container[] containers)
|
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
|
||||||
{
|
{
|
||||||
string path;
|
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
|
||||||
string fileName;
|
Item[] filteredItems;
|
||||||
string directory;
|
string? topDirectory;
|
||||||
DateTime dateTime;
|
string? checkDirectory;
|
||||||
int selectedTotal;
|
string destinationDirectory;
|
||||||
const int minimum = 3;
|
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
|
||||||
List<DateTime> dateTimes;
|
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
|
||||||
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)
|
foreach (Container.Models.Container container in containers)
|
||||||
{
|
{
|
||||||
if (container.Items.Count == 0)
|
if (container.Items.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
selectedTotal = 0;
|
if (!_Configuration.KeepFullPath)
|
||||||
threeStandardDeviationHigh = Property.Models.Stateless.IProperty.GetThreeStandardDeviationHigh(minimum, container);
|
destinationDirectory = destinationRoot;
|
||||||
if (threeStandardDeviationHigh.TotalHours > maximumHours)
|
|
||||||
threeStandardDeviationHigh = new(maximumHours, 0, 0);
|
|
||||||
for (int i = 0; i < container.Items.Count; i++)
|
|
||||||
{
|
|
||||||
(i, dateTimes, selectedItems) = Property.Models.Stateless.IProperty.Get(container, threeStandardDeviationHigh, i);
|
|
||||||
selectedTotal += selectedItems.Count;
|
|
||||||
foreach (Item item in selectedItems)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
else
|
else
|
||||||
dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
destinationDirectory = string.Concat(destinationRoot, container.SourceDirectory[configuration.RootDirectory.Length..]);
|
||||||
path = Path.GetFullPath($"{configuration.RootDirectory}{item.RelativePath[..^5]}");
|
checkDirectory = Path.GetFullPath(container.SourceDirectory);
|
||||||
directory = Path.Combine($"{aPropertyContentDirectory}{relativePathDirectory}", $"{dateTimes.Min():yyyy-MM-dd_HH-mm-ss}---{dateTimes.Max():yyyy-MM-dd_HH-mm-ss}");
|
for (int z = 0; z < int.MaxValue; z++)
|
||||||
if (!Directory.Exists(directory))
|
{
|
||||||
_ = Directory.CreateDirectory(directory);
|
if (checkDirectory == configuration.RootDirectory)
|
||||||
fileName = Path.Combine(directory, $"{Path.GetFileName(item.RelativePath[..^5])}.lnk");
|
break;
|
||||||
if (File.Exists(fileName))
|
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
continue;
|
continue;
|
||||||
windowsShortcut = new() { Path = path };
|
topDirectory = checkDirectory;
|
||||||
windowsShortcut.Save(fileName);
|
filteredItems = GetFilterItems(container);
|
||||||
windowsShortcut.Dispose();
|
if (filteredItems.Length == 0)
|
||||||
if (!File.Exists(fileName))
|
|
||||||
continue;
|
continue;
|
||||||
File.SetLastWriteTime(fileName, dateTime);
|
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.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
|
||||||
|
flag = '=';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selectedTotal < container.Items.Count && selectedTotal < (from l in container.Items where l.Property is not null select true).Count())
|
(season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||||
continue;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -70,12 +70,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "C:/Tmp/phares/Pictures",
|
"RootDirectory": "C:/Tmp/phares/Pictures",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"PropertyContentCollectionFiles": [],
|
"PropertyContentCollectionFiles": [],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
@ -92,7 +112,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
],
|
],
|
||||||
"VerifyToSeason": [
|
"VerifyToSeason": [
|
||||||
". 2000",
|
". 2000",
|
||||||
|
@ -72,12 +72,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -93,7 +113,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -88,7 +108,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ public partial class E_Distance : IDistance
|
|||||||
locationContainer = LocationContainer.Get(keyValue.Value, encoding, keepExifDirectory: false);
|
locationContainer = LocationContainer.Get(keyValue.Value, encoding, keepExifDirectory: false);
|
||||||
keyValuePairs.Add(keyValue.Key, locationContainer);
|
keyValuePairs.Add(keyValue.Key, locationContainer);
|
||||||
}
|
}
|
||||||
results.Add(keyValuePair.Key, new(keyValuePairs));
|
results.Add(keyValuePair.Key, keyValuePairs.AsReadOnly());
|
||||||
}
|
}
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
@ -394,7 +394,7 @@ public partial class E_Distance : IDistance
|
|||||||
continue;
|
continue;
|
||||||
if (!string.IsNullOrEmpty(focusModel))
|
if (!string.IsNullOrEmpty(focusModel))
|
||||||
{
|
{
|
||||||
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(locationContainer.ExifDirectory);
|
model = IMetaBase.GetModel(locationContainer.ExifDirectory);
|
||||||
if (string.IsNullOrEmpty(model) || !model.Contains(focusModel))
|
if (string.IsNullOrEmpty(model) || !model.Contains(focusModel))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -571,14 +571,14 @@ public partial class E_Distance : IDistance
|
|||||||
return results.AsReadOnly();
|
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)
|
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> preFiltered, DistanceLimits distanceLimits, List<LocationContainer> postFiltered, Action? tick)
|
||||||
{
|
{
|
||||||
List<LocationContainer> results = [];
|
List<LocationContainer> results = [];
|
||||||
ReadOnlyCollection<LocationContainer> locationContainers;
|
ReadOnlyCollection<LocationContainer> locationContainers;
|
||||||
ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered);
|
ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered);
|
||||||
foreach (LocationContainer locationContainer in postFiltered)
|
foreach (LocationContainer locationContainer in postFiltered)
|
||||||
{
|
{
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer);
|
locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer);
|
||||||
foreach (LocationContainer item in locationContainers)
|
foreach (LocationContainer item in locationContainers)
|
||||||
{
|
{
|
||||||
@ -634,9 +634,9 @@ public partial class E_Distance : IDistance
|
|||||||
FileHolder fileHolder;
|
FileHolder fileHolder;
|
||||||
int distancePermyriad;
|
int distancePermyriad;
|
||||||
List<string> files = [];
|
List<string> files = [];
|
||||||
|
List<Relation> mappedRelations;
|
||||||
long ticks = DateTime.Now.Ticks;
|
long ticks = DateTime.Now.Ticks;
|
||||||
FaceDistance? faceDistanceEncoding;
|
FaceDistance? faceDistanceEncoding;
|
||||||
List<Relation> mappedRelations;
|
|
||||||
List<FaceDistance> faceDistanceLengths;
|
List<FaceDistance> faceDistanceLengths;
|
||||||
List<FaceDistance> faceDistanceEncodings = [];
|
List<FaceDistance> faceDistanceEncodings = [];
|
||||||
foreach (Record record in records)
|
foreach (Record record in records)
|
||||||
@ -670,7 +670,7 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mappedRelations = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList();
|
mappedRelations = (from l in mappedRelations orderby l.DistancePermyriad select l).Take(locationContainerDistanceTake).ToList();
|
||||||
results.Add(new(fileHolder, new(mappedRelations)));
|
results.Add(new(fileHolder, mappedRelations.AsReadOnly()));
|
||||||
}
|
}
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ using Phares.Shared;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using View_by_Distance.Drag_Drop.Models;
|
using View_by_Distance.Drag_Drop.Models;
|
||||||
using View_by_Distance.Property.Models;
|
|
||||||
using View_by_Distance.Resize.Models;
|
using View_by_Distance.Resize.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
@ -20,7 +19,7 @@ public partial class DragDropSearch : Form
|
|||||||
private readonly IsEnvironment _IsEnvironment;
|
private readonly IsEnvironment _IsEnvironment;
|
||||||
private readonly Dictionary<int, Item> _IdToItem;
|
private readonly Dictionary<int, Item> _IdToItem;
|
||||||
private readonly string _ResizeFileNameExtension;
|
private readonly string _ResizeFileNameExtension;
|
||||||
private readonly Models.Configuration _Configuration;
|
private readonly Configuration _Configuration;
|
||||||
private readonly IConfigurationRoot _ConfigurationRoot;
|
private readonly IConfigurationRoot _ConfigurationRoot;
|
||||||
private readonly Property.Models.Configuration _PropertyConfiguration;
|
private readonly Property.Models.Configuration _PropertyConfiguration;
|
||||||
|
|
||||||
@ -30,8 +29,8 @@ public partial class DragDropSearch : Form
|
|||||||
_IdToItem = [];
|
_IdToItem = [];
|
||||||
AppSettings appSettings;
|
AppSettings appSettings;
|
||||||
string workingDirectory;
|
string workingDirectory;
|
||||||
|
Configuration configuration;
|
||||||
IsEnvironment isEnvironment;
|
IsEnvironment isEnvironment;
|
||||||
Models.Configuration configuration;
|
|
||||||
IConfigurationRoot configurationRoot;
|
IConfigurationRoot configurationRoot;
|
||||||
Property.Models.Configuration propertyConfiguration;
|
Property.Models.Configuration propertyConfiguration;
|
||||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
@ -64,63 +63,6 @@ public partial class DragDropSearch : Form
|
|||||||
Controls.Add(_TextBox);
|
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.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.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)
|
public static string? GetFaceEncoding(string file)
|
||||||
{
|
{
|
||||||
string? result;
|
string? result;
|
||||||
@ -147,6 +89,36 @@ public partial class DragDropSearch : Form
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadData()
|
||||||
|
{
|
||||||
|
Container.Models.Container[] containers;
|
||||||
|
(_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration);
|
||||||
|
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)
|
private void GetDirectoriesOrDoDragDrop(string[] paths)
|
||||||
{
|
{
|
||||||
string name;
|
string name;
|
||||||
@ -168,6 +140,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)
|
private void Form1_DragDrop(object? sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -183,4 +168,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Phares.Shared;
|
using Phares.Shared;
|
||||||
using ShellProgressBar;
|
using ShellProgressBar;
|
||||||
@ -9,6 +9,7 @@ using View_by_Distance.Duplicate.Search.Models;
|
|||||||
using View_by_Distance.Property.Models;
|
using View_by_Distance.Property.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Methods;
|
using View_by_Distance.Shared.Models.Methods;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Duplicate.Search;
|
namespace View_by_Distance.Duplicate.Search;
|
||||||
|
|
||||||
@ -61,6 +62,149 @@ public class DuplicateSearch
|
|||||||
File.WriteAllText(Path.Combine(alongSideDirectory, $"{directoryName}-{ticks}.json"), json);
|
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();
|
||||||
|
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration);
|
||||||
|
}
|
||||||
|
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? model;
|
||||||
|
string directory;
|
||||||
|
const int zero = 0;
|
||||||
|
DateTime? dateTime;
|
||||||
|
FileHolder resizedFileHolder;
|
||||||
|
DateTime[] containerDateTimes;
|
||||||
|
MappingFromItem? mappingFromItem;
|
||||||
|
List<MappingFromItem?>? collection;
|
||||||
|
ReadOnlyCollection<string> keywords;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
model = IMetaBase.GetModel(item.ExifDirectory);
|
||||||
|
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
|
||||||
|
keywords = IMetaBase.GetKeywords(item.ExifDirectory?.ExifBaseDirectories);
|
||||||
|
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
|
||||||
|
collection[0] = new(mappingFromItem.ContainerDateTimes, dateTime, mappingFromItem.Id, mappingFromItem.IsArchive, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, keywords, mappingFromItem.MinimumDateTime, model, mappingFromItem.RelativePath, resizedFileHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath));
|
||||||
|
mappingFromItem = 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)
|
private static void Move(ILogger<Program>? logger, long ticks, string destinationRoot, List<(FilePath FilePath, string Destination)> collection)
|
||||||
{
|
{
|
||||||
StringBuilder stringBuilder = new();
|
StringBuilder stringBuilder = new();
|
||||||
@ -107,142 +251,4 @@ public class DuplicateSearch
|
|||||||
logger?.LogInformation(". . .");
|
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.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 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.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -68,12 +68,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
"RootDirectory": "C:/Tmp/Phares/Compare/Images-dd514b88",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -89,7 +109,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,8 +116,8 @@ public class D_Face : IFaceD
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
maker = IMetadata.GetMaker(exifDirectory);
|
maker = IMetaBase.GetMaker(exifDirectory);
|
||||||
model = IMetadata.GetModel(exifDirectory);
|
model = IMetaBase.GetModel(exifDirectory);
|
||||||
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
|
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
|
||||||
json = IMetadata.GetOutputResolution(faceExifDirectory);
|
json = IMetadata.GetOutputResolution(faceExifDirectory);
|
||||||
if (json is not null && json.Contains(nameof(DateTime)))
|
if (json is not null && json.Contains(nameof(DateTime)))
|
||||||
@ -264,7 +264,7 @@ public class D_Face : IFaceD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
public List<Shared.Models.Face> GetFaces(string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, ExifDirectory exifDirectory, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
|
||||||
{
|
{
|
||||||
List<Shared.Models.Face>? results;
|
List<Shared.Models.Face>? results;
|
||||||
string? json;
|
string? json;
|
||||||
@ -314,7 +314,7 @@ public class D_Face : IFaceD
|
|||||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||||
if (results is null || locations.Count > 0)
|
if (results is null || locations.Count > 0)
|
||||||
{
|
{
|
||||||
results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
|
results = GetFaces(cResultsFullGroupDirectory, exifDirectory, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations);
|
||||||
if (results.Count == 0)
|
if (results.Count == 0)
|
||||||
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
|
||||||
else
|
else
|
||||||
@ -338,7 +338,7 @@ public class D_Face : IFaceD
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
|
private List<Shared.Models.Face> GetFaces(string cResultsFullGroupDirectory, ExifDirectory exifDirectory, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, List<Location> locations)
|
||||||
{
|
{
|
||||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||||
@ -369,12 +369,11 @@ public class D_Face : IFaceD
|
|||||||
{ unknownImage = null; }
|
{ unknownImage = null; }
|
||||||
if (unknownImage is not 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;
|
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
||||||
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
|
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
|
||||||
collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
|
collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
|
||||||
if (collection.Count == 0)
|
if (collection.Count == 0)
|
||||||
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
|
results.Add(new(exifDirectory, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double[] rawEncoding;
|
double[] rawEncoding;
|
||||||
@ -382,7 +381,7 @@ public class D_Face : IFaceD
|
|||||||
Shared.Models.FaceEncoding convertedFaceEncoding;
|
Shared.Models.FaceEncoding convertedFaceEncoding;
|
||||||
foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary<FacePart, FacePoint[]>? faceParts) in collection)
|
foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary<FacePart, FacePoint[]>? faceParts) in collection)
|
||||||
{
|
{
|
||||||
face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location);
|
face = new(exifDirectory, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location);
|
||||||
if (faceEncoding is not null)
|
if (faceEncoding is not null)
|
||||||
{
|
{
|
||||||
rawEncoding = faceEncoding.GetRawEncoding();
|
rawEncoding = faceEncoding.GetRawEncoding();
|
||||||
@ -454,8 +453,8 @@ public class D_Face : IFaceD
|
|||||||
string faceFileJson;
|
string faceFileJson;
|
||||||
string faceEncodingJson;
|
string faceEncodingJson;
|
||||||
PropertyItem? propertyItem;
|
PropertyItem? propertyItem;
|
||||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
string? maker = IMetaBase.GetMaker(exifDirectory);
|
||||||
string? model = IMetadata.GetModel(exifDirectory);
|
string? model = IMetaBase.GetModel(exifDirectory);
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
using Bitmap source = new(resizedFileHolder.FullName);
|
using Bitmap source = new(resizedFileHolder.FullName);
|
||||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
@ -476,7 +475,7 @@ public class D_Face : IFaceD
|
|||||||
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
|
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, source.Height, source.Width, collection.Count);
|
||||||
if (location is null)
|
if (location is null)
|
||||||
continue;
|
continue;
|
||||||
width = location.Right - location.Left;
|
width = location.Right - location.Left;
|
||||||
@ -507,7 +506,7 @@ public class D_Face : IFaceD
|
|||||||
}
|
}
|
||||||
if (File.Exists(fileName))
|
if (File.Exists(fileName))
|
||||||
File.Delete(fileName);
|
File.Delete(fileName);
|
||||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, source.Height, source.Width, collection.Count);
|
||||||
if (location is null)
|
if (location is null)
|
||||||
continue;
|
continue;
|
||||||
width = location.Right - location.Left;
|
width = location.Right - location.Left;
|
||||||
|
@ -92,8 +92,8 @@ public class D2_FaceParts
|
|||||||
List<FaceFile> faceFiles = [];
|
List<FaceFile> faceFiles = [];
|
||||||
StringBuilder stringBuilder = new();
|
StringBuilder stringBuilder = new();
|
||||||
MappingFromPerson? mappingFromPerson;
|
MappingFromPerson? mappingFromPerson;
|
||||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
string? maker = Shared.Models.Stateless.Methods.IMetaBase.GetMaker(exifDirectory);
|
||||||
string? model = IMetadata.GetModel(exifDirectory);
|
string? model = Shared.Models.Stateless.Methods.IMetaBase.GetModel(exifDirectory);
|
||||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||||
@ -468,8 +468,8 @@ public class D2_FaceParts
|
|||||||
int pointSize;
|
int pointSize;
|
||||||
FaceFile faceFile;
|
FaceFile faceFile;
|
||||||
MappingFromPerson? mappingFromPerson;
|
MappingFromPerson? mappingFromPerson;
|
||||||
string? maker = IMetadata.GetMaker(exifDirectory);
|
string? maker = Shared.Models.Stateless.Methods.IMetaBase.GetMaker(exifDirectory);
|
||||||
string? model = IMetadata.GetModel(exifDirectory);
|
string? model = Shared.Models.Stateless.Methods.IMetaBase.GetModel(exifDirectory);
|
||||||
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
foreach ((Shared.Models.Face face, string fileName, string _) in collection)
|
foreach ((Shared.Models.Face face, string fileName, string _) in collection)
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,6 @@
|
|||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
|
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
|
||||||
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
|
||||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -82,8 +82,8 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
List<string> personKeyFormattedCollection = [];
|
List<string> personKeyFormattedCollection = [];
|
||||||
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
|
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
|
||||||
Stateless.MapLogic.SetPersonCollectionsAfterSetSkipCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
Stateless.MapLogic.SetPersonCollectionsAfterSetSkipCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
||||||
readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection);
|
readOnlyPersonKeyFormattedCollection = personKeyFormattedCollection.AsReadOnly();
|
||||||
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted);
|
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = personKeyFormattedToNewestPersonKeyFormatted.AsReadOnly();
|
||||||
}
|
}
|
||||||
List<Stateless.Record> records = Stateless.DistanceLogic.DeleteEmptyDirectoriesAndGetCollection(propertyConfiguration, configuration, ticks, eDistanceContentDirectory, readOnlyPersonKeyFormattedToNewestPersonKeyFormatted, readOnlyPersonKeyFormattedCollection);
|
List<Stateless.Record> records = Stateless.DistanceLogic.DeleteEmptyDirectoriesAndGetCollection(propertyConfiguration, configuration, ticks, eDistanceContentDirectory, readOnlyPersonKeyFormattedToNewestPersonKeyFormatted, readOnlyPersonKeyFormattedCollection);
|
||||||
ReadOnlyCollection<(Stateless.MapLogic.PersonKeyFormattedIdThenWholePercentages, PersonContainer)> readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer;
|
ReadOnlyCollection<(Stateless.MapLogic.PersonKeyFormattedIdThenWholePercentages, PersonContainer)> readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer;
|
||||||
@ -103,10 +103,10 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
personKeyFormattedToPersonContainer,
|
personKeyFormattedToPersonContainer,
|
||||||
personKeyToPersonContainerCollection,
|
personKeyToPersonContainerCollection,
|
||||||
possiblyNewPersonDisplayDirectoryNamesAndPersonContainer);
|
possiblyNewPersonDisplayDirectoryNamesAndPersonContainer);
|
||||||
readOnlyPersonKeyToCount = new(personKeyToCount);
|
readOnlyPersonKeyToCount = personKeyToCount.AsReadOnly();
|
||||||
readOnlyPersonKeyFormattedToPersonContainer = new(personKeyFormattedToPersonContainer);
|
readOnlyPersonKeyFormattedToPersonContainer = personKeyFormattedToPersonContainer.AsReadOnly();
|
||||||
readOnlyPersonKeyToPersonContainerCollection = new(personKeyToPersonContainerCollection);
|
readOnlyPersonKeyToPersonContainerCollection = personKeyToPersonContainerCollection.AsReadOnly();
|
||||||
readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new(possiblyNewPersonDisplayDirectoryNamesAndPersonContainer);
|
readOnlyPossiblyNewPersonDisplayDirectoryNamesAndPersonContainer = possiblyNewPersonDisplayDirectoryNamesAndPersonContainer.AsReadOnly();
|
||||||
Stateless.MapLogic.SetPersonKeyToPersonContainer(configuration,
|
Stateless.MapLogic.SetPersonKeyToPersonContainer(configuration,
|
||||||
personContainers,
|
personContainers,
|
||||||
readOnlyPersonKeyToCount,
|
readOnlyPersonKeyToCount,
|
||||||
@ -320,12 +320,12 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
public ReadOnlyCollection<LocationContainer> GetLocationContainers(Item item)
|
public ReadOnlyCollection<LocationContainer> GetLocationContainers(Item item)
|
||||||
{
|
{
|
||||||
LocationContainer[] results;
|
LocationContainer[] results;
|
||||||
if (item.Property?.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
results = [];
|
results = [];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<LocationContainer>? locationContainers;
|
List<LocationContainer>? locationContainers;
|
||||||
if (_IdToLocationContainers.TryGetValue(item.Property.Id.Value, out locationContainers))
|
if (_IdToLocationContainers.TryGetValue(item.ExifDirectory.FilePath.Id.Value, out locationContainers))
|
||||||
results = locationContainers.ToArray();
|
results = locationContainers.ToArray();
|
||||||
else
|
else
|
||||||
results = [];
|
results = [];
|
||||||
@ -921,16 +921,16 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, Action? tick)
|
||||||
{
|
{
|
||||||
string[] directories;
|
string[] directories;
|
||||||
string? directoryName;
|
string? directoryName;
|
||||||
List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
|
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
List<string> distinctFilteredFileNameFirstSegments = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
List<string> distinctFilteredFileNameFirstSegments = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
@ -939,7 +939,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
@ -948,7 +948,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
@ -957,7 +957,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
dlibDotNet.Tick();
|
tick?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds)
|
private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds)
|
||||||
|
@ -64,20 +64,19 @@ internal abstract class FaceFileLogic
|
|||||||
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
||||||
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
||||||
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
||||||
LocationContainer locationContainer = new(dateOnly,
|
LocationContainer locationContainer = new(CreationDateOnly: dateOnly,
|
||||||
exifDirectory,
|
ExifDirectory: exifDirectory,
|
||||||
mappedFile.DirectoryNumber,
|
DirectoryNumber: mappedFile.DirectoryNumber,
|
||||||
personDisplayDirectoryName,
|
DisplayDirectoryName: personDisplayDirectoryName,
|
||||||
null,
|
Encoding: null,
|
||||||
null,
|
FaceFile: null,
|
||||||
mappedFile.FilePath,
|
FilePath: mappedFile.FilePath,
|
||||||
fromDistanceContent,
|
FromDistanceContent: fromDistanceContent,
|
||||||
id.Value,
|
Id: id.Value,
|
||||||
null,
|
LengthPermyriad: null,
|
||||||
null,
|
LengthSource: null,
|
||||||
mappedFile.PersonKey,
|
PersonKey: mappedFile.PersonKey,
|
||||||
rectangle,
|
WholePercentages: wholePercentages.Value);
|
||||||
wholePercentages.Value);
|
|
||||||
lock (locationContainers)
|
lock (locationContainers)
|
||||||
locationContainers.Add(locationContainer);
|
locationContainers.Add(locationContainer);
|
||||||
}
|
}
|
||||||
@ -167,23 +166,19 @@ internal abstract class FaceFileLogic
|
|||||||
MoveUnableToMatch(filePath);
|
MoveUnableToMatch(filePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
LocationContainer locationContainer = new(CreationDateOnly: dateOnly,
|
||||||
if (rectangle is null)
|
ExifDirectory: exifDirectory,
|
||||||
return;
|
DirectoryNumber: null,
|
||||||
LocationContainer locationContainer = new(dateOnly,
|
DisplayDirectoryName: null,
|
||||||
exifDirectory,
|
Encoding: null,
|
||||||
null,
|
FaceFile: faceFile,
|
||||||
null,
|
FilePath: filePath,
|
||||||
null,
|
FromDistanceContent: fromDistanceContent,
|
||||||
faceFile,
|
Id: filePath.Id.Value,
|
||||||
filePath,
|
LengthPermyriad: null,
|
||||||
fromDistanceContent,
|
LengthSource: null,
|
||||||
filePath.Id.Value,
|
PersonKey: null,
|
||||||
null,
|
WholePercentages: wholePercentages.Value);
|
||||||
null,
|
|
||||||
null,
|
|
||||||
rectangle,
|
|
||||||
wholePercentages.Value);
|
|
||||||
lock (locationContainers)
|
lock (locationContainers)
|
||||||
locationContainers.Add(locationContainer);
|
locationContainers.Add(locationContainer);
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,9 @@ internal abstract class MapLogic
|
|||||||
continue;
|
continue;
|
||||||
personContainers.Add(personContainer);
|
personContainers.Add(personContainer);
|
||||||
}
|
}
|
||||||
keyValuePairs.Add(wholePercentagesTo.Key, new(personContainers));
|
keyValuePairs.Add(wholePercentagesTo.Key, personContainers.AsReadOnly());
|
||||||
}
|
}
|
||||||
results.Add(idTo.Key, new(keyValuePairs));
|
results.Add(idTo.Key, keyValuePairs.AsReadOnly());
|
||||||
}
|
}
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ internal abstract class MapLogic
|
|||||||
List<Face> results = [];
|
List<Face> results = [];
|
||||||
foreach (Item item in items)
|
foreach (Item item in items)
|
||||||
{
|
{
|
||||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
foreach (Face face in item.Faces)
|
foreach (Face face in item.Faces)
|
||||||
{
|
{
|
||||||
@ -384,7 +384,7 @@ internal abstract class MapLogic
|
|||||||
{
|
{
|
||||||
Dictionary<int, ReadOnlyDictionary<int, Mapping>> results = [];
|
Dictionary<int, ReadOnlyDictionary<int, Mapping>> results = [];
|
||||||
foreach (KeyValuePair<int, Dictionary<int, Mapping>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<int, Dictionary<int, Mapping>> keyValuePair in keyValuePairs)
|
||||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,7 +602,7 @@ internal abstract class MapLogic
|
|||||||
if (check)
|
if (check)
|
||||||
continue;
|
continue;
|
||||||
personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2));
|
personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2));
|
||||||
personContainer = PersonContainer.Get(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey);
|
personContainer = PersonContainer.Get(approximateYears, [personBirthday], personDisplayDirectoryAllFilePaths.AsReadOnly(), configuration.MappingDefaultName, personKey);
|
||||||
results.Add(personContainer);
|
results.Add(personContainer);
|
||||||
if (results.Count > 99)
|
if (results.Count > 99)
|
||||||
break;
|
break;
|
||||||
@ -1095,7 +1095,7 @@ internal abstract class MapLogic
|
|||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<LocationContainer> locationContainers = new(results.OrderBy(l => l.DirectoryNumber).ToArray());
|
ReadOnlyCollection<LocationContainer> locationContainers = results.OrderBy(l => l.DirectoryNumber).ToArray().AsReadOnly();
|
||||||
LookForPossibleDuplicates(configuration, locationContainers);
|
LookForPossibleDuplicates(configuration, locationContainers);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
@ -1152,22 +1152,20 @@ internal abstract class MapLogic
|
|||||||
exifDirectory = null;
|
exifDirectory = null;
|
||||||
else
|
else
|
||||||
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
||||||
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
|
||||||
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
||||||
LocationContainer locationContainer = new(dateOnly,
|
LocationContainer locationContainer = new(CreationDateOnly: dateOnly,
|
||||||
exifDirectory,
|
ExifDirectory: exifDirectory,
|
||||||
mappedFile.DirectoryNumber,
|
DirectoryNumber: mappedFile.DirectoryNumber,
|
||||||
personDisplayDirectoryName,
|
DisplayDirectoryName: personDisplayDirectoryName,
|
||||||
null,
|
Encoding: null,
|
||||||
null,
|
FaceFile: null,
|
||||||
mappedFile.FilePath,
|
FilePath: mappedFile.FilePath,
|
||||||
fromDistanceContent,
|
FromDistanceContent: fromDistanceContent,
|
||||||
id.Value,
|
Id: id.Value,
|
||||||
null,
|
LengthPermyriad: null,
|
||||||
null,
|
LengthSource: null,
|
||||||
mappedFile.PersonKey,
|
PersonKey: mappedFile.PersonKey,
|
||||||
rectangle,
|
WholePercentages: wholePercentages.Value);
|
||||||
wholePercentages.Value);
|
|
||||||
lock (locationContainers)
|
lock (locationContainers)
|
||||||
locationContainers.Add(locationContainer);
|
locationContainers.Add(locationContainer);
|
||||||
}
|
}
|
||||||
@ -1192,12 +1190,18 @@ internal abstract class MapLogic
|
|||||||
if (item.WholePercentages == locationContainer.WholePercentages)
|
if (item.WholePercentages == locationContainer.WholePercentages)
|
||||||
continue;
|
continue;
|
||||||
itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages);
|
itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages);
|
||||||
if (itemPercentagesRectangle is null || locationContainer.Rectangle is null)
|
if (itemPercentagesRectangle is null)
|
||||||
|
percent = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages);
|
||||||
|
if (rectangle is null)
|
||||||
percent = null;
|
percent = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height;
|
itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height;
|
||||||
percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, locationContainer.Rectangle.Value);
|
percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, rectangle.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete.Add(item.FilePath);
|
delete.Add(item.FilePath);
|
||||||
delete.Add(locationContainer.FilePath);
|
delete.Add(locationContainer.FilePath);
|
||||||
|
@ -86,8 +86,8 @@ public class MetadataQuery
|
|||||||
exifDirectory = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
exifDirectory = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
if (exifDirectory is null)
|
if (exifDirectory is null)
|
||||||
continue;
|
continue;
|
||||||
maker = Metadata.Models.Stateless.Methods.IMetadata.GetMaker(exifDirectory);
|
maker = Shared.Models.Stateless.Methods.IMetaBase.GetMaker(exifDirectory);
|
||||||
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(exifDirectory);
|
model = Shared.Models.Stateless.Methods.IMetaBase.GetModel(exifDirectory);
|
||||||
// collection.Add(new(fileInfo.Name, keyValuePair.Key, keyValue.Key, keyValue.Value));
|
// collection.Add(new(fileInfo.Name, keyValuePair.Key, keyValue.Key, keyValue.Value));
|
||||||
}
|
}
|
||||||
progressBar.Dispose();
|
progressBar.Dispose();
|
||||||
|
@ -68,12 +68,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "D:/Images",
|
"RootDirectory": "D:/Images",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -89,7 +109,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System.Text.Json;
|
|||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Methods;
|
using View_by_Distance.Shared.Models.Methods;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models;
|
namespace View_by_Distance.Metadata.Models;
|
||||||
|
|
||||||
@ -13,30 +14,25 @@ namespace View_by_Distance.Metadata.Models;
|
|||||||
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private readonly Dictionary<int, ExifDirectory> _ExifDirectoriesById;
|
||||||
|
|
||||||
|
// First
|
||||||
|
// Set DateGroupDirectory
|
||||||
|
// Create a directories for Singleton
|
||||||
|
// Populate Collection
|
||||||
|
// Populate Singleton
|
||||||
|
// Populate existing ExifDirectories
|
||||||
|
// Run similar for resize
|
||||||
|
// Second
|
||||||
|
// Populate needed ExifDirectories Dictionary can't be init only
|
||||||
|
|
||||||
private readonly bool _PropertiesChangedForMetadata;
|
private readonly bool _PropertiesChangedForMetadata;
|
||||||
private readonly IPropertyConfiguration _PropertyConfiguration;
|
private readonly IPropertyConfiguration _PropertyConfiguration;
|
||||||
private readonly bool _ForceMetadataLastWriteTimeToCreationTime;
|
private readonly bool _ForceMetadataLastWriteTimeToCreationTime;
|
||||||
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;
|
||||||
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultSingletonFileGroups;
|
||||||
|
|
||||||
public B_Metadata(IPropertyConfiguration propertyConfiguration)
|
public B_Metadata(IDlibDotNet? dlibDotNet, IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, long ticks, string bResultsFullGroupDirectory)
|
||||||
{
|
|
||||||
_PropertiesChangedForMetadata = false;
|
|
||||||
_PropertyConfiguration = propertyConfiguration;
|
|
||||||
_ForceMetadataLastWriteTimeToCreationTime = false;
|
|
||||||
_ResultSingletonFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
|
|
||||||
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
|
||||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]);
|
|
||||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
|
||||||
{
|
|
||||||
if (keyValuePair.Key == _PropertyConfiguration.ResultSingleton)
|
|
||||||
_ResultSingletonFileGroups[0] = keyValuePair.Value;
|
|
||||||
else
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory)
|
|
||||||
{
|
{
|
||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
_PropertiesChangedForMetadata = propertiesChangedForMetadata;
|
_PropertiesChangedForMetadata = propertiesChangedForMetadata;
|
||||||
@ -51,33 +47,80 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
else
|
else
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
const string extension = ".json";
|
||||||
|
const string fileSearchFilter = "*";
|
||||||
|
string filesCollectionRootDirectory;
|
||||||
|
const string directorySearchFilter = "*";
|
||||||
|
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
||||||
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
|
Action? tick = dlibDotNet is null ? null : dlibDotNet.Tick;
|
||||||
|
filesCollectionRootDirectory = propertyConfiguration.RootDirectory;
|
||||||
|
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);
|
||||||
|
ReadOnlyCollection<FilePair> filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupSingletonDirectory, filePathsCollection);
|
||||||
|
string message = $") {nameof(B_Metadata)} - 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(filePairs[i], exifDirectoriesById, tick));
|
||||||
|
_ExifDirectoriesById = exifDirectoriesById;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public ReadOnlyDictionary<int, ExifDirectory> GetKeyValuePairsAndClear()
|
||||||
{
|
{
|
||||||
string result = JsonSerializer.Serialize(this, _WriteIndentedJsonSerializerOptions);
|
Dictionary<int, ExifDirectory> results = [];
|
||||||
|
foreach (KeyValuePair<int, ExifDirectory> keyValuePair in _ExifDirectoriesById)
|
||||||
|
results.Add(keyValuePair.Key, keyValuePair.Value);
|
||||||
|
_ExifDirectoriesById.Clear();
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParallelFor(FilePair filePair, Dictionary<int, ExifDirectory> results, Action? tick)
|
||||||
|
{
|
||||||
|
tick?.Invoke();
|
||||||
|
if (filePair.FilePath.Id is null)
|
||||||
|
return;
|
||||||
|
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
||||||
|
if (exifDirectory is null)
|
||||||
|
return;
|
||||||
|
lock (results)
|
||||||
|
{
|
||||||
|
if (!results.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
|
results.Add(filePair.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExifDirectory? GetExifDirectory(FilePair filePair)
|
||||||
|
{
|
||||||
|
ExifDirectory? result;
|
||||||
|
if (filePair.Match is null)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string json;
|
||||||
|
json = File.ReadAllText(filePair.Match.FullName);
|
||||||
|
if (string.IsNullOrEmpty(json))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
|
if (result?.FilePath?.Id is null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||||
|
json = JsonSerializer.Serialize(result, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
|
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(filePair.Match.FullName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||||
|
}
|
||||||
|
catch (Exception) { result = null; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
|
||||||
{
|
|
||||||
string[] segments = directory.Split(cei.Combined);
|
|
||||||
string? checkDirectory = segments.Length == 1 ?
|
|
||||||
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
|
||||||
segments.Length == 2 ?
|
|
||||||
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
|
||||||
null;
|
|
||||||
if (checkDirectory is not null && System.IO.Directory.Exists(checkDirectory))
|
|
||||||
{
|
|
||||||
string checkFile = Path.Combine(checkDirectory, fileName);
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
{
|
|
||||||
File.Move(checkFile, fileInfo.FullName);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExifDirectory GetMetadataCollection(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem)
|
public ExifDirectory GetMetadataCollection(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem)
|
||||||
{
|
{
|
||||||
ExifDirectory? result = null;
|
ExifDirectory? result = null;
|
||||||
@ -142,13 +185,32 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||||
|
{
|
||||||
|
string[] segments = directory.Split(cei.Combined);
|
||||||
|
string? checkDirectory = segments.Length == 1 ?
|
||||||
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
||||||
|
segments.Length == 2 ?
|
||||||
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
||||||
|
null;
|
||||||
|
if (checkDirectory is not null && System.IO.Directory.Exists(checkDirectory))
|
||||||
|
{
|
||||||
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
{
|
||||||
|
File.Move(checkFile, fileInfo.FullName);
|
||||||
|
fileInfo.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories)
|
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FilePath filePath, IReadOnlyList<MetadataExtractor.Directory> directories)
|
||||||
{
|
{
|
||||||
List<DateTime?> results = [];
|
List<DateTime?> results = [];
|
||||||
DateTime? result = null;
|
DateTime? result = null;
|
||||||
DateTime? dateTime;
|
DateTime? dateTime;
|
||||||
DateTime checkDateTime;
|
DateTime checkDateTime;
|
||||||
string dateTimeFormat = Stateless.Methods.IMetadata.DateTimeFormat();
|
string dateTimeFormat = IMetaBase.DateTimeFormat();
|
||||||
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
|
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
|
||||||
results.Add(new DateTime(filePath.CreationTicks));
|
results.Add(new DateTime(filePath.CreationTicks));
|
||||||
results.Add(new DateTime(filePath.LastWriteTicks));
|
results.Add(new DateTime(filePath.LastWriteTicks));
|
||||||
@ -158,7 +220,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
results.Add(checkDateTime);
|
results.Add(checkDateTime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
results.Add(dateTime.Value);
|
results.Add(dateTime.Value);
|
||||||
}
|
}
|
||||||
@ -166,7 +228,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
results.Add(checkDateTime);
|
results.Add(checkDateTime);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
results.Add(dateTime.Value);
|
results.Add(dateTime.Value);
|
||||||
}
|
}
|
||||||
@ -177,7 +239,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -195,7 +257,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -213,7 +275,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
@ -231,7 +293,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
dateTime = IMetaBase.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
{
|
{
|
||||||
result ??= dateTime.Value;
|
result ??= dateTime.Value;
|
||||||
|
@ -8,18 +8,18 @@ internal static class Dimensions
|
|||||||
#pragma warning disable IDE0230
|
#pragma warning disable IDE0230
|
||||||
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
|
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
|
||||||
{
|
{
|
||||||
|
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
||||||
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
|
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
|
||||||
|
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
|
||||||
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
|
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
|
||||||
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
|
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
|
||||||
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
|
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
|
||||||
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
|
||||||
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
|
|
||||||
};
|
};
|
||||||
#pragma warning restore IDE0230
|
#pragma warning restore IDE0230
|
||||||
|
|
||||||
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
|
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < thatBytes.Length; i += 1)
|
for (int i = 0; i < thisBytes.Count && i < thatBytes.Length; i += 1)
|
||||||
{
|
{
|
||||||
if (thisBytes[i] == thatBytes[i])
|
if (thisBytes[i] == thatBytes[i])
|
||||||
continue;
|
continue;
|
||||||
@ -103,24 +103,41 @@ internal static class Dimensions
|
|||||||
|
|
||||||
internal static Size? GetDimensions(BinaryReader binaryReader)
|
internal static Size? GetDimensions(BinaryReader binaryReader)
|
||||||
{
|
{
|
||||||
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
|
Size? result;
|
||||||
byte[] magicBytes = new byte[maxMagicBytesLength];
|
List<byte> magicBytes = [];
|
||||||
for (int i = 0; i < maxMagicBytesLength; i += 1)
|
int[] magicBytesLengths = (from l in _ImageFormatDecoders.Keys where l.Length <= binaryReader.BaseStream.Length orderby l.Length descending select l.Length).ToArray();
|
||||||
|
if (magicBytesLengths.Length == 0)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
magicBytes[i] = binaryReader.ReadByte();
|
result = null;
|
||||||
|
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
|
||||||
|
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
for (int i = 0; i < magicBytesLengths[0]; i++)
|
||||||
|
{
|
||||||
|
magicBytes.Add(binaryReader.ReadByte());
|
||||||
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
|
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
|
||||||
{
|
{
|
||||||
if (StartsWith(magicBytes, kvPair.Key))
|
if (StartsWith(magicBytes, kvPair.Key))
|
||||||
return kvPair.Value(binaryReader);
|
{
|
||||||
|
result = kvPair.Value(binaryReader);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
if (result is not null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Size? GetDimensions(string path)
|
internal static Size? GetDimensions(string path)
|
||||||
{
|
{
|
||||||
using BinaryReader binaryReader = new(File.OpenRead(path));
|
Size? result;
|
||||||
return GetDimensions(binaryReader);
|
using FileStream fileStream = File.OpenRead(path);
|
||||||
|
using BinaryReader binaryReader = new(fileStream);
|
||||||
|
result = GetDimensions(binaryReader);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -75,9 +75,11 @@ internal abstract class Exif
|
|||||||
string? fileSource = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagFileSource);
|
string? fileSource = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagFileSource);
|
||||||
string? imageDescription = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageDescription);
|
string? imageDescription = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageDescription);
|
||||||
string? imageHeight = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageHeight);
|
string? imageHeight = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageHeight);
|
||||||
|
int? imageHeightValue = imageHeight is null ? null : exifDirectoryBase.GetInt32(ExifDirectoryBase.TagImageHeight);
|
||||||
string? imageNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageNumber);
|
string? imageNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageNumber);
|
||||||
string? imageUniqueId = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageUniqueId);
|
string? imageUniqueId = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageUniqueId);
|
||||||
string? imageWidth = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageWidth);
|
string? imageWidth = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageWidth);
|
||||||
|
int? imageWidthValue = imageWidth is null ? null : exifDirectoryBase.GetInt32(ExifDirectoryBase.TagImageWidth);
|
||||||
string? isoSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagIsoSpeed);
|
string? isoSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagIsoSpeed);
|
||||||
string? lensMake = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensMake);
|
string? lensMake = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensMake);
|
||||||
string? lensModel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensModel);
|
string? lensModel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensModel);
|
||||||
@ -164,52 +166,54 @@ internal abstract class Exif
|
|||||||
&& xResolution is not null
|
&& xResolution is not null
|
||||||
&& yResolution is null)
|
&& yResolution is null)
|
||||||
continue;
|
continue;
|
||||||
results.Add(new(aperture,
|
results.Add(new(Aperture: aperture,
|
||||||
applicationNotes,
|
ApplicationNotes: applicationNotes,
|
||||||
artist,
|
Artist: artist,
|
||||||
bitsPerSample,
|
BitsPerSample: bitsPerSample,
|
||||||
bodySerialNumber,
|
BodySerialNumber: bodySerialNumber,
|
||||||
cameraOwnerName,
|
CameraOwnerName: cameraOwnerName,
|
||||||
compressedAverageBitsPerPixel,
|
CompressedAverageBitsPerPixel: compressedAverageBitsPerPixel,
|
||||||
compression,
|
Compression: compression,
|
||||||
copyright,
|
Copyright: copyright,
|
||||||
dateTime,
|
DateTime: dateTime,
|
||||||
dateTimeDigitized,
|
DateTimeDigitized: dateTimeDigitized,
|
||||||
dateTimeOriginal,
|
DateTimeOriginal: dateTimeOriginal,
|
||||||
documentName,
|
DocumentName: documentName,
|
||||||
exifVersion,
|
ExifVersion: exifVersion,
|
||||||
exposureTime,
|
ExposureTime: exposureTime,
|
||||||
fileSource,
|
FileSource: fileSource,
|
||||||
imageDescription,
|
ImageDescription: imageDescription,
|
||||||
imageHeight,
|
ImageHeight: imageHeight,
|
||||||
imageNumber,
|
ImageHeightValue: imageHeightValue,
|
||||||
imageUniqueId,
|
ImageNumber: imageNumber,
|
||||||
imageWidth,
|
ImageUniqueId: imageUniqueId,
|
||||||
isoSpeed,
|
ImageWidth: imageWidth,
|
||||||
lensMake,
|
ImageWidthValue: imageWidthValue,
|
||||||
lensModel,
|
IsoSpeed: isoSpeed,
|
||||||
lensSerialNumber,
|
LensMake: lensMake,
|
||||||
make,
|
LensModel: lensModel,
|
||||||
makerNote,
|
LensSerialNumber: lensSerialNumber,
|
||||||
model,
|
Make: make,
|
||||||
orientation,
|
MakerNote: makerNote,
|
||||||
orientationValue,
|
Model: model,
|
||||||
rating,
|
Orientation: orientation,
|
||||||
ratingPercent,
|
OrientationValue: orientationValue,
|
||||||
securityClassification,
|
Rating: rating,
|
||||||
shutterSpeed,
|
RatingPercent: ratingPercent,
|
||||||
software,
|
SecurityClassification: securityClassification,
|
||||||
timeZone,
|
ShutterSpeed: shutterSpeed,
|
||||||
timeZoneDigitized,
|
Software: software,
|
||||||
timeZoneOriginal,
|
TimeZone: timeZone,
|
||||||
userComment,
|
TimeZoneDigitized: timeZoneDigitized,
|
||||||
winAuthor,
|
TimeZoneOriginal: timeZoneOriginal,
|
||||||
winComment,
|
UserComment: userComment,
|
||||||
winKeywords,
|
WinAuthor: winAuthor,
|
||||||
winSubject,
|
WinComment: winComment,
|
||||||
winTitle,
|
WinKeywords: winKeywords,
|
||||||
xResolution,
|
WinSubject: winSubject,
|
||||||
yResolution));
|
WinTitle: winTitle,
|
||||||
|
XResolution: xResolution,
|
||||||
|
YResolution: yResolution));
|
||||||
}
|
}
|
||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
@ -499,21 +503,21 @@ internal abstract class Exif
|
|||||||
Shared.Models.FileMetadataDirectory[] fileMetadataDirectories = GetFileMetadataDirectories(filePath.FullName, directories);
|
Shared.Models.FileMetadataDirectory[] fileMetadataDirectories = GetFileMetadataDirectories(filePath.FullName, directories);
|
||||||
Shared.Models.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
|
Shared.Models.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
|
||||||
Shared.Models.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
|
Shared.Models.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
|
||||||
result = new(aviDirectories,
|
result = new(AviDirectories: aviDirectories,
|
||||||
exifBaseDirectories,
|
ExifBaseDirectories: exifBaseDirectories,
|
||||||
fileMetadataDirectories,
|
FileMetadataDirectories: fileMetadataDirectories,
|
||||||
filePath,
|
FilePath: filePath,
|
||||||
gifHeaderDirectories,
|
GifHeaderDirectories: gifHeaderDirectories,
|
||||||
gpsDirectories,
|
GpsDirectories: gpsDirectories,
|
||||||
size?.Height,
|
Height: size?.Height ?? Shared.Models.Stateless.Methods.IMetaBase.GetHeight(exifBaseDirectories),
|
||||||
jpegDirectories,
|
JpegDirectories: jpegDirectories,
|
||||||
makernoteDirectories,
|
MakernoteDirectories: makernoteDirectories,
|
||||||
photoshopDirectories,
|
PhotoshopDirectories: photoshopDirectories,
|
||||||
pngDirectories,
|
PngDirectories: pngDirectories,
|
||||||
quickTimeMovieHeaderDirectories,
|
QuickTimeMovieHeaderDirectories: quickTimeMovieHeaderDirectories,
|
||||||
quickTimeTrackHeaderDirectories,
|
QuickTimeTrackHeaderDirectories: quickTimeTrackHeaderDirectories,
|
||||||
webPDirectories,
|
WebPDirectories: webPDirectories,
|
||||||
size?.Width);
|
Width: size?.Width ?? Shared.Models.Stateless.Methods.IMetaBase.GetWidth(exifBaseDirectories));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,16 +19,6 @@ public interface IMetadata
|
|||||||
static ExifDirectory GetExifDirectory(FilePath filePath) =>
|
static ExifDirectory GetExifDirectory(FilePath filePath) =>
|
||||||
Exif.GetExifDirectory(filePath);
|
Exif.GetExifDirectory(filePath);
|
||||||
|
|
||||||
string? TestStatic_GetMaker(ExifDirectory? exifDirectory) =>
|
|
||||||
GetMaker(exifDirectory);
|
|
||||||
static string? GetMaker(ExifDirectory? exifDirectory) =>
|
|
||||||
Base.GetMaker(exifDirectory?.ExifBaseDirectories);
|
|
||||||
|
|
||||||
string? TestStatic_GetModel(ExifDirectory? exifDirectory) =>
|
|
||||||
GetModel(exifDirectory);
|
|
||||||
static string? GetModel(ExifDirectory? exifDirectory) =>
|
|
||||||
Base.GetModel(exifDirectory?.ExifBaseDirectories);
|
|
||||||
|
|
||||||
string? TestStatic_GetOutputResolution(ExifDirectory? exifDirectory) =>
|
string? TestStatic_GetOutputResolution(ExifDirectory? exifDirectory) =>
|
||||||
GetOutputResolution(exifDirectory);
|
GetOutputResolution(exifDirectory);
|
||||||
static string? GetOutputResolution(ExifDirectory? exifDirectory) =>
|
static string? GetOutputResolution(ExifDirectory? exifDirectory) =>
|
||||||
@ -64,14 +54,4 @@ public interface IMetadata
|
|||||||
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
|
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
|
||||||
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
|
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
|
||||||
|
|
||||||
string TestStatic_DateTimeFormat() =>
|
|
||||||
DateTimeFormat();
|
|
||||||
static string DateTimeFormat() =>
|
|
||||||
"yyyy:MM:dd HH:mm:ss";
|
|
||||||
|
|
||||||
DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
|
||||||
GetDateTime(dateTimeFormat, value);
|
|
||||||
static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
|
||||||
Base.GetDateTime(dateTimeFormat, value);
|
|
||||||
|
|
||||||
}
|
}
|
@ -68,12 +68,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "D:/Images",
|
"RootDirectory": "D:/Images",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -89,7 +109,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "D:/Images",
|
"RootDirectory": "D:/Images",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -88,7 +108,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,12 +60,32 @@
|
|||||||
"PropertiesChangedForProperty": false,
|
"PropertiesChangedForProperty": false,
|
||||||
"RootDirectory": "C:/Tmp/Phares/Pictures",
|
"RootDirectory": "C:/Tmp/Phares/Pictures",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"PropertyContentCollectionFiles": [],
|
"PropertyContentCollectionFiles": [],
|
||||||
"Spelling": [
|
"Spelling": [
|
||||||
@ -108,7 +128,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
],
|
],
|
||||||
"VerifyToSeason": [
|
"VerifyToSeason": [
|
||||||
". 2000",
|
". 2000",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using ShellProgressBar;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@ -66,39 +65,6 @@ public class A_Property
|
|||||||
converted: false));
|
converted: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
||||||
{
|
{
|
||||||
_AngleBracketCollection.Clear();
|
_AngleBracketCollection.Clear();
|
||||||
@ -111,177 +77,6 @@ public class A_Property
|
|||||||
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
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.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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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 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;
|
|
||||||
int? id = null;
|
|
||||||
FileInfo fileInfo;
|
|
||||||
string? json = null;
|
|
||||||
bool hasWrongYearProperty = false;
|
|
||||||
string[] changesFrom = [];
|
|
||||||
string angleBracket = _AngleBracketCollection[0];
|
|
||||||
bool populateId = _Configuration.PopulatePropertyId;
|
|
||||||
if (!item.IsUniqueFileName)
|
|
||||||
fileInfo = new(Path.Combine(angleBracket.Replace("<>", _PropertyConfiguration.ResultSingleton), $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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")))
|
|
||||||
{
|
|
||||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
}
|
|
||||||
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
|
||||||
{
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
}
|
|
||||||
if (_Configuration.PropertiesChangedForProperty)
|
|
||||||
result = null;
|
|
||||||
else if (!fileInfo.Exists)
|
|
||||||
result = 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)
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
json = File.ReadAllText(fileInfo.FullName);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (item.Property is not null)
|
|
||||||
result = item.Property;
|
|
||||||
else
|
|
||||||
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
|
||||||
if (result is not null && json.Contains("WrongYear"))
|
|
||||||
{
|
|
||||||
id = result.Id;
|
|
||||||
hasWrongYearProperty = true;
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && ((populateId && result?.Id is null) || result?.Width is null || result.Height is null))
|
|
||||||
{
|
|
||||||
id = result?.Id;
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && populateId && result is not null && result.LastWriteTime.Ticks != item.FilePath.LastWriteTicks)
|
|
||||||
{
|
|
||||||
id = null;
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result?.Width is not null && result.Height is not null && result.Width.Value == result.Height.Value)
|
|
||||||
{
|
|
||||||
id = result.Id;
|
|
||||||
result = null;
|
|
||||||
if (result?.Width is not null && result.Height is not null && result.Width.Value != result.Height.Value)
|
|
||||||
throw new Exception("Was square!");
|
|
||||||
}
|
|
||||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result is not null && result.FileSize != item.FilePath.Length)
|
|
||||||
{
|
|
||||||
id = result.Id;
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
if (result is not null)
|
|
||||||
{
|
|
||||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.LastWriteTime));
|
|
||||||
if (fileInfo.CreationTime != result.LastWriteTime)
|
|
||||||
{
|
|
||||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
parseExceptions.Add(nameof(A_Property));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result is null)
|
|
||||||
{
|
|
||||||
id ??= item.FilePath.Id;
|
|
||||||
(_, _, result) = Stateless.Property.GetProperty(populateId, metadata, item.FilePath, result, isIgnoreExtension, item.IsValidImageFormatExtension, id, _ASCIIEncoding);
|
|
||||||
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
|
|
||||||
if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
|
|
||||||
{
|
|
||||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
|
||||||
if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime)
|
|
||||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (hasWrongYearProperty)
|
|
||||||
{
|
|
||||||
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
|
|
||||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
|
|
||||||
{
|
|
||||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
|
||||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
|
||||||
fileInfo.Refresh();
|
|
||||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||||
{
|
{
|
||||||
string[] segments = directory.Split(cei.Combined);
|
string[] segments = directory.Split(cei.Combined);
|
||||||
@ -301,21 +96,4 @@ public class A_Property
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
|
|
||||||
if (!angleBracketCollectionAny)
|
|
||||||
{
|
|
||||||
if (item.FilePath.DirectoryFullPath is null)
|
|
||||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryFullPath));
|
|
||||||
SetAngleBracketCollection(item.FilePath.DirectoryFullPath, !item.IsUniqueFileName);
|
|
||||||
}
|
|
||||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
|
||||||
result = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
|
||||||
if (!angleBracketCollectionAny)
|
|
||||||
_AngleBracketCollection.Clear();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -21,9 +21,9 @@ internal partial class Property
|
|||||||
List<long> ticksCollection = [];
|
List<long> ticksCollection = [];
|
||||||
foreach (Item item in container.Items)
|
foreach (Item item in container.Items)
|
||||||
{
|
{
|
||||||
if (item.Property is null)
|
if (item.ExifDirectory is null)
|
||||||
continue;
|
continue;
|
||||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
minimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(item.ExifDirectory);
|
||||||
if (minimumDateTime is null)
|
if (minimumDateTime is null)
|
||||||
continue;
|
continue;
|
||||||
ticksCollection.Add(minimumDateTime.Value.Ticks);
|
ticksCollection.Add(minimumDateTime.Value.Ticks);
|
||||||
@ -108,12 +108,12 @@ internal partial class Property
|
|||||||
format = dateFormat[1];
|
format = dateFormat[1];
|
||||||
length = dateFormat[0].Length + dateFormat[1].Length;
|
length = dateFormat[0].Length + dateFormat[1].Length;
|
||||||
for (int i = dateFormat[0].Length; i < length; i++)
|
for (int i = dateFormat[0].Length; i < length; i++)
|
||||||
_ = value.Append(filePath.NameWithoutExtension[i]);
|
_ = value.Append(filePath.FileNameFirstSegment[i]);
|
||||||
if (value.Length != format.Length)
|
if (value.Length != format.Length)
|
||||||
continue;
|
continue;
|
||||||
if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
|
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;
|
result = checkDateTime;
|
||||||
else
|
else
|
||||||
result = new DateTime(ticks);
|
result = new DateTime(ticks);
|
||||||
@ -195,17 +195,17 @@ internal partial class Property
|
|||||||
{
|
{
|
||||||
ticks = null;
|
ticks = null;
|
||||||
item = container.Items[j];
|
item = container.Items[j];
|
||||||
if (item.Property is null)
|
if (item.ExifDirectory is null)
|
||||||
continue;
|
continue;
|
||||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
minimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(item.ExifDirectory);
|
||||||
if (minimumDateTime is null)
|
if (minimumDateTime is null)
|
||||||
continue;
|
continue;
|
||||||
for (int k = j + 1; k < container.Items.Count; k++)
|
for (int k = j + 1; k < container.Items.Count; k++)
|
||||||
{
|
{
|
||||||
nextItem = container.Items[k];
|
nextItem = container.Items[k];
|
||||||
if (nextItem.Property is null)
|
if (nextItem.ExifDirectory is null)
|
||||||
continue;
|
continue;
|
||||||
nextMinimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(nextItem.Property);
|
nextMinimumDateTime = Shared.Models.Stateless.Methods.IDate.GetMinimum(nextItem.ExifDirectory);
|
||||||
if (nextMinimumDateTime is null)
|
if (nextMinimumDateTime is null)
|
||||||
continue;
|
continue;
|
||||||
ticks = nextMinimumDateTime.Value.Ticks;
|
ticks = nextMinimumDateTime.Value.Ticks;
|
||||||
|
26
Rename/.vscode/appsettings.example.json
vendored
26
Rename/.vscode/appsettings.example.json
vendored
@ -82,12 +82,32 @@
|
|||||||
"xxxRootDirectory": "D:/1-Images-A/Images-dd514b88/Facebook/2023.3 Facebook",
|
"xxxRootDirectory": "D:/1-Images-A/Images-dd514b88/Facebook/2023.3 Facebook",
|
||||||
"RootDirectory": "D:/7-Question/California",
|
"RootDirectory": "D:/7-Question/California",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -103,7 +123,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -191,7 +191,7 @@ public class C_Resize
|
|||||||
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber) =>
|
public FileHolder GetResizedFileHolder(string cResultsFullGroupDirectory, Item item, bool outputResolutionHasNumber) =>
|
||||||
GetResizedFileHolder(cResultsFullGroupDirectory, item.FilePath, outputResolutionHasNumber, item.FilePath.Name);
|
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, Shared.Models.Property property, MappingFromItem mappingFromItem)
|
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;
|
Dictionary<string, int[]>? results;
|
||||||
string json;
|
string json;
|
||||||
@ -238,7 +238,7 @@ public class C_Resize
|
|||||||
}
|
}
|
||||||
if (results is null)
|
if (results is null)
|
||||||
{
|
{
|
||||||
results = GetImageResizes(property);
|
results = GetImageResizes(exifDirectory);
|
||||||
json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions);
|
json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions);
|
||||||
bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
|
||||||
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
|
||||||
@ -276,7 +276,7 @@ public class C_Resize
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, int[]> GetImageResizes(Shared.Models.Property property)
|
private Dictionary<string, int[]> GetImageResizes(ExifDirectory exifDirectory)
|
||||||
{
|
{
|
||||||
Dictionary<string, int[]> results = [];
|
Dictionary<string, int[]> results = [];
|
||||||
int[] desired;
|
int[] desired;
|
||||||
@ -284,13 +284,13 @@ public class C_Resize
|
|||||||
int checkHeight;
|
int checkHeight;
|
||||||
int desiredWidth;
|
int desiredWidth;
|
||||||
int desiredHeight;
|
int desiredHeight;
|
||||||
int orientation = property.Orientation is null || string.IsNullOrEmpty(property.Orientation) || !int.TryParse(property.Orientation, out int propertyOrientation) ? 0 : propertyOrientation;
|
int? orientation = Shared.Models.Stateless.Methods.IMetaBase.GetOrientation(exifDirectory);
|
||||||
if (property is null || property.Width is null || property.Height is null)
|
if (exifDirectory is null || orientation is null || exifDirectory.Width is null || exifDirectory.Height is null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
checkWidth = property.Width.Value;
|
checkWidth = exifDirectory.Width.Value;
|
||||||
checkHeight = property.Height.Value;
|
checkHeight = exifDirectory.Height.Value;
|
||||||
if (!_ValidResolutions.Contains(_Original))
|
if (!_ValidResolutions.Contains(_Original))
|
||||||
results.Add(_Original, [checkWidth, checkHeight, orientation]);
|
results.Add(_Original, [checkWidth, checkHeight, orientation.Value]);
|
||||||
foreach (string validResolution in _ValidResolutions)
|
foreach (string validResolution in _ValidResolutions)
|
||||||
{
|
{
|
||||||
if (validResolution == _Original)
|
if (validResolution == _Original)
|
||||||
@ -305,22 +305,22 @@ public class C_Resize
|
|||||||
desiredHeight = desired[1];
|
desiredHeight = desired[1];
|
||||||
}
|
}
|
||||||
if (checkWidth <= desiredWidth && checkHeight <= desiredHeight)
|
if (checkWidth <= desiredWidth && checkHeight <= desiredHeight)
|
||||||
results.Add(validResolution, [checkWidth, checkHeight, orientation]);
|
results.Add(validResolution, [checkWidth, checkHeight, orientation.Value]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (desiredWidth != desiredHeight)
|
if (desiredWidth != desiredHeight)
|
||||||
{
|
{
|
||||||
if (checkWidth * desiredHeight > desiredWidth * checkHeight)
|
if (checkWidth * desiredHeight > desiredWidth * checkHeight)
|
||||||
results.Add(validResolution, [desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth), orientation]);
|
results.Add(validResolution, [desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth), orientation.Value]);
|
||||||
else
|
else
|
||||||
results.Add(validResolution, [Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight, orientation]);
|
results.Add(validResolution, [Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight, orientation.Value]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (checkWidth * desiredHeight <= desiredWidth * checkHeight)
|
if (checkWidth * desiredHeight <= desiredWidth * checkHeight)
|
||||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation, desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth)]);
|
results.Add(validResolution, [desiredWidth, desiredHeight, orientation.Value, desiredWidth, Convert.ToInt32(desiredWidth * checkHeight / (double)checkWidth)]);
|
||||||
else
|
else
|
||||||
results.Add(validResolution, [desiredWidth, desiredHeight, orientation, Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight]);
|
results.Add(validResolution, [desiredWidth, desiredHeight, orientation.Value, Convert.ToInt32(desiredHeight * checkWidth / (double)checkHeight), desiredHeight]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,7 +336,7 @@ public class C_Resize
|
|||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
if (mappingFromItem.ResizedFileHolder is null)
|
||||||
throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder));
|
throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder));
|
||||||
@ -378,18 +378,19 @@ public class C_Resize
|
|||||||
check = true;
|
check = true;
|
||||||
if (check)
|
if (check)
|
||||||
{
|
{
|
||||||
SaveResizedSubfile(property, mappingFromItem, resize);
|
SaveResizedSubfile(exifDirectory, mappingFromItem, resize);
|
||||||
item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
item.SetResizedFileHolder(_FileNameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(mappingFromItem.ResizedFileHolder));
|
||||||
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveResizedSubfile(Shared.Models.Property property, MappingFromItem mappingFromItem, int[] resize)
|
private void SaveResizedSubfile(ExifDirectory exifDirectory, MappingFromItem mappingFromItem, int[] resize)
|
||||||
{
|
{
|
||||||
string dateTimeFormat = IProperty.DateTimeFormat;
|
string dateTimeFormat = IProperty.DateTimeFormat;
|
||||||
DateTime dateTime = property.DateTimeOriginal is not null ? property.DateTimeOriginal.Value : Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property);
|
DateTime? dateTime = Shared.Models.Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
string dateTimeValue = dateTime.ToString(dateTimeFormat);
|
dateTime ??= Shared.Models.Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
||||||
|
string dateTimeValue = dateTime.Value.ToString(dateTimeFormat);
|
||||||
byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue);
|
byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue);
|
||||||
if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue)
|
if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue)
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
|
@ -69,12 +69,32 @@
|
|||||||
"ResultSingleton": "{}",
|
"ResultSingleton": "{}",
|
||||||
"RootDirectory": "D:/Images",
|
"RootDirectory": "D:/Images",
|
||||||
"IgnoreExtensions": [
|
"IgnoreExtensions": [
|
||||||
|
".ffs_db",
|
||||||
|
".FFS_DB",
|
||||||
".gif",
|
".gif",
|
||||||
".GIF",
|
".GIF",
|
||||||
|
".html",
|
||||||
|
".HTML",
|
||||||
|
".ico",
|
||||||
|
".ICO",
|
||||||
|
".json",
|
||||||
|
".JSON",
|
||||||
|
".lnk",
|
||||||
|
".LNK",
|
||||||
|
".lsv",
|
||||||
|
".LSV",
|
||||||
".nef",
|
".nef",
|
||||||
".NEF",
|
".NEF",
|
||||||
".pdf",
|
".pdf",
|
||||||
".PDF"
|
".PDF",
|
||||||
|
".ts",
|
||||||
|
".TS",
|
||||||
|
".txt",
|
||||||
|
".TXT",
|
||||||
|
".webp",
|
||||||
|
".WEBP",
|
||||||
|
".xmp",
|
||||||
|
".XMP"
|
||||||
],
|
],
|
||||||
"ValidImageFormatExtensions": [
|
"ValidImageFormatExtensions": [
|
||||||
".bmp",
|
".bmp",
|
||||||
@ -90,7 +110,9 @@
|
|||||||
".tiff",
|
".tiff",
|
||||||
".TIFF",
|
".TIFF",
|
||||||
".tif",
|
".tif",
|
||||||
".TIF"
|
".TIF",
|
||||||
|
".webp",
|
||||||
|
".WEBP"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
{
|
||||||
|
}
|
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
|
||||||
|
{
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace View_by_Distance.Shared.Models;
|
|||||||
public record ExifDirectory(AviDirectory[] AviDirectories,
|
public record ExifDirectory(AviDirectory[] AviDirectories,
|
||||||
ExifDirectoryBase[] ExifBaseDirectories,
|
ExifDirectoryBase[] ExifBaseDirectories,
|
||||||
FileMetadataDirectory[] FileMetadataDirectories,
|
FileMetadataDirectory[] FileMetadataDirectories,
|
||||||
FilePath FilePath,
|
FilePath? FilePath,
|
||||||
GifHeaderDirectory[] GifHeaderDirectories,
|
GifHeaderDirectory[] GifHeaderDirectories,
|
||||||
GpsDirectory[] GpsDirectories,
|
GpsDirectory[] GpsDirectories,
|
||||||
int? Height,
|
int? Height,
|
||||||
|
@ -21,9 +21,11 @@ public record ExifDirectoryBase(string? Aperture,
|
|||||||
string? FileSource,
|
string? FileSource,
|
||||||
string? ImageDescription,
|
string? ImageDescription,
|
||||||
string? ImageHeight,
|
string? ImageHeight,
|
||||||
|
int? ImageHeightValue,
|
||||||
string? ImageNumber,
|
string? ImageNumber,
|
||||||
string? ImageUniqueId,
|
string? ImageUniqueId,
|
||||||
string? ImageWidth,
|
string? ImageWidth,
|
||||||
|
int? ImageWidthValue,
|
||||||
string? IsoSpeed,
|
string? IsoSpeed,
|
||||||
string? LensMake,
|
string? LensMake,
|
||||||
string? LensModel,
|
string? LensModel,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
@ -33,13 +34,12 @@ public class Face : Properties.IFace
|
|||||||
_OutputResolution = outputResolution;
|
_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)
|
this(DateTime.MinValue, null, null, null, location, null, null)
|
||||||
{
|
{
|
||||||
DateTime?[] dateTimes;
|
|
||||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||||
dateTimes = [property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp];
|
ReadOnlyCollection<DateTime> dateTimes = Stateless.Methods.IDate.GetDateTimes(exifDirectory);
|
||||||
_DateTime = (from l in dateTimes where l.HasValue select l.Value).Min();
|
_DateTime = dateTimes.Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@ -48,12 +48,16 @@ public class Face : Properties.IFace
|
|||||||
return result;
|
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;
|
||||||
|
|
||||||
}
|
}
|
@ -76,7 +76,7 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom);
|
System.Drawing.Size size = Stateless.Methods.Dimensions.GetDimensions(fileInfo.FullName, faceRight, faceBottom);
|
||||||
imageWidth = size.Width;
|
imageWidth = size.Width;
|
||||||
imageHeight = size.Height;
|
imageHeight = size.Height;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
public record FilePair(string Path,
|
public record FilePair(FilePath FilePath,
|
||||||
bool IsUnique,
|
bool IsUnique,
|
||||||
bool? IsNotUniqueAndNeedsReview,
|
bool? IsNotUniqueAndNeedsReview,
|
||||||
List<string> Collection,
|
ReadOnlyCollection<FilePath> Collection,
|
||||||
string? Match)
|
FilePath? Match)
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -21,9 +21,17 @@ public record FilePath(long CreationTicks,
|
|||||||
int? SortOrder)
|
int? SortOrder)
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public static FilePath? GetNullSafe(Properties.IPropertyConfiguration propertyConfiguration, FileHolder fileHolder, int? index)
|
||||||
{
|
{
|
||||||
string result = JsonSerializer.Serialize(this, FilePathSourceGenerationContext.Default.FilePath);
|
FilePath? result;
|
||||||
|
if (fileHolder.CreationTime is null)
|
||||||
|
result = null;
|
||||||
|
else if (fileHolder.LastWriteTime is null)
|
||||||
|
result = null;
|
||||||
|
else if (fileHolder.Length is null)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = Get(propertyConfiguration, fileHolder, index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,10 +115,16 @@ public record FilePath(long CreationTicks,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (KeyValuePair<int, List<FilePath>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<int, List<FilePath>> keyValuePair in keyValuePairs)
|
||||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string result = JsonSerializer.Serialize(this, FilePathSourceGenerationContext.Default.FilePath);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||||
|
@ -6,6 +6,7 @@ namespace View_by_Distance.Shared.Models;
|
|||||||
public class Item : Properties.IItem
|
public class Item : Properties.IItem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected ExifDirectory? _ExifDirectory;
|
||||||
protected List<Face> _Faces;
|
protected List<Face> _Faces;
|
||||||
protected readonly bool? _FileSizeChanged;
|
protected readonly bool? _FileSizeChanged;
|
||||||
protected readonly FilePath _FilePath;
|
protected readonly FilePath _FilePath;
|
||||||
@ -15,10 +16,10 @@ public class Item : Properties.IItem
|
|||||||
protected bool _IsValidImageFormatExtension;
|
protected bool _IsValidImageFormatExtension;
|
||||||
protected bool? _LastWriteTimeChanged;
|
protected bool? _LastWriteTimeChanged;
|
||||||
protected bool? _Moved;
|
protected bool? _Moved;
|
||||||
protected Property? _Property;
|
|
||||||
protected readonly string _RelativePath;
|
protected readonly string _RelativePath;
|
||||||
protected FileHolder? _ResizedFileHolder;
|
protected FileHolder? _ResizedFileHolder;
|
||||||
protected readonly FileHolder _SourceDirectoryFileHolder;
|
protected readonly FileHolder _SourceDirectoryFileHolder;
|
||||||
|
public ExifDirectory? ExifDirectory => _ExifDirectory;
|
||||||
public List<Face> Faces => _Faces;
|
public List<Face> Faces => _Faces;
|
||||||
public bool? FileSizeChanged => _FileSizeChanged;
|
public bool? FileSizeChanged => _FileSizeChanged;
|
||||||
public FilePath FilePath => _FilePath;
|
public FilePath FilePath => _FilePath;
|
||||||
@ -28,13 +29,12 @@ public class Item : Properties.IItem
|
|||||||
public bool IsValidImageFormatExtension => _IsValidImageFormatExtension;
|
public bool IsValidImageFormatExtension => _IsValidImageFormatExtension;
|
||||||
public bool? LastWriteTimeChanged => _LastWriteTimeChanged;
|
public bool? LastWriteTimeChanged => _LastWriteTimeChanged;
|
||||||
public bool? Moved => _Moved;
|
public bool? Moved => _Moved;
|
||||||
public Property? Property => _Property;
|
|
||||||
public string RelativePath => _RelativePath;
|
public string RelativePath => _RelativePath;
|
||||||
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
||||||
public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder;
|
public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder;
|
||||||
|
|
||||||
[JsonConstructor]
|
[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;
|
_Faces = faces;
|
||||||
_FilePath = filePath;
|
_FilePath = filePath;
|
||||||
@ -45,25 +45,28 @@ public class Item : Properties.IItem
|
|||||||
_IsValidImageFormatExtension = isValidImageFormatExtension;
|
_IsValidImageFormatExtension = isValidImageFormatExtension;
|
||||||
_LastWriteTimeChanged = lastWriteTimeChanged;
|
_LastWriteTimeChanged = lastWriteTimeChanged;
|
||||||
_Moved = moved;
|
_Moved = moved;
|
||||||
_Property = property;
|
_ExifDirectory = exifDirectory;
|
||||||
_RelativePath = relativePath;
|
_RelativePath = relativePath;
|
||||||
_ResizedFileHolder = resizedFileHolder;
|
_ResizedFileHolder = resizedFileHolder;
|
||||||
_SourceDirectoryFileHolder = sourceDirectoryFileHolder;
|
_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;
|
Item result;
|
||||||
if (relativePath.EndsWith(".json"))
|
if (relativePath.EndsWith(".json"))
|
||||||
throw new ArgumentException("Can not be a *.json file!");
|
throw new ArgumentException("Can not be a *.json file!");
|
||||||
if (filePath.ExtensionLowered is ".json")
|
if (filePath.ExtensionLowered is ".json")
|
||||||
throw new ArgumentException("Can not be a *.json file!");
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Item Get(FilePath filePath, FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) =>
|
public bool Any() =>
|
||||||
Get(filePath, sourceDirectoryFileHolder, relativePath, null, null, false, isValidImageFormatExtension, null, null, null, null);
|
!_SourceDirectoryFileHolder.Exists || (_FileSizeChanged.HasValue && _FileSizeChanged.Value) || (_LastWriteTimeChanged.HasValue && _LastWriteTimeChanged.Value) || (_Moved.HasValue && _Moved.Value);
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
@ -71,6 +74,9 @@ public class Item : Properties.IItem
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Update(ExifDirectory exifDirectory) =>
|
||||||
|
_ExifDirectory = exifDirectory;
|
||||||
|
|
||||||
public void SetMoved(bool moved) => _Moved = moved;
|
public void SetMoved(bool moved) => _Moved = moved;
|
||||||
|
|
||||||
public void SetResizedFileHolder(string filenameExtension, FileHolder fileHolder)
|
public void SetResizedFileHolder(string filenameExtension, FileHolder fileHolder)
|
||||||
@ -83,8 +89,4 @@ public class Item : Properties.IItem
|
|||||||
_ResizedFileHolder = fileHolder;
|
_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;
|
|
||||||
|
|
||||||
}
|
}
|
@ -23,7 +23,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
|||||||
_ = Stateless.Methods.Location.Check(bottom, left, right, top, zCount: 1, throwException: true);
|
_ = Stateless.Methods.Location.Check(bottom, left, right, top, zCount: 1, throwException: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location(double confidence, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) :
|
public Location(double confidence, int height, Location location, int width, int zCount) :
|
||||||
this(
|
this(
|
||||||
location.Bottom,
|
location.Bottom,
|
||||||
confidence,
|
confidence,
|
||||||
@ -32,7 +32,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
|||||||
location.Top) =>
|
location.Top) =>
|
||||||
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
||||||
|
|
||||||
public Location(int bottom, double confidence, int height, int left, int locationDigits, int locationFactor, int right, int top, int width, int zCount) :
|
public Location(int bottom, double confidence, int height, int left, int right, int top, int width, int zCount) :
|
||||||
this(
|
this(
|
||||||
bottom,
|
bottom,
|
||||||
confidence,
|
confidence,
|
||||||
@ -41,7 +41,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
|||||||
top) =>
|
top) =>
|
||||||
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
||||||
|
|
||||||
public Location(int height, Location location, int locationDigits, int locationFactor, int width, int zCount) :
|
public Location(int height, Location location, int width, int zCount) :
|
||||||
this(
|
this(
|
||||||
location.Bottom,
|
location.Bottom,
|
||||||
location.Confidence,
|
location.Confidence,
|
||||||
@ -50,7 +50,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
|||||||
location.Top) =>
|
location.Top) =>
|
||||||
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
|
||||||
|
|
||||||
public Location(double confidence, int factor, int height, Location location, int locationDigits, int locationFactor, int width, int zCount)
|
public Location(double confidence, int factor, int height, Location location, int width, int zCount)
|
||||||
{
|
{
|
||||||
int x = (location.Right - location.Left) / factor;
|
int x = (location.Right - location.Left) / factor;
|
||||||
int y = (location.Bottom - location.Top) / factor;
|
int y = (location.Bottom - location.Top) / factor;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
public record LocationContainer(DateOnly CreationDateOnly,
|
public record LocationContainer(DateOnly CreationDateOnly,
|
||||||
@ -14,47 +12,44 @@ public record LocationContainer(DateOnly CreationDateOnly,
|
|||||||
int? LengthPermyriad,
|
int? LengthPermyriad,
|
||||||
FilePath? LengthSource,
|
FilePath? LengthSource,
|
||||||
long? PersonKey,
|
long? PersonKey,
|
||||||
RectangleF? Rectangle,
|
|
||||||
int WholePercentages)
|
int WholePercentages)
|
||||||
{
|
{
|
||||||
|
|
||||||
public static LocationContainer Get(LocationContainer locationContainer, object? encoding, bool keepExifDirectory)
|
public static LocationContainer Get(LocationContainer locationContainer, object? encoding, bool keepExifDirectory)
|
||||||
{
|
{
|
||||||
LocationContainer result;
|
LocationContainer result;
|
||||||
result = new(locationContainer.CreationDateOnly,
|
result = new(CreationDateOnly: locationContainer.CreationDateOnly,
|
||||||
keepExifDirectory ? locationContainer.ExifDirectory : null,
|
ExifDirectory: keepExifDirectory ? locationContainer.ExifDirectory : null,
|
||||||
locationContainer.DirectoryNumber,
|
DirectoryNumber: locationContainer.DirectoryNumber,
|
||||||
locationContainer.DisplayDirectoryName,
|
DisplayDirectoryName: locationContainer.DisplayDirectoryName,
|
||||||
encoding,
|
Encoding: encoding,
|
||||||
locationContainer.FaceFile,
|
FaceFile: locationContainer.FaceFile,
|
||||||
locationContainer.FilePath,
|
FilePath: locationContainer.FilePath,
|
||||||
locationContainer.FromDistanceContent,
|
FromDistanceContent: locationContainer.FromDistanceContent,
|
||||||
locationContainer.Id,
|
Id: locationContainer.Id,
|
||||||
locationContainer.LengthPermyriad,
|
LengthPermyriad: locationContainer.LengthPermyriad,
|
||||||
locationContainer.LengthSource,
|
LengthSource: locationContainer.LengthSource,
|
||||||
locationContainer.PersonKey,
|
PersonKey: locationContainer.PersonKey,
|
||||||
locationContainer.Rectangle,
|
WholePercentages: locationContainer.WholePercentages);
|
||||||
locationContainer.WholePercentages);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocationContainer Get(LocationContainer source, LocationContainer locationContainer, int lengthPermyriad, bool keepExifDirectory, bool keepEncoding)
|
public static LocationContainer Get(LocationContainer source, LocationContainer locationContainer, int lengthPermyriad, bool keepExifDirectory, bool keepEncoding)
|
||||||
{
|
{
|
||||||
LocationContainer result;
|
LocationContainer result;
|
||||||
result = new(locationContainer.CreationDateOnly,
|
result = new(CreationDateOnly: locationContainer.CreationDateOnly,
|
||||||
keepExifDirectory ? locationContainer.ExifDirectory : null,
|
ExifDirectory: keepExifDirectory ? locationContainer.ExifDirectory : null,
|
||||||
locationContainer.DirectoryNumber,
|
DirectoryNumber: locationContainer.DirectoryNumber,
|
||||||
locationContainer.DisplayDirectoryName,
|
DisplayDirectoryName: locationContainer.DisplayDirectoryName,
|
||||||
keepEncoding ? locationContainer.Encoding : null,
|
Encoding: keepEncoding ? locationContainer.Encoding : null,
|
||||||
locationContainer.FaceFile,
|
FaceFile: locationContainer.FaceFile,
|
||||||
locationContainer.FilePath,
|
FilePath: locationContainer.FilePath,
|
||||||
locationContainer.FromDistanceContent,
|
FromDistanceContent: locationContainer.FromDistanceContent,
|
||||||
locationContainer.Id,
|
Id: locationContainer.Id,
|
||||||
lengthPermyriad,
|
LengthPermyriad: lengthPermyriad,
|
||||||
source.FilePath,
|
LengthSource: source.FilePath,
|
||||||
locationContainer.PersonKey,
|
PersonKey: locationContainer.PersonKey,
|
||||||
locationContainer.Rectangle,
|
WholePercentages: locationContainer.WholePercentages);
|
||||||
locationContainer.WholePercentages);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
public record MappingFromItem(DateTime[] ContainerDateTimes,
|
public record MappingFromItem(DateTime[] ContainerDateTimes,
|
||||||
DateTime? DateTimeDigitized,
|
|
||||||
DateTime? DateTimeOriginal,
|
DateTime? DateTimeOriginal,
|
||||||
int Id,
|
int Id,
|
||||||
bool? IsArchive,
|
bool? IsArchive,
|
||||||
FilePath FilePath,
|
FilePath FilePath,
|
||||||
bool? IsWrongYear,
|
bool? IsWrongYear,
|
||||||
string[] Keywords,
|
ReadOnlyCollection<string> Keywords,
|
||||||
DateTime MinimumDateTime,
|
DateTime MinimumDateTime,
|
||||||
string? Model,
|
string? Model,
|
||||||
string RelativePath,
|
string RelativePath,
|
||||||
@ -29,14 +29,18 @@ public record MappingFromItem(DateTime[] ContainerDateTimes,
|
|||||||
internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder)
|
internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder)
|
||||||
{
|
{
|
||||||
MappingFromItem result;
|
MappingFromItem result;
|
||||||
if (item.Property?.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
if (resizedFileHolder is null)
|
if (resizedFileHolder is null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
List<DateTime> dateTimes = item.Property.GetDateTimes();
|
ExifDirectory exifDirectory = item.ExifDirectory;
|
||||||
DateTime minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
string? model = Stateless.Methods.IMetaBase.GetModel(exifDirectory);
|
||||||
(bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.FilePath, item.Property.DateTimeOriginal, dateTimes);
|
DateTime minimumDateTime = Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
||||||
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);
|
DateTime? dateTime = Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
|
ReadOnlyCollection<DateTime> dateTimes = Stateless.Methods.IDate.GetDateTimes(exifDirectory);
|
||||||
|
ReadOnlyCollection<string> keywords = Stateless.Methods.IMetaBase.GetKeywords(exifDirectory);
|
||||||
|
(bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.FilePath, dateTime, dateTimes.ToList());
|
||||||
|
result = new(containerDateTimes, dateTime, exifDirectory.FilePath.Id.Value, item.IsArchive, item.FilePath, isWrongYear, keywords, minimumDateTime, model, item.RelativePath, resizedFileHolder);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 interface IItem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public ExifDirectory? ExifDirectory { get; }
|
||||||
public bool? FileSizeChanged { get; }
|
public bool? FileSizeChanged { get; }
|
||||||
public List<Face> Faces { get; }
|
public List<Face> Faces { get; }
|
||||||
public FilePath FilePath { get; }
|
public FilePath FilePath { get; }
|
||||||
@ -11,7 +12,6 @@ public interface IItem
|
|||||||
public bool IsUniqueFileName { get; }
|
public bool IsUniqueFileName { get; }
|
||||||
public bool IsValidImageFormatExtension { get; }
|
public bool IsValidImageFormatExtension { get; }
|
||||||
public bool? Moved { get; }
|
public bool? Moved { get; }
|
||||||
public Property? Property { get; }
|
|
||||||
public string RelativePath { get; }
|
public string RelativePath { get; }
|
||||||
public FileHolder? ResizedFileHolder { get; }
|
public FileHolder? ResizedFileHolder { get; }
|
||||||
public FileHolder SourceDirectoryFileHolder { get; }
|
public FileHolder SourceDirectoryFileHolder { get; }
|
||||||
|
149
Shared/Models/Stateless/Methods/Dimensions.cs
Normal file
149
Shared/Models/Stateless/Methods/Dimensions.cs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
internal static class Dimensions
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma warning disable IDE0230
|
||||||
|
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
|
||||||
|
{
|
||||||
|
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
||||||
|
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
|
||||||
|
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
|
||||||
|
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
|
||||||
|
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
|
||||||
|
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
|
||||||
|
};
|
||||||
|
#pragma warning restore IDE0230
|
||||||
|
|
||||||
|
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < thisBytes.Count && i < thatBytes.Length; i += 1)
|
||||||
|
{
|
||||||
|
if (thisBytes[i] == thatBytes[i])
|
||||||
|
continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static short ReadLittleEndianInt16(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[sizeof(short)];
|
||||||
|
for (int i = 0; i < sizeof(short); i += 1)
|
||||||
|
bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
|
||||||
|
return BitConverter.ToInt16(bytes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ReadLittleEndianInt32(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[sizeof(int)];
|
||||||
|
for (int i = 0; i < sizeof(int); i += 1)
|
||||||
|
bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
|
||||||
|
return BitConverter.ToInt32(bytes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? DecodeBitmap(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
_ = binaryReader.ReadBytes(16);
|
||||||
|
int width = binaryReader.ReadInt32();
|
||||||
|
int height = binaryReader.ReadInt32();
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? DecodeGif(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
int width = binaryReader.ReadInt16();
|
||||||
|
int height = binaryReader.ReadInt16();
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? DecodePng(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
_ = binaryReader.ReadBytes(8);
|
||||||
|
int width = ReadLittleEndianInt32(binaryReader);
|
||||||
|
int height = ReadLittleEndianInt32(binaryReader);
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? DecodeJfif(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
while (binaryReader.ReadByte() == 0xff)
|
||||||
|
{
|
||||||
|
byte marker = binaryReader.ReadByte();
|
||||||
|
short chunkLength = ReadLittleEndianInt16(binaryReader);
|
||||||
|
if (marker == 0xc0)
|
||||||
|
{
|
||||||
|
_ = binaryReader.ReadByte();
|
||||||
|
int height = ReadLittleEndianInt16(binaryReader);
|
||||||
|
int width = ReadLittleEndianInt16(binaryReader);
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
if (chunkLength >= 0)
|
||||||
|
_ = binaryReader.ReadBytes(chunkLength - 2);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ushort uChunkLength = (ushort)chunkLength;
|
||||||
|
_ = binaryReader.ReadBytes(uChunkLength - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? DecodeWebP(BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
_ = binaryReader.ReadUInt32(); // Size
|
||||||
|
_ = binaryReader.ReadBytes(15); // WEBP, VP8 + more
|
||||||
|
_ = binaryReader.ReadBytes(3); // SYNC
|
||||||
|
int width = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits width
|
||||||
|
int height = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits height
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom)
|
||||||
|
{
|
||||||
|
Size? result;
|
||||||
|
List<byte> magicBytes = [];
|
||||||
|
int[] magicBytesLengths = (from l in _ImageFormatDecoders.Keys where l.Length <= binaryReader.BaseStream.Length orderby l.Length descending select l.Length).ToArray();
|
||||||
|
if (magicBytesLengths.Length == 0)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
|
||||||
|
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
for (int i = 0; i < magicBytesLengths[0]; i++)
|
||||||
|
{
|
||||||
|
magicBytes.Add(binaryReader.ReadByte());
|
||||||
|
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
|
||||||
|
{
|
||||||
|
if (StartsWith(magicBytes, kvPair.Key))
|
||||||
|
{
|
||||||
|
result = kvPair.Value(binaryReader);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result is not null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
if (faceRight is null || faceBottom is null)
|
||||||
|
throw new Exception("face is null!");
|
||||||
|
result = new(faceRight.Value, faceBottom.Value);
|
||||||
|
}
|
||||||
|
return result.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
|
||||||
|
{
|
||||||
|
Size result;
|
||||||
|
using FileStream fileStream = File.OpenRead(path);
|
||||||
|
using BinaryReader binaryReader = new(fileStream);
|
||||||
|
result = GetDimensions(binaryReader, faceRight, faceBottom);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
149
Shared/Models/Stateless/Methods/FilePair.cs
Normal file
149
Shared/Models/Stateless/Methods/FilePair.cs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
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)
|
||||||
|
{
|
||||||
|
List<Models.FilePair>? results = null;
|
||||||
|
int renamed;
|
||||||
|
const bool useCeilingAverage = true;
|
||||||
|
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
|
IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? compareFileNamesToFiles = null;
|
||||||
|
for (int i = 0; i < idToFilePaths.Count; i++)
|
||||||
|
{
|
||||||
|
renamed = 0;
|
||||||
|
jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||||
|
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, idToFilePaths, extension);
|
||||||
|
if (renamed > 0)
|
||||||
|
continue;
|
||||||
|
compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
|
||||||
|
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, idToFilePaths, 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, ReadOnlyCollection<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, ReadOnlyCollection<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
string checkFile;
|
||||||
|
string directory;
|
||||||
|
FilePath filePath;
|
||||||
|
string fileNameWith;
|
||||||
|
string checkDirectory;
|
||||||
|
string directoryName;
|
||||||
|
Models.FileHolder fileHolder;
|
||||||
|
List<string> directoryNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (files.Any(l => l.StartsWith(propertyConfiguration.RootDirectory)))
|
||||||
|
continue;
|
||||||
|
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, ReadOnlyCollection<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||||
|
{
|
||||||
|
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
||||||
|
FilePath filePath;
|
||||||
|
List<FilePath>? collection;
|
||||||
|
Models.FileHolder fileHolder;
|
||||||
|
Dictionary<int, List<FilePath>> keyValuePairs = [];
|
||||||
|
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 (!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, keyValuePair.Value.AsReadOnly());
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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);
|
||||||
|
|
||||||
|
}
|
@ -11,32 +11,32 @@ public interface IDirectory
|
|||||||
public static char GetDirectory(string fileName) =>
|
public static char GetDirectory(string fileName) =>
|
||||||
fileName.Split('-').Length > 2 ? '-' : fileName.Split('.')[0][^1];
|
fileName.Split('-').Length > 2 ? '-' : fileName.Split('.')[0][^1];
|
||||||
|
|
||||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups, Action? tick) =>
|
|
||||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick);
|
|
||||||
|
|
||||||
public 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);
|
XDirectory.MoveFiles(files, find, replace);
|
||||||
|
|
||||||
public 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);
|
XDirectory.CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||||
|
|
||||||
public static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
|
||||||
XDirectory.MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
|
||||||
|
|
||||||
public static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
public static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||||
XDirectory.GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
XDirectory.GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
|
|
||||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) =>
|
public static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<Models.FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
||||||
XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
|
XDirectory.MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
||||||
|
|
||||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage) =>
|
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, bool useIgnoreExtensions) =>
|
||||||
XDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useCeilingAverage);
|
XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
|
|
||||||
public static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
|
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, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles) =>
|
||||||
XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||||
|
|
||||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups, Action? tick) =>
|
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: false, ifCanUseId: true, filePathsCollection, fileGroups, 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, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||||
|
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||||
|
|
||||||
internal int TestStatic_GetDirectory(char directory) =>
|
internal int TestStatic_GetDirectory(char directory) =>
|
||||||
GetDirectory(directory);
|
GetDirectory(directory);
|
||||||
@ -50,25 +50,25 @@ public interface IDirectory
|
|||||||
internal List<string> TestStatic_CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
internal List<string> TestStatic_CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
|
||||||
CopyOrMove(toDoCollection, move, moveBack, tick);
|
CopyOrMove(toDoCollection, move, moveBack, tick);
|
||||||
|
|
||||||
internal int TestStatic_MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
|
||||||
MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
|
||||||
|
|
||||||
internal ReadOnlyCollection<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
internal ReadOnlyCollection<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) =>
|
||||||
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
|
|
||||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) =>
|
internal int TestStatic_MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<Models.FilePair> filePairs, string jsonGroupDirectory, string extension) =>
|
||||||
GetFilePathCollections(propertyConfiguration, filesCollection);
|
MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
|
||||||
|
|
||||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage) =>
|
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, bool useIgnoreExtensions) =>
|
||||||
GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useCeilingAverage);
|
GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
|
|
||||||
internal List<FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
|
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, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles) =>
|
||||||
GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||||
|
|
||||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups, Action? tick) =>
|
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, filePathsCollection, fileGroups, tick);
|
|
||||||
|
|
||||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups, Action? tick) =>
|
|
||||||
GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, 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, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||||
|
GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||||
|
|
||||||
}
|
}
|
@ -4,7 +4,10 @@ public interface IDlibDotNet
|
|||||||
{
|
{
|
||||||
|
|
||||||
void Tick();
|
void Tick();
|
||||||
|
long Ticks { get; }
|
||||||
|
int? CurrentTick { get; }
|
||||||
(string, string) GetResultsFullGroupDirectories();
|
(string, string) GetResultsFullGroupDirectories();
|
||||||
|
void ConstructProgressBar(int maxTicks, string message);
|
||||||
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
||||||
|
|
||||||
}
|
}
|
15
Shared/Models/Stateless/Methods/IFilePair.cs
Normal file
15
Shared/Models/Stateless/Methods/IFilePair.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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);
|
||||||
|
|
||||||
|
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||||
|
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
|
|
||||||
|
}
|
@ -29,19 +29,19 @@ public interface IId
|
|||||||
Id.NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder.NameWithoutExtension.Split('.')[0]);
|
Id.NameWithoutExtensionIsIdFormat(propertyConfiguration, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||||
|
|
||||||
public static bool NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
public static bool NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||||
fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
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, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
public static string GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||||
Id.GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
Id.GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||||
|
|
||||||
public static string GetPaddedId(IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
|
||||||
Id.GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
|
||||||
|
|
||||||
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||||
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
||||||
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
|
&& 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);
|
&& 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) =>
|
internal int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
||||||
GetDeterministicHashCode(value);
|
GetDeterministicHashCode(value);
|
||||||
|
|
||||||
@ -63,13 +63,13 @@ public interface IId
|
|||||||
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
|
||||||
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
|
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
|
||||||
|
|
||||||
internal string TestStatic_GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
internal string TestStatic_GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||||
GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||||
|
|
||||||
internal string TestStatic_GetPaddedId(IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
|
||||||
GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
|
||||||
|
|
||||||
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, 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);
|
||||||
|
|
||||||
}
|
}
|
@ -55,15 +55,15 @@ public interface ILocation
|
|||||||
static string GetLeftPadded(int locationDigits, int value) =>
|
static string GetLeftPadded(int locationDigits, int value) =>
|
||||||
GetLeftPadded(locationDigits, value.ToString());
|
GetLeftPadded(locationDigits, value.ToString());
|
||||||
|
|
||||||
Models.Location? TestStatic_GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) =>
|
Models.Location? TestStatic_GetLocation(Models.Location? location, int height, int width, int zCount) =>
|
||||||
GetLocation(location, locationDigits, locationFactor, height, width, zCount);
|
GetLocation(location, height, width, zCount);
|
||||||
static Models.Location? GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) =>
|
static Models.Location? GetLocation(Models.Location? location, int height, int width, int zCount) =>
|
||||||
location is null ? null : new(location.Confidence, height, location, locationDigits, locationFactor, width, zCount);
|
location is null ? null : new(location.Confidence, height, location, width, zCount);
|
||||||
|
|
||||||
Models.Location? TestStatic_GetLocation(int factor, Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) =>
|
Models.Location? TestStatic_GetLocation(int factor, Models.Location? location, int height, int width, int zCount) =>
|
||||||
GetLocation(factor, location, locationDigits, locationFactor, height, width, zCount);
|
GetLocation(factor, location, height, width, zCount);
|
||||||
static Models.Location? GetLocation(int factor, Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) =>
|
static Models.Location? GetLocation(int factor, Models.Location? location, int height, int width, int zCount) =>
|
||||||
location is null ? null : new(location.Confidence, factor, height, location, locationDigits, locationFactor, width, zCount);
|
location is null ? null : new(location.Confidence, factor, height, location, width, zCount);
|
||||||
|
|
||||||
(decimal?, decimal?, decimal?, decimal?) TestStatic_GetHeightLeftTopWidth(int bottom, int height, int left, int right, int top, int width) =>
|
(decimal?, decimal?, decimal?, decimal?) TestStatic_GetHeightLeftTopWidth(int bottom, int height, int left, int right, int top, int width) =>
|
||||||
GetHeightLeftTopWidth(bottom, height, left, right, top, width);
|
GetHeightLeftTopWidth(bottom, height, left, right, top, width);
|
||||||
@ -107,8 +107,6 @@ public interface ILocation
|
|||||||
detectionConfidence,
|
detectionConfidence,
|
||||||
height,
|
height,
|
||||||
Math.Max(rectangle.Left, 0),
|
Math.Max(rectangle.Left, 0),
|
||||||
Stateless.ILocation.Digits,
|
|
||||||
Stateless.ILocation.Factor,
|
|
||||||
Math.Min(rectangle.Right, width),
|
Math.Min(rectangle.Right, width),
|
||||||
Math.Max(rectangle.Top, 0),
|
Math.Max(rectangle.Top, 0),
|
||||||
width,
|
width,
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
public interface IMappingFromItem
|
public interface IMappingFromItem
|
||||||
{ // ...
|
{
|
||||||
|
|
||||||
MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
public static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
||||||
=> GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
|
||||||
static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder)
|
|
||||||
=> MappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
=> MappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||||
|
|
||||||
MappingFromItem TestStatic_GetMappingFromItem(Models.Item item)
|
public static MappingFromItem GetMappingFromItem(Models.Item item)
|
||||||
=> GetMappingFromItem(item);
|
|
||||||
static MappingFromItem GetMappingFromItem(Models.Item item)
|
|
||||||
=> GetMappingFromItem(containerDateTimes: [], item, item.ResizedFileHolder);
|
=> 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);
|
||||||
|
|
||||||
}
|
}
|
74
Shared/Models/Stateless/Methods/IMetaBase.cs
Normal file
74
Shared/Models/Stateless/Methods/IMetaBase.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
public interface IMetaBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string DateTimeFormat() =>
|
||||||
|
"yyyy:MM:dd HH:mm:ss";
|
||||||
|
|
||||||
|
public static string? GetMaker(ExifDirectory? exifDirectory) =>
|
||||||
|
MetaBase.GetMaker(exifDirectory?.ExifBaseDirectories);
|
||||||
|
|
||||||
|
public static string? GetModel(ExifDirectory? exifDirectory) =>
|
||||||
|
MetaBase.GetModel(exifDirectory?.ExifBaseDirectories);
|
||||||
|
|
||||||
|
public static int? GetOrientation(ExifDirectory? exifDirectory) =>
|
||||||
|
MetaBase.GetOrientation(exifDirectory?.ExifBaseDirectories);
|
||||||
|
|
||||||
|
public static int? GetWidth(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetWidth(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static int? GetHeight(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetHeight(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetMaker(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetModel(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
MetaBase.GetDateTime(dateTimeFormat, value);
|
||||||
|
|
||||||
|
public static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetOrientation(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<string> GetKeywords(ExifDirectory? exifDirectory) =>
|
||||||
|
MetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
MetaBase.GetKeywords(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal string TestStatic_DateTimeFormat() =>
|
||||||
|
DateTimeFormat();
|
||||||
|
|
||||||
|
internal string? TestStatic_GetMaker(ExifDirectory? exifDirectory) =>
|
||||||
|
GetMaker(exifDirectory);
|
||||||
|
|
||||||
|
internal string? TestStatic_GetModel(ExifDirectory? exifDirectory) =>
|
||||||
|
GetModel(exifDirectory);
|
||||||
|
|
||||||
|
internal static int? TestStatic_GetWidth(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
GetWidth(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal static int? TestStatic_GetHeight(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
GetHeight(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal static string? TestStatic_GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
GetMaker(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal static string? TestStatic_GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
|
GetModel(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal static DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
GetDateTime(dateTimeFormat, value);
|
||||||
|
|
||||||
|
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
|
|
||||||
{
|
|
||||||
|
|
||||||
// ...
|
|
||||||
|
|
||||||
}
|
|
@ -24,6 +24,9 @@ public interface IPath
|
|||||||
public static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
public static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||||
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||||
|
|
||||||
|
public static void CreateDirectories(ReadOnlyCollection<string> directories) =>
|
||||||
|
XPath.CreateDirectories(directories);
|
||||||
|
|
||||||
public static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
public static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||||
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||||
|
|
||||||
@ -65,6 +68,9 @@ public interface IPath
|
|||||||
internal void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
internal void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
|
||||||
MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
MakeHiddenIfAllItemsAreHidden(rootDirectory);
|
||||||
|
|
||||||
|
internal void TestStatic_CreateDirectories(ReadOnlyCollection<string> directories) =>
|
||||||
|
CreateDirectories(directories);
|
||||||
|
|
||||||
internal void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
internal void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
|
||||||
ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
ChangeDateForEmptyDirectories(rootDirectory, ticks);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -27,7 +28,20 @@ internal abstract class Id
|
|||||||
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||||
(byte)(filePath.Id > -1 ? 8 : 2);
|
(byte)(filePath.Id > -1 ? 8 : 2);
|
||||||
|
|
||||||
internal static int GetId(Properties.IPropertyConfiguration propertyConfiguration, string intelligentId)
|
internal static byte GetHasDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||||
|
(byte)(IsIgnoreOrValidVideoFormatExtension(propertyConfiguration, filePath) ? filePath.Id > -1 ? 6 : 4 : filePath.Id > -1 ? 9 : 1);
|
||||||
|
|
||||||
|
private static bool IsIgnoreOrValidVideoFormatExtension(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||||
|
IsIgnoreOrValidVideoFormatExtension(propertyConfiguration, filePath.ExtensionLowered);
|
||||||
|
|
||||||
|
private static bool IsIgnoreOrValidVideoFormatExtension(IPropertyConfiguration propertyConfiguration, string extensionLowered) =>
|
||||||
|
propertyConfiguration.IgnoreExtensions.Contains(extensionLowered)
|
||||||
|
|| propertyConfiguration.ValidVideoFormatExtensions.Contains(extensionLowered);
|
||||||
|
|
||||||
|
internal static byte GetMissingDateTimeOriginal(IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||||
|
(byte)(IsIgnoreOrValidVideoFormatExtension(propertyConfiguration, filePath) ? filePath.Id > -1 ? 5 : 0 : filePath.Id > -1 ? 7 : 3);
|
||||||
|
|
||||||
|
internal static int GetId(IPropertyConfiguration propertyConfiguration, string intelligentId)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
StringBuilder results = new();
|
StringBuilder results = new();
|
||||||
@ -37,20 +51,14 @@ internal abstract class Id
|
|||||||
_ = results.Append(intelligentId[i]);
|
_ = results.Append(intelligentId[i]);
|
||||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||||
result = int.Parse(results.ToString());
|
result = int.Parse(results.ToString());
|
||||||
if (intelligentId[^1] is '1' or '2' or '3' or '4')
|
if (intelligentId[^1] is '0' or '1' or '2' or '3' or '4')
|
||||||
result *= -1;
|
result *= -1;
|
||||||
else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
|
else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte GetHasDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
internal static bool NameWithoutExtensionIsIdFormat(IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
||||||
(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 : 5);
|
|
||||||
|
|
||||||
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
|
||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
if (fileNameWithoutExtension.Length < 5 || fileNameWithoutExtension.Length > propertyConfiguration.IntMinValueLength)
|
if (fileNameWithoutExtension.Length < 5 || fileNameWithoutExtension.Length > propertyConfiguration.IntMinValueLength)
|
||||||
@ -63,25 +71,34 @@ internal abstract class Id
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
internal static string GetIntelligentId(IPropertyConfiguration propertyConfiguration, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
StringBuilder stringBuilder = new();
|
StringBuilder stringBuilder = new();
|
||||||
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
if (propertyConfiguration.IntMinValueLength < (propertyConfiguration.ResultAllInOneSubdirectoryLength + 2))
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
if (hasDateTimeOriginal is null)
|
|
||||||
{ }
|
|
||||||
int key;
|
int key;
|
||||||
string value;
|
string value;
|
||||||
List<char> resultAllInOneSubdirectoryChars = [];
|
List<char> resultAllInOneSubdirectoryChars = [];
|
||||||
if (id > -1)
|
if (hasDateTimeOriginal is null)
|
||||||
{
|
{
|
||||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 9 : 7;
|
key = 0;
|
||||||
|
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||||
|
}
|
||||||
|
else if (id > -1)
|
||||||
|
{
|
||||||
|
if (IsIgnoreOrValidVideoFormatExtension(propertyConfiguration, extensionLowered))
|
||||||
|
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 6 : 5;
|
||||||
|
else
|
||||||
|
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal.Value ? 9 : 7;
|
||||||
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 1 : 3;
|
if (IsIgnoreOrValidVideoFormatExtension(propertyConfiguration, extensionLowered))
|
||||||
|
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 4 : 0;
|
||||||
|
else
|
||||||
|
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal.Value ? 1 : 3;
|
||||||
value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0');
|
||||||
}
|
}
|
||||||
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
||||||
@ -92,14 +109,14 @@ internal abstract class Id
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
|
internal static string GetPaddedId(IPropertyConfiguration propertyConfiguration, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
if (propertyConfiguration.Offset < 0)
|
if (propertyConfiguration.Offset < 0)
|
||||||
result = Guid.NewGuid().ToString();
|
result = Guid.NewGuid().ToString();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string intelligentId = GetIntelligentId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
string intelligentId = GetIntelligentId(propertyConfiguration, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||||
int check = GetId(propertyConfiguration, intelligentId);
|
int check = GetId(propertyConfiguration, intelligentId);
|
||||||
if (check != id)
|
if (check != id)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|
||||||
|
|
||||||
internal abstract class ImageHelper
|
|
||||||
{
|
|
||||||
|
|
||||||
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < thatBytes.Length; i += 1)
|
|
||||||
{
|
|
||||||
if (thisBytes[i] != thatBytes[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static short ReadLittleEndianInt16(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[sizeof(short)];
|
|
||||||
for (int i = 0; i < sizeof(short); i += 1)
|
|
||||||
bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
|
|
||||||
return BitConverter.ToInt16(bytes, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ReadLittleEndianInt32(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[sizeof(int)];
|
|
||||||
for (int i = 0; i < sizeof(int); i += 1)
|
|
||||||
bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
|
|
||||||
return BitConverter.ToInt32(bytes, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Size DecodeBitmap(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
_ = binaryReader.ReadBytes(16);
|
|
||||||
int width = binaryReader.ReadInt32();
|
|
||||||
int height = binaryReader.ReadInt32();
|
|
||||||
return new Size(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Size DecodeGif(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
int width = binaryReader.ReadInt16();
|
|
||||||
int height = binaryReader.ReadInt16();
|
|
||||||
return new Size(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Size DecodePng(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
_ = binaryReader.ReadBytes(8);
|
|
||||||
int width = ReadLittleEndianInt32(binaryReader);
|
|
||||||
int height = ReadLittleEndianInt32(binaryReader);
|
|
||||||
return new Size(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Size DecodeJfif(BinaryReader binaryReader)
|
|
||||||
{
|
|
||||||
while (binaryReader.ReadByte() == 0xff)
|
|
||||||
{
|
|
||||||
byte marker = binaryReader.ReadByte();
|
|
||||||
short chunkLength = ReadLittleEndianInt16(binaryReader);
|
|
||||||
if (marker == 0xc0)
|
|
||||||
{
|
|
||||||
_ = binaryReader.ReadByte();
|
|
||||||
int height = ReadLittleEndianInt16(binaryReader);
|
|
||||||
int width = ReadLittleEndianInt16(binaryReader);
|
|
||||||
return new Size(width, height);
|
|
||||||
}
|
|
||||||
_ = binaryReader.ReadBytes(chunkLength - 2);
|
|
||||||
}
|
|
||||||
throw new ArgumentException("Could not recognize image format.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dimensions of an image.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path of the image to get the dimensions of.</param>
|
|
||||||
/// <returns>The dimensions of the specified image.</returns>
|
|
||||||
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
|
|
||||||
internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom)
|
|
||||||
{
|
|
||||||
Size? result = null;
|
|
||||||
#pragma warning disable IDE0230
|
|
||||||
Dictionary<byte[], Func<BinaryReader, Size>> _ImageFormatDecoders = new()
|
|
||||||
{
|
|
||||||
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
|
|
||||||
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
|
|
||||||
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
|
|
||||||
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
|
|
||||||
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
|
||||||
};
|
|
||||||
#pragma warning restore IDE0230
|
|
||||||
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
|
|
||||||
byte[] magicBytes = new byte[maxMagicBytesLength];
|
|
||||||
for (int i = 0; i < maxMagicBytesLength; i += 1)
|
|
||||||
{
|
|
||||||
magicBytes[i] = binaryReader.ReadByte();
|
|
||||||
foreach (KeyValuePair<byte[], Func<BinaryReader, Size>> kvPair in _ImageFormatDecoders)
|
|
||||||
{
|
|
||||||
if (!StartsWith(magicBytes, kvPair.Key))
|
|
||||||
continue;
|
|
||||||
result = kvPair.Value(binaryReader);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (result is not null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (result is null)
|
|
||||||
{
|
|
||||||
if (faceRight is null || faceBottom is null)
|
|
||||||
throw new Exception("face is null!");
|
|
||||||
result = new(faceRight.Value, faceBottom.Value);
|
|
||||||
}
|
|
||||||
return result.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dimensions of an image.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path of the image to get the dimensions of.</param>
|
|
||||||
/// <returns>The dimensions of the specified image.</returns>
|
|
||||||
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
|
|
||||||
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
|
|
||||||
{
|
|
||||||
Size result;
|
|
||||||
using BinaryReader binaryReader = new(File.OpenRead(path));
|
|
||||||
result = GetDimensions(binaryReader, faceRight, faceBottom);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -136,7 +136,10 @@ internal abstract class Location
|
|||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!int.TryParse(segments[1], out int xWholePercent) || !int.TryParse(segments[2], out int yWholePercent) || !int.TryParse(segments[3], out int wWholePercent) || !int.TryParse(segments[4], out int hWholePercent))
|
if (!int.TryParse(segments[1], out int xWholePercent)
|
||||||
|
|| !int.TryParse(segments[2], out int yWholePercent)
|
||||||
|
|| !int.TryParse(segments[3], out int wWholePercent)
|
||||||
|
|| !int.TryParse(segments[4], out int hWholePercent))
|
||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using View_by_Distance.Shared.Models;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
internal static class Base
|
internal static class MetaBase
|
||||||
{
|
{
|
||||||
|
|
||||||
internal static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories)
|
internal static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories)
|
||||||
@ -48,7 +48,72 @@ internal static class Base
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int? GetWidth(ExifDirectoryBase[]? exifBaseDirectories)
|
||||||
|
{
|
||||||
|
int? result = null;
|
||||||
|
// public const int TagImageWidth = 256;
|
||||||
|
if (exifBaseDirectories is not null)
|
||||||
|
{
|
||||||
|
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||||
|
{
|
||||||
|
result = exifDirectoryBase?.ImageWidthValue;
|
||||||
|
if (result is not null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int? GetHeight(ExifDirectoryBase[]? exifBaseDirectories)
|
||||||
|
{
|
||||||
|
int? result = null;
|
||||||
|
// public const int TagImageHeight = 257;
|
||||||
|
if (exifBaseDirectories is not null)
|
||||||
|
{
|
||||||
|
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||||
|
{
|
||||||
|
result = exifDirectoryBase?.ImageHeightValue;
|
||||||
|
if (result is not null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||||
{
|
{
|
||||||
@ -65,6 +130,6 @@ internal static class Base
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
}
|
}
|
252
Shared/Models/Stateless/Methods/XDate.cs
Normal file
252
Shared/Models/Stateless/Methods/XDate.cs
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
internal abstract class XDate
|
||||||
|
{
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<DateTime> GetDateTimes(ExifDirectory exifDirectory)
|
||||||
|
{
|
||||||
|
List<DateTime> results = [];
|
||||||
|
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
||||||
|
{
|
||||||
|
if (exifDirectoryBase.DateTimeOriginal is not null)
|
||||||
|
results.Add(exifDirectoryBase.DateTimeOriginal.Value);
|
||||||
|
}
|
||||||
|
foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories)
|
||||||
|
{
|
||||||
|
if (aviDirectory.DateTimeOriginal is not null)
|
||||||
|
results.Add(aviDirectory.DateTimeOriginal.Value);
|
||||||
|
}
|
||||||
|
foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories)
|
||||||
|
{
|
||||||
|
if (quickTimeMovieHeaderDirectory.Created is not null)
|
||||||
|
{
|
||||||
|
if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1)
|
||||||
|
continue;
|
||||||
|
results.Add(quickTimeMovieHeaderDirectory.Created.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories)
|
||||||
|
{
|
||||||
|
if (quickTimeTrackHeaderDirectory.Created is not null)
|
||||||
|
{
|
||||||
|
if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1)
|
||||||
|
continue;
|
||||||
|
results.Add(quickTimeTrackHeaderDirectory.Created.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (results.Count == 0)
|
||||||
|
{
|
||||||
|
string? fileNameWithoutExtension = exifDirectory.FilePath is null ? null : Path.GetFileNameWithoutExtension(exifDirectory.FilePath.Name);
|
||||||
|
DateTime? dateTime = fileNameWithoutExtension is null ? null : GetDateTimeFromName(fileNameWithoutExtension);
|
||||||
|
if (dateTime is not null)
|
||||||
|
results.Add(dateTime.Value);
|
||||||
|
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
||||||
|
{
|
||||||
|
if (exifDirectoryBase.DateTime is not null)
|
||||||
|
results.Add(exifDirectoryBase.DateTime.Value);
|
||||||
|
if (exifDirectoryBase.DateTimeDigitized is not null)
|
||||||
|
results.Add(exifDirectoryBase.DateTimeDigitized.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (results.Count == 0)
|
||||||
|
{
|
||||||
|
foreach (FileMetadataDirectory fileMetadataDirectory in exifDirectory.FileMetadataDirectories)
|
||||||
|
{
|
||||||
|
if (fileMetadataDirectory.FileModifiedDate is not null)
|
||||||
|
results.Add(fileMetadataDirectory.FileModifiedDate.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension)
|
||||||
|
{
|
||||||
|
DateTime? result = null;
|
||||||
|
int length;
|
||||||
|
string format;
|
||||||
|
string fullFormat;
|
||||||
|
StringBuilder value = new();
|
||||||
|
const string ticksExample = "##################";
|
||||||
|
string[][] dateFormats =
|
||||||
|
[
|
||||||
|
[string.Empty, "yyyyMMdd_HHmmss", string.Empty],
|
||||||
|
[string.Empty, "yyyyMMddHHmmssfff", string.Empty],
|
||||||
|
[string.Empty, "yyyyMMdd_", ticksExample],
|
||||||
|
[string.Empty, "yyyy-MM-dd_", ticksExample],
|
||||||
|
[string.Empty, "yyyy-MM-dd.", ticksExample],
|
||||||
|
// [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"],
|
||||||
|
[string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty],
|
||||||
|
[string.Empty, "yyyyMMdd_HHmmss", "_LLS"],
|
||||||
|
[string.Empty, "yyyyMMdd_HHmmss", "_HDR"],
|
||||||
|
["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"],
|
||||||
|
["IMG_", "yyyyMMdd_HHmmss", string.Empty],
|
||||||
|
["IMG#####-", "yyyyMMdd-HHmm", string.Empty],
|
||||||
|
["CameraZOOM-", "yyyyMMddHHmmss", string.Empty],
|
||||||
|
["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty]
|
||||||
|
];
|
||||||
|
foreach (string[] dateFormat in dateFormats)
|
||||||
|
{
|
||||||
|
_ = value.Clear();
|
||||||
|
if (dateFormat.Length != 3)
|
||||||
|
throw new Exception();
|
||||||
|
fullFormat = string.Join(string.Empty, dateFormat);
|
||||||
|
if (fileNameWithoutExtension.Length != fullFormat.Length)
|
||||||
|
continue;
|
||||||
|
format = dateFormat[1];
|
||||||
|
length = dateFormat[0].Length + dateFormat[1].Length;
|
||||||
|
for (int i = dateFormat[0].Length; i < length; i++)
|
||||||
|
_ = value.Append(fileNameWithoutExtension[i]);
|
||||||
|
if (value.Length != format.Length)
|
||||||
|
continue;
|
||||||
|
if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
|
||||||
|
{
|
||||||
|
if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks))
|
||||||
|
result = checkDateTime;
|
||||||
|
else
|
||||||
|
result = new DateTime(ticks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static DateTime GetMinimum(ExifDirectory exifDirectory)
|
||||||
|
{
|
||||||
|
DateTime result;
|
||||||
|
ReadOnlyCollection<DateTime> results = GetDateTimes(exifDirectory);
|
||||||
|
result = results.Count == 0 ? DateTime.MinValue : results.Min();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (int Season, string seasonName) GetSeason(int dayOfYear)
|
||||||
|
{
|
||||||
|
(int Season, string seasonName) result = dayOfYear switch
|
||||||
|
{
|
||||||
|
< 78 => new(0, "Winter"),
|
||||||
|
< 124 => new(1, "Spring"),
|
||||||
|
< 171 => new(2, "Spring"),
|
||||||
|
< 217 => new(3, "Summer"),
|
||||||
|
< 264 => new(4, "Summer"),
|
||||||
|
< 309 => new(5, "Fall"),
|
||||||
|
< 354 => new(6, "Fall"),
|
||||||
|
_ => new(7, "Winter")
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory)
|
||||||
|
{
|
||||||
|
DateTime? result;
|
||||||
|
List<DateTime> results = [];
|
||||||
|
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
||||||
|
{
|
||||||
|
if (exifDirectoryBase.DateTimeOriginal is not null)
|
||||||
|
results.Add(exifDirectoryBase.DateTimeOriginal.Value);
|
||||||
|
}
|
||||||
|
foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories)
|
||||||
|
{
|
||||||
|
if (aviDirectory.DateTimeOriginal is not null)
|
||||||
|
results.Add(aviDirectory.DateTimeOriginal.Value);
|
||||||
|
}
|
||||||
|
foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories)
|
||||||
|
{
|
||||||
|
if (quickTimeMovieHeaderDirectory.Created is not null)
|
||||||
|
{
|
||||||
|
if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1)
|
||||||
|
continue;
|
||||||
|
results.Add(quickTimeMovieHeaderDirectory.Created.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories)
|
||||||
|
{
|
||||||
|
if (quickTimeTrackHeaderDirectory.Created is not null)
|
||||||
|
{
|
||||||
|
if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1)
|
||||||
|
continue;
|
||||||
|
results.Add(quickTimeTrackHeaderDirectory.Created.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = results.Count == 0 ? null : results.Min();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory)
|
||||||
|
{
|
||||||
|
string[] results = [];
|
||||||
|
bool? result = null;
|
||||||
|
string year;
|
||||||
|
string directoryName;
|
||||||
|
string[] directorySegments;
|
||||||
|
List<DateTime> collection = [];
|
||||||
|
string? check = Path.GetFullPath(filePath.FullName);
|
||||||
|
DateTime? dateTimeOriginal = GetDateTimeOriginal(exifDirectory);
|
||||||
|
if (dateTimeOriginal is not null)
|
||||||
|
collection.Add(dateTimeOriginal.Value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<DateTime> dateTimes = GetDateTimes(exifDirectory);
|
||||||
|
foreach (DateTime dateTime in dateTimes)
|
||||||
|
collection.Add(dateTime);
|
||||||
|
}
|
||||||
|
foreach (DateTime dateTime in collection)
|
||||||
|
{
|
||||||
|
year = dateTime.ToString("yyyy");
|
||||||
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
|
{
|
||||||
|
check = Path.GetDirectoryName(check);
|
||||||
|
if (string.IsNullOrEmpty(check))
|
||||||
|
break;
|
||||||
|
directoryName = Path.GetFileName(check);
|
||||||
|
directorySegments = directoryName.Split(' ');
|
||||||
|
(result, results) = IsWrongYear(directorySegments, year);
|
||||||
|
if (result is not null)
|
||||||
|
break;
|
||||||
|
if (check == directoryInfo.FullName)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result is not null && !result.Value)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new(result, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Record IsWrongYear(string[] segments, string year)
|
||||||
|
{
|
||||||
|
Record result;
|
||||||
|
bool? check;
|
||||||
|
string[] results = (
|
||||||
|
from l
|
||||||
|
in segments
|
||||||
|
where l?.Length > 2
|
||||||
|
&& (
|
||||||
|
l[..2] is "18" or "19" or "20"
|
||||||
|
|| (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|
||||||
|
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|
||||||
|
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
|
||||||
|
)
|
||||||
|
select l
|
||||||
|
).ToArray();
|
||||||
|
string[] matches = (
|
||||||
|
from l
|
||||||
|
in results
|
||||||
|
where l == year
|
||||||
|
|| (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#'))
|
||||||
|
|| (l.Length == 6 && l[..4] == year && l[4] == '.')
|
||||||
|
|| (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.')
|
||||||
|
select l
|
||||||
|
).ToArray();
|
||||||
|
if (results.Length == 0)
|
||||||
|
check = null;
|
||||||
|
else
|
||||||
|
check = matches.Length == 0;
|
||||||
|
result = new(check, results);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Record(bool? IsWrongYear, string[] Years);
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -67,57 +68,6 @@ internal abstract partial class XDirectory
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<FilePair> filePairs, string jsonGroupDirectory, string extension)
|
|
||||||
{
|
|
||||||
FileInfo? toFileInfo;
|
|
||||||
FileInfo fromFileInfo;
|
|
||||||
string checkDirectory;
|
|
||||||
List<(string, string)> rename = [];
|
|
||||||
foreach (FilePair filePair in filePairs)
|
|
||||||
{
|
|
||||||
if (filePair.IsUnique)
|
|
||||||
continue;
|
|
||||||
IsNotUniqueLoop(propertyConfiguration, jsonGroupDirectory, extension, filePair, rename);
|
|
||||||
}
|
|
||||||
foreach ((string from, string to) in rename)
|
|
||||||
{
|
|
||||||
toFileInfo = null;
|
|
||||||
checkDirectory = to;
|
|
||||||
fromFileInfo = new(from);
|
|
||||||
if (!fromFileInfo.Exists)
|
|
||||||
continue;
|
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
|
||||||
{
|
|
||||||
toFileInfo = new(checkDirectory);
|
|
||||||
if (toFileInfo.Directory is null)
|
|
||||||
continue;
|
|
||||||
if (!toFileInfo.Directory.Exists)
|
|
||||||
_ = Directory.CreateDirectory(toFileInfo.Directory.FullName);
|
|
||||||
if (checkDirectory.Length > 199)
|
|
||||||
throw new Exception();
|
|
||||||
if (!toFileInfo.Exists)
|
|
||||||
break;
|
|
||||||
else if (fromFileInfo.Length == toFileInfo.Length && fromFileInfo.LastWriteTime == toFileInfo.LastWriteTime)
|
|
||||||
checkDirectory = string.Concat(checkDirectory, ".del");
|
|
||||||
else
|
|
||||||
checkDirectory = string.Concat(checkDirectory, ".j");
|
|
||||||
}
|
|
||||||
File.Move(from, checkDirectory);
|
|
||||||
}
|
|
||||||
return rename.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void IsNotUniqueLoop(Properties.IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, FilePair filePair, List<(string, string)> rename)
|
|
||||||
{
|
|
||||||
int length = propertyConfiguration.RootDirectory.Length;
|
|
||||||
foreach (string path in filePair.Collection)
|
|
||||||
{
|
|
||||||
if (filePair.Match is null || path != filePair.Match)
|
|
||||||
continue;
|
|
||||||
rename.Add(new(path, string.Concat(jsonGroupDirectory, filePair.Path[length..], extension)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage)
|
internal static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage)
|
||||||
{
|
{
|
||||||
List<string[]> results = [];
|
List<string[]> results = [];
|
||||||
@ -173,7 +123,54 @@ internal abstract partial class XDirectory
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
internal static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<Models.FilePair> filePairs, string jsonGroupDirectory, string extension)
|
||||||
|
{
|
||||||
|
FileInfo? toFileInfo;
|
||||||
|
string checkDirectory;
|
||||||
|
List<(FilePath, string)> rename = [];
|
||||||
|
foreach (Models.FilePair filePair in filePairs)
|
||||||
|
{
|
||||||
|
if (filePair.IsUnique)
|
||||||
|
continue;
|
||||||
|
IsNotUniqueLoop(propertyConfiguration, jsonGroupDirectory, extension, filePair, rename);
|
||||||
|
}
|
||||||
|
foreach ((FilePath from, string to) in rename)
|
||||||
|
{
|
||||||
|
toFileInfo = null;
|
||||||
|
checkDirectory = to;
|
||||||
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
|
{
|
||||||
|
toFileInfo = new(checkDirectory);
|
||||||
|
if (toFileInfo.Directory is null)
|
||||||
|
continue;
|
||||||
|
if (!toFileInfo.Directory.Exists)
|
||||||
|
_ = Directory.CreateDirectory(toFileInfo.Directory.FullName);
|
||||||
|
if (checkDirectory.Length > 199)
|
||||||
|
throw new Exception();
|
||||||
|
if (!toFileInfo.Exists)
|
||||||
|
break;
|
||||||
|
else if (from.Length == toFileInfo.Length && from.LastWriteTicks == toFileInfo.LastWriteTime.Ticks)
|
||||||
|
checkDirectory = string.Concat(checkDirectory, ".del");
|
||||||
|
else
|
||||||
|
checkDirectory = string.Concat(checkDirectory, ".j");
|
||||||
|
}
|
||||||
|
File.Move(from.FullName, checkDirectory);
|
||||||
|
}
|
||||||
|
return rename.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void IsNotUniqueLoop(Properties.IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, Models.FilePair filePair, List<(FilePath, string)> rename)
|
||||||
|
{
|
||||||
|
int length = propertyConfiguration.RootDirectory.Length;
|
||||||
|
foreach (FilePath path in filePair.Collection)
|
||||||
|
{
|
||||||
|
if (filePair.Match is null || path != filePair.Match)
|
||||||
|
continue;
|
||||||
|
rename.Add(new(path, string.Concat(jsonGroupDirectory, filePair.FilePath.FullName[length..], extension)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, bool useIgnoreExtensions)
|
||||||
{
|
{
|
||||||
List<ReadOnlyCollection<FilePath>> results = [];
|
List<ReadOnlyCollection<FilePath>> results = [];
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
@ -185,70 +182,72 @@ internal abstract partial class XDirectory
|
|||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
fileHolder = IFileHolder.Get(file);
|
fileHolder = IFileHolder.Get(file);
|
||||||
if (propertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
if (!fileHolder.Exists)
|
||||||
|
continue;
|
||||||
|
if (useIgnoreExtensions && propertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
continue;
|
continue;
|
||||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
filePaths.Add(filePath);
|
filePaths.Add(filePath);
|
||||||
}
|
}
|
||||||
results.Add(new(filePaths));
|
results.Add(filePaths.AsReadOnly());
|
||||||
}
|
}
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useCeilingAverage)
|
internal static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage)
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> results;
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> results;
|
||||||
ReadOnlyCollection<string[]> filesCollection = GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
ReadOnlyCollection<string[]> filesCollection = GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
results = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
|
results = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles)
|
internal static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles)
|
||||||
{
|
{
|
||||||
List<FilePair> results = [];
|
List<Models.FilePair> results = [];
|
||||||
string? match;
|
FilePath? match;
|
||||||
FilePair filePair;
|
|
||||||
bool uniqueFileName;
|
bool uniqueFileName;
|
||||||
List<string>? collection;
|
Models.FilePair filePair;
|
||||||
bool? isNotUniqueAndNeedsReview;
|
bool? isNotUniqueAndNeedsReview;
|
||||||
string fileNameWithoutExtensionMinusOne;
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||||
{
|
{
|
||||||
foreach (FilePath filePath in filePaths)
|
foreach (FilePath filePath in filePaths)
|
||||||
{
|
{
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
isNotUniqueAndNeedsReview = null;
|
isNotUniqueAndNeedsReview = null;
|
||||||
if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered))
|
if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered))
|
||||||
continue;
|
continue;
|
||||||
fileNameWithoutExtensionMinusOne = filePath.NameWithoutExtension[..^1];
|
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||||
if (!fileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
|
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
uniqueFileName = collection.Count == 1;
|
uniqueFileName = collection.Count == 1;
|
||||||
if (!uniqueFileName)
|
if (!uniqueFileName)
|
||||||
isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath.FullName, collection);
|
isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath, collection);
|
||||||
if (!compareFileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
|
if (!compareFileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||||
filePair = new(Path: filePath.FullName,
|
filePair = new(FilePath: filePath,
|
||||||
IsUnique: uniqueFileName,
|
IsUnique: uniqueFileName,
|
||||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||||
Collection: [],
|
Collection: new([]),
|
||||||
Match: null);
|
Match: null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (collection.Count == 0)
|
if (collection.Count == 0)
|
||||||
filePair = new(Path: filePath.FullName,
|
filePair = new(FilePath: filePath,
|
||||||
IsUnique: uniqueFileName,
|
IsUnique: uniqueFileName,
|
||||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||||
Collection: collection,
|
Collection: collection,
|
||||||
Match: null);
|
Match: null);
|
||||||
else if (uniqueFileName && collection.Count == 1)
|
else if (uniqueFileName && collection.Count == 1)
|
||||||
filePair = new(Path: filePath.FullName,
|
filePair = new(FilePath: filePath,
|
||||||
IsUnique: uniqueFileName,
|
IsUnique: uniqueFileName,
|
||||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||||
Collection: collection,
|
Collection: collection,
|
||||||
Match: collection.First());
|
Match: collection.First());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
match = GetMatch(filePath.FullName, collection);
|
match = GetMatch(filePath, collection);
|
||||||
filePair = new(Path: filePath.FullName,
|
filePair = new(FilePath: filePath,
|
||||||
IsUnique: uniqueFileName,
|
IsUnique: uniqueFileName,
|
||||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||||
Collection: collection,
|
Collection: collection,
|
||||||
@ -261,19 +260,20 @@ internal abstract partial class XDirectory
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool GetIsNotUniqueAndNeedsReview(string file, List<string> collection)
|
private static bool GetIsNotUniqueAndNeedsReview(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
FileInfo possibleFileInfo;
|
long max;
|
||||||
FileInfo fileInfo = new(file);
|
foreach (FilePath possible in collection)
|
||||||
foreach (string possible in collection)
|
|
||||||
{
|
{
|
||||||
if (possible == file)
|
if (possible.FullName == filePath.FullName)
|
||||||
continue;
|
continue;
|
||||||
possibleFileInfo = new(possible);
|
if (possible.LastWriteTicks != filePath.LastWriteTicks)
|
||||||
if (possibleFileInfo.LastWriteTime != fileInfo.LastWriteTime)
|
{
|
||||||
File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Max());
|
max = new long[] { possible.LastWriteTicks, filePath.LastWriteTicks }.Max();
|
||||||
if (possibleFileInfo.LastWriteTime == fileInfo.LastWriteTime && possibleFileInfo.Length == fileInfo.Length)
|
File.SetLastWriteTime(filePath.FullName, new DateTime(max));
|
||||||
|
}
|
||||||
|
if (possible.LastWriteTicks == filePath.LastWriteTicks && possible.Length == filePath.Length)
|
||||||
continue;
|
continue;
|
||||||
if (!result)
|
if (!result)
|
||||||
result = true;
|
result = true;
|
||||||
@ -281,50 +281,48 @@ internal abstract partial class XDirectory
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? GetMatch(string file, List<string> collection)
|
private static FilePath? GetMatch(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||||
{
|
{
|
||||||
string? result = null;
|
FilePath? result = null;
|
||||||
FileInfo possibleFileInfo;
|
|
||||||
List<long> lengths = [];
|
List<long> lengths = [];
|
||||||
List<string> matches = [];
|
List<FilePath> matches = [];
|
||||||
FileInfo fileInfo = new(file);
|
List<long> lastWriteTicks = [];
|
||||||
List<DateTime> creationTimes = [];
|
foreach (FilePath possible in collection)
|
||||||
foreach (string possible in collection)
|
|
||||||
{
|
{
|
||||||
possibleFileInfo = new(possible);
|
lengths.Add(possible.Length);
|
||||||
lengths.Add(possibleFileInfo.Length);
|
lastWriteTicks.Add(possible.LastWriteTicks);
|
||||||
creationTimes.Add(possibleFileInfo.CreationTime);
|
if (possible.LastWriteTicks != filePath.LastWriteTicks)
|
||||||
if (possibleFileInfo.CreationTime != fileInfo.LastWriteTime)
|
|
||||||
continue;
|
continue;
|
||||||
matches.Add(possible);
|
matches.Add(possible);
|
||||||
}
|
}
|
||||||
if (matches.Count == 1 || (matches.Count > 0 && lengths.Distinct().Count() == 1 && creationTimes.Distinct().Count() == 1))
|
if (matches.Count == 1 || (matches.Count > 0 && lengths.Distinct().Count() == 1 && lastWriteTicks.Distinct().Count() == 1))
|
||||||
result = matches.First();
|
result = matches.First();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups, Action? tick)
|
internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, Action? tick)
|
||||||
{
|
{
|
||||||
List<(FilePath, string)> results = [];
|
List<(FilePath, string)> results = [];
|
||||||
string paddedId;
|
string paddedId;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
string directory;
|
string directory;
|
||||||
FileInfo fileInfo;
|
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
|
DateTime? dateTime;
|
||||||
string paddedIdFile;
|
string paddedIdFile;
|
||||||
bool wrapped = false;
|
bool wrapped = false;
|
||||||
string intelligentId;
|
string intelligentId;
|
||||||
CombinedEnumAndIndex cei;
|
bool? hasIgnoreKeyword;
|
||||||
bool paddedCheck = false;
|
bool paddedCheck = false;
|
||||||
|
CombinedEnumAndIndex cei;
|
||||||
string fileDirectoryName;
|
string fileDirectoryName;
|
||||||
|
bool? hasDateTimeOriginal;
|
||||||
List<int> distinctIds = [];
|
List<int> distinctIds = [];
|
||||||
List<string> distinct = [];
|
List<string> distinct = [];
|
||||||
|
ExifDirectory? exifDirectory;
|
||||||
Models.FileHolder fileHolder;
|
Models.FileHolder fileHolder;
|
||||||
|
ReadOnlyCollection<string> keywords;
|
||||||
List<string> distinctDirectories = [];
|
List<string> distinctDirectories = [];
|
||||||
FilePath[] sortedRecords = GetSortedRecords(filePathsCollection);
|
FilePath[] sortedRecords = GetSortedRecords(filePathsCollection);
|
||||||
ReadOnlyDictionary<byte, ReadOnlyCollection<string>>? keyValuePairs;
|
|
||||||
if (!fileGroups.TryGetValue(propertyConfiguration.ResultContent, out keyValuePairs))
|
|
||||||
throw new NotImplementedException();
|
|
||||||
bool isOffsetDeterministicHashCode = IId.IsOffsetDeterministicHashCode(propertyConfiguration);
|
bool isOffsetDeterministicHashCode = IId.IsOffsetDeterministicHashCode(propertyConfiguration);
|
||||||
for (int i = 0; i < sortedRecords.Length; i++)
|
for (int i = 0; i < sortedRecords.Length; i++)
|
||||||
{
|
{
|
||||||
@ -338,23 +336,45 @@ internal abstract partial class XDirectory
|
|||||||
{
|
{
|
||||||
if (wrapped)
|
if (wrapped)
|
||||||
continue;
|
continue;
|
||||||
directory = keyValuePairs[cei.Enum][cei.Index];
|
if (cei.Enum == 0)
|
||||||
|
continue;
|
||||||
|
directory = fileGroups[cei.Enum][cei.Index];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!wrapped)
|
if (!wrapped)
|
||||||
wrapped = true;
|
wrapped = true;
|
||||||
directory = Path.Combine(keyValuePairs[cei.Enum][cei.Index], fileDirectoryName);
|
directory = Path.Combine(fileGroups[cei.Enum][cei.Index], fileDirectoryName);
|
||||||
}
|
}
|
||||||
if (ifCanUseId && filePath.IsIntelligentIdFormat && filePath.Id is not null && filePath.DirectoryFullPath is not null)
|
if (ifCanUseId && filePath.IsIntelligentIdFormat && filePath.Id is not null && filePath.DirectoryFullPath is not null)
|
||||||
{
|
{
|
||||||
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, i);
|
if (filePath.Id == -748161839 || filePath.FileNameFirstSegment == "740318810015")
|
||||||
|
{
|
||||||
|
if (filePath.ExtensionLowered == ".mov") // -748161839)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
if (exifDirectoriesById is null || !exifDirectoriesById.TryGetValue(filePath.Id.Value, out exifDirectory))
|
||||||
|
{
|
||||||
|
hasIgnoreKeyword = filePath.HasIgnoreKeyword;
|
||||||
|
hasDateTimeOriginal = filePath.HasDateTimeOriginal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
|
hasDateTimeOriginal = dateTime is not null;
|
||||||
|
if (dateTime is null && propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||||
|
continue;
|
||||||
|
keywords = MetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||||
|
hasIgnoreKeyword = propertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
||||||
|
}
|
||||||
|
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.ExtensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, i);
|
||||||
paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}");
|
paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}");
|
||||||
if (!File.Exists(paddedIdFile))
|
if (!File.Exists(paddedIdFile))
|
||||||
{
|
{
|
||||||
File.Move(filePath.FullName, paddedIdFile);
|
File.Move(filePath.FullName, paddedIdFile);
|
||||||
fileInfo = new(paddedIdFile);
|
fileHolder = IFileHolder.Get(paddedIdFile);
|
||||||
fileHolder = Models.FileHolder.Get(fileInfo);
|
if (!fileHolder.Exists)
|
||||||
|
continue;
|
||||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
if (!paddedCheck)
|
if (!paddedCheck)
|
||||||
paddedCheck = true;
|
paddedCheck = true;
|
||||||
@ -365,15 +385,20 @@ internal abstract partial class XDirectory
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (filePath.Id is null)
|
if (filePath.Id is null)
|
||||||
|
{
|
||||||
|
if (Debugger.IsAttached)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
throw new NullReferenceException(nameof(filePath.Id));
|
throw new NullReferenceException(nameof(filePath.Id));
|
||||||
intelligentId = IId.GetIntelligentId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
}
|
||||||
|
intelligentId = IId.GetIntelligentId(propertyConfiguration, filePath.Id.Value, filePath.ExtensionLowered, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
||||||
if (!isOffsetDeterministicHashCode)
|
if (!isOffsetDeterministicHashCode)
|
||||||
checkFile = Path.Combine(directory, $"{intelligentId}{filePath.ExtensionLowered}");
|
checkFile = Path.Combine(directory, $"{intelligentId}{filePath.ExtensionLowered}");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (filePath.DirectoryFullPath is null)
|
if (filePath.DirectoryFullPath is null)
|
||||||
continue;
|
continue;
|
||||||
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, i);
|
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.ExtensionLowered, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, i);
|
||||||
paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}");
|
paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}");
|
||||||
if (File.Exists(paddedIdFile))
|
if (File.Exists(paddedIdFile))
|
||||||
continue;
|
continue;
|
||||||
@ -391,8 +416,8 @@ internal abstract partial class XDirectory
|
|||||||
continue;
|
continue;
|
||||||
for (int j = 1; j < int.MaxValue; j++)
|
for (int j = 1; j < int.MaxValue; j++)
|
||||||
{
|
{
|
||||||
fileInfo = new(checkFile);
|
fileHolder = IFileHolder.Get(checkFile);
|
||||||
if (!fileInfo.Exists || filePath.Length == fileInfo.Length && filePath.LastWriteTicks == fileInfo.LastWriteTime.Ticks)
|
if (!fileHolder.Exists || fileHolder.LastWriteTime is null || filePath.Length == fileHolder.Length && filePath.LastWriteTicks == fileHolder.LastWriteTime.Value.Ticks)
|
||||||
checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}dup{filePath.ExtensionLowered}");
|
checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}dup{filePath.ExtensionLowered}");
|
||||||
else
|
else
|
||||||
checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}why{filePath.ExtensionLowered}");
|
checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}why{filePath.ExtensionLowered}");
|
||||||
|
@ -58,15 +58,30 @@ internal abstract class XPath
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath, string fileNameFirstSegment)
|
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(IPropertyConfiguration propertyConfiguration, FilePath filePath, string fileNameWithoutExtension)
|
||||||
{
|
{
|
||||||
CombinedEnumAndIndex result;
|
CombinedEnumAndIndex result;
|
||||||
|
byte @enum;
|
||||||
int converted;
|
int converted;
|
||||||
string combined;
|
string combined;
|
||||||
byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePath);
|
||||||
string check = fileNameFirstSegment.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength ?
|
if (!filePath.IsIntelligentIdFormat)
|
||||||
|
@enum = missingDateTimeOriginal;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null)
|
||||||
|
throw new NotImplementedException("Chicken and Egg!");
|
||||||
|
if (filePath.HasIgnoreKeyword.Value)
|
||||||
|
@enum = IId.GetHasIgnoreKeyword(filePath);
|
||||||
|
else if (!filePath.HasDateTimeOriginal.Value)
|
||||||
|
@enum = missingDateTimeOriginal;
|
||||||
|
else
|
||||||
|
@enum = IId.GetHasDateTimeOriginal(propertyConfiguration, filePath);
|
||||||
|
}
|
||||||
|
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
|
||||||
|
string check = fileNameBeforeFirst.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength ?
|
||||||
new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength) :
|
new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength) :
|
||||||
fileNameFirstSegment.Split('.')[0][^propertyConfiguration.ResultAllInOneSubdirectoryLength..];
|
fileNameBeforeFirst[^propertyConfiguration.ResultAllInOneSubdirectoryLength..];
|
||||||
if (check.Any(l => !char.IsNumber(l)))
|
if (check.Any(l => !char.IsNumber(l)))
|
||||||
{
|
{
|
||||||
combined = $"{@enum}{new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength)}";
|
combined = $"{@enum}{new('-', propertyConfiguration.ResultAllInOneSubdirectoryLength)}";
|
||||||
@ -81,6 +96,9 @@ internal abstract class XPath
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static byte GetEnum(FilePath filePath) =>
|
||||||
|
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
||||||
|
|
||||||
private static byte GetEnum(bool? ik, bool? dto)
|
private static byte GetEnum(bool? ik, bool? dto)
|
||||||
{
|
{
|
||||||
byte result;
|
byte result;
|
||||||
@ -107,9 +125,6 @@ internal abstract class XPath
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte GetEnum(FilePath filePath) =>
|
|
||||||
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
|
||||||
|
|
||||||
internal static List<string> GetDirectories(string directory)
|
internal static List<string> GetDirectories(string directory)
|
||||||
{
|
{
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
@ -218,6 +233,20 @@ internal abstract class XPath
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void CreateDirectories(ReadOnlyCollection<string> directories)
|
||||||
|
{
|
||||||
|
string checkDirectory;
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 101; i++)
|
||||||
|
{
|
||||||
|
checkDirectory = Path.Combine(directory, i.ToString("000"));
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
|
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
|
||||||
{
|
{
|
||||||
DateTime dateTime = new(ticks);
|
DateTime dateTime = new(ticks);
|
||||||
@ -401,22 +430,23 @@ internal abstract class XPath
|
|||||||
|
|
||||||
private static byte[] GetBytes() =>
|
private static byte[] GetBytes() =>
|
||||||
[
|
[
|
||||||
11,
|
0,
|
||||||
15,
|
1,
|
||||||
19,
|
2,
|
||||||
51,
|
3,
|
||||||
55,
|
4,
|
||||||
59,
|
5,
|
||||||
91,
|
6,
|
||||||
95,
|
7,
|
||||||
99
|
8,
|
||||||
|
9
|
||||||
];
|
];
|
||||||
|
|
||||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
|
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
|
||||||
{
|
{
|
||||||
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
||||||
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
||||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
|
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
|
||||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -162,8 +162,8 @@ public partial class UnitTestCalculations
|
|||||||
width = 100;
|
width = 100;
|
||||||
height = 100;
|
height = 100;
|
||||||
Location location = new(bottom, confidence, left, right, top);
|
Location location = new(bottom, confidence, left, right, top);
|
||||||
_ = new Location(confidence, height, location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, 1);
|
_ = new Location(confidence, height, location, width, 1);
|
||||||
_ = new Location(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
|
_ = new Location(bottom, confidence, height, left, right, top, width, 1);
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ public partial class UnitTestCalculations
|
|||||||
bottom = 50;
|
bottom = 50;
|
||||||
width = 100;
|
width = 100;
|
||||||
height = 100;
|
height = 100;
|
||||||
location = new(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
|
location = new(bottom, confidence, height, left, right, top, width, 1);
|
||||||
areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, height, location, width);
|
areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, height, location, width);
|
||||||
Assert.IsTrue(areaPermyriad == 2500);
|
Assert.IsTrue(areaPermyriad == 2500);
|
||||||
left = 0;
|
left = 0;
|
||||||
@ -197,7 +197,7 @@ public partial class UnitTestCalculations
|
|||||||
bottom = 25;
|
bottom = 25;
|
||||||
width = 100;
|
width = 100;
|
||||||
height = 100;
|
height = 100;
|
||||||
location = new(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
|
location = new(bottom, confidence, height, left, right, top, width, 1);
|
||||||
OutputResolution outputResolution = new(height, 0, width);
|
OutputResolution outputResolution = new(height, 0, width);
|
||||||
areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, location, outputResolution);
|
areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, location, outputResolution);
|
||||||
Assert.IsTrue(areaPermyriad == 625);
|
Assert.IsTrue(areaPermyriad == 625);
|
||||||
|
@ -54,6 +54,55 @@ public partial class UnitTestHardCoded
|
|||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodId()
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
id = 748161839;
|
||||||
|
string imageTrueTruePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: true, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700398", imageTrueTruePositive);
|
||||||
|
string imageTrueFalsePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: true, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700398", imageTrueFalsePositive);
|
||||||
|
string imageFalseFalsePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: false, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700397", imageFalseFalsePositive);
|
||||||
|
string imageFalseTruePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: false, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700399", imageFalseTruePositive);
|
||||||
|
try
|
||||||
|
{ string videoTrueTruePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: true, hasDateTimeOriginal: true, index: null); }
|
||||||
|
catch (Exception)
|
||||||
|
{ }
|
||||||
|
try
|
||||||
|
{ string videoTrueFalsePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: true, hasDateTimeOriginal: false, index: null); }
|
||||||
|
catch (Exception)
|
||||||
|
{ }
|
||||||
|
string videoFalseFalsePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: false, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700395", videoFalseFalsePositive);
|
||||||
|
string videoFalseTruePositive = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: false, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700396", videoFalseTruePositive);
|
||||||
|
id = -748161839;
|
||||||
|
string imageTrueTrueNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: true, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700392", imageTrueTrueNegative);
|
||||||
|
string imageTrueFalseNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: true, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700392", imageTrueFalseNegative);
|
||||||
|
string imageFalseFalseNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: false, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700393", imageFalseFalseNegative);
|
||||||
|
string imageFalseTrueNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".jpg", hasIgnoreKeyword: false, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700391", imageFalseTrueNegative);
|
||||||
|
try
|
||||||
|
{ string videoTrueTrueNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: true, hasDateTimeOriginal: true, index: null); }
|
||||||
|
catch (Exception)
|
||||||
|
{ }
|
||||||
|
try
|
||||||
|
{ string videoTrueFalseNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: true, hasDateTimeOriginal: false, index: null); }
|
||||||
|
catch (Exception)
|
||||||
|
{ }
|
||||||
|
string videoFalseFalseNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: false, hasDateTimeOriginal: false, index: null);
|
||||||
|
Assert.AreEqual("816184700390", videoFalseFalseNegative);
|
||||||
|
string videoFalseTrueNegative = IId.GetPaddedId(_PropertyConfiguration, id, ".mov", hasIgnoreKeyword: false, hasDateTimeOriginal: true, index: null);
|
||||||
|
Assert.AreEqual("816184700394", videoFalseTrueNegative);
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
private static void NonThrowTryCatch()
|
private static void NonThrowTryCatch()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -61,18 +110,6 @@ public partial class UnitTestHardCoded
|
|||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TestMethodNull()
|
|
||||||
{
|
|
||||||
Assert.IsFalse(_AppSettings is null);
|
|
||||||
Assert.IsFalse(_Configuration is null);
|
|
||||||
Assert.IsFalse(_IsEnvironment is null);
|
|
||||||
Assert.IsFalse(_WorkingDirectory is null);
|
|
||||||
Assert.IsFalse(_ConfigurationRoot is null);
|
|
||||||
Assert.IsFalse(_PropertyConfiguration is null);
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodDel()
|
public void TestMethodDel()
|
||||||
{
|
{
|
||||||
@ -86,30 +123,6 @@ public partial class UnitTestHardCoded
|
|||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TestMethodGetApproximateYears()
|
|
||||||
{
|
|
||||||
string personDisplayDirectory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A2)People/{_Git}", "/{}/^/Sydney Dupray^9");
|
|
||||||
if (Directory.Exists(Directory.GetDirectoryRoot(personDisplayDirectory)) && Directory.Exists(personDisplayDirectory))
|
|
||||||
{
|
|
||||||
char numberSign = '#';
|
|
||||||
string? minusOne = null;
|
|
||||||
char[] personCharacters = ['^'];
|
|
||||||
string personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory);
|
|
||||||
string personBirthdayFormat = _Configuration.PropertyConfiguration.PersonBirthdayFormat;
|
|
||||||
string[] personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
List<(string, PersonBirthday)> collection = IPersonBirthday.GetPersonBirthdays(personBirthdayFormat, personKeyDirectories, personDisplayDirectoryName);
|
|
||||||
int? approximateYears = IAge.GetApproximateYears(personCharacters, personDisplayDirectoryName);
|
|
||||||
if (approximateYears is null)
|
|
||||||
throw new NullReferenceException(nameof(approximateYears));
|
|
||||||
Assert.IsNotNull(approximateYears);
|
|
||||||
Assert.IsTrue(approximateYears.Value == 9);
|
|
||||||
string? change = IPersonContainer.VerifyAge(numberSign, personDisplayDirectory, minusOne, personDisplayDirectoryName, approximateYears, collection);
|
|
||||||
Assert.IsNull(change);
|
|
||||||
}
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodDel2()
|
public void TestMethodDel2()
|
||||||
{
|
{
|
||||||
@ -123,14 +136,35 @@ public partial class UnitTestHardCoded
|
|||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (string?, string, string) Get(string[] segments)
|
[TestMethod]
|
||||||
|
public void TestMethodNull()
|
||||||
{
|
{
|
||||||
(string?, string, string) result;
|
Assert.IsNotNull(_AppSettings);
|
||||||
if ((!segments[0].Contains('#') && (segments[3].Contains('~') || segments[3].Contains('#'))) || (segments[0].Contains('#') && !segments[3].Contains('#')))
|
Assert.IsNotNull(_Configuration);
|
||||||
result = new(null, segments[3], segments[4]);
|
Assert.IsNotNull(_IsEnvironment);
|
||||||
else
|
Assert.IsNotNull(_WorkingDirectory);
|
||||||
result = new(segments[0], segments[3], segments[4]);
|
Assert.IsNotNull(_ConfigurationRoot);
|
||||||
return result;
|
Assert.IsNotNull(_PropertyConfiguration);
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodRename()
|
||||||
|
{
|
||||||
|
// string $directory = "D:/2-Images-B/Not-Copy-Copy-{_Git}";
|
||||||
|
string directory = $"D:/1-Images-A/Images-{_Git}";
|
||||||
|
// string $directory = "D:/2-Images-B/Not-Copy-Copy-{_Git}";
|
||||||
|
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
string[] directories = Directory.GetDirectories(directory, "*;*", SearchOption.AllDirectories);
|
||||||
|
foreach (string subDirectory in directories.OrderByDescending(l => l.Length - l.Replace(@"\", string.Empty).Length))
|
||||||
|
{
|
||||||
|
if (!subDirectory.EndsWith(";9"))
|
||||||
|
continue;
|
||||||
|
Directory.Move(subDirectory, $"{subDirectory[..^2]} !9");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -189,64 +223,14 @@ public partial class UnitTestHardCoded
|
|||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
private static (string?, string, string) Get(string[] segments)
|
||||||
public void TestMethodRenameAbandoned()
|
|
||||||
{
|
{
|
||||||
string directory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A2)People/{_Git}", "/{}/!/Abandoned");
|
(string?, string, string) result;
|
||||||
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
if ((!segments[0].Contains('#') && (segments[3].Contains('~') || segments[3].Contains('#'))) || (segments[0].Contains('#') && !segments[3].Contains('#')))
|
||||||
{
|
result = new(null, segments[3], segments[4]);
|
||||||
string checkFile;
|
else
|
||||||
string[] files = Directory.GetFiles(directory, "*.abd", SearchOption.TopDirectoryOnly);
|
result = new(segments[0], segments[3], segments[4]);
|
||||||
foreach (string file in files)
|
return result;
|
||||||
{
|
|
||||||
checkFile = file[..^4];
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
}
|
|
||||||
Assert.IsTrue(true);
|
|
||||||
}
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TestMethodRenameDelete()
|
|
||||||
{
|
|
||||||
string directory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A)Property/{_Git}", "/{}");
|
|
||||||
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
|
||||||
{
|
|
||||||
string checkFile;
|
|
||||||
string[] files = Directory.GetFiles(directory, "*.del", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
checkFile = file[..^4];
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
}
|
|
||||||
Assert.IsTrue(true);
|
|
||||||
}
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TestMethodRenameOld()
|
|
||||||
{
|
|
||||||
string directory = $"D:/1-Images-A/Images-{_Git}-Results/E)Distance/{_Git}/()";
|
|
||||||
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
|
||||||
{
|
|
||||||
string checkFile;
|
|
||||||
string[] files = Directory.GetFiles(directory, "*.old", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
checkFile = file[..^4];
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
}
|
|
||||||
Assert.IsTrue(true);
|
|
||||||
}
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -285,33 +269,59 @@ public partial class UnitTestHardCoded
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodRename()
|
public void TestMethodRenameOld()
|
||||||
{
|
{
|
||||||
// string $directory = "D:/2-Images-B/Not-Copy-Copy-{_Git}";
|
string directory = $"D:/1-Images-A/Images-{_Git}-Results/E)Distance/{_Git}/()";
|
||||||
string directory = $"D:/1-Images-A/Images-{_Git}";
|
|
||||||
// string $directory = "D:/2-Images-B/Not-Copy-Copy-{_Git}";
|
|
||||||
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
string[] directories = Directory.GetDirectories(directory, "*;*", SearchOption.AllDirectories);
|
string checkFile;
|
||||||
foreach (string subDirectory in directories.OrderByDescending(l => l.Length - l.Replace(@"\", string.Empty).Length))
|
string[] files = Directory.GetFiles(directory, "*.old", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
if (!subDirectory.EndsWith(";9"))
|
checkFile = file[..^4];
|
||||||
|
if (File.Exists(checkFile))
|
||||||
continue;
|
continue;
|
||||||
Directory.Move(subDirectory, $"{subDirectory[..^2]} !9");
|
File.Move(file, checkFile);
|
||||||
}
|
}
|
||||||
|
Assert.IsTrue(true);
|
||||||
}
|
}
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodRenameForUnknown()
|
public void TestMethodImmichAsset()
|
||||||
{
|
{
|
||||||
string directory = $"D:/1-Images-A/Images-{_Git}-Results/E)Distance/{_Git}/(RectInt-2023-06-19-less-0.99)";
|
if (!string.IsNullOrEmpty(_Configuration.ImmichAssetsFile) && File.Exists(_Configuration.ImmichAssetsFile))
|
||||||
|
{
|
||||||
|
Dictionary<string, ImmichAsset> keyValuePairs = [];
|
||||||
|
string json = File.ReadAllText(_Configuration.ImmichAssetsFile);
|
||||||
|
ImmichAsset[]? immichAssets = JsonSerializer.Deserialize(json, ImmichAssetCollectionSourceGenerationContext.Default.ImmichAssetArray);
|
||||||
|
if (immichAssets is not null)
|
||||||
|
{
|
||||||
|
foreach (ImmichAsset immichAsset in immichAssets)
|
||||||
|
keyValuePairs.Add(immichAsset.OriginalPath, immichAsset);
|
||||||
|
}
|
||||||
|
Assert.IsTrue(keyValuePairs.Count > 0);
|
||||||
|
}
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodRenameDelete()
|
||||||
|
{
|
||||||
|
string directory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A)Property/{_Git}", "/{}");
|
||||||
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
string[] files = Directory.GetFiles(directory, "*.unk", SearchOption.AllDirectories);
|
string checkFile;
|
||||||
|
string[] files = Directory.GetFiles(directory, "*.del", SearchOption.AllDirectories);
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
File.Move(file, file[..^4]);
|
{
|
||||||
|
checkFile = file[..^4];
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
}
|
||||||
|
Assert.IsTrue(true);
|
||||||
}
|
}
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
@ -347,19 +357,58 @@ public partial class UnitTestHardCoded
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodImmichAsset()
|
public void TestMethodRenameAbandoned()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_Configuration.ImmichAssetsFile) && File.Exists(_Configuration.ImmichAssetsFile))
|
string directory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A2)People/{_Git}", "/{}/!/Abandoned");
|
||||||
|
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
Dictionary<string, ImmichAsset> keyValuePairs = [];
|
string checkFile;
|
||||||
string json = File.ReadAllText(_Configuration.ImmichAssetsFile);
|
string[] files = Directory.GetFiles(directory, "*.abd", SearchOption.TopDirectoryOnly);
|
||||||
ImmichAsset[]? immichAssets = JsonSerializer.Deserialize(json, ImmichAssetCollectionSourceGenerationContext.Default.ImmichAssetArray);
|
foreach (string file in files)
|
||||||
if (immichAssets is not null)
|
|
||||||
{
|
{
|
||||||
foreach (ImmichAsset immichAsset in immichAssets)
|
checkFile = file[..^4];
|
||||||
keyValuePairs.Add(immichAsset.OriginalPath, immichAsset);
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(file, checkFile);
|
||||||
}
|
}
|
||||||
Assert.IsTrue(keyValuePairs.Count > 0);
|
Assert.IsTrue(true);
|
||||||
|
}
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodRenameForUnknown()
|
||||||
|
{
|
||||||
|
string directory = $"D:/1-Images-A/Images-{_Git}-Results/E)Distance/{_Git}/(RectInt-2023-06-19-less-0.99)";
|
||||||
|
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
string[] files = Directory.GetFiles(directory, "*.unk", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
File.Move(file, file[..^4]);
|
||||||
|
}
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodGetApproximateYears()
|
||||||
|
{
|
||||||
|
string personDisplayDirectory = string.Concat($"D:/1-Images-A/Images-{_Git}-Results/A2)People/{_Git}", "/{}/^/Sydney Dupray^9");
|
||||||
|
if (Directory.Exists(Directory.GetDirectoryRoot(personDisplayDirectory)) && Directory.Exists(personDisplayDirectory))
|
||||||
|
{
|
||||||
|
char numberSign = '#';
|
||||||
|
string? minusOne = null;
|
||||||
|
char[] personCharacters = ['^'];
|
||||||
|
string personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory);
|
||||||
|
string personBirthdayFormat = _Configuration.PropertyConfiguration.PersonBirthdayFormat;
|
||||||
|
string[] personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
List<(string, PersonBirthday)> collection = IPersonBirthday.GetPersonBirthdays(personBirthdayFormat, personKeyDirectories, personDisplayDirectoryName);
|
||||||
|
int? approximateYears = IAge.GetApproximateYears(personCharacters, personDisplayDirectoryName);
|
||||||
|
if (approximateYears is null)
|
||||||
|
throw new NullReferenceException(nameof(approximateYears));
|
||||||
|
Assert.IsNotNull(approximateYears);
|
||||||
|
Assert.AreEqual(9, approximateYears.Value);
|
||||||
|
string? change = IPersonContainer.VerifyAge(numberSign, personDisplayDirectory, minusOne, personDisplayDirectoryName, approximateYears, collection);
|
||||||
|
Assert.IsNull(change);
|
||||||
}
|
}
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,6 @@ public class UnitTestResize
|
|||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void NonThrowTryCatch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{ throw new Exception(); }
|
|
||||||
catch (Exception) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodNull()
|
public void TestMethodNull()
|
||||||
{
|
{
|
||||||
@ -75,13 +68,80 @@ public class UnitTestResize
|
|||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
|
private static void NonThrowTryCatch()
|
||||||
{
|
{
|
||||||
A_Property result;
|
try
|
||||||
if (_Configuration?.PropertyConfiguration is null)
|
{ throw new Exception(); }
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration));
|
catch (Exception) { }
|
||||||
result = new(_AppSettings.MaxDegreeOfParallelism, _PropertyConfiguration, _Configuration.OutputExtension, reverse, aResultsFullGroupDirectory);
|
}
|
||||||
return result;
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodResize()
|
||||||
|
{
|
||||||
|
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||||
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||||
|
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
||||||
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
||||||
|
// string sourceFileName = "100000507001158650387.jpg";
|
||||||
|
// string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
||||||
|
string sourceFileName = "105131603001106320328.jpg";
|
||||||
|
string sourceDirectoryName = "Mike iCloud Have Date Taken 2022 !9";
|
||||||
|
Item item;
|
||||||
|
bool reverse = false;
|
||||||
|
bool isArchive = false;
|
||||||
|
FileHolder resizedFileHolder;
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
List<string> parseExceptions = [];
|
||||||
|
const bool isValidImageFormatExtension = true;
|
||||||
|
List<Tuple<string, DateTime>> subFileTuples = [];
|
||||||
|
int length = _PropertyConfiguration.RootDirectory.Length;
|
||||||
|
string[] changesFrom = [nameof(A_Property)];
|
||||||
|
string outputResolution = _Configuration.OutputResolutions[0];
|
||||||
|
bool outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
|
||||||
|
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
|
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
||||||
|
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_PropertyConfiguration);
|
||||||
|
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
||||||
|
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||||
|
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||||
|
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality);
|
||||||
|
B_Metadata metadata = new(null, _PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, ticks, bResultsFullGroupDirectory);
|
||||||
|
_ = metadata.ToString();
|
||||||
|
C_Resize resize = new(_PropertyConfiguration, _Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension);
|
||||||
|
_ = resize.ToString();
|
||||||
|
bool isUniqueFileName = false;
|
||||||
|
bool? isNotUniqueAndNeedsReview = null;
|
||||||
|
FileHolder sourceDirectoryFileHolder = IFileHolder.Get(".json");
|
||||||
|
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
||||||
|
FileHolder fileHolder = IFileHolder.Get(Path.Combine(sourceDirectory, sourceFileName));
|
||||||
|
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
||||||
|
Assert.IsNotNull(filePath.Id);
|
||||||
|
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
||||||
|
ExifDirectory? exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
|
||||||
|
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
||||||
|
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
||||||
|
if (outputResolutionHasNumber)
|
||||||
|
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||||
|
resize.Update(cResultsFullGroupDirectory);
|
||||||
|
blurHasher.Update(cResultsFullGroupDirectory);
|
||||||
|
item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, exifDirectory, false, false, false);
|
||||||
|
if (item.ExifDirectory is null)
|
||||||
|
throw new NullReferenceException(nameof(item.ExifDirectory));
|
||||||
|
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, filePath.Id.Value);
|
||||||
|
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
||||||
|
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
||||||
|
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem);
|
||||||
|
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
||||||
|
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.ExifDirectory, mappingFromItem, outputResolutionToResize);
|
||||||
|
string blurHash = blurHasher.Encode(resizedFileHolder);
|
||||||
|
Assert.IsNotNull(blurHash);
|
||||||
|
exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
||||||
|
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
|
||||||
|
File.WriteAllText("../../../.json", json);
|
||||||
|
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
||||||
|
double? distance = geoLocation is null ? null : Metadata.Models.Stateless.Methods.IMetadata.GetDistance(1, 1, geoLocation.Latitude, geoLocation.Longitude);
|
||||||
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (string, string) GetResultsFullGroupDirectories()
|
private (string, string) GetResultsFullGroupDirectories()
|
||||||
@ -117,77 +177,13 @@ public class UnitTestResize
|
|||||||
return new(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
return new(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
|
||||||
public void TestMethodResize()
|
|
||||||
{
|
{
|
||||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
A_Property result;
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
if (_Configuration?.PropertyConfiguration is null)
|
||||||
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
throw new NullReferenceException(nameof(_PropertyConfiguration));
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
result = new(_AppSettings.MaxDegreeOfParallelism, _PropertyConfiguration, _Configuration.OutputExtension, reverse, aResultsFullGroupDirectory);
|
||||||
// string sourceFileName = "100000507001158650387.jpg";
|
return result;
|
||||||
// string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
|
||||||
string sourceFileName = "105131603001106320328.jpg";
|
|
||||||
string sourceDirectoryName = "Mike iCloud Have Date Taken 2022 !9";
|
|
||||||
Item item;
|
|
||||||
bool reverse = false;
|
|
||||||
bool isArchive = false;
|
|
||||||
FileHolder resizedFileHolder;
|
|
||||||
List<string> parseExceptions = [];
|
|
||||||
Shared.Models.Property? property = null;
|
|
||||||
const bool isValidImageFormatExtension = true;
|
|
||||||
List<Tuple<string, DateTime>> subFileTuples = [];
|
|
||||||
int length = _PropertyConfiguration.RootDirectory.Length;
|
|
||||||
string[] changesFrom = [nameof(A_Property)];
|
|
||||||
string outputResolution = _Configuration.OutputResolutions[0];
|
|
||||||
bool outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
|
|
||||||
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
|
||||||
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
|
||||||
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_PropertyConfiguration);
|
|
||||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
|
||||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
|
||||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
|
||||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
|
||||||
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality);
|
|
||||||
B_Metadata metadata = new(_PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
|
|
||||||
_ = metadata.ToString();
|
|
||||||
C_Resize resize = new(_PropertyConfiguration, _Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension);
|
|
||||||
_ = resize.ToString();
|
|
||||||
bool isUniqueFileName = false;
|
|
||||||
bool? isNotUniqueAndNeedsReview = null;
|
|
||||||
FileHolder sourceDirectoryFileHolder = IFileHolder.Get(".json");
|
|
||||||
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
|
||||||
FileHolder fileHolder = IFileHolder.Get(Path.Combine(sourceDirectory, sourceFileName));
|
|
||||||
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
|
||||||
Assert.IsNotNull(filePath.Id);
|
|
||||||
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
|
||||||
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
|
||||||
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
|
||||||
if (outputResolutionHasNumber)
|
|
||||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
|
||||||
resize.Update(cResultsFullGroupDirectory);
|
|
||||||
blurHasher.Update(cResultsFullGroupDirectory);
|
|
||||||
item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
|
|
||||||
if (item.Property is null)
|
|
||||||
{
|
|
||||||
property = propertyLogic.GetProperty(metadata, item, subFileTuples, parseExceptions);
|
|
||||||
item.Update(property);
|
|
||||||
}
|
|
||||||
if (property is null || item.Property is null)
|
|
||||||
throw new NullReferenceException(nameof(property));
|
|
||||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, filePath.Id.Value);
|
|
||||||
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
|
||||||
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
|
||||||
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.Property, mappingFromItem);
|
|
||||||
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
|
||||||
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
|
|
||||||
string blurHash = blurHasher.Encode(resizedFileHolder);
|
|
||||||
Assert.IsNotNull(blurHash);
|
|
||||||
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
|
||||||
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
|
|
||||||
File.WriteAllText("../../../.json", json);
|
|
||||||
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
|
||||||
double? distance = geoLocation is null ? null : Metadata.Models.Stateless.Methods.IMetadata.GetDistance(1, 1, geoLocation.Latitude, geoLocation.Longitude);
|
|
||||||
NonThrowTryCatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -39,7 +39,6 @@
|
|||||||
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
|
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
|
||||||
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
|
||||||
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
<ProjectReference Include="..\Metadata\Metadata.csproj" />
|
||||||
<ProjectReference Include="..\Property\Property.csproj" />
|
|
||||||
<ProjectReference Include="..\Resize\Resize.csproj" />
|
<ProjectReference Include="..\Resize\Resize.csproj" />
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -58,33 +58,113 @@ public class UnitTestFace
|
|||||||
_PropertyConfiguration = propertyConfiguration;
|
_PropertyConfiguration = propertyConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void NonThrowTryCatch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{ throw new Exception(); }
|
|
||||||
catch (Exception) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestConfiguration()
|
public void TestMethodFace()
|
||||||
{
|
{
|
||||||
if (_Configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits)
|
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||||
throw new Exception("Configuration has to match interface!");
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||||
if (_Configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor)
|
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
||||||
throw new Exception("Configuration has to match interface!");
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
||||||
|
string sourceFileName = "100000507001158650387.jpg";
|
||||||
|
string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
||||||
|
Item item;
|
||||||
|
bool reverse = false;
|
||||||
|
bool isArchive = false;
|
||||||
|
FileHolder resizedFileHolder;
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
List<string> parseExceptions = [];
|
||||||
|
const bool isValidImageFormatExtension = true;
|
||||||
|
List<Tuple<string, DateTime>> subFileTuples = [];
|
||||||
|
int length = _PropertyConfiguration.RootDirectory.Length;
|
||||||
|
string[] changesFrom = [nameof(A_Property)];
|
||||||
|
string outputResolution = _Configuration.OutputResolutions[0];
|
||||||
|
bool outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
|
||||||
|
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
|
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
||||||
|
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_PropertyConfiguration);
|
||||||
|
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
||||||
|
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
||||||
|
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||||
|
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality);
|
||||||
|
B_Metadata metadata = new(null, _PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, ticks, bResultsFullGroupDirectory);
|
||||||
|
_ = metadata.ToString();
|
||||||
|
C_Resize resize = new(_PropertyConfiguration, _Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension);
|
||||||
|
_ = resize.ToString();
|
||||||
|
bool isUniqueFileName = false;
|
||||||
|
bool? isNotUniqueAndNeedsReview = null;
|
||||||
|
FileHolder sourceDirectoryFileHolder = IFileHolder.Get(".json");
|
||||||
|
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
||||||
|
FileHolder fileHolder = IFileHolder.Get(Path.Combine(sourceDirectory, sourceFileName));
|
||||||
|
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
||||||
|
Assert.IsNotNull(filePath.Id);
|
||||||
|
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
||||||
|
ExifDirectory? exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
|
||||||
|
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
||||||
|
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
||||||
|
if (outputResolutionHasNumber)
|
||||||
|
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
||||||
|
resize.Update(cResultsFullGroupDirectory);
|
||||||
|
blurHasher.Update(cResultsFullGroupDirectory);
|
||||||
|
item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, exifDirectory, false, false, false);
|
||||||
|
if (item.ExifDirectory is null)
|
||||||
|
throw new NullReferenceException(nameof(item.ExifDirectory));
|
||||||
|
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, filePath.Id.Value);
|
||||||
|
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
||||||
|
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
||||||
|
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem);
|
||||||
|
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
||||||
|
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.ExifDirectory, mappingFromItem, outputResolutionToResize);
|
||||||
|
string blurHash = blurHasher.Encode(resizedFileHolder);
|
||||||
|
Assert.IsNotNull(blurHash);
|
||||||
|
exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
||||||
|
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
|
||||||
|
File.WriteAllText("../../../.json", json);
|
||||||
|
Image image = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||||
|
Assert.IsNotNull(image);
|
||||||
|
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration);
|
||||||
|
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, model, modelParameter, predictorModel);
|
||||||
|
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
||||||
|
collection = faceRecognition.GetCollection(image, locations: [], includeFaceEncoding: true, includeFaceParts: true);
|
||||||
|
Assert.IsTrue(collection.Count == 2);
|
||||||
|
List<FaceDistance> faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList();
|
||||||
|
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncodings[0]);
|
||||||
|
Assert.IsTrue(faceDistanceLengths.Count == 2);
|
||||||
|
Assert.IsNotNull(sourceFileName);
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
private (string, string) GetResultsFullGroupDirectories()
|
||||||
public void TestMethodNull()
|
|
||||||
{
|
{
|
||||||
Assert.IsFalse(_AppSettings is null);
|
string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
||||||
Assert.IsFalse(_Configuration is null);
|
_PropertyConfiguration,
|
||||||
Assert.IsFalse(_IsEnvironment is null);
|
nameof(A_Property),
|
||||||
Assert.IsFalse(_WorkingDirectory is null);
|
string.Empty,
|
||||||
Assert.IsFalse(_ConfigurationRoot is null);
|
includeResizeGroup: false,
|
||||||
Assert.IsFalse(_PropertyConfiguration is null);
|
includeModel: false,
|
||||||
NonThrowTryCatch();
|
includePredictorModel: false);
|
||||||
|
string bResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
||||||
|
_PropertyConfiguration,
|
||||||
|
nameof(B_Metadata),
|
||||||
|
string.Empty,
|
||||||
|
includeResizeGroup: false,
|
||||||
|
includeModel: false,
|
||||||
|
includePredictorModel: false);
|
||||||
|
return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (string, string, string) GetResultsFullGroupDirectories(string outputResolution)
|
||||||
|
{
|
||||||
|
string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
||||||
|
_PropertyConfiguration,
|
||||||
|
nameof(C_Resize),
|
||||||
|
outputResolution,
|
||||||
|
includeResizeGroup: true,
|
||||||
|
includeModel: false,
|
||||||
|
includePredictorModel: false);
|
||||||
|
string dResultsFullGroupDirectory = string.Empty;
|
||||||
|
string d2ResultsFullGroupDirectory = string.Empty;
|
||||||
|
return new(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
|
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
|
||||||
@ -137,6 +217,25 @@ public class UnitTestFace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void NonThrowTryCatch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{ throw new Exception(); }
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethodNull()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(_AppSettings is null);
|
||||||
|
Assert.IsFalse(_Configuration is null);
|
||||||
|
Assert.IsFalse(_IsEnvironment is null);
|
||||||
|
Assert.IsFalse(_WorkingDirectory is null);
|
||||||
|
Assert.IsFalse(_ConfigurationRoot is null);
|
||||||
|
Assert.IsFalse(_PropertyConfiguration is null);
|
||||||
|
NonThrowTryCatch();
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodRoundB()
|
public void TestMethodRoundB()
|
||||||
{
|
{
|
||||||
@ -159,116 +258,13 @@ public class UnitTestFace
|
|||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (string, string) GetResultsFullGroupDirectories()
|
|
||||||
{
|
|
||||||
string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
|
||||||
_PropertyConfiguration,
|
|
||||||
nameof(A_Property),
|
|
||||||
string.Empty,
|
|
||||||
includeResizeGroup: false,
|
|
||||||
includeModel: false,
|
|
||||||
includePredictorModel: false);
|
|
||||||
string bResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
|
||||||
_PropertyConfiguration,
|
|
||||||
nameof(B_Metadata),
|
|
||||||
string.Empty,
|
|
||||||
includeResizeGroup: false,
|
|
||||||
includeModel: false,
|
|
||||||
includePredictorModel: false);
|
|
||||||
return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private (string, string, string) GetResultsFullGroupDirectories(string outputResolution)
|
|
||||||
{
|
|
||||||
string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
|
|
||||||
_PropertyConfiguration,
|
|
||||||
nameof(C_Resize),
|
|
||||||
outputResolution,
|
|
||||||
includeResizeGroup: true,
|
|
||||||
includeModel: false,
|
|
||||||
includePredictorModel: false);
|
|
||||||
string dResultsFullGroupDirectory = string.Empty;
|
|
||||||
string d2ResultsFullGroupDirectory = string.Empty;
|
|
||||||
return new(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMethodFace()
|
public void TestConfiguration()
|
||||||
{
|
{
|
||||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
if (_Configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits)
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
throw new Exception("Configuration has to match interface!");
|
||||||
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
|
if (_Configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor)
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
|
throw new Exception("Configuration has to match interface!");
|
||||||
string sourceFileName = "100000507001158650387.jpg";
|
|
||||||
string sourceDirectoryName = "Facebook/2023.2 Summer Facebook";
|
|
||||||
Item item;
|
|
||||||
bool reverse = false;
|
|
||||||
bool isArchive = false;
|
|
||||||
FileHolder resizedFileHolder;
|
|
||||||
List<string> parseExceptions = [];
|
|
||||||
Shared.Models.Property? property = null;
|
|
||||||
const bool isValidImageFormatExtension = true;
|
|
||||||
List<Tuple<string, DateTime>> subFileTuples = [];
|
|
||||||
int length = _PropertyConfiguration.RootDirectory.Length;
|
|
||||||
string[] changesFrom = [nameof(A_Property)];
|
|
||||||
string outputResolution = _Configuration.OutputResolutions[0];
|
|
||||||
bool outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
|
|
||||||
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
|
|
||||||
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
|
|
||||||
Shared.Models.Methods.IBlurHasher blurHasher = new BlurHash.Models.C2_BlurHasher(_PropertyConfiguration);
|
|
||||||
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
|
|
||||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
|
|
||||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
|
||||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
|
||||||
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality);
|
|
||||||
B_Metadata metadata = new(_PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
|
|
||||||
_ = metadata.ToString();
|
|
||||||
C_Resize resize = new(_PropertyConfiguration, _Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension);
|
|
||||||
_ = resize.ToString();
|
|
||||||
bool isUniqueFileName = false;
|
|
||||||
bool? isNotUniqueAndNeedsReview = null;
|
|
||||||
FileHolder sourceDirectoryFileHolder = IFileHolder.Get(".json");
|
|
||||||
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
|
|
||||||
FileHolder fileHolder = IFileHolder.Get(Path.Combine(sourceDirectory, sourceFileName));
|
|
||||||
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
|
||||||
Assert.IsNotNull(filePath.Id);
|
|
||||||
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
|
|
||||||
string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
|
|
||||||
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
|
|
||||||
if (outputResolutionHasNumber)
|
|
||||||
resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory);
|
|
||||||
resize.Update(cResultsFullGroupDirectory);
|
|
||||||
blurHasher.Update(cResultsFullGroupDirectory);
|
|
||||||
item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
|
|
||||||
if (item.Property is null)
|
|
||||||
{
|
|
||||||
property = propertyLogic.GetProperty(metadata, item, subFileTuples, parseExceptions);
|
|
||||||
item.Update(property);
|
|
||||||
}
|
|
||||||
if (property is null || item.Property is null)
|
|
||||||
throw new NullReferenceException(nameof(property));
|
|
||||||
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, filePath.Id.Value);
|
|
||||||
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
|
|
||||||
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
|
|
||||||
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.Property, mappingFromItem);
|
|
||||||
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
|
|
||||||
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
|
|
||||||
string blurHash = blurHasher.Encode(resizedFileHolder);
|
|
||||||
Assert.IsNotNull(blurHash);
|
|
||||||
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
|
||||||
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
|
|
||||||
File.WriteAllText("../../../.json", json);
|
|
||||||
Image image = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
|
|
||||||
Assert.IsNotNull(image);
|
|
||||||
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration);
|
|
||||||
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, model, modelParameter, predictorModel);
|
|
||||||
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
|
|
||||||
collection = faceRecognition.GetCollection(image, locations: [], includeFaceEncoding: true, includeFaceParts: true);
|
|
||||||
Assert.IsTrue(collection.Count == 2);
|
|
||||||
List<FaceDistance> faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList();
|
|
||||||
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(new(faceDistanceEncodings), faceDistanceEncodings[0]);
|
|
||||||
Assert.IsTrue(faceDistanceLengths.Count == 2);
|
|
||||||
Assert.IsNotNull(sourceFileName);
|
|
||||||
NonThrowTryCatch();
|
NonThrowTryCatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlurHash", "BlurHash\BlurHa
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Copy-Distinct", "Copy-Distinct\Copy-Distinct.csproj", "{E08CB662-FF25-48DF-A378-A770E1EFBA56}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Copy-Distinct", "Copy-Distinct\Copy-Distinct.csproj", "{E08CB662-FF25-48DF-A378-A770E1EFBA56}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Date-Group", "Date-Group\Date-Group.csproj", "{DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Distinct", "Delete-By-Distinct\Delete-By-Distinct.csproj", "{3F00BDD5-75F8-470C-ACED-1A26FDC8D7B3}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Distinct", "Delete-By-Distinct\Delete-By-Distinct.csproj", "{3F00BDD5-75F8-470C-ACED-1A26FDC8D7B3}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Relative", "Delete-By-Relative\Delete-By-Relative.csproj", "{9DFCA595-80AA-4E78-A9AF-5B4AB4D737C4}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Relative", "Delete-By-Relative\Delete-By-Relative.csproj", "{9DFCA595-80AA-4E78-A9AF-5B4AB4D737C4}"
|
||||||
@ -51,14 +49,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrepareForOld", "PrepareFor
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property-Compare", "Property-Compare\Property-Compare.csproj", "{692AA058-F142-44B0-88BC-F22AB5BE5EDF}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property-Compare", "Property-Compare\Property-Compare.csproj", "{692AA058-F142-44B0-88BC-F22AB5BE5EDF}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property", "Property\Property.csproj", "{964B969A-719C-48AF-86C0-F97AF1397347}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rename", "Rename\Rename.csproj", "{83FD089F-8034-4597-B87F-87D343C0486B}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resize", "Resize\Resize.csproj", "{27D0D869-394D-4B07-83DF-2095B16026FC}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Set-Created-Date", "Set-Created-Date\Set-Created-Date.csproj", "{B067643E-9F59-46A1-A001-ACF4661F059C}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{B4FB6B43-36EC-404D-B934-5C695C6E32CC}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{B4FB6B43-36EC-404D-B934-5C695C6E32CC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsWithFaceRecognitionDotNet", "TestsWithFaceRecognitionDotNet\TestsWithFaceRecognitionDotNet.csproj", "{A67D73C7-A1A1-4443-B681-776339CFA08A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsWithFaceRecognitionDotNet", "TestsWithFaceRecognitionDotNet\TestsWithFaceRecognitionDotNet.csproj", "{A67D73C7-A1A1-4443-B681-776339CFA08A}"
|
||||||
|
Reference in New Issue
Block a user