Testing
This commit is contained in:
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -148,6 +148,18 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": "$msCompile"
|
"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",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Text.Json;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
@ -8,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<FilePath> Collection,
|
ReadOnlyCollection<FilePath> Collection,
|
||||||
FilePath FilePath,
|
FilePath FilePath,
|
||||||
Item Item);
|
Item Item);
|
||||||
|
|
||||||
@ -47,7 +50,7 @@ internal abstract class Container
|
|||||||
continue;
|
continue;
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (results.Contains(item.ExifDirectory.FilePath.Id.Value))
|
if (results.Contains(item.ExifDirectory.FilePath.Id.Value))
|
||||||
continue;
|
continue;
|
||||||
@ -57,7 +60,7 @@ internal abstract class Container
|
|||||||
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;
|
||||||
@ -66,18 +69,18 @@ internal abstract class Container
|
|||||||
const string fileSearchFilter = "*";
|
const string fileSearchFilter = "*";
|
||||||
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
IDlibDotNet dlibDotNet = GetDlibDotNet();
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById = null;
|
ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = new(new Dictionary<int, ExifDirectory>());
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
|
|
||||||
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, useIgnoreExtensions);
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection, useIgnoreExtensions);
|
||||||
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, 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, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, 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;
|
||||||
@ -101,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, exifDirectoriesById, 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))
|
||||||
@ -120,104 +119,159 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
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)
|
||||||
{
|
{
|
||||||
List<FilePair> results = [];
|
ReadOnlyCollection<FilePair> results;
|
||||||
const string extension = ".json";
|
const string extension = ".json";
|
||||||
|
Dictionary<int, ExifDirectory> keyValuePairs = [];
|
||||||
ReadOnlyCollection<Shared.Models.FilePair> filePairs;
|
ReadOnlyCollection<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 };
|
||||||
|
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
|
string jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
|
if (!Directory.Exists(jsonGroupDirectory))
|
||||||
|
_ = Directory.CreateDirectory(jsonGroupDirectory);
|
||||||
filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
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, exifDirectoriesById, 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, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, 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();
|
List<FilePair> results = [];
|
||||||
bool abandoned = false;
|
Item item;
|
||||||
|
string json;
|
||||||
|
char? change;
|
||||||
|
bool abandoned;
|
||||||
|
bool? isArchive;
|
||||||
|
string fileName;
|
||||||
|
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;
|
FileHolder sourceDirectoryFileHolder;
|
||||||
if (exifDirectoriesById is null || filePair.FilePath.Id is null || !exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory))
|
ReadOnlyCollection<FilePath>? filePaths;
|
||||||
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
foreach (Shared.Models.FilePair filePair in filePairs)
|
||||||
ReadOnlyCollection<string> keywords = IMetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
|
||||||
bool? shouldIgnore = propertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
|
||||||
bool? fileSizeChanged = exifDirectory is not null ? exifDirectory.FilePath.Length != filePair.FilePath.Length : null;
|
|
||||||
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePair.FilePath.ExtensionLowered);
|
|
||||||
bool? isArchive = filePair.FilePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePair.FilePath.Id.Value, out Identifier? identifier);
|
|
||||||
if (exifDirectory is not null && filePair.FilePath.Id is not null && filePair.FilePath.HasIgnoreKeyword is not null && filePair.FilePath.HasDateTimeOriginal is not null)
|
|
||||||
{
|
{
|
||||||
char? change;
|
abandoned = false;
|
||||||
ReadOnlyCollection<FilePath>? filePaths = null;
|
if (filePair.FilePath.Id is null || (!exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out exifDirectory) && !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out exifDirectory)))
|
||||||
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||||
char hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePair.FilePath).ToString()[0];
|
keywords = IMetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||||
char hasDateTimeOriginal = IId.GetHasDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
shouldIgnore = propertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
||||||
char missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(propertyConfiguration, filePair.FilePath).ToString()[0];
|
fileSizeChanged = exifDirectory?.FilePath is not null ? exifDirectory.FilePath.Length != filePair.FilePath.Length : null;
|
||||||
if (shouldIgnore is not null && shouldIgnore.Value)
|
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)
|
||||||
{
|
{
|
||||||
if (filePair.FilePath.FileNameFirstSegment[^1] == hasIgnoreKeyword)
|
filePaths = null;
|
||||||
change = null;
|
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
else
|
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)
|
||||||
{
|
{
|
||||||
change = hasIgnoreKeyword;
|
if (filePair.FilePath.FileNameFirstSegment[^1] == hasIgnoreKeyword)
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
change = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
change = hasIgnoreKeyword;
|
||||||
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((shouldIgnore is null || !shouldIgnore.Value) && dateTime is null)
|
||||||
|
{
|
||||||
|
if (filePair.FilePath.FileNameFirstSegment[^1] == missingDateTimeOriginal)
|
||||||
|
change = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
change = missingDateTimeOriginal;
|
||||||
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (filePair.FilePath.FileNameFirstSegment[^1] != hasDateTimeOriginal)
|
||||||
|
{
|
||||||
|
change = hasDateTimeOriginal;
|
||||||
|
if (!idToFilePaths.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
||||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ((shouldIgnore is null || !shouldIgnore.Value) && dateTime is null)
|
|
||||||
{
|
|
||||||
if (filePair.FilePath.FileNameFirstSegment[^1] == missingDateTimeOriginal)
|
|
||||||
change = null;
|
|
||||||
else
|
else
|
||||||
{
|
change = null;
|
||||||
change = missingDateTimeOriginal;
|
if (filePaths is not null && change is not null)
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
RenameFile(filePair, filePair.FilePath, change.Value, filePaths);
|
||||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (filePair.FilePath.FileNameFirstSegment[^1] != hasDateTimeOriginal)
|
|
||||||
{
|
|
||||||
change = hasDateTimeOriginal;
|
|
||||||
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePair.FilePath.Id.Value, out filePaths) || filePaths is null)
|
|
||||||
throw new NotSupportedException($"Rename File! <{filePair.FilePath.FileNameFirstSegment}>");
|
|
||||||
}
|
}
|
||||||
|
relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.FilePath.FullName, rootDirectoryLength, forceExtensionToLower: true);
|
||||||
|
lastWriteTimeChanged = exifDirectory?.FilePath is not null ? propertyConfiguration.PropertiesChangedForProperty || exifDirectory.FilePath.LastWriteTicks != filePair.FilePath.LastWriteTicks : null;
|
||||||
|
if (filePair.Match is not null)
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
||||||
|
else if (!filePair.IsUnique)
|
||||||
|
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
||||||
else
|
else
|
||||||
change = null;
|
{
|
||||||
if (filePaths is not null && change is not null)
|
fileName = Path.GetFileName(filePair.FilePath.FullName);
|
||||||
RenameFile(filePair, filePair.FilePath, change.Value, filePaths);
|
cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePair.FilePath);
|
||||||
}
|
directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
||||||
string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.FilePath.FullName, rootDirectoryLength, forceExtensionToLower: true);
|
jsonFileName = $"{fileName}{extension}";
|
||||||
bool? lastWriteTimeChanged = exifDirectory is not null ? propertyConfiguration.PropertiesChangedForProperty || exifDirectory.FilePath.LastWriteTicks != filePair.FilePath.LastWriteTicks : null;
|
fullFileName = Path.Combine(directory, jsonFileName);
|
||||||
if (filePair.Match is not null)
|
MoveIf(jsonFileName, cei, directory, fullFileName);
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
|
fileInfo = new(fullFileName);
|
||||||
else if (!filePair.IsUnique)
|
if (exifDirectory is not null && !fileInfo.Exists)
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
|
{
|
||||||
else
|
json = JsonSerializer.Serialize(exifDirectory, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
{
|
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||||
string fileName = Path.GetFileName(filePair.FilePath.FullName);
|
fileInfo.Refresh();
|
||||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePair.FilePath);
|
}
|
||||||
string directory = Path.Combine(jsonGroupDirectory, cei.Combined);
|
sourceDirectoryFileHolder = IFileHolder.Get(fileInfo);
|
||||||
string jsonFileName = $"{fileName}{extension}";
|
}
|
||||||
string fullFileName = Path.Combine(directory, jsonFileName);
|
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
||||||
MoveIf(jsonFileName, cei, directory, fullFileName);
|
{
|
||||||
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
|
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePair.FilePath.LastWriteTicks));
|
||||||
}
|
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
||||||
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
}
|
||||||
{
|
item = Item.Get(filePair.FilePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, exifDirectory, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
||||||
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePair.FilePath.LastWriteTicks));
|
|
||||||
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
|
|
||||||
}
|
|
||||||
Item item = Item.Get(filePair.FilePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, exifDirectory, abandoned, fileSizeChanged, lastWriteTimeChanged);
|
|
||||||
lock (results)
|
|
||||||
results.Add(new(filePair.IsUnique, filePair.Collection, filePair.FilePath, item));
|
results.Add(new(filePair.IsUnique, filePair.Collection, filePair.FilePath, item));
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParallelFor(ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Shared.Models.FilePair filePair, Dictionary<int, ExifDirectory> keyValuePairs, Action? tick)
|
||||||
|
{
|
||||||
|
tick?.Invoke();
|
||||||
|
if (filePair.FilePath.Id is not null && (!exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory) || exifDirectory.FilePath?.Id is null))
|
||||||
|
{
|
||||||
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||||
|
lock (keyValuePairs)
|
||||||
|
{
|
||||||
|
if (!keyValuePairs.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
|
keyValuePairs.Add(filePair.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RenameFile(Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
private static void RenameFile(Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
|
||||||
@ -230,13 +284,13 @@ internal abstract class Container
|
|||||||
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(filePair.Match.NameWithoutExtension);
|
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(filePair.Match.NameWithoutExtension);
|
||||||
string extensionSecond = Path.GetExtension(filePair.Match.Name);
|
string extensionSecond = Path.GetExtension(filePair.Match.Name);
|
||||||
checkFile = Path.Combine(filePair.Match.DirectoryFullPath, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{filePair.Match.ExtensionLowered}");
|
checkFile = Path.Combine(filePair.Match.DirectoryFullPath, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{filePair.Match.ExtensionLowered}");
|
||||||
if (!File.Exists(checkFile))
|
if (!File.Exists(checkFile) && File.Exists(filePair.Match.FullName))
|
||||||
File.Move(filePair.Match.FullName, checkFile);
|
File.Move(filePair.Match.FullName, 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);
|
||||||
}
|
}
|
||||||
@ -271,7 +325,7 @@ internal abstract class Container
|
|||||||
continue;
|
continue;
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.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;
|
||||||
@ -300,7 +354,7 @@ internal abstract class Container
|
|||||||
}
|
}
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (distinctItems)
|
if (distinctItems)
|
||||||
{
|
{
|
||||||
@ -314,42 +368,41 @@ 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, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById)
|
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;
|
Models.Container[] results;
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
if (keyValuePairs is not null)
|
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, idToFilePaths, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||||
DoGetFilePairsForRemaining(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, directorySearchFilter);
|
AnyMoved(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, idToFilePaths, directorySearchFilter);
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoGetFilePairsForRemaining(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
|
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";
|
const string extension = ".json";
|
||||||
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
|
||||||
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
if (!Directory.Exists(bMetaSingletonDirectory))
|
if (!Directory.Exists(bMetaSingletonDirectory))
|
||||||
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
|
||||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection);
|
||||||
(string cResultsFullGroupDirectory, _, string dResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories("Original");
|
(string cResultsFullGroupDirectory, _, string dResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories("Original");
|
||||||
string cResizeSingletonDirectory = Path.Combine(cResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
string cResizeSingletonDirectory = Path.Combine(cResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
if (!Directory.Exists(cResizeSingletonDirectory))
|
if (!Directory.Exists(cResizeSingletonDirectory))
|
||||||
_ = Directory.CreateDirectory(cResizeSingletonDirectory);
|
_ = Directory.CreateDirectory(cResizeSingletonDirectory);
|
||||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection);
|
||||||
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
if (!Directory.Exists(dFaceCollectionDirectory))
|
if (!Directory.Exists(dFaceCollectionDirectory))
|
||||||
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
|
||||||
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection, fileNamesToFiles);
|
_ = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection);
|
||||||
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
|
||||||
if (!Directory.Exists(dFaceContentDirectory))
|
if (!Directory.Exists(dFaceContentDirectory))
|
||||||
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
_ = Directory.CreateDirectory(dFaceContentDirectory);
|
||||||
AnyMovedFace(propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, fileNamesToFiles, dFaceContentDirectory);
|
AnyMovedFace(propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, idToFilePaths, dFaceContentDirectory);
|
||||||
AnyMovedDistance(propertyConfiguration, facesFileNameExtension, fileNamesToFiles, eDistanceContentDirectory);
|
AnyMovedDistance(propertyConfiguration, facesFileNameExtension, idToFilePaths, eDistanceContentDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, string extension, string hiddenExtension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, string extension, string hiddenExtension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, string jsonGroupDirectory)
|
||||||
{
|
{
|
||||||
string directory;
|
string directory;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -382,26 +435,26 @@ internal abstract class Container
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (directories.Count > 0)
|
if (directories.Count > 0)
|
||||||
AnyMovedFace(propertyConfiguration, fileNamesToFiles, directories);
|
AnyMovedFace(propertyConfiguration, idToFilePaths, directories);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, List<string> directories)
|
private static void AnyMovedFace(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, List<string> directories)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
FilePath filePath;
|
FilePath? filePath;
|
||||||
string subDirectory;
|
string subDirectory;
|
||||||
string directoryName;
|
string directoryName;
|
||||||
string checkDirectory;
|
string checkDirectory;
|
||||||
FileHolder fileHolder;
|
FileHolder fileHolder;
|
||||||
string directoryNameWith;
|
string directoryNameWith;
|
||||||
List<FilePath>? collection;
|
|
||||||
List<string> directoryNames = [];
|
List<string> directoryNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
fileHolder = IFileHolder.Get(Path.GetFileName(directory));
|
fileHolder = IFileHolder.Get(Path.GetFileName(directory));
|
||||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
filePath = FilePath.GetNullSafe(propertyConfiguration, fileHolder, index: null);
|
||||||
if (filePath.Id is null)
|
if (filePath?.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
@ -437,7 +490,7 @@ internal abstract class Container
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AnyMovedDistance(IPropertyConfiguration propertyConfiguration, string extension, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string jsonGroupDirectory)
|
private static void AnyMovedDistance(IPropertyConfiguration propertyConfiguration, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths, string jsonGroupDirectory)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -445,8 +498,8 @@ internal abstract class Container
|
|||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
FileHolder fileHolder;
|
FileHolder fileHolder;
|
||||||
string[] fileNameSegments;
|
string[] fileNameSegments;
|
||||||
List<FilePath>? collection;
|
|
||||||
List<string> fileNames = [];
|
List<string> fileNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
|
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
@ -457,7 +510,7 @@ internal abstract class Container
|
|||||||
if (filePath.Id is null)
|
if (filePath.Id is null)
|
||||||
continue;
|
continue;
|
||||||
fileNameSegments = filePath.Name.Split('.');
|
fileNameSegments = filePath.Name.Split('.');
|
||||||
if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
|
if (!idToFilePaths.TryGetValue(filePath.Id.Value, out collection))
|
||||||
continue;
|
continue;
|
||||||
fileNames.Clear();
|
fileNames.Clear();
|
||||||
foreach (FilePath f in collection)
|
foreach (FilePath f in collection)
|
||||||
|
@ -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, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
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, exifDirectoriesById);
|
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, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
|
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, exifDirectoriesById);
|
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 System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -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();
|
||||||
@ -93,12 +92,11 @@ public partial class DragDropSearch : Form
|
|||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
Container.Models.Container[] containers;
|
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);
|
||||||
(_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
|
|
||||||
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
List<Item> collection = Program.GetItemCollection(_Configuration, containers);
|
||||||
foreach (Item item in collection)
|
foreach (Item item in collection)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (_IdToItem.ContainsKey(item.ExifDirectory.FilePath.Id.Value))
|
if (_IdToItem.ContainsKey(item.ExifDirectory.FilePath.Id.Value))
|
||||||
continue;
|
continue;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -71,8 +72,7 @@ public class DuplicateSearch
|
|||||||
using (ProgressBar progressBar = new(1, message, options))
|
using (ProgressBar progressBar = new(1, message, options))
|
||||||
{
|
{
|
||||||
progressBar.Tick();
|
progressBar.Tick();
|
||||||
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
|
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration);
|
||||||
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
|
|
||||||
}
|
}
|
||||||
return containers;
|
return containers;
|
||||||
}
|
}
|
||||||
@ -101,12 +101,15 @@ public class DuplicateSearch
|
|||||||
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds)
|
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds)
|
||||||
{
|
{
|
||||||
Dictionary<int, List<MappingFromItem?>> results = [];
|
Dictionary<int, List<MappingFromItem?>> results = [];
|
||||||
|
string? model;
|
||||||
string directory;
|
string directory;
|
||||||
const int zero = 0;
|
const int zero = 0;
|
||||||
|
DateTime? dateTime;
|
||||||
FileHolder resizedFileHolder;
|
FileHolder resizedFileHolder;
|
||||||
DateTime[] containerDateTimes;
|
DateTime[] containerDateTimes;
|
||||||
MappingFromItem? mappingFromItem;
|
MappingFromItem? mappingFromItem;
|
||||||
List<MappingFromItem?>? collection;
|
List<MappingFromItem?>? collection;
|
||||||
|
ReadOnlyCollection<string> keywords;
|
||||||
ReadOnlyCollection<Item> validImageItems;
|
ReadOnlyCollection<Item> validImageItems;
|
||||||
const string duplicates = "-Duplicate(s)";
|
const string duplicates = "-Duplicate(s)";
|
||||||
if (containers.Length != 0)
|
if (containers.Length != 0)
|
||||||
@ -126,7 +129,7 @@ public class DuplicateSearch
|
|||||||
containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
|
containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(validImageItems);
|
||||||
foreach (Item item in validImageItems)
|
foreach (Item item in validImageItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
{
|
{
|
||||||
if (int.TryParse(item.FilePath.NameWithoutExtension, out int id))
|
if (int.TryParse(item.FilePath.NameWithoutExtension, out int id))
|
||||||
continue;
|
continue;
|
||||||
@ -145,12 +148,15 @@ public class DuplicateSearch
|
|||||||
mappingFromItem = collection[zero];
|
mappingFromItem = collection[zero];
|
||||||
if (mappingFromItem is not null)
|
if (mappingFromItem is not null)
|
||||||
{
|
{
|
||||||
|
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
|
||||||
|
keywords = IMetaBase.GetKeywords(item.ExifDirectory?.ExifBaseDirectories);
|
||||||
|
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(item.ExifDirectory);
|
||||||
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
|
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
|
||||||
collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.IsArchive, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, item.Property.Keywords ?? [], mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder);
|
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));
|
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);
|
mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||||
collection.Add(mappingFromItem);
|
collection.Add(mappingFromItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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, ExifDirectory exifDirectory, 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, exifDirectory, 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, ExifDirectory exifDirectory, 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,7 +369,6 @@ 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);
|
||||||
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -29,9 +29,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string FilesCollectionRootDirectory,
|
string FilesCollectionRootDirectory,
|
||||||
bool FilesCollectionCountIsOne,
|
bool FilesCollectionCountIsOne,
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> FilePathsCollection,
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> FilePathsCollection,
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? IdToFilePaths,
|
|
||||||
ReadOnlyDictionary<int, Identifier>? SplatNineIdentifiers);
|
ReadOnlyDictionary<int, Identifier>? SplatNineIdentifiers);
|
||||||
|
|
||||||
|
public long Ticks { get; init; }
|
||||||
|
|
||||||
private readonly D_Face _Faces;
|
private readonly D_Face _Faces;
|
||||||
private ProgressBar? _ProgressBar;
|
private ProgressBar? _ProgressBar;
|
||||||
private readonly C_Resize _Resize;
|
private readonly C_Resize _Resize;
|
||||||
@ -67,11 +68,12 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
_Exceptions = [];
|
_Exceptions = [];
|
||||||
_Console = console;
|
_Console = console;
|
||||||
_AppSettings = appSettings;
|
_AppSettings = appSettings;
|
||||||
|
IDlibDotNet dlibDotNet = this;
|
||||||
_IsEnvironment = isEnvironment;
|
_IsEnvironment = isEnvironment;
|
||||||
long ticks = DateTime.Now.Ticks;
|
Ticks = DateTime.Now.Ticks;
|
||||||
_JLinkResolvedDirectories = [];
|
_JLinkResolvedDirectories = [];
|
||||||
if (ticks.ToString().Last() == '0')
|
if (Ticks.ToString().Last() == '0')
|
||||||
ticks += 1;
|
Ticks += 1;
|
||||||
ReadOnlyCollection<PersonContainer> personContainers;
|
ReadOnlyCollection<PersonContainer> personContainers;
|
||||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
|
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
|
||||||
@ -126,10 +128,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
personContainers = new([]);
|
personContainers = new([]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds);
|
||||||
message = $") Building People Collection - {totalSeconds} total second(s)";
|
message = $") Building People Collection - {totalSeconds} total second(s)";
|
||||||
using ProgressBar progressBar = new(1, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(1, message);
|
||||||
progressBar.Tick();
|
dlibDotNet.Tick();
|
||||||
string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People));
|
string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People));
|
||||||
string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception();
|
string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception();
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, propertyConfiguration.ResultSingleton));
|
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, propertyConfiguration.ResultSingleton));
|
||||||
@ -158,12 +160,12 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
filenameExtension);
|
filenameExtension);
|
||||||
}
|
}
|
||||||
if (!configuration.SkipSearch)
|
if (!configuration.SkipSearch)
|
||||||
Search(ticks, personContainers, argZero, propertyRoot);
|
Search(personContainers, argZero, propertyRoot);
|
||||||
if (!_PropertyRootExistedBefore && !_IsEnvironment.Development && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory)
|
if (!_PropertyRootExistedBefore && !_IsEnvironment.Development && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory)
|
||||||
{
|
{
|
||||||
string d2FacePartsRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(D2_FaceParts));
|
string d2FacePartsRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(D2_FaceParts));
|
||||||
_Logger?.LogInformation(string.Concat("Cleaning <", d2FacePartsRootDirectory, ">"));
|
_Logger?.LogInformation(string.Concat("Cleaning <", d2FacePartsRootDirectory, ">"));
|
||||||
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsRootDirectory, ticks);
|
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsRootDirectory, dlibDotNet.Ticks);
|
||||||
}
|
}
|
||||||
message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}";
|
message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}";
|
||||||
_Logger?.LogInformation(message);
|
_Logger?.LogInformation(message);
|
||||||
@ -196,7 +198,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string[] changesFrom = [nameof(A_Property)];
|
string[] changesFrom = [nameof(A_Property)];
|
||||||
List<Tuple<string, DateTime>> subFileTuples = [];
|
List<Tuple<string, DateTime>> subFileTuples = [];
|
||||||
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
||||||
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
if (item.ExifDirectory is null || item.ExifDirectory.FilePath?.Id is null)
|
||||||
|
throw new Exception();
|
||||||
|
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime && item.SourceDirectoryFileHolder.LastWriteTime.Value != item.SourceDirectoryFileHolder.CreationTime.Value)
|
if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime && item.SourceDirectoryFileHolder.LastWriteTime.Value != item.SourceDirectoryFileHolder.CreationTime.Value)
|
||||||
{
|
{
|
||||||
@ -220,7 +224,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<string> keywords = IMetaBase.GetKeywords(exifDirectory.ExifBaseDirectories);
|
ReadOnlyCollection<string> keywords = IMetaBase.GetKeywords(exifDirectory);
|
||||||
shouldIgnore = _Configuration.PropertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
shouldIgnore = _Configuration.PropertyConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains);
|
||||||
if (shouldIgnore.Value)
|
if (shouldIgnore.Value)
|
||||||
{
|
{
|
||||||
@ -261,47 +265,54 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
distance += 1;
|
distance += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Dictionary<string, int[]> outputResolutionToResize = _Resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem);
|
int? orientation = IMetaBase.GetOrientation(exifDirectory);
|
||||||
if (_Configuration.SaveResizedSubfiles)
|
if (exifDirectory is null || orientation is null || exifDirectory.Width is null || exifDirectory.Height is null)
|
||||||
{
|
|
||||||
if (shouldIgnore is not null && item.FilePath.HasIgnoreKeyword is not null && item.FilePath.HasIgnoreKeyword.Value != shouldIgnore.Value)
|
|
||||||
faces = [];
|
|
||||||
else
|
|
||||||
_Resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.ExifDirectory, mappingFromItem, outputResolutionToResize);
|
|
||||||
}
|
|
||||||
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution))
|
|
||||||
faces = [];
|
|
||||||
else if (!mappingFromItem.ResizedFileHolder.Exists && !File.Exists(mappingFromItem.ResizedFileHolder.FullName))
|
|
||||||
faces = [];
|
faces = [];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
|
Dictionary<string, int[]> outputResolutionToResize = _Resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem);
|
||||||
if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection))
|
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
||||||
mappingFromPhotoPrismCollection = null;
|
if (_Configuration.SaveResizedSubfiles)
|
||||||
bool move = _Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution);
|
|
||||||
faces = _Faces.GetFaces(outputResolution, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem, outputResolutionToResize, mappingFromPhotoPrismCollection);
|
|
||||||
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
|
||||||
List<(Shared.Models.Face, FileHolder?, string, bool Saved)> faceCollection = _Faces.SaveFaces(item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces);
|
|
||||||
if (move && faceCollection.All(l => !l.Saved))
|
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<LocationContainer> locationContainers = mapLogic.GetLocationContainers(item);
|
if (shouldIgnore is not null && item.FilePath.HasIgnoreKeyword is not null && item.FilePath.HasIgnoreKeyword.Value != shouldIgnore.Value)
|
||||||
if (locationContainers.Count > 0)
|
faces = [];
|
||||||
|
else
|
||||||
|
_Resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.ExifDirectory, mappingFromItem, outputResolutionToResize);
|
||||||
|
}
|
||||||
|
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution))
|
||||||
|
faces = [];
|
||||||
|
else if (!mappingFromItem.ResizedFileHolder.Exists && !File.Exists(mappingFromItem.ResizedFileHolder.FullName))
|
||||||
|
faces = [];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
|
||||||
|
if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection))
|
||||||
|
mappingFromPhotoPrismCollection = null;
|
||||||
|
bool move = _Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution);
|
||||||
|
faces = _Faces.GetFaces(cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.ExifDirectory, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, mappingFromPhotoPrismCollection);
|
||||||
|
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
||||||
|
List<(Shared.Models.Face, FileHolder?, string, bool Saved)> faceCollection = _Faces.SaveFaces(item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces);
|
||||||
|
if (move && faceCollection.All(l => !l.Saved))
|
||||||
{
|
{
|
||||||
Map.Models.Stateless.Methods.IMapLogic.SetCreationTime(mappingFromItem, locationContainers);
|
ReadOnlyCollection<LocationContainer> locationContainers = mapLogic.GetLocationContainers(item);
|
||||||
if (_Configuration.LocationContainerDistanceTolerance is null && _Configuration.MoveToDecade)
|
if (locationContainers.Count > 0)
|
||||||
Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(_Configuration.PropertyConfiguration, mappingFromItem, locationContainers);
|
{
|
||||||
_Distance.LookForMatchFacesAndPossiblyRename(_Configuration.OverrideForFaceImages, _DistanceLimits, _Faces, item.FilePath, mappingFromItem, exifDirectory, faces, locationContainers);
|
Map.Models.Stateless.Methods.IMapLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||||
|
if (_Configuration.LocationContainerDistanceTolerance is null && _Configuration.MoveToDecade)
|
||||||
|
Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(_Configuration.PropertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
_Distance.LookForMatchFacesAndPossiblyRename(_Configuration.OverrideForFaceImages, _DistanceLimits, _Faces, item.FilePath, mappingFromItem, exifDirectory, faces, locationContainers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
||||||
|
if (review || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
||||||
|
{
|
||||||
|
bool saveRotated = false;
|
||||||
|
string sourceDirectorySegment = Property.Models.Stateless.IResult.GetRelativePath(_Configuration.PropertyConfiguration, container.SourceDirectory);
|
||||||
|
_FaceParts.SaveFaceLandmarkImages(_Configuration.PropertyConfiguration, d2ResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces, saveRotated);
|
||||||
|
}
|
||||||
|
if (_Configuration.SaveFaceLandmarkForOutputResolutionsV2.Contains(outputResolution))
|
||||||
|
_FaceParts.SaveFaceLandmarkImages(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
||||||
}
|
}
|
||||||
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
|
||||||
if (review || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
|
||||||
{
|
|
||||||
bool saveRotated = false;
|
|
||||||
string sourceDirectorySegment = Property.Models.Stateless.IResult.GetRelativePath(_Configuration.PropertyConfiguration, container.SourceDirectory);
|
|
||||||
_FaceParts.SaveFaceLandmarkImages(_Configuration.PropertyConfiguration, d2ResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces, saveRotated);
|
|
||||||
}
|
|
||||||
if (_Configuration.SaveFaceLandmarkForOutputResolutionsV2.Contains(outputResolution))
|
|
||||||
_FaceParts.SaveFaceLandmarkImages(d2ResultsFullGroupDirectory, mappingFromItem, exifDirectory, faces);
|
|
||||||
}
|
}
|
||||||
lock (sourceDirectoryChanges)
|
lock (sourceDirectoryChanges)
|
||||||
{
|
{
|
||||||
@ -327,14 +338,18 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int exceptionsCount = 0;
|
int exceptionsCount = 0;
|
||||||
|
IDlibDotNet dlibDotNet = this;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
DateTime[] containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
|
DateTime[] containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
|
||||||
string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory));
|
string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory));
|
||||||
bool? isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
|
bool? isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
|
||||||
bool anyPropertiesChangedForX = _Configuration.PropertyConfiguration.PropertiesChangedForProperty || _Configuration.PropertiesChangedForDistance || _Configuration.PropertiesChangedForFaces || _Configuration.PropertiesChangedForIndex || _Configuration.PropertiesChangedForMetadata || _Configuration.PropertiesChangedForResize;
|
bool anyPropertiesChangedForX = _Configuration.PropertyConfiguration.PropertiesChangedForProperty || _Configuration.PropertiesChangedForDistance || _Configuration.PropertiesChangedForFaces || _Configuration.PropertiesChangedForIndex || _Configuration.PropertiesChangedForMetadata || _Configuration.PropertiesChangedForResize;
|
||||||
using ProgressBar progressBar = new(filteredItems.Count, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(filteredItems.Count, message);
|
||||||
_ = Parallel.For(0, filteredItems.Count, parallelOptions, (i, state) =>
|
_ = Parallel.For(0, filteredItems.Count, parallelOptions, (i, state) =>
|
||||||
{
|
{
|
||||||
|
Item item = filteredItems[i];
|
||||||
|
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result += FullParallelForWork(metadata,
|
result += FullParallelForWork(metadata,
|
||||||
@ -347,11 +362,11 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
fileNameToCollection,
|
fileNameToCollection,
|
||||||
record,
|
record,
|
||||||
container,
|
container,
|
||||||
filteredItems[i],
|
item,
|
||||||
containerDateTimes,
|
containerDateTimes,
|
||||||
isFocusRelativePath);
|
isFocusRelativePath);
|
||||||
if (!anyPropertiesChangedForX && (i == 0 || sourceDirectoryChanges.Count > 0))
|
if (!anyPropertiesChangedForX && (i == 0 || sourceDirectoryChanges.Count > 0))
|
||||||
progressBar.Tick();
|
dlibDotNet.Tick();
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
@ -365,7 +380,6 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
|
|
||||||
private void FullDoWork(string argZero,
|
private void FullDoWork(string argZero,
|
||||||
string propertyRoot,
|
string propertyRoot,
|
||||||
long ticks,
|
|
||||||
string fPhotoPrismSingletonDirectory,
|
string fPhotoPrismSingletonDirectory,
|
||||||
int count,
|
int count,
|
||||||
B_Metadata metadata,
|
B_Metadata metadata,
|
||||||
@ -413,7 +427,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
continue;
|
continue;
|
||||||
sourceDirectoryChanges.Clear();
|
sourceDirectoryChanges.Clear();
|
||||||
anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName);
|
anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName);
|
||||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds);
|
||||||
message = $"{totalSeconds} total second(s) - {outputResolution} - {i + 1:000} / {readOnlyContainers.Count:000} - {total} / {count} total - <{container.SourceDirectory}> [{filteredItems.Count:000}] - total not mapped {totalNotMapped:000000}";
|
message = $"{totalSeconds} total second(s) - {outputResolution} - {i + 1:000} / {readOnlyContainers.Count:000} - {total} / {count} total - <{container.SourceDirectory}> [{filteredItems.Count:000}] - total not mapped {totalNotMapped:000000}";
|
||||||
if (outputResolutionHasNumber)
|
if (outputResolutionHasNumber)
|
||||||
_Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory);
|
_Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory);
|
||||||
@ -448,10 +462,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
total += container.Items.Count;
|
total += container.Items.Count;
|
||||||
}
|
}
|
||||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds);
|
||||||
message = $"{totalSeconds} total second(s) - {outputResolution} - ### [###] / {readOnlyContainers.Count:000} - {total} / {count} total - <> - total not mapped {totalNotMapped:000000}";
|
message = $"{totalSeconds} total second(s) - {outputResolution} - ### [###] / {readOnlyContainers.Count:000} - {total} / {count} total - <> - total not mapped {totalNotMapped:000000}";
|
||||||
using ProgressBar progressBar = new(1, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(1, message);
|
||||||
progressBar.Tick();
|
dlibDotNet.Tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,14 +621,36 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
{
|
{
|
||||||
ExifDirectory? result;
|
ExifDirectory? result;
|
||||||
if (filePair.Match is null)
|
if (filePair.Match is null)
|
||||||
result = null;
|
{
|
||||||
|
try
|
||||||
|
{ result = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath); }
|
||||||
|
catch (Exception) { result = null; }
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string json = File.ReadAllText(filePair.Match.FullName);
|
string json = File.ReadAllText(filePair.Match.FullName);
|
||||||
if (string.IsNullOrEmpty(json))
|
if (string.IsNullOrEmpty(json))
|
||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||||
|
if (result?.FilePath?.Id is null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = Metadata.Models.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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result is not null && result.FilePath?.Id is null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{ result = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath); }
|
||||||
|
catch (Exception) { result = null; }
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -715,7 +751,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
List<(string, string, string)> collection = [];
|
List<(string, string, string)> collection = [];
|
||||||
foreach (Item item in distinctValidImageItems)
|
foreach (Item item in distinctValidImageItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (item.IsNotUniqueAndNeedsReview is null || !item.IsNotUniqueAndNeedsReview.Value)
|
if (item.IsNotUniqueAndNeedsReview is null || !item.IsNotUniqueAndNeedsReview.Value)
|
||||||
continue;
|
continue;
|
||||||
@ -728,7 +764,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
foreach (Item item in distinctValidImageItems)
|
foreach (Item item in distinctValidImageItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
continue;
|
continue;
|
||||||
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
|
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
|
||||||
if (dateTime is null)
|
if (dateTime is null)
|
||||||
@ -809,7 +845,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<FilePath> HideSplatNineAndGetMovedDuplicatesWithSameSplatNine(Property.Models.Configuration propertyConfiguration, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> keyValuePairs)
|
private static ReadOnlyCollection<FilePath> HideSplatNineAndGetMovedDuplicatesWithSameSplatNine(Property.Models.Configuration propertyConfiguration, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths)
|
||||||
{
|
{
|
||||||
List<FilePath> results = [];
|
List<FilePath> results = [];
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -817,7 +853,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
FilePath? filePath;
|
FilePath? filePath;
|
||||||
string checkDirectory;
|
string checkDirectory;
|
||||||
List<FilePath> collection = [];
|
List<FilePath> collection = [];
|
||||||
foreach (KeyValuePair<int, ReadOnlyCollection<FilePath>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<int, ReadOnlyCollection<FilePath>> keyValuePair in idToFilePaths)
|
||||||
{
|
{
|
||||||
collection.Clear();
|
collection.Clear();
|
||||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||||
@ -851,7 +887,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiers(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> keyValuePairs)
|
private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiers(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths)
|
||||||
{
|
{
|
||||||
Dictionary<int, Identifier> results = [];
|
Dictionary<int, Identifier> results = [];
|
||||||
string json;
|
string json;
|
||||||
@ -862,7 +898,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string bMetadataCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
string bMetadataCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
if (!Directory.Exists(bMetadataCollectionDirectory))
|
if (!Directory.Exists(bMetadataCollectionDirectory))
|
||||||
_ = Directory.CreateDirectory(bMetadataCollectionDirectory);
|
_ = Directory.CreateDirectory(bMetadataCollectionDirectory);
|
||||||
foreach (KeyValuePair<int, ReadOnlyCollection<FilePath>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<int, ReadOnlyCollection<FilePath>> keyValuePair in idToFilePaths)
|
||||||
{
|
{
|
||||||
filePath = null;
|
filePath = null;
|
||||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||||
@ -894,17 +930,18 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiersAndHideSplatNine(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> keyValuePairs)
|
private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiersAndHideSplatNine(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||||
{
|
{
|
||||||
ReadOnlyDictionary<int, Identifier> results;
|
ReadOnlyDictionary<int, Identifier> results;
|
||||||
if (keyValuePairs.Count == 0)
|
if (filePathsCollection.Count == 0)
|
||||||
results = new(new Dictionary<int, Identifier>());
|
results = new(new Dictionary<int, Identifier>());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<FilePath> moved = HideSplatNineAndGetMovedDuplicatesWithSameSplatNine(propertyConfiguration, keyValuePairs);
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
|
ReadOnlyCollection<FilePath> moved = HideSplatNineAndGetMovedDuplicatesWithSameSplatNine(propertyConfiguration, idToFilePaths);
|
||||||
if (moved.Count > 0)
|
if (moved.Count > 0)
|
||||||
throw new Exception($"House cleaning needed!{Environment.NewLine}{string.Join(Environment.NewLine, moved.Select(l => l.Id))}");
|
throw new Exception($"House cleaning needed!{Environment.NewLine}{string.Join(Environment.NewLine, moved.Select(l => l.Id))}");
|
||||||
results = GetSplatNineIdentifiers(propertyConfiguration, bResultsFullGroupDirectory, keyValuePairs);
|
results = GetSplatNineIdentifiers(propertyConfiguration, bResultsFullGroupDirectory, idToFilePaths);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@ -983,13 +1020,13 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReadOnlyCollection<FilePath> GetFilePath(long ticks, string dFacesContentDirectory)
|
private ReadOnlyCollection<FilePath> GetFilePath(string dFacesContentDirectory)
|
||||||
{
|
{
|
||||||
List<FilePath> results = [];
|
List<FilePath> results = [];
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
FileHolder fileHolder;
|
FileHolder fileHolder;
|
||||||
string[] files = Directory.GetFiles(dFacesContentDirectory, $"*{_Faces.FileNameExtension}", SearchOption.AllDirectories);
|
string[] files = Directory.GetFiles(dFacesContentDirectory, $"*{_Faces.FileNameExtension}", SearchOption.AllDirectories);
|
||||||
long? skipOlderThan = _Configuration.SkipOlderThanDays is null ? null : new DateTime(ticks).AddDays(-_Configuration.SkipOlderThanDays.Value).Ticks;
|
long? skipOlderThan = _Configuration.SkipOlderThanDays is null ? null : new DateTime(Ticks).AddDays(-_Configuration.SkipOlderThanDays.Value).Ticks;
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
|
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
|
||||||
@ -1003,19 +1040,22 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParallelFor(IDlibDotNet dlibDotNet, FilePair filePair, Dictionary<int, ExifDirectory> results)
|
private void ParallelFor(FilePair filePair, Dictionary<int, ExifDirectory> results, Action? tick)
|
||||||
{
|
{
|
||||||
dlibDotNet?.Tick();
|
tick?.Invoke();
|
||||||
if (filePair.FilePath.Id is null || results.ContainsKey(filePair.FilePath.Id.Value))
|
if (filePair.FilePath.Id is null || results.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
return;
|
return;
|
||||||
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
||||||
if (exifDirectory is null)
|
if (exifDirectory is null)
|
||||||
return;
|
return;
|
||||||
lock (results)
|
lock (results)
|
||||||
results.Add(filePair.FilePath.Id.Value, exifDirectory);
|
{
|
||||||
|
if (!results.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
|
results.Add(filePair.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetRunToDoCollectionFirst(Models.Configuration configuration, long ticks, string[] checkDirectories)
|
private bool GetRunToDoCollectionFirst(Models.Configuration configuration, string[] checkDirectories)
|
||||||
{
|
{
|
||||||
bool result = configuration.SaveSortingWithoutPerson;
|
bool result = configuration.SaveSortingWithoutPerson;
|
||||||
if (!result)
|
if (!result)
|
||||||
@ -1030,7 +1070,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
{
|
{
|
||||||
string seasonDirectory;
|
string seasonDirectory;
|
||||||
DirectoryInfo directoryInfo;
|
DirectoryInfo directoryInfo;
|
||||||
DateTime dateTime = new(ticks);
|
DateTime dateTime = new(Ticks);
|
||||||
string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory;
|
string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory;
|
||||||
string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
|
string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
|
||||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||||
@ -1067,15 +1107,14 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Search(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string argZero, string propertyRoot)
|
private void Search(ReadOnlyCollection<PersonContainer> personContainers, string argZero, string propertyRoot)
|
||||||
{
|
{
|
||||||
string message;
|
|
||||||
MapLogic? mapLogic;
|
MapLogic? mapLogic;
|
||||||
Record? record = null;
|
Record? record = null;
|
||||||
string seasonDirectory;
|
string seasonDirectory;
|
||||||
A_Property propertyLogic;
|
A_Property propertyLogic;
|
||||||
IDlibDotNet dlibDotNet = this;
|
IDlibDotNet dlibDotNet = this;
|
||||||
DateTime dateTime = new(ticks);
|
DateTime dateTime = new(Ticks);
|
||||||
string eDistanceContentDirectory;
|
string eDistanceContentDirectory;
|
||||||
string? a2PeopleContentDirectory;
|
string? a2PeopleContentDirectory;
|
||||||
string aResultsFullGroupDirectory;
|
string aResultsFullGroupDirectory;
|
||||||
@ -1087,25 +1126,25 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
bool configurationOutputResolutionsHas = false;
|
bool configurationOutputResolutionsHas = false;
|
||||||
ReadOnlyDictionary<long, List<int>> personKeyToIds;
|
ReadOnlyDictionary<long, List<int>> personKeyToIds;
|
||||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
|
||||||
string[] checkDirectories =
|
string[] checkDirectories =
|
||||||
[
|
[
|
||||||
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Ancestry"),
|
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Ancestry"),
|
||||||
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Facebook"),
|
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Facebook"),
|
||||||
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "LinkedIn")
|
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "LinkedIn")
|
||||||
];
|
];
|
||||||
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks, checkDirectories);
|
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, checkDirectories);
|
||||||
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||||
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks);
|
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||||
|
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, dlibDotNet.Ticks);
|
||||||
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
|
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
|
||||||
eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
|
eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
|
||||||
string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton);
|
string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton);
|
||||||
_ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, ticks.ToString()));
|
_ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, dlibDotNet.Ticks.ToString()));
|
||||||
B_Metadata metadata = new(dlibDotNet, _Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, ticks, bResultsFullGroupDirectory);
|
B_Metadata metadata = new(dlibDotNet, _Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, dlibDotNet.Ticks, bResultsFullGroupDirectory);
|
||||||
if (runToDoCollectionFirst)
|
if (runToDoCollectionFirst)
|
||||||
mapLogic = null;
|
mapLogic = null;
|
||||||
else
|
else
|
||||||
mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, dlibDotNet.Ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
if (outputResolution.Any(char.IsNumber))
|
if (outputResolution.Any(char.IsNumber))
|
||||||
@ -1113,7 +1152,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
configurationOutputResolutionsHas = true;
|
configurationOutputResolutionsHas = true;
|
||||||
if (!runToDoCollectionFirst)
|
if (!runToDoCollectionFirst)
|
||||||
break;
|
break;
|
||||||
record = GetFilesCollectionThenCopyOrMove(dlibDotNet, ticks, fileSearchFilter, directorySearchFilter, bResultsFullGroupDirectory, outputResolution);
|
record = GetFilesCollectionThenCopyOrMove(dlibDotNet, metadata, fileSearchFilter, directorySearchFilter, bResultsFullGroupDirectory, outputResolution);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent);
|
fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent);
|
||||||
@ -1145,30 +1184,21 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
{
|
{
|
||||||
if (outputResolution.Any(char.IsNumber))
|
if (outputResolution.Any(char.IsNumber))
|
||||||
continue;
|
continue;
|
||||||
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
|
||||||
(cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
(cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||||
string? filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
string? filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: true);
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: true);
|
||||||
|
ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = record?.ExifDirectoriesById ?? new(new Dictionary<int, ExifDirectory>());
|
||||||
record = new(FilesCollectionRootDirectory: filesCollectionRootDirectory,
|
record = new(FilesCollectionRootDirectory: filesCollectionRootDirectory,
|
||||||
FilesCollectionCountIsOne: false,
|
FilesCollectionCountIsOne: false,
|
||||||
FilePathsCollection: filePathsCollection,
|
FilePathsCollection: filePathsCollection,
|
||||||
ExifDirectoriesById: new(exifDirectoriesById),
|
ExifDirectoriesById: exifDirectoriesById,
|
||||||
IdToFilePaths: null,
|
|
||||||
SplatNineIdentifiers: null);
|
SplatNineIdentifiers: null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(record?.FilesCollectionRootDirectory) || record.FilePathsCollection.Count == 0)
|
if (string.IsNullOrEmpty(record?.FilesCollectionRootDirectory) || record.FilePathsCollection.Count == 0)
|
||||||
throw new NullReferenceException(nameof(record.FilePathsCollection));
|
throw new NullReferenceException(nameof(record.FilePathsCollection));
|
||||||
foreach (string checkDirectory in checkDirectories)
|
|
||||||
{
|
|
||||||
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
|
|
||||||
if (!Directory.Exists(seasonDirectory))
|
|
||||||
_ = Directory.CreateDirectory(seasonDirectory);
|
|
||||||
}
|
|
||||||
int count = record.FilePathsCollection.Select(l => l.Count).Sum();
|
int count = record.FilePathsCollection.Select(l => l.Count).Sum();
|
||||||
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
|
||||||
_ProgressBar = new(count, message, _ProgressBarOptions);
|
|
||||||
ReadOnlyCollection<Container.Models.Container> readOnlyContainers =
|
ReadOnlyCollection<Container.Models.Container> readOnlyContainers =
|
||||||
Container.Models.Stateless.Methods.IContainer.GetContainers(dlibDotNet,
|
Container.Models.Stateless.Methods.IContainer.GetContainers(dlibDotNet,
|
||||||
_Configuration.PropertyConfiguration,
|
_Configuration.PropertyConfiguration,
|
||||||
@ -1176,24 +1206,21 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
_Faces.HiddenFileNameExtension,
|
_Faces.HiddenFileNameExtension,
|
||||||
eDistanceContentDirectory,
|
eDistanceContentDirectory,
|
||||||
record.FilesCollectionRootDirectory,
|
record.FilesCollectionRootDirectory,
|
||||||
record.IdToFilePaths,
|
|
||||||
record.SplatNineIdentifiers,
|
record.SplatNineIdentifiers,
|
||||||
record.FilePathsCollection,
|
record.FilePathsCollection,
|
||||||
record.ExifDirectoriesById);
|
record.ExifDirectoriesById);
|
||||||
_ProgressBar.Dispose();
|
Verify(argZero, readOnlyContainers);
|
||||||
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
foreach (string checkDirectory in checkDirectories)
|
||||||
|
{
|
||||||
|
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
|
||||||
|
if (!Directory.Exists(seasonDirectory))
|
||||||
|
_ = Directory.CreateDirectory(seasonDirectory);
|
||||||
|
}
|
||||||
|
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, dlibDotNet.Ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
DeleteContinueFiles(personContainers);
|
DeleteContinueFiles(personContainers);
|
||||||
if (!runToDoCollectionFirst)
|
if (!runToDoCollectionFirst)
|
||||||
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory);
|
MapFaceFileLogic(personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory);
|
||||||
FullDoWork(argZero,
|
FullDoWork(argZero, propertyRoot, fPhotoPrismSingletonDirectory, count, metadata, record, readOnlyContainers, mapLogic);
|
||||||
propertyRoot,
|
|
||||||
ticks,
|
|
||||||
fPhotoPrismSingletonDirectory,
|
|
||||||
count,
|
|
||||||
metadata,
|
|
||||||
record,
|
|
||||||
readOnlyContainers,
|
|
||||||
mapLogic);
|
|
||||||
ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
|
ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
|
||||||
if (_Configuration.LookForAbandoned)
|
if (_Configuration.LookForAbandoned)
|
||||||
{
|
{
|
||||||
@ -1201,10 +1228,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string d2ResultsFullGroupDirectory;
|
string d2ResultsFullGroupDirectory;
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(5, nameof(mapLogic.LookForAbandoned));
|
||||||
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||||
mapLogic.LookForAbandoned(dlibDotNet, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
mapLogic.LookForAbandoned(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, dlibDotNet.Tick);
|
||||||
_ProgressBar.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_Distance.Clear();
|
_Distance.Clear();
|
||||||
@ -1215,7 +1241,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
if (!Directory.Exists(eDistanceContentDirectory))
|
if (!Directory.Exists(eDistanceContentDirectory))
|
||||||
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
||||||
string json = JsonSerializer.Serialize(distinctValidImageMappingCollection);
|
string json = JsonSerializer.Serialize(distinctValidImageMappingCollection);
|
||||||
File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json);
|
File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{Ticks}.json"), json);
|
||||||
}
|
}
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
@ -1233,7 +1259,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
&& outputResolution == _Configuration.OutputResolutions[0]
|
&& outputResolution == _Configuration.OutputResolutions[0]
|
||||||
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
|
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
|
||||||
&& _Exceptions.Count == 0)
|
&& _Exceptions.Count == 0)
|
||||||
MapLogic(ticks, readOnlyContainers, fPhotoPrismContentDirectory, mapLogic, outputResolution, new(personKeyToIds), distinctValidImageFaces, distinctValidImageMappingCollection);
|
MapLogic(readOnlyContainers, fPhotoPrismContentDirectory, mapLogic, outputResolution, personKeyToIds.AsReadOnly(), distinctValidImageFaces, distinctValidImageMappingCollection);
|
||||||
if (runToDoCollectionFirst && _Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && record?.SplatNineIdentifiers is not null && distinctValidImageMappingCollection.Count > 0)
|
if (runToDoCollectionFirst && _Configuration.SaveRandomForOutputResolutions.Contains(outputResolution) && personKeyToIds.Count > 0 && record?.SplatNineIdentifiers is not null && distinctValidImageMappingCollection.Count > 0)
|
||||||
_Random.Random(_Configuration.PropertyConfiguration, _Configuration.ImmichAssetsFile, _Configuration.ImmichOwnerId, _Configuration.ImmichRoot, _Configuration.RadomUseBirthdayMinimum, _Configuration.ValidKeyWordsToIgnoreInRandom, personKeyToIds, record.SplatNineIdentifiers, distinctValidImageMappingCollection);
|
_Random.Random(_Configuration.PropertyConfiguration, _Configuration.ImmichAssetsFile, _Configuration.ImmichOwnerId, _Configuration.ImmichRoot, _Configuration.RadomUseBirthdayMinimum, _Configuration.ValidKeyWordsToIgnoreInRandom, personKeyToIds, record.SplatNineIdentifiers, distinctValidImageMappingCollection);
|
||||||
if (_IsEnvironment.Development)
|
if (_IsEnvironment.Development)
|
||||||
@ -1253,59 +1279,96 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Record GetFilesCollectionThenCopyOrMove(IDlibDotNet dlibDotNet, long ticks, string fileSearchFilter, string directorySearchFilter, string bResultsFullGroupDirectory, string outputResolution)
|
private void Verify(string argZero, ReadOnlyCollection<Container.Models.Container> readOnlyContainers)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
List<Item> items = [];
|
||||||
|
Container.Models.Container container;
|
||||||
|
ReadOnlyCollection<Item> filteredItems;
|
||||||
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < readOnlyContainers.Count; i++)
|
||||||
|
{
|
||||||
|
container = readOnlyContainers[i];
|
||||||
|
if (container.Items.Count == 0)
|
||||||
|
continue;
|
||||||
|
if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
|
||||||
|
continue;
|
||||||
|
filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, container);
|
||||||
|
if (filteredItems.Count == 0)
|
||||||
|
continue;
|
||||||
|
foreach (Item item in filteredItems)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (item.ExifDirectory is null || item.ExifDirectory.FilePath?.Id is null)
|
||||||
|
{
|
||||||
|
items.Add(item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||||
|
{
|
||||||
|
items.Add(item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (items.Count > 0)
|
||||||
|
throw new Exception($"{items.Count} item(s) of {count} item(s) are not setup!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Record GetFilesCollectionThenCopyOrMove(IDlibDotNet dlibDotNet, B_Metadata metadata, string fileSearchFilter, string directorySearchFilter, string bResultsFullGroupDirectory, string outputResolution)
|
||||||
{
|
{
|
||||||
Record result;
|
Record result;
|
||||||
int count;
|
int count;
|
||||||
string message;
|
string message;
|
||||||
ProgressBar progressBar;
|
|
||||||
const string extension = ".json";
|
const string extension = ".json";
|
||||||
ReadOnlyCollection<FilePair> filePairs;
|
ReadOnlyCollection<FilePair> filePairs;
|
||||||
|
Dictionary<int, ExifDirectory> results = [];
|
||||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
|
||||||
string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory;
|
string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
(string cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
(string cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||||
string jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton);
|
string jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton);
|
||||||
if (!Directory.Exists(jsonGroupDirectory))
|
if (!Directory.Exists(jsonGroupDirectory))
|
||||||
_ = Directory.CreateDirectory(jsonGroupDirectory);
|
_ = Directory.CreateDirectory(jsonGroupDirectory);
|
||||||
IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs =
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs =
|
||||||
Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent]);
|
Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent]);
|
||||||
ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups = keyValuePairs[_Configuration.PropertyConfiguration.ResultContent];
|
ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups = keyValuePairs[_Configuration.PropertyConfiguration.ResultContent];
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
||||||
|
foreach (KeyValuePair<int, ExifDirectory> keyValuePair in metadata.GetKeyValuePairsAndClear())
|
||||||
|
results.Add(keyValuePair.Key, keyValuePair.Value);
|
||||||
count = filePathsCollection.Select(l => l.Count).Sum();
|
count = filePathsCollection.Select(l => l.Count).Sum();
|
||||||
filePairs = IFilePair.GetFilePairs(_Configuration.PropertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
filePairs = IFilePair.GetFilePairs(_Configuration.PropertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
message = $") {nameof(DlibDotNet)} - Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds)} total second(s)";
|
||||||
progressBar = new(count, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(count, message);
|
||||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], exifDirectoriesById));
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(filePairs[i], results, dlibDotNet.Tick));
|
||||||
progressBar.Dispose();
|
if (results.Count == 0)
|
||||||
|
throw new Exception("No exif directories were found!");
|
||||||
count = filePathsCollection.Select(l => l.Count).Sum();
|
count = filePathsCollection.Select(l => l.Count).Sum();
|
||||||
|
ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = results.AsReadOnly();
|
||||||
bool filesCollectionCountIsOne = GetFilesCollectionCountIsOne(filePathsCollection);
|
bool filesCollectionCountIsOne = GetFilesCollectionCountIsOne(filePathsCollection);
|
||||||
message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds)} total second(s)";
|
||||||
progressBar = new(count, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(count, message);
|
||||||
(string[] distinctDirectories, List<(FilePath, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, () => progressBar.Tick());
|
(string[] distinctDirectories, List<(FilePath, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, dlibDotNet.Tick);
|
||||||
progressBar.Dispose();
|
|
||||||
foreach (string distinctDirectory in distinctDirectories)
|
foreach (string distinctDirectory in distinctDirectories)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(distinctDirectory))
|
if (!Directory.Exists(distinctDirectory))
|
||||||
_ = Directory.CreateDirectory(distinctDirectory);
|
_ = Directory.CreateDirectory(distinctDirectory);
|
||||||
}
|
}
|
||||||
message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds)} total second(s)";
|
||||||
progressBar = new(count, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(count, message);
|
||||||
_ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick());
|
_ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, dlibDotNet.Tick);
|
||||||
progressBar.Dispose();
|
ReadOnlyDictionary<int, Identifier> splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, filePathsCollection);
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
result = new(ExifDirectoriesById: exifDirectoriesById,
|
||||||
ReadOnlyDictionary<int, Identifier> splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, idToFilePaths);
|
|
||||||
result = new(ExifDirectoriesById: new(exifDirectoriesById),
|
|
||||||
FilesCollectionRootDirectory: filesCollectionRootDirectory,
|
FilesCollectionRootDirectory: filesCollectionRootDirectory,
|
||||||
FilesCollectionCountIsOne: filesCollectionCountIsOne,
|
FilesCollectionCountIsOne: filesCollectionCountIsOne,
|
||||||
FilePathsCollection: filePathsCollection,
|
FilePathsCollection: filePathsCollection,
|
||||||
IdToFilePaths: idToFilePaths,
|
|
||||||
SplatNineIdentifiers: splatNineIdentifiers);
|
SplatNineIdentifiers: splatNineIdentifiers);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MapFaceFileLogic(long ticks, ReadOnlyCollection<PersonContainer> personContainers, MapLogic mapLogic, string? a2PeopleContentDirectory, string eDistanceContentDirectory)
|
private void MapFaceFileLogic(ReadOnlyCollection<PersonContainer> personContainers, MapLogic mapLogic, string? a2PeopleContentDirectory, string eDistanceContentDirectory)
|
||||||
{
|
{
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
@ -1323,7 +1386,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
continue;
|
continue;
|
||||||
if (!_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution))
|
if (!_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution))
|
||||||
continue;
|
continue;
|
||||||
List<SaveContainer> saveContainers = GetSaveContainers(ticks, personContainers, a2PeopleContentDirectory, eDistanceContentDirectory, mapLogic, outputResolution);
|
List<SaveContainer> saveContainers = GetSaveContainers(personContainers, a2PeopleContentDirectory, eDistanceContentDirectory, mapLogic, outputResolution);
|
||||||
if (saveContainers.Count > 0)
|
if (saveContainers.Count > 0)
|
||||||
{
|
{
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
@ -1333,24 +1396,24 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SaveContainer> GetSaveContainers(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, MapLogic mapLogic, string outputResolution)
|
private List<SaveContainer> GetSaveContainers(ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, MapLogic mapLogic, string outputResolution)
|
||||||
{
|
{
|
||||||
List<SaveContainer> results;
|
List<SaveContainer> results;
|
||||||
IDlibDotNet dlibDotNet = this;
|
IDlibDotNet dlibDotNet = this;
|
||||||
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
||||||
(string cResultsFullGroupDirectory, string _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
(string cResultsFullGroupDirectory, string _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||||
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped = Map.Models.Stateless.Methods.IMapLogic.GetMapped(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped = Map.Models.Stateless.Methods.IMapLogic.GetMapped(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, dlibDotNet.Ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
if (mapped.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
if (mapped.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
||||||
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
||||||
ReadOnlyCollection<FilePath> filePaths = GetFilePath(ticks, dFacesContentDirectory);
|
ReadOnlyCollection<FilePath> filePaths = GetFilePath(dFacesContentDirectory);
|
||||||
List<LocationContainer> available = Map.Models.Stateless.Methods.IMapLogic.GetAvailable(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, _Faces, ticks, filePaths);
|
List<LocationContainer> available = Map.Models.Stateless.Methods.IMapLogic.GetAvailable(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, _Faces, dlibDotNet.Ticks, filePaths);
|
||||||
if (!string.IsNullOrEmpty(_Configuration.FocusDirectory) && _Configuration.FocusDirectory.Length != 2)
|
if (!string.IsNullOrEmpty(_Configuration.FocusDirectory) && _Configuration.FocusDirectory.Length != 2)
|
||||||
throw new NotSupportedException($"{nameof(_Configuration.FocusDirectory)} currently only works with output directory! Example 00.");
|
throw new NotSupportedException($"{nameof(_Configuration.FocusDirectory)} currently only works with output directory! Example 00.");
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding = E_Distance.GetMappedWithEncoding(mapped);
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding = E_Distance.GetMappedWithEncoding(mapped);
|
||||||
if (mappedWithEncoding.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
if (mappedWithEncoding.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
||||||
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
||||||
List<LocationContainer> preFiltered = E_Distance.GetPreFilterLocationContainer(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, _Configuration.FocusDirectory, _Configuration.FocusModel, _Configuration.SkipPersonWithMoreThen, ticks, mapLogic, jLinkResolvedPersonKeys, mapped, available);
|
List<LocationContainer> preFiltered = E_Distance.GetPreFilterLocationContainer(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, _Configuration.FocusDirectory, _Configuration.FocusModel, _Configuration.SkipPersonWithMoreThen, dlibDotNet.Ticks, mapLogic, jLinkResolvedPersonKeys, mapped, available);
|
||||||
if (preFiltered.Count == 0)
|
if (preFiltered.Count == 0)
|
||||||
results = [];
|
results = [];
|
||||||
else
|
else
|
||||||
@ -1361,10 +1424,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
results = [];
|
results = [];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - dlibDotNet.Ticks).TotalSeconds)} total second(s)";
|
||||||
_ProgressBar = new(postFiltered.Count, message, _ProgressBarOptions);
|
dlibDotNet.ConstructProgressBar(postFiltered.Count, message);
|
||||||
ReadOnlyCollection<LocationContainer> matrix = E_Distance.GetMatrixLocationContainers(dlibDotNet, _MapConfiguration, ticks, mapLogic, mappedWithEncoding, preFiltered, distanceLimits, postFiltered);
|
ReadOnlyCollection<LocationContainer> matrix = E_Distance.GetMatrixLocationContainers(_MapConfiguration, dlibDotNet.Ticks, mapLogic, mappedWithEncoding, preFiltered, distanceLimits, postFiltered, dlibDotNet.Tick);
|
||||||
_ProgressBar.Dispose();
|
|
||||||
ReadOnlyDictionary<string, LocationContainer> onlyOne = GetOnlyOne(distanceLimits, matrix);
|
ReadOnlyDictionary<string, LocationContainer> onlyOne = GetOnlyOne(distanceLimits, matrix);
|
||||||
if (onlyOne.Count == 0)
|
if (onlyOne.Count == 0)
|
||||||
results = [];
|
results = [];
|
||||||
@ -1403,7 +1465,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
|
isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
|
||||||
foreach (Item item in filteredItems)
|
foreach (Item item in filteredItems)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null || item.ResizedFileHolder is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder);
|
mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder);
|
||||||
if (distinctItems)
|
if (distinctItems)
|
||||||
@ -1458,7 +1520,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
return (result, notMapped);
|
return (result, notMapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MapLogic(long ticks, ReadOnlyCollection<Container.Models.Container> containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
private void MapLogic(ReadOnlyCollection<Container.Models.Container> containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||||
{
|
{
|
||||||
IDlibDotNet dlibDotNet = this;
|
IDlibDotNet dlibDotNet = this;
|
||||||
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||||
@ -1467,24 +1529,25 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContentCollection);
|
string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContentCollection);
|
||||||
if (distinctValidImageMappingCollection.Count > 0)
|
if (distinctValidImageMappingCollection.Count > 0)
|
||||||
{
|
{
|
||||||
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, ticks);
|
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(d2FacePartsContentDirectory, dlibDotNet.Ticks);
|
||||||
if (Directory.Exists(d2FacePartsContentCollectionDirectory))
|
if (Directory.Exists(d2FacePartsContentCollectionDirectory))
|
||||||
Shared.Models.Stateless.Methods.IPath.MakeHiddenIfAllItemsAreHidden(d2FacePartsContentCollectionDirectory);
|
Shared.Models.Stateless.Methods.IPath.MakeHiddenIfAllItemsAreHidden(d2FacePartsContentCollectionDirectory);
|
||||||
}
|
}
|
||||||
if (Directory.Exists(fPhotoPrismContentDirectory))
|
if (Directory.Exists(fPhotoPrismContentDirectory))
|
||||||
F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, ticks, distinctValidImageFaces, mapLogic);
|
F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, _Configuration.RectangleIntersectMinimums, dlibDotNet.Ticks, distinctValidImageFaces, mapLogic);
|
||||||
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
|
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
|
||||||
mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctValidImageMappingCollection);
|
mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctValidImageMappingCollection);
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||||
if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution))
|
if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution))
|
||||||
mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctValidImageMappingCollection, idToWholePercentagesToMapping);
|
mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, personKeyToIds, distinctValidImageMappingCollection, idToWholePercentagesToMapping);
|
||||||
if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution))
|
if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution))
|
||||||
SaveFaceDistances(ticks, mapLogic, distinctValidImageFaces, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping);
|
SaveFaceDistances(mapLogic, distinctValidImageFaces, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveFaceDistances(long ticks, MapLogic mapLogic, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
|
private void SaveFaceDistances(MapLogic mapLogic, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping)
|
||||||
{
|
{
|
||||||
E_Distance.PreFilterSetFaceDistances(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, distinctValidImageFaces);
|
IDlibDotNet dlibDotNet = this;
|
||||||
|
E_Distance.PreFilterSetFaceDistances(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, dlibDotNet.Ticks, distinctValidImageFaces);
|
||||||
ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers = E_Distance.GetFaceDistanceContainers(distinctValidImageFaces);
|
ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers = E_Distance.GetFaceDistanceContainers(distinctValidImageFaces);
|
||||||
if (faceDistanceContainers.Count > 0)
|
if (faceDistanceContainers.Count > 0)
|
||||||
{
|
{
|
||||||
@ -1495,24 +1558,25 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
continue;
|
continue;
|
||||||
faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance);
|
faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance);
|
||||||
}
|
}
|
||||||
SaveFaceDistances(ticks, mapLogic, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, new(faceDistanceEncodings), faceDistanceContainers);
|
SaveFaceDistances(mapLogic, dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, faceDistanceEncodings.AsReadOnly(), faceDistanceContainers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveFaceDistances(long ticks, MapLogic mapLogic, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers)
|
private void SaveFaceDistances(MapLogic mapLogic, string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers)
|
||||||
{
|
{
|
||||||
int? useFiltersCounter = null;
|
int? useFiltersCounter = null;
|
||||||
|
IDlibDotNet dlibDotNet = this;
|
||||||
DistanceLimits distanceLimits;
|
DistanceLimits distanceLimits;
|
||||||
ReadOnlyCollection<SortingContainer> sortingContainers;
|
ReadOnlyCollection<SortingContainer> sortingContainers;
|
||||||
FaceDistanceContainer[] filteredFaceDistanceContainers;
|
FaceDistanceContainer[] filteredFaceDistanceContainers;
|
||||||
long? skipOlderThan = _Configuration.SkipOlderThanDays is null ? null : new DateTime(ticks).AddDays(-_Configuration.SkipOlderThanDays.Value).Ticks;
|
long? skipOlderThan = _Configuration.SkipOlderThanDays is null ? null : new DateTime(Ticks).AddDays(-_Configuration.SkipOlderThanDays.Value).Ticks;
|
||||||
distanceLimits = new(_Configuration.FaceAreaPermyriad, _Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh);
|
distanceLimits = new(_Configuration.FaceAreaPermyriad, _Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh);
|
||||||
filteredFaceDistanceContainers = E_Distance.FilteredPostLoadFaceDistanceContainers(mapLogic, faceDistanceContainers, skipOlderThan, distanceLimits);
|
filteredFaceDistanceContainers = E_Distance.FilteredPostLoadFaceDistanceContainers(mapLogic, faceDistanceContainers, skipOlderThan, distanceLimits);
|
||||||
if (filteredFaceDistanceContainers.Length == 0)
|
if (filteredFaceDistanceContainers.Length == 0)
|
||||||
_Logger?.LogInformation("All images have been filtered!");
|
_Logger?.LogInformation("All images have been filtered!");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortedSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distanceLimits, faceDistanceEncodings, filteredFaceDistanceContainers);
|
sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortedSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, dlibDotNet.Ticks, mapLogic, distanceLimits, faceDistanceEncodings, filteredFaceDistanceContainers);
|
||||||
if (sortingContainers.Count == 0)
|
if (sortingContainers.Count == 0)
|
||||||
{
|
{
|
||||||
for (useFiltersCounter = 1; useFiltersCounter < _Configuration.UseFilterTries; useFiltersCounter++)
|
for (useFiltersCounter = 1; useFiltersCounter < _Configuration.UseFilterTries; useFiltersCounter++)
|
||||||
@ -1523,7 +1587,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
_Logger?.LogInformation("All images have been filtered!");
|
_Logger?.LogInformation("All images have been filtered!");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortedSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distanceLimits, faceDistanceEncodings, filteredFaceDistanceContainers);
|
sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortedSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, dlibDotNet.Ticks, mapLogic, distanceLimits, faceDistanceEncodings, filteredFaceDistanceContainers);
|
||||||
if (sortingContainers.Count == 0)
|
if (sortingContainers.Count == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1599,11 +1663,11 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
MappingFromFilterPre mappingFromFilterPre;
|
MappingFromFilterPre mappingFromFilterPre;
|
||||||
MappingFromFilterPost mappingFromFilterPost;
|
MappingFromFilterPost mappingFromFilterPost;
|
||||||
bool? isFocusModel = GetIsFocusModel(item.ExifDirectory);
|
bool? isFocusModel = GetIsFocusModel(item.ExifDirectory);
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(item.ExifDirectory?.FilePath.Id);
|
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(item.ExifDirectory?.FilePath?.Id);
|
||||||
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
||||||
foreach (Shared.Models.Face face in faces)
|
foreach (Shared.Models.Face face in faces)
|
||||||
{
|
{
|
||||||
if (item.ExifDirectory?.FilePath.Id is null || face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
if (item.ExifDirectory?.FilePath?.Id is null || face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||||
{
|
{
|
||||||
canReMap = null;
|
canReMap = null;
|
||||||
isFocusPerson = null;
|
isFocusPerson = null;
|
||||||
|
@ -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,7 +320,7 @@ 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.ExifDirectory?.FilePath.Id is null)
|
if (item.ExifDirectory?.FilePath?.Id is null)
|
||||||
results = [];
|
results = [];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -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)
|
||||||
|
@ -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.ExifDirectory?.FilePath.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;
|
||||||
|
@ -14,10 +14,7 @@ namespace View_by_Distance.Metadata.Models;
|
|||||||
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
||||||
{
|
{
|
||||||
|
|
||||||
public string DateGroupDirectory { get; init; }
|
private readonly Dictionary<int, ExifDirectory> _ExifDirectoriesById;
|
||||||
public ReadOnlyCollection<FilePath> Collection { get; private set; }
|
|
||||||
public ReadOnlyDictionary<int, List<FilePath>> SingletonById { get; private set; }
|
|
||||||
public ReadOnlyDictionary<int, ExifDirectory> ExifDirectoriesById { get; private set; }
|
|
||||||
|
|
||||||
// First
|
// First
|
||||||
// Set DateGroupDirectory
|
// Set DateGroupDirectory
|
||||||
@ -50,52 +47,49 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
else
|
else
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
List<ExifDirectory> results = [];
|
|
||||||
string jsonGroupDirectory;
|
|
||||||
const string extension = ".json";
|
const string extension = ".json";
|
||||||
const string fileSearchFilter = "*";
|
const string fileSearchFilter = "*";
|
||||||
string filesCollectionRootDirectory;
|
string filesCollectionRootDirectory;
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
|
||||||
filesCollectionRootDirectory = propertyConfiguration.RootDirectory;
|
|
||||||
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
||||||
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
|
Action? tick = dlibDotNet is null ? null : dlibDotNet.Tick;
|
||||||
|
filesCollectionRootDirectory = propertyConfiguration.RootDirectory;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
string jsonGroupSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
string jsonGroupSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||||
string jsonGroupCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
string jsonGroupCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
||||||
ReadOnlyCollection<string> directories = new([jsonGroupSingletonDirectory, jsonGroupCollectionDirectory]);
|
ReadOnlyCollection<string> directories = new([jsonGroupSingletonDirectory, jsonGroupCollectionDirectory]);
|
||||||
Shared.Models.Stateless.Methods.IPath.CreateDirectories(directories);
|
Shared.Models.Stateless.Methods.IPath.CreateDirectories(directories);
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: false);
|
||||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
ReadOnlyCollection<FilePair> filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupSingletonDirectory, filePathsCollection);
|
||||||
ReadOnlyCollection<FilePair> filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupSingletonDirectory, filePathsCollection, fileNamesToFiles);
|
string message = $") {nameof(B_Metadata)} - Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||||
string message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
|
||||||
dlibDotNet?.ConstructProgressBar(filePairs.Count, message);
|
dlibDotNet?.ConstructProgressBar(filePairs.Count, message);
|
||||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], results));
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(filePairs[i], exifDirectoriesById, tick));
|
||||||
jsonGroupDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
|
_ExifDirectoriesById = exifDirectoriesById;
|
||||||
foreach (ExifDirectory exifDirectory in results)
|
|
||||||
{
|
|
||||||
if (exifDirectory.FilePath.Id is null || exifDirectoriesById.ContainsKey(exifDirectory.FilePath.Id.Value))
|
|
||||||
continue;
|
|
||||||
exifDirectoriesById.Add(exifDirectory.FilePath.Id.Value, exifDirectory);
|
|
||||||
}
|
|
||||||
ExifDirectoriesById = new(exifDirectoriesById);
|
|
||||||
DateGroupDirectory = bResultsFullGroupDirectory;
|
|
||||||
SingletonById = fileNamesToFiles;
|
|
||||||
filesCollectionRootDirectory = jsonGroupCollectionDirectory;
|
|
||||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsSingletonCollection = IDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory,
|
|
||||||
useIgnoreExtensions: false, useCeilingAverage: false);
|
|
||||||
Collection = filePathsSingletonCollection[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParallelFor(IDlibDotNet? dlibDotNet, FilePair filePair, List<ExifDirectory> results)
|
public ReadOnlyDictionary<int, ExifDirectory> GetKeyValuePairsAndClear()
|
||||||
{
|
{
|
||||||
dlibDotNet?.Tick();
|
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)
|
if (filePair.FilePath.Id is null)
|
||||||
return;
|
return;
|
||||||
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
|
||||||
if (exifDirectory is null)
|
if (exifDirectory is null)
|
||||||
return;
|
return;
|
||||||
lock (results)
|
lock (results)
|
||||||
results.Add(exifDirectory);
|
{
|
||||||
|
if (!results.ContainsKey(filePair.FilePath.Id.Value))
|
||||||
|
results.Add(filePair.FilePath.Id.Value, exifDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExifDirectory? GetExifDirectory(FilePair filePair)
|
private static ExifDirectory? GetExifDirectory(FilePair filePair)
|
||||||
@ -105,11 +99,24 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string json = File.ReadAllText(filePair.Match.FullName);
|
string json;
|
||||||
|
json = File.ReadAllText(filePair.Match.FullName);
|
||||||
if (string.IsNullOrEmpty(json))
|
if (string.IsNullOrEmpty(json))
|
||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
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;
|
||||||
}
|
}
|
||||||
@ -203,7 +210,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
|
|||||||
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));
|
||||||
@ -213,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);
|
||||||
}
|
}
|
||||||
@ -221,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);
|
||||||
}
|
}
|
||||||
@ -232,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;
|
||||||
@ -250,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;
|
||||||
@ -268,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;
|
||||||
@ -286,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;
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
using System.Globalization;
|
|
||||||
using View_by_Distance.Shared.Models;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
|
||||||
|
|
||||||
internal static class Base
|
|
||||||
{
|
|
||||||
|
|
||||||
internal static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories)
|
|
||||||
{
|
|
||||||
string? result = null;
|
|
||||||
if (exifBaseDirectories is not null)
|
|
||||||
{
|
|
||||||
string value;
|
|
||||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
|
||||||
{
|
|
||||||
value = exifDirectoryBase?.Make is null ? string.Empty : exifDirectoryBase.Make.ToString().Trim();
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = $"{value[0].ToString().ToUpper()}{value[1..].ToLower()}";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories)
|
|
||||||
{
|
|
||||||
string? result = null;
|
|
||||||
if (exifBaseDirectories is not null)
|
|
||||||
{
|
|
||||||
string value;
|
|
||||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
|
||||||
{
|
|
||||||
value = exifDirectoryBase?.Model is null ? string.Empty : exifDirectoryBase.Model.ToString().Trim();
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
|
||||||
|
|
||||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
|
||||||
{
|
|
||||||
DateTime? result;
|
|
||||||
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
|
||||||
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
|
||||||
result = dateTime;
|
|
||||||
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
|
||||||
result = dateTime;
|
|
||||||
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
|
||||||
result = dateTime;
|
|
||||||
else
|
|
||||||
result = null;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
|
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
|
||||||
|
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
for (int i = 0; i < magicBytesLengths[0]; i++)
|
||||||
{
|
{
|
||||||
if (StartsWith(magicBytes, kvPair.Key))
|
magicBytes.Add(binaryReader.ReadByte());
|
||||||
return kvPair.Value(binaryReader);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
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);
|
|
||||||
|
|
||||||
}
|
}
|
@ -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,40 +65,6 @@ public class A_Property
|
|||||||
converted: false));
|
converted: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ExifDirectory")]
|
|
||||||
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container.Models.Container[] containers)
|
|
||||||
{
|
|
||||||
int total = 0;
|
|
||||||
string message;
|
|
||||||
int totalSeconds;
|
|
||||||
bool anyNullOrNoIsUniqueFileName;
|
|
||||||
List<Exception> exceptions = [];
|
|
||||||
Container.Models.Container container;
|
|
||||||
int containersLength = containers.Length;
|
|
||||||
const string outputResolution = "Original";
|
|
||||||
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
|
|
||||||
string propertyRoot = IResult.GetResultsGroupDirectory(_PropertyConfiguration, nameof(A_Property));
|
|
||||||
for (int i = 0; i < containers.Length; i++)
|
|
||||||
{
|
|
||||||
container = containers[i];
|
|
||||||
if (container.Items.Count == 0)
|
|
||||||
continue;
|
|
||||||
sourceDirectoryChanges.Clear();
|
|
||||||
if (container.Items.Count == 0)
|
|
||||||
continue;
|
|
||||||
anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName);
|
|
||||||
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
|
|
||||||
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
||||||
message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
|
||||||
SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message);
|
|
||||||
if (exceptions.Count == container.Items.Count)
|
|
||||||
throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!"));
|
|
||||||
if (exceptions.Count != 0)
|
|
||||||
_ExceptionsDirectories.Add(container.SourceDirectory);
|
|
||||||
total += container.Items.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
||||||
{
|
{
|
||||||
_AngleBracketCollection.Clear();
|
_AngleBracketCollection.Clear();
|
||||||
@ -112,180 +77,6 @@ public class A_Property
|
|||||||
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ExifDirectory")]
|
|
||||||
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container.Models.Container container, ReadOnlyCollection<Item> items, string message)
|
|
||||||
{
|
|
||||||
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
|
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
|
||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
using ProgressBar progressBar = new(items.Count, message, options);
|
|
||||||
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long ticks = DateTime.Now.Ticks;
|
|
||||||
DateTime dateTime = DateTime.Now;
|
|
||||||
List<Tuple<string, DateTime>> collection;
|
|
||||||
SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
|
|
||||||
if (i == 0 || sourceDirectoryChanges.Count != 0)
|
|
||||||
progressBar.Tick();
|
|
||||||
lock (sourceDirectoryFileTuples)
|
|
||||||
collection = (from l in sourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList();
|
|
||||||
lock (sourceDirectoryChanges)
|
|
||||||
sourceDirectoryChanges.AddRange(collection);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
lock (exceptions)
|
|
||||||
exceptions.Add(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("Use ExifDirectory")]
|
|
||||||
private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
|
|
||||||
{
|
|
||||||
Shared.Models.Property property;
|
|
||||||
List<string> parseExceptions = [];
|
|
||||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
|
||||||
string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}");
|
|
||||||
if (item.IsValidImageFormatExtension && item.FilePath.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.FilePath.FullName != filteredSourceDirectoryFileExtensionLowered)
|
|
||||||
File.Move(item.FilePath.FullName, filteredSourceDirectoryFileExtensionLowered);
|
|
||||||
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.ExifDirectory is null)
|
|
||||||
{
|
|
||||||
property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
|
||||||
lock (sourceDirectoryChanges)
|
|
||||||
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
|
||||||
lock (item)
|
|
||||||
item.Update(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("Use ExifDirectory")]
|
|
||||||
private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension)
|
|
||||||
{
|
|
||||||
Shared.Models.Property? result;
|
|
||||||
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.ExifDirectory is not null)
|
|
||||||
result = null;
|
|
||||||
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);
|
||||||
@ -305,22 +96,4 @@ public class A_Property
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ExifDirectory")]
|
|
||||||
public Shared.Models.Property GetProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions)
|
|
||||||
{
|
|
||||||
Shared.Models.Property result;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -284,7 +284,7 @@ public class C_Resize
|
|||||||
int checkHeight;
|
int checkHeight;
|
||||||
int desiredWidth;
|
int desiredWidth;
|
||||||
int desiredHeight;
|
int desiredHeight;
|
||||||
int? orientation = Shared.Models.Stateless.Methods.IMetaBase.GetOrientation(exifDirectory.ExifBaseDirectories);
|
int? orientation = Shared.Models.Stateless.Methods.IMetaBase.GetOrientation(exifDirectory);
|
||||||
if (exifDirectory is null || orientation is null || exifDirectory.Width is null || exifDirectory.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 = exifDirectory.Width.Value;
|
checkWidth = exifDirectory.Width.Value;
|
||||||
|
@ -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,
|
||||||
|
@ -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,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;
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ namespace View_by_Distance.Shared.Models;
|
|||||||
public record FilePair(FilePath FilePath,
|
public record FilePair(FilePath FilePath,
|
||||||
bool IsUnique,
|
bool IsUnique,
|
||||||
bool? IsNotUniqueAndNeedsReview,
|
bool? IsNotUniqueAndNeedsReview,
|
||||||
List<FilePath> Collection,
|
ReadOnlyCollection<FilePath> Collection,
|
||||||
FilePath? Match)
|
FilePath? Match)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -21,6 +21,20 @@ public record FilePath(long CreationTicks,
|
|||||||
int? SortOrder)
|
int? SortOrder)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static FilePath? GetNullSafe(Properties.IPropertyConfiguration propertyConfiguration, FileHolder fileHolder, int? index)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
public static FilePath Get(Properties.IPropertyConfiguration propertyConfiguration, FileHolder fileHolder, int? index)
|
public static FilePath Get(Properties.IPropertyConfiguration propertyConfiguration, FileHolder fileHolder, int? index)
|
||||||
{
|
{
|
||||||
if (fileHolder.CreationTime is null)
|
if (fileHolder.CreationTime is null)
|
||||||
@ -78,28 +92,6 @@ public record FilePath(long CreationTicks,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReadOnlyDictionary<int, List<FilePath>> GetFilesKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
|
||||||
{
|
|
||||||
Dictionary<int, List<FilePath>> results = [];
|
|
||||||
List<FilePath>? collection;
|
|
||||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
|
||||||
{
|
|
||||||
foreach (FilePath filePath in filePaths)
|
|
||||||
{
|
|
||||||
if (filePath.Id is null)
|
|
||||||
continue;
|
|
||||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
|
||||||
{
|
|
||||||
results.Add(filePath.Id.Value, []);
|
|
||||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
collection.Add(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> GetKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
public static ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> GetKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||||
{
|
{
|
||||||
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
||||||
@ -123,7 +115,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,17 +29,17 @@ 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.ExifDirectory?.FilePath.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();
|
||||||
ExifDirectory exifDirectory = item.ExifDirectory;
|
ExifDirectory exifDirectory = item.ExifDirectory;
|
||||||
|
string? model = Stateless.Methods.IMetaBase.GetModel(exifDirectory);
|
||||||
DateTime minimumDateTime = Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
DateTime minimumDateTime = Stateless.Methods.IDate.GetMinimum(exifDirectory);
|
||||||
DateTime? dateTime = Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
DateTime? dateTime = Stateless.Methods.IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
string? model = Stateless.Methods.MetaBase.GetModel(exifDirectory.ExifBaseDirectories);
|
|
||||||
ReadOnlyCollection<DateTime> dateTimes = Stateless.Methods.IDate.GetDateTimes(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());
|
(bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.FilePath, dateTime, dateTimes.ToList());
|
||||||
ReadOnlyCollection<string> keywords = Stateless.Methods.MetaBase.GetKeywords(exifDirectory.ExifBaseDirectories);
|
|
||||||
result = new(containerDateTimes, dateTime, exifDirectory.FilePath.Id.Value, item.IsArchive, item.FilePath, isWrongYear, keywords, minimumDateTime, model, item.RelativePath, resizedFileHolder);
|
result = new(containerDateTimes, dateTime, exifDirectory.FilePath.Id.Value, item.IsArchive, item.FilePath, isWrongYear, keywords, minimumDateTime, model, item.RelativePath, resizedFileHolder);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,29 +7,22 @@ internal abstract class FilePair
|
|||||||
{
|
{
|
||||||
|
|
||||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||||
{
|
|
||||||
ReadOnlyCollection<Models.FilePair> results;
|
|
||||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
|
||||||
results = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles)
|
|
||||||
{
|
{
|
||||||
List<Models.FilePair>? results = null;
|
List<Models.FilePair>? results = null;
|
||||||
int renamed;
|
int renamed;
|
||||||
const bool useCeilingAverage = true;
|
const bool useCeilingAverage = true;
|
||||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||||
IReadOnlyDictionary<int, List<FilePath>>? compareFileNamesToFiles = null;
|
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||||
for (int i = 0; i < fileNamesToFiles.Count; i++)
|
IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? compareFileNamesToFiles = null;
|
||||||
|
for (int i = 0; i < idToFilePaths.Count; i++)
|
||||||
{
|
{
|
||||||
renamed = 0;
|
renamed = 0;
|
||||||
jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||||
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, fileNamesToFiles, extension);
|
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, idToFilePaths, extension);
|
||||||
if (renamed > 0)
|
if (renamed > 0)
|
||||||
continue;
|
continue;
|
||||||
compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
|
compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
|
||||||
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, idToFilePaths, compareFileNamesToFiles);
|
||||||
renamed += XDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
|
renamed += XDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
|
||||||
if (renamed == 0)
|
if (renamed == 0)
|
||||||
break;
|
break;
|
||||||
@ -41,7 +34,7 @@ internal abstract class FilePair
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension)
|
private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, string extension)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
bool check;
|
bool check;
|
||||||
@ -63,7 +56,7 @@ internal abstract class FilePair
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -72,11 +65,13 @@ internal abstract class FilePair
|
|||||||
string fileNameWith;
|
string fileNameWith;
|
||||||
string checkDirectory;
|
string checkDirectory;
|
||||||
string directoryName;
|
string directoryName;
|
||||||
List<FilePath>? collection;
|
|
||||||
Models.FileHolder fileHolder;
|
Models.FileHolder fileHolder;
|
||||||
List<string> directoryNames = [];
|
List<string> directoryNames = [];
|
||||||
|
ReadOnlyCollection<FilePath>? collection;
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
|
if (files.Any(l => l.StartsWith(propertyConfiguration.RootDirectory)))
|
||||||
|
continue;
|
||||||
if (!file.EndsWith(extension))
|
if (!file.EndsWith(extension))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
fileHolder = IFileHolder.Get(file);
|
fileHolder = IFileHolder.Get(file);
|
||||||
@ -120,12 +115,13 @@ internal abstract class FilePair
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyDictionary<int, List<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
private static ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||||
{
|
{
|
||||||
Dictionary<int, List<FilePath>> results = [];
|
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
||||||
List<FilePath>? collection;
|
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
|
List<FilePath>? collection;
|
||||||
Models.FileHolder fileHolder;
|
Models.FileHolder fileHolder;
|
||||||
|
Dictionary<int, List<FilePath>> keyValuePairs = [];
|
||||||
foreach (string[] files in filesCollection)
|
foreach (string[] files in filesCollection)
|
||||||
{
|
{
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
@ -136,15 +132,17 @@ internal abstract class FilePair
|
|||||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
if (filePath.Id is null)
|
if (filePath.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||||
{
|
{
|
||||||
results.Add(filePath.Id.Value, []);
|
keyValuePairs.Add(filePath.Id.Value, []);
|
||||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
collection.Add(filePath);
|
collection.Add(filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (KeyValuePair<int, List<FilePath>> keyValuePair in keyValuePairs)
|
||||||
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,13 +29,13 @@ public interface IDirectory
|
|||||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
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);
|
XDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||||
|
|
||||||
public static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
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, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, 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, ifCanUseId, filePathsCollection, fileGroups, null, tick);
|
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, null, tick);
|
||||||
|
|
||||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
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);
|
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||||
|
|
||||||
internal int TestStatic_GetDirectory(char directory) =>
|
internal int TestStatic_GetDirectory(char directory) =>
|
||||||
@ -62,13 +62,13 @@ public interface IDirectory
|
|||||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
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);
|
GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||||
|
|
||||||
internal List<Models.FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
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, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, 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, 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, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? 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);
|
GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||||
|
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ public interface IDlibDotNet
|
|||||||
{
|
{
|
||||||
|
|
||||||
void Tick();
|
void Tick();
|
||||||
|
long Ticks { get; }
|
||||||
(string, string) GetResultsFullGroupDirectories();
|
(string, string) GetResultsFullGroupDirectories();
|
||||||
void ConstructProgressBar(int maxTicks, string message);
|
void ConstructProgressBar(int maxTicks, string message);
|
||||||
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
||||||
|
@ -9,13 +9,7 @@ public interface IFilePair
|
|||||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
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);
|
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
|
|
||||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
|
||||||
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
|
||||||
|
|
||||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||||
|
|
||||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
|
||||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,24 +5,66 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|||||||
public interface IMetaBase
|
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) =>
|
public static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
MetaBase.GetMaker(exifBaseDirectories);
|
MetaBase.GetMaker(exifBaseDirectories);
|
||||||
|
|
||||||
public static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
public static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
MetaBase.GetModel(exifBaseDirectories);
|
MetaBase.GetModel(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
MetaBase.GetDateTime(dateTimeFormat, value);
|
||||||
|
|
||||||
public static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
public static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
MetaBase.GetOrientation(exifBaseDirectories);
|
MetaBase.GetOrientation(exifBaseDirectories);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<string> GetKeywords(ExifDirectory? exifDirectory) =>
|
||||||
|
MetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||||
|
|
||||||
public static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
public static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
MetaBase.GetKeywords(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) =>
|
internal static string? TestStatic_GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
GetMaker(exifBaseDirectories);
|
GetMaker(exifBaseDirectories);
|
||||||
|
|
||||||
internal static string? TestStatic_GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
internal static string? TestStatic_GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
GetModel(exifBaseDirectories);
|
GetModel(exifBaseDirectories);
|
||||||
|
|
||||||
|
internal static DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||||
|
GetDateTime(dateTimeFormat, value);
|
||||||
|
|
||||||
internal static int? TestStatic_GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
internal static int? TestStatic_GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||||
GetOrientation(exifBaseDirectories);
|
GetOrientation(exifBaseDirectories);
|
||||||
|
|
||||||
|
@ -45,10 +45,10 @@ internal abstract class Id
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static byte GetHasDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
internal static byte GetHasDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
|
(byte)(propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered) || propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 6 : 4 : filePath.Id > -1 ? 9 : 1);
|
||||||
|
|
||||||
internal static byte GetMissingDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
internal static byte GetMissingDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : filePath.Id > -1 ? 5 : 0);
|
(byte)(propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered) || propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 5 : 0 : filePath.Id > -1 ? 7 : 3);
|
||||||
|
|
||||||
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -80,4 +81,55 @@ internal static class MetaBase
|
|||||||
return results.AsReadOnly();
|
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)
|
||||||
|
{
|
||||||
|
DateTime? result;
|
||||||
|
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
|
||||||
|
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||||
|
result = dateTime;
|
||||||
|
else
|
||||||
|
result = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
}
|
}
|
@ -40,8 +40,8 @@ internal abstract class XDate
|
|||||||
}
|
}
|
||||||
if (results.Count == 0)
|
if (results.Count == 0)
|
||||||
{
|
{
|
||||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(exifDirectory.FilePath.Name);
|
string? fileNameWithoutExtension = exifDirectory.FilePath is null ? null : Path.GetFileNameWithoutExtension(exifDirectory.FilePath.Name);
|
||||||
DateTime? dateTime = GetDateTimeFromName(fileNameWithoutExtension);
|
DateTime? dateTime = fileNameWithoutExtension is null ? null : GetDateTimeFromName(fileNameWithoutExtension);
|
||||||
if (dateTime is not null)
|
if (dateTime is not null)
|
||||||
results.Add(dateTime.Value);
|
results.Add(dateTime.Value);
|
||||||
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
||||||
|
@ -188,7 +188,7 @@ internal abstract partial class XDirectory
|
|||||||
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();
|
||||||
}
|
}
|
||||||
@ -201,14 +201,14 @@ internal abstract partial class XDirectory
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> 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<Models.FilePair> results = [];
|
List<Models.FilePair> results = [];
|
||||||
FilePath? match;
|
FilePath? match;
|
||||||
bool uniqueFileName;
|
bool uniqueFileName;
|
||||||
List<FilePath>? collection;
|
|
||||||
Models.FilePair filePair;
|
Models.FilePair filePair;
|
||||||
bool? isNotUniqueAndNeedsReview;
|
bool? isNotUniqueAndNeedsReview;
|
||||||
|
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)
|
||||||
@ -227,7 +227,7 @@ internal abstract partial class XDirectory
|
|||||||
filePair = new(FilePath: filePath,
|
filePair = new(FilePath: filePath,
|
||||||
IsUnique: uniqueFileName,
|
IsUnique: uniqueFileName,
|
||||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||||
Collection: [],
|
Collection: new([]),
|
||||||
Match: null);
|
Match: null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -259,7 +259,7 @@ internal abstract partial class XDirectory
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool GetIsNotUniqueAndNeedsReview(FilePath filePath, List<FilePath> collection)
|
private static bool GetIsNotUniqueAndNeedsReview(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
long max;
|
long max;
|
||||||
@ -280,7 +280,7 @@ internal abstract partial class XDirectory
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FilePath? GetMatch(FilePath filePath, List<FilePath> collection)
|
private static FilePath? GetMatch(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||||
{
|
{
|
||||||
FilePath? result = null;
|
FilePath? result = null;
|
||||||
List<long> lengths = [];
|
List<long> lengths = [];
|
||||||
@ -299,7 +299,7 @@ internal abstract partial class XDirectory
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory>? exifDirectoriesById, 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;
|
||||||
|
@ -446,7 +446,7 @@ internal abstract class XPath
|
|||||||
{
|
{
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Search", "Drag-Dr
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Set-Property-Item", "Drag-Drop-Set-Property-Item\Drag-Drop-Set-Property-Item.csproj", "{BFF75D8C-48E6-4B84-B480-3E5A4F9B2DD8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Set-Property-Item", "Drag-Drop-Set-Property-Item\Drag-Drop-Set-Property-Item.csproj", "{BFF75D8C-48E6-4B84-B480-3E5A4F9B2DD8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicate-Search", "Duplicate-Search\Duplicate-Search.csproj", "{48E87D9B-B802-467A-BDC7-E86F7FD01D5C}"
|
||||||
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Face", "Face\Face.csproj", "{A12E19E5-59C0-40D4-B807-DF1334D4906D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Face", "Face\Face.csproj", "{A12E19E5-59C0-40D4-B807-DF1334D4906D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceParts", "FaceParts\FaceParts.csproj", "{919525B1-60BA-40C6-BA66-6F7F4C526E01}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceParts", "FaceParts\FaceParts.csproj", "{919525B1-60BA-40C6-BA66-6F7F4C526E01}"
|
||||||
|
Reference in New Issue
Block a user