Removed Obsolete A_Property Methods
Changed GetDimensions to handle a stream at the end and one exit Switched to using Action? over IDlibDotNet for Tick method Switched to using AsReadOnly over new() Moved Meta Base to Shared
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)
|
||||||
{
|
{
|
||||||
|
model = IMetaBase.GetModel(item.ExifDirectory);
|
||||||
|
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
|
||||||
|
keywords = IMetaBase.GetKeywords(item.ExifDirectory?.ExifBaseDirectories);
|
||||||
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
|
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