added-numbers-to-distinguish-has-ignore-keyword-and-has-date-time-original

moved-container-to-new-project-to-prepare-to-remove-property-file

added-logic-to-rename-to-3-and-7-like-should-ignore-for-missing-date-time-original
This commit is contained in:
Mike Phares 2025-03-16 21:20:46 -07:00
parent d9d55d9e4c
commit d5fa108f81
41 changed files with 1246 additions and 730 deletions

View File

@ -160,7 +160,7 @@ public class Compare
} }
if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId) if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId)
throw new Exception("Copy keyValuePairs-####.json file"); throw new Exception("Copy keyValuePairs-####.json file");
(int j, int f, int t, Shared.Models.Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic); (int j, int f, int t, Shared.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
if (propertyLogic.ExceptionsDirectories.Any()) if (propertyLogic.ExceptionsDirectories.Any())
throw new Exception(); throw new Exception();
if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers)) if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers))

1
Container/.vscode/format-report.json vendored Normal file
View File

@ -0,0 +1 @@
[]

8
Container/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"cSpell.words": [
"dlib",
"Exif",
"nosj",
"Serilog"
]
}

View File

@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>library</OutputType>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<PackageId>Phares.View.by.Distance.Container</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>9.0.100.1</Version>
<Authors>Mike Phares</Authors>
<Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup>
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">
true
</IsWindows>
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">
true
</IsOSX>
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">
true
</IsLinux>
</PropertyGroup>
<PropertyGroup Condition="'$(IsWindows)'=='true'">
<DefineConstants>Windows</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsOSX)'=='true'">
<DefineConstants>OSX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsLinux)'=='true'">
<DefineConstants>Linux</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
<SupportedPlatform Include="browser" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Text.Json" Version="9.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,8 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Shared.Models; namespace View_by_Distance.Container.Models;
public record Container(string SourceDirectory, ReadOnlyCollection<Item> Items) public record Container(string SourceDirectory, ReadOnlyCollection<Item> Items)
{ {

View File

@ -0,0 +1,664 @@
using System.Collections.ObjectModel;
using System.Text.Json;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Container.Models.Stateless.Methods;
internal abstract class Container
{
private record FilePair(bool IsUnique, List<string> Collection, FilePath FilePath, Item Item) { }
internal static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items)
{
DateTime[] results;
long containerMinimumTicks = (from l in items select l.FilePath.LastWriteTicks).Min();
long containerMaximumTicks = (from l in items select l.FilePath.LastWriteTicks).Max();
results = [new(containerMinimumTicks), new(containerMaximumTicks)];
return results;
}
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container)
{
List<Item> results = [];
foreach (Item item in container.Items)
{
if (!item.IsValidImageFormatExtension || propertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered))
continue;
results.Add(item);
}
return container.Items.Count == results.Count ? container.Items : results.AsReadOnly();
}
private static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
{
Dictionary<string, List<string>> results = [];
List<string>? collection;
string fileNameWithoutExtensionMinusOne;
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{
foreach (FilePath filePath in filePaths)
{
fileNameWithoutExtensionMinusOne = filePath.NameWithoutExtension[..^1];
if (!results.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
{
results.Add(fileNameWithoutExtensionMinusOne, []);
if (!results.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
throw new Exception();
}
collection.Add(filePath.FullName);
}
}
return results;
}
private static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<string[]> filesCollection)
{
Dictionary<string, List<string>> results = [];
string fileNameWithoutExtension;
string fileNameWithoutExtensionSecond;
string fileNameWithoutExtensionSecondMinusOne;
List<string>? collection;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(fileNameWithoutExtension);
if (string.IsNullOrEmpty(fileNameWithoutExtensionSecond) || fileNameWithoutExtensionSecond == fileNameWithoutExtension)
continue;
fileNameWithoutExtensionSecondMinusOne = fileNameWithoutExtensionSecond[..^1];
if (!results.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
{
results.Add(fileNameWithoutExtensionSecondMinusOne, []);
if (!results.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
throw new Exception();
}
collection.Add(file);
}
}
return results;
}
private static bool AnyMoved(IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
{
bool result = false;
string checkFile;
string directory;
string fileNameWith;
string checkDirectory;
string directoryName;
List<string>? collection;
string fileNameWithoutExtension;
List<string> directoryNames = [];
string fileNameWithoutExtensionSecond;
string fileNameWithoutExtensionSecondMinusOne;
foreach (string file in files)
{
if (!file.EndsWith(extension))
throw new Exception();
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(fileNameWithoutExtension);
if (string.IsNullOrEmpty(fileNameWithoutExtensionSecond) || fileNameWithoutExtensionSecond == fileNameWithoutExtension)
continue;
fileNameWithoutExtensionSecondMinusOne = fileNameWithoutExtensionSecond[..^1];
if (!fileNamesToFiles.TryGetValue(fileNameWithoutExtensionSecondMinusOne, out collection))
renameCollection.Add(file);
else
{
directoryNames.Clear();
directoryName = Path.GetFileName(Path.GetDirectoryName(file)) ?? throw new Exception();
foreach (string f in collection)
directoryNames.Add(Path.GetFileName(Path.GetDirectoryName(f)) ?? throw new Exception());
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
continue;
if (directoryName != directoryNames[0])
{
directory = Path.GetDirectoryName(Path.GetDirectoryName(file)) ?? throw new Exception();
checkDirectory = Path.Combine(directory, directoryNames[0]);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
fileNameWith = collection.Count > 1 ? Path.GetFileName(file) : $"{Path.GetFileName(collection[0])}{extension}";
checkFile = Path.Combine(checkDirectory, fileNameWith);
if (!result)
result = true;
if (!File.Exists(checkFile))
File.Move(file, checkFile);
else
{
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
File.Delete(file);
else
File.Move(file, checkFile, true);
}
}
}
}
return result;
}
private static int LookForAbandoned(ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension)
{
int result;
bool check;
bool moved = false;
List<string> renameCollection = [];
foreach (string[] files in jsonFilesCollection)
{
if (files.Length == 0)
continue;
check = AnyMoved(fileNamesToFiles, extension, renameCollection, files);
if (!moved && check)
moved = true;
}
if (renameCollection.Count > 0)
IDirectory.MoveFiles(renameCollection, "{}", "{abd}");
result = renameCollection.Count;
if (moved && result == 0)
result = 1;
return result;
}
private static List<Shared.Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles)
{
List<Shared.Models.FilePair>? results = null;
int renamed;
const bool useCeilingAverage = true;
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
for (int i = 0; i < short.MaxValue; i++)
{
renamed = 0;
jsonFilesCollection = IDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
compareFileNamesToFiles = GetFilesKeyValuePairs(jsonFilesCollection);
renamed += LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
results = IDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
renamed += IDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
if (renamed == 0)
break;
if (i > 10)
throw new NotImplementedException();
}
if (results is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
throw new NullReferenceException(nameof(results));
return results;
}
private static Property? GetProperty(Shared.Models.FilePair filePair)
{
Property? result;
if (filePair.Match is null)
result = null;
else
{
string json = File.ReadAllText(filePair.Match);
if (string.IsNullOrEmpty(json))
result = null;
else
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
}
return result;
}
private static ExifDirectory? GetExifDirectory(Shared.Models.FilePair filePair)
{
ExifDirectory? result;
if (filePair.Match is null)
result = null;
else
{
string json = File.ReadAllText(filePair.Match);
if (string.IsNullOrEmpty(json))
result = null;
else
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
}
return result;
}
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
{
string[] segments = directory.Split(cei.Combined);
string? checkDirectory = segments.Length == 1 ?
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
segments.Length == 2 ?
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
null;
if (checkDirectory is not null && Directory.Exists(checkDirectory))
{
string checkFile = Path.Combine(checkDirectory, fileName);
if (File.Exists(checkFile))
File.Move(checkFile, fullFileName);
}
}
private static void RenameFile(string extension, Shared.Models.FilePair filePair, FilePath filePath, char change, ReadOnlyCollection<FilePath> filePaths)
{
string checkFile;
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
File.Delete(filePath.FullName);
if (!string.IsNullOrEmpty(filePair.Match))
{
string directory = Path.GetDirectoryName(filePair.Match) ?? throw new Exception();
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePair.Match);
string fileNameWithoutExtensionSecond = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(filePair.Match));
string extensionSecond = Path.GetExtension(fileNameWithoutExtension);
checkFile = Path.Combine(directory, $"{fileNameWithoutExtensionSecond[..^1]}{change}{extensionSecond}{extension}");
if (!File.Exists(checkFile))
File.Move(filePair.Match, checkFile);
}
foreach (FilePath f in filePaths)
{
checkFile = Path.Combine(f.DirectoryFullPath, $"{f.NameWithoutExtension[..^1]}{change}{f.ExtensionLowered}");
if (File.Exists(checkFile))
continue;
File.Move(f.FullName, checkFile);
}
}
private static void ParallelFor(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, int rootDirectoryLength, Shared.Models.FilePair filePair, List<FilePair> results)
{
dlibDotNet?.Tick();
bool abandoned = false;
FileHolder sourceDirectoryFileHolder;
Property? property = GetProperty(filePair);
FileHolder fileHolder = IFileHolder.Get(filePair.Path);
ExifDirectory? exifDirectory = GetExifDirectory(filePair);
FilePath filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
bool? fileSizeChanged = property is not null ? property.FileSize != filePath.Length : null;
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePath.ExtensionLowered);
bool? shouldIgnore = property is null || property.Keywords is null ? null : propertyConfiguration.IgnoreRulesKeyWords.Any(l => property.Keywords.Contains(l));
bool? isArchive = filePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePath.Id.Value, out Identifier? identifier);
if (property is not null && filePath.Id is not null && filePath.HasIgnoreKeyword is not null && filePath.HasDateTimeOriginal is not null)
{
char? change;
ReadOnlyCollection<FilePath>? filePaths = null;
char hasIgnoreKeyword = IId.GetHasIgnoreKeyword(filePath).ToString()[0];
char hasDateTimeOriginal = IId.GetHasDateTimeOriginal(filePath).ToString()[0];
char missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(filePath).ToString()[0];
if (shouldIgnore is not null && shouldIgnore.Value)
{
if (filePath.NameWithoutExtension[^1] == hasIgnoreKeyword)
change = null;
else
{
change = hasIgnoreKeyword;
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
}
}
else if ((shouldIgnore is null || !shouldIgnore.Value) && property.DateTimeOriginal is null)
{
if (filePath.NameWithoutExtension[^1] == missingDateTimeOriginal)
change = null;
else
{
change = missingDateTimeOriginal;
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
}
}
else if (filePath.NameWithoutExtension[^1] != hasDateTimeOriginal)
{
change = hasDateTimeOriginal;
if (keyValuePairs is null || !keyValuePairs.TryGetValue(filePath.Id.Value, out filePaths) || filePaths is null)
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
}
else
change = null;
if (filePaths is not null && change is not null)
RenameFile(extension, filePair, filePath, change.Value, filePaths);
}
string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(filePair.Path, rootDirectoryLength, forceExtensionToLower: true);
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime.Ticks != filePath.LastWriteTicks : null;
if (filePair.Match is not null)
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
else if (!filePair.IsUnique)
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(jsonGroupDirectory, relativePath, extension)));
else
{
string fileName = Path.GetFileName(filePair.Path);
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
string directory = Path.Combine(jsonGroupDirectory, cei.Combined);
string jsonFileName = $"{fileName}{extension}";
string fullFileName = Path.Combine(directory, jsonFileName);
MoveIf(jsonFileName, cei, directory, fullFileName);
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
}
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
{
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePath.LastWriteTicks));
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
}
Item item = Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
lock (results)
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
}
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
{
List<FilePair> results = [];
const string extension = ".json";
List<Shared.Models.FilePair> filePairs;
string jsonGroupDirectory = aPropertySingletonDirectory;
int maxDegreeOfParallelism = Environment.ProcessorCount;
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = GetFilesKeyValuePairs(filePathsCollection);
filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
ParallelFor(dlibDotNet, propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, filePairs[i], results));
return results;
}
private static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
{
List<Models.Container> results = [];
string directory;
List<Item>? items;
Models.Container container;
List<string> directories = [];
Dictionary<string, List<Item>> directoryToItems = [];
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{
if (filePaths.Count == 0)
continue;
directory = filePaths[0].DirectoryFullPath;
if (directory is null)
continue;
if (!directories.Contains(directory))
directories.Add(directory);
if (!directoryToItems.TryGetValue(directory, out items))
{
directoryToItems.Add(directory, []);
if (!directoryToItems.TryGetValue(directory, out items))
throw new Exception();
}
}
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories();
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
if (!Directory.Exists(aPropertySingletonDirectory))
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
foreach (FilePair filePair in filePairs)
{
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
{
directoryToItems.Add(filePair.FilePath.DirectoryFullPath, []);
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
throw new Exception();
}
items.Add(filePair.Item);
}
foreach (KeyValuePair<string, List<Item>> keyValuePair in directoryToItems)
{
if (keyValuePair.Value.Count == 0)
continue;
container = new(keyValuePair.Key, new(keyValuePair.Value));
results.Add(container);
}
return (filePairs.Count, results.ToArray());
}
private static void AnyMovedFace(IReadOnlyDictionary<string, List<string>> fileNamesToFiles, List<string> directories)
{
bool result = false;
string checkFile;
string subDirectory;
string directoryName;
string checkDirectory;
List<string>? collection;
string directoryNameWith;
string directoryNameMinusOne;
List<string> directoryNames = [];
foreach (string directory in directories)
{
directoryNameMinusOne = Path.GetFileName(directory)[..^1];
if (!fileNamesToFiles.TryGetValue(directoryNameMinusOne, out collection))
throw new Exception();
directoryNames.Clear();
foreach (string f in collection)
directoryNames.Add(Path.GetFileName(Path.GetDirectoryName(f)) ?? throw new Exception());
if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
continue;
directoryName = Path.GetFileName(Path.GetDirectoryName(directory)) ?? throw new Exception();
if (directoryName != directoryNames[0])
{
subDirectory = Path.GetDirectoryName(Path.GetDirectoryName(directory)) ?? throw new Exception();
checkDirectory = Path.Combine(subDirectory, directoryNames[0]);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
directoryNameWith = collection.Count > 1 ? directoryName : $"{Path.GetFileNameWithoutExtension(collection[0])}";
checkFile = Path.Combine(checkDirectory, directoryNameWith);
if (!result)
result = true;
if (!Directory.Exists(checkFile))
Directory.Move(directory, checkFile);
else
{
if (new DirectoryInfo(directory).LastWriteTime > new DirectoryInfo(checkFile).LastWriteTime)
Directory.Delete(directory, recursive: true);
else
{
Directory.Delete(checkFile, recursive: true);
Directory.Move(directory, checkFile);
}
}
}
}
}
private static void AnyMovedFace(string extension, string hiddenExtension, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string jsonGroupDirectory)
{
string directory;
string checkFile;
string directoryName;
List<string> files = [];
string[] fileNameSegments;
List<string> directories = [];
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories));
files.AddRange(Directory.GetFiles(jsonGroupDirectory, $"*{hiddenExtension}", SearchOption.AllDirectories));
foreach (string file in files)
{
directory = Path.GetDirectoryName(file) ?? throw new Exception();
if (!directories.Contains(directory))
directories.Add(directory);
directoryName = Path.GetFileName(directory);
fileNameSegments = Path.GetFileName(file).Split('.');
if (fileNameSegments[0] != directoryName)
{
fileNameSegments[0] = string.Empty;
checkFile = Path.Combine(directory, $"{directoryName}{string.Join('.', fileNameSegments)}");
if (!File.Exists(checkFile))
File.Move(file, checkFile);
else
{
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
File.Delete(file);
else
File.Move(file, checkFile, true);
}
}
}
if (directories.Count > 0)
AnyMovedFace(fileNamesToFiles, directories);
}
private static void AnyMovedDistance(string extension, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string jsonGroupDirectory)
{
bool result = false;
string fileName;
string checkFile;
string directory;
List<string>? collection;
string[] fileNameSegments;
List<string> fileNames = [];
string fileNameSegmentsZeroMinusOne;
string[] files = Directory.GetFiles(jsonGroupDirectory, $"*{extension}", SearchOption.AllDirectories);
foreach (string file in files)
{
fileName = Path.GetFileName(file);
fileNameSegments = fileName.Split('.');
fileNameSegmentsZeroMinusOne = fileNameSegments[0][..^1];
if (!fileNamesToFiles.TryGetValue(fileNameSegmentsZeroMinusOne, out collection))
continue;
fileNames.Clear();
foreach (string f in collection)
fileNames.Add(Path.GetFileNameWithoutExtension(f) ?? throw new Exception());
if (fileNames.Count == 0 || fileNames.Distinct().Count() != 1)
continue;
if (fileNameSegments[0] != fileNames[0])
{
fileNameSegments[0] = string.Empty;
directory = Path.GetDirectoryName(file) ?? throw new Exception();
checkFile = Path.Combine(directory, $"{fileNames[0]}{string.Join('.', fileNameSegments)}");
if (!result)
result = true;
if (!File.Exists(checkFile))
File.Move(file, checkFile);
else
{
if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
File.Delete(file);
else
File.Move(file, checkFile, true);
}
}
}
}
private static void DoGetFilePairsForRemaining(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
{
const string extension = ".json";
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = GetFilesKeyValuePairs(filePathsCollection);
string bMetaSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
if (!Directory.Exists(bMetaSingletonDirectory))
_ = Directory.CreateDirectory(bMetaSingletonDirectory);
_ = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, bMetaSingletonDirectory, filePathsCollection, fileNamesToFiles);
(string cResultsFullGroupDirectory, _, string dResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories("Original");
string cResizeSingletonDirectory = Path.Combine(cResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
if (!Directory.Exists(cResizeSingletonDirectory))
_ = Directory.CreateDirectory(cResizeSingletonDirectory);
_ = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, cResizeSingletonDirectory, filePathsCollection, fileNamesToFiles);
string dFaceCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
if (!Directory.Exists(dFaceCollectionDirectory))
_ = Directory.CreateDirectory(dFaceCollectionDirectory);
_ = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, dFaceCollectionDirectory, filePathsCollection, fileNamesToFiles);
string dFaceContentDirectory = Path.Combine(dResultsFullGroupDirectory, propertyConfiguration.ResultContent);
if (!Directory.Exists(dFaceContentDirectory))
_ = Directory.CreateDirectory(dFaceContentDirectory);
AnyMovedFace(facesFileNameExtension, facesHiddenFileNameExtension, fileNamesToFiles, dFaceContentDirectory);
AnyMovedDistance(facesFileNameExtension, fileNamesToFiles, eDistanceContentDirectory);
}
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)
{
Models.Container[] results;
const string directorySearchFilter = "*";
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
if (keyValuePairs is not null)
DoGetFilePairsForRemaining(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filePathsCollection, directorySearchFilter);
return results.AsReadOnly();
}
private static IDlibDotNet GetDlibDotNet() =>
throw new NotImplementedException();
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string _)
{
int count;
Models.Container[] results;
const bool useCeilingAverage = true;
const string fileSearchFilter = "*";
IDlibDotNet dlibDotNet = GetDlibDotNet();
const string directorySearchFilter = "*";
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, propertyConfiguration.RootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
return (count, results);
}
internal static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
{
List<int> results = [];
ReadOnlyCollection<Item> filteredItems;
foreach (Models.Container container in readOnlyContainers)
{
if (container.Items.Count == 0)
continue;
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
foreach (Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (results.Contains(item.Property.Id.Value))
continue;
results.Add(item.Property.Id.Value);
}
}
return results;
}
internal static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
{
List<string> results = [];
ReadOnlyCollection<Item> filteredItems;
foreach (Models.Container container in readOnlyContainers)
{
if (container.Items.Count == 0)
continue;
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
foreach (Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (results.Contains(item.FilePath.FileNameFirstSegment))
continue;
results.Add(item.FilePath.FileNameFirstSegment);
}
}
return results;
}
internal static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
{
List<Item> results = [];
List<int> distinct = [];
ReadOnlyCollection<Item> filteredItems;
foreach (Models.Container container in containers)
{
if (container.Items.Count == 0)
continue;
if (!filterItems)
filteredItems = container.Items;
else
{
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
}
foreach (Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (distinctItems)
{
if (distinct.Contains(item.Property.Id.Value))
continue;
distinct.Add(item.Property.Id.Value);
}
results.Add(item);
}
}
return results.AsReadOnly();
}
}

View File

@ -0,0 +1,51 @@
using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Container.Models.Stateless.Methods;
public interface IContainer
{
DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
GetContainerDateTimes(items);
static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
Container.GetContainerDateTimes(items);
ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
GetValidImageItems(propertyConfiguration, container);
static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
Container.GetValidImageItems(propertyConfiguration, container);
(int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
(int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
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) =>
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection);
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) =>
Container.GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection);
List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
static List<string> GetFilteredDistinctFileNameFirstSegments(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
}

View File

@ -57,11 +57,11 @@ public class DateGroup
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}"); string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
if (!Directory.Exists(aPropertySingletonDirectory)) if (!Directory.Exists(aPropertySingletonDirectory))
_ = Directory.CreateDirectory(aPropertySingletonDirectory); _ = Directory.CreateDirectory(aPropertySingletonDirectory);
(int t, Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory); (int t, Container.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory, aResultsFullGroupDirectory); A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory, aResultsFullGroupDirectory);
if (propertyLogic.ExceptionsDirectories.Count != 0) if (propertyLogic.ExceptionsDirectories.Count != 0)
throw new Exception(); throw new Exception();
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers)) if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Property.Models.Stateless.IProperty.Any(containers))
{ {
propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers); propertyLogic.SavePropertyParallelWork(ticks, metadata, t, containers);
if (propertyLogic.ExceptionsDirectories.Count != 0) if (propertyLogic.ExceptionsDirectories.Count != 0)
@ -302,7 +302,7 @@ public class DateGroup
return result; return result;
} }
private static Item[] GetFilterItems(Container container) private static Item[] GetFilterItems(Container.Models.Container container)
{ {
List<Item> results = []; List<Item> results = [];
foreach (Item item in container.Items) foreach (Item item in container.Items)
@ -313,7 +313,7 @@ public class DateGroup
return results.ToArray(); return results.ToArray();
} }
private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container[] containers) private (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] GetFileMoveCollectionAll(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
{ {
(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results; (Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)[] results;
Item[] filteredItems; Item[] filteredItems;
@ -322,7 +322,7 @@ public class DateGroup
string destinationDirectory; string destinationDirectory;
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = []; List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollection = [];
List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory; List<(Item Item, long LastWriteTimeTicks, long MinimumDateTimeTicks, string[] Destination)> fileMoveCollectionDirectory;
foreach (Container container in containers) foreach (Container.Models.Container container in containers)
{ {
if (container.Items.Count == 0) if (container.Items.Count == 0)
continue; continue;
@ -352,7 +352,7 @@ public class DateGroup
return results; return results;
} }
private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container[] containers) private void MoveFiles(Property.Models.Configuration configuration, string destinationRoot, Container.Models.Container[] containers)
{ {
string checkDirectory; string checkDirectory;
bool hasDuplicate; bool hasDuplicate;
@ -453,7 +453,7 @@ public class DateGroup
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(configuration.RootDirectory);
} }
private static void CreateDateShortcut(Property.Models.Configuration configuration, Container[] containers) private static void CreateDateShortcut(Property.Models.Configuration configuration, Container.Models.Container[] containers)
{ {
string path; string path;
string fileName; string fileName;
@ -468,17 +468,17 @@ public class DateGroup
WindowsShortcut windowsShortcut; WindowsShortcut windowsShortcut;
TimeSpan threeStandardDeviationHigh; TimeSpan threeStandardDeviationHigh;
string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()"); string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()");
foreach (Container container in containers) foreach (Container.Models.Container container in containers)
{ {
if (container.Items.Count == 0) if (container.Items.Count == 0)
continue; continue;
selectedTotal = 0; selectedTotal = 0;
threeStandardDeviationHigh = Shared.Models.Stateless.Methods.IProperty.GetThreeStandardDeviationHigh(minimum, container); threeStandardDeviationHigh = Property.Models.Stateless.IProperty.GetThreeStandardDeviationHigh(minimum, container);
if (threeStandardDeviationHigh.TotalHours > maximumHours) if (threeStandardDeviationHigh.TotalHours > maximumHours)
threeStandardDeviationHigh = new(maximumHours, 0, 0); threeStandardDeviationHigh = new(maximumHours, 0, 0);
for (int i = 0; i < container.Items.Count; i++) for (int i = 0; i < container.Items.Count; i++)
{ {
(i, dateTimes, selectedItems) = Shared.Models.Stateless.Methods.IProperty.Get(container, threeStandardDeviationHigh, i); (i, dateTimes, selectedItems) = Property.Models.Stateless.IProperty.Get(container, threeStandardDeviationHigh, i);
selectedTotal += selectedItems.Count; selectedTotal += selectedItems.Count;
foreach (Item item in selectedItems) foreach (Item item in selectedItems)
{ {

View File

@ -34,6 +34,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />
<ProjectReference Include="..\Container\Container.csproj" />
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Resize\Resize.csproj" /> <ProjectReference Include="..\Resize\Resize.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -107,9 +107,9 @@ public partial class DragDropSearch : Form
private void LoadData() private void LoadData()
{ {
Container[] containers; Container.Models.Container[] containers;
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}"); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}");
(_, containers) = IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory); (_, 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)
{ {

View File

@ -12,7 +12,7 @@ public class Program
// ApplicationConfiguration.Initialize(); // ApplicationConfiguration.Initialize();
Application.Run(new DragDropSearch()); Application.Run(new DragDropSearch());
private static Item[] GetFilterItems(Models.Configuration configuration, Container container) private static Item[] GetFilterItems(Models.Configuration configuration, Container.Models.Container container)
{ {
List<Item> results = []; List<Item> results = [];
foreach (Item item in container.Items) foreach (Item item in container.Items)
@ -24,11 +24,11 @@ public class Program
return results.ToArray(); return results.ToArray();
} }
public static List<Item> GetItemCollection(Models.Configuration configuration, Container[] containers) public static List<Item> GetItemCollection(Models.Configuration configuration, Container.Models.Container[] containers)
{ {
List<Item> results = []; List<Item> results = [];
Item[] filteredItems; Item[] filteredItems;
foreach (Container container in containers) foreach (Container.Models.Container container in containers)
{ {
if (container.Items.Count == 0) if (container.Items.Count == 0)
continue; continue;

View File

@ -30,7 +30,7 @@ public class DuplicateSearch
else else
{ {
Configuration.Verify(configuration, requireExist: false); Configuration.Verify(configuration, requireExist: false);
Container[] containers = GetContainers(ticks, configuration); Container.Models.Container[] containers = GetContainers(ticks, configuration);
string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(configuration.RootDirectory); string argZero = args.Count > 0 ? Path.GetFullPath(args[0]) : Path.GetFullPath(configuration.RootDirectory);
bool argZeroIsConfigurationRootDirectory = configuration.RootDirectory == argZero; bool argZeroIsConfigurationRootDirectory = configuration.RootDirectory == argZero;
string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved"); string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved");
@ -125,10 +125,10 @@ public class DuplicateSearch
} }
} }
private static Container[] GetContainers(long ticks, Configuration configuration) private static Container.Models.Container[] GetContainers(long ticks, Configuration configuration)
{ {
int f; int f;
Container[] containers; Container.Models.Container[] containers;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Container(s) - {totalSeconds} total second(s)"; string message = $") Building Container(s) - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
@ -136,12 +136,12 @@ public class DuplicateSearch
{ {
progressBar.Tick(); progressBar.Tick();
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}");
(f, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory); (f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
} }
return containers; return containers;
} }
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, 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 directory; string directory;
@ -157,16 +157,16 @@ public class DuplicateSearch
foreach (int id in preloadIds) foreach (int id in preloadIds)
results.Add(id, [null]); results.Add(id, [null]);
} }
foreach (Container container in containers) foreach (Container.Models.Container container in containers)
{ {
if (container.Items.Count == 0) if (container.Items.Count == 0)
continue; continue;
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero)) if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue; continue;
validImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container); validImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(configuration, container);
if (validImageItems.Count == 0) if (validImageItems.Count == 0)
continue; continue;
containerDateTimes = Shared.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.Property?.Id is null) if (item.Property?.Id is null)

View File

@ -403,7 +403,7 @@ public class D2_FaceParts
} }
} }
public void SaveFaceLandmarkImages(Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces, bool saveRotated) public void SaveFaceLandmarkImages(Property.Models.Configuration configuration, string d2ResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces, bool saveRotated)
{ {
FileInfo fileInfo; FileInfo fileInfo;
bool check = false; bool check = false;

View File

@ -300,6 +300,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string message; string message;
MapLogic? mapLogic; MapLogic? mapLogic;
A_Property propertyLogic; A_Property propertyLogic;
IDlibDotNet dlibDotNet = this;
string eDistanceContentDirectory; string eDistanceContentDirectory;
string? a2PeopleContentDirectory; string? a2PeopleContentDirectory;
string aResultsFullGroupDirectory; string aResultsFullGroupDirectory;
@ -314,15 +315,17 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
bool configurationOutputResolutionsHas = false; bool configurationOutputResolutionsHas = false;
ReadOnlyDictionary<long, List<int>> personKeyToIds; ReadOnlyDictionary<long, List<int>> personKeyToIds;
ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers = null; ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers = null;
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = null; ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = null;
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks); bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks);
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks); Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks);
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
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}")); _ = Directory.CreateDirectory(Path.Combine(eDistanceContentDirectory, ticks.ToString()));
if (runToDoCollectionFirst) if (runToDoCollectionFirst)
mapLogic = null; mapLogic = null;
else else
@ -335,7 +338,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
if (!runToDoCollectionFirst) if (!runToDoCollectionFirst)
break; break;
(filesCollectionRootDirectory, filePathsCollection, filesCollectionCountIsOne) = GetFilesCollectionThenCopyOrMove(ticks, fileSearchFilter, directorySearchFilter, options, outputResolution); (filesCollectionRootDirectory, filePathsCollection, filesCollectionCountIsOne) = GetFilesCollectionThenCopyOrMove(ticks, fileSearchFilter, directorySearchFilter, options, outputResolution);
splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, filePathsCollection); keyValuePairs = FilePath.GetKeyValuePairs(filePathsCollection);
splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, keyValuePairs);
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);
@ -357,7 +361,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
} }
argZero = SaveUrlAndGetNewRootDirectory(filePathsCollection.First()); argZero = SaveUrlAndGetNewRootDirectory(filePathsCollection.First());
_Configuration.PropertyConfiguration.ChangeRootDirectory(argZero); _Configuration.PropertyConfiguration.ChangeRootDirectory(argZero);
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false);
propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory);
} }
@ -367,7 +371,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
{ {
if (outputResolution.Any(char.IsNumber)) if (outputResolution.Any(char.IsNumber))
continue; continue;
(cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: true); filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: true);
break; break;
@ -375,20 +379,17 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
} }
if (filesCollectionRootDirectory is null || filePathsCollection is null) if (filesCollectionRootDirectory is null || filePathsCollection is null)
throw new NullReferenceException(nameof(filePathsCollection)); throw new NullReferenceException(nameof(filePathsCollection));
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton);
if (!Directory.Exists(aPropertySingletonDirectory))
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
int count = filePathsCollection.Select(l => l.Count).Sum(); int count = filePathsCollection.Select(l => l.Count).Sum();
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
_ProgressBar = new(count, message, options); _ProgressBar = new(count, message, options);
ReadOnlyCollection<Container> readOnlyContainers = Shared.Models.Stateless.Methods.IContainer.GetContainers(this, _Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, splatNineIdentifiers, filePathsCollection); ReadOnlyCollection<Container.Models.Container> readOnlyContainers = Container.Models.Stateless.Methods.IContainer.GetContainers(this, _Configuration.PropertyConfiguration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, eDistanceContentDirectory, filesCollectionRootDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection);
_ProgressBar.Dispose(); _ProgressBar.Dispose();
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
DeleteContinueFiles(personContainers); DeleteContinueFiles(personContainers);
if (!runToDoCollectionFirst) if (!runToDoCollectionFirst)
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory, options); MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory, options);
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, count, readOnlyContainers, propertyLogic, mapLogic); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, count, metadata, readOnlyContainers, propertyLogic, mapLogic);
ReadOnlyCollection<Item> distinctValidImageItems = Shared.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)
{ {
string dResultsFullGroupDirectory; string dResultsFullGroupDirectory;
@ -396,7 +397,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), options); _ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), options);
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
mapLogic.LookForAbandoned(this, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); mapLogic.LookForAbandoned(this, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
_ProgressBar.Dispose(); _ProgressBar.Dispose();
} }
@ -437,7 +438,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string dResultsFullGroupDirectory; string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory; string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory; string d2ResultsFullGroupDirectory;
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton));
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton));
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton));
@ -549,33 +550,32 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return result; return result;
} }
private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string fPhotoPrismSingletonDirectory, int count, ReadOnlyCollection<Container> readOnlyContainers, A_Property propertyLogic, MapLogic mapLogic) private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string fPhotoPrismSingletonDirectory, int count, B_Metadata metadata, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, A_Property propertyLogic, MapLogic mapLogic)
{ {
int total; int total;
int notMapped; int notMapped;
string message; string message;
bool exceptions; bool exceptions;
int totalSeconds; int totalSeconds;
Container container;
int totalNotMapped = 0; int totalNotMapped = 0;
IDlibDotNet dlibDotNet = this;
bool outputResolutionHasNumber; bool outputResolutionHasNumber;
bool anyNullOrNoIsUniqueFileName; bool anyNullOrNoIsUniqueFileName;
string cResultsFullGroupDirectory; string cResultsFullGroupDirectory;
string dResultsFullGroupDirectory; string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory; string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory; string d2ResultsFullGroupDirectory;
Container.Models.Container container;
ReadOnlyCollection<Item> filteredItems; ReadOnlyCollection<Item> filteredItems;
int containersLength = readOnlyContainers.Count;
List<Tuple<string, DateTime>> sourceDirectoryChanges = []; List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism;
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = [] : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = [] : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory);
string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face));
B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
total = 0; total = 0;
outputResolutionHasNumber = outputResolution.Any(char.IsNumber); outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
_Faces.Update(dResultsFullGroupDirectory); _Faces.Update(dResultsFullGroupDirectory);
_Resize.Update(cResultsFullGroupDirectory); _Resize.Update(cResultsFullGroupDirectory);
_FaceParts.Update(d2ResultsFullGroupDirectory); _FaceParts.Update(d2ResultsFullGroupDirectory);
@ -587,13 +587,13 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
continue; continue;
if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero)) if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue; continue;
filteredItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, container); filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, container);
if (filteredItems.Count == 0) if (filteredItems.Count == 0)
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 - ticks).TotalSeconds);
message = $"{i + 1:000} [{filteredItems.Count:000}] / {containersLength:000} - {total} / {count} total - {totalSeconds} total second(s) - {outputResolution} - <{container.SourceDirectory}> - 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}";
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, container.SourceDirectory, anyNullOrNoIsUniqueFileName); propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, container.SourceDirectory, anyNullOrNoIsUniqueFileName);
if (outputResolutionHasNumber) if (outputResolutionHasNumber)
_Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory); _Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory);
@ -629,7 +629,7 @@ 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 - ticks).TotalSeconds);
message = $"### [###] / {containersLength:000} - {total} / {count} total - {totalSeconds} total second(s) - {outputResolution} - <> - total not mapped {totalNotMapped:000000}"; message = $"{totalSeconds} total second(s) - {outputResolution} - ### [###] / {readOnlyContainers.Count:000} - {total} / {count} total - <> - total not mapped {totalNotMapped:000000}";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(1, message, options); using ProgressBar progressBar = new(1, message, options);
progressBar.Tick(); progressBar.Tick();
@ -678,14 +678,24 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static Identifier GetIdentifier(Property.Models.Configuration propertyConfiguration, FilePath filePath, KeyValuePair<int, ReadOnlyCollection<FilePath>> keyValuePair)
{
Identifier result;
if (filePath.Id is null)
throw new Exception();
string[] directoryNames = keyValuePair.Value.Select(l => l.DirectoryFullPath.Replace('\\', '/')).ToArray();
string paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, index: null);
result = new(directoryNames, filePath.ExtensionLowered, filePath.HasDateTimeOriginal, filePath.Id.Value, filePath.Length, paddedId, filePath.LastWriteTicks);
return result;
}
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>> keyValuePairs)
{ {
Dictionary<int, Identifier> results = []; Dictionary<int, Identifier> results = [];
string json; string json;
string paddedId;
FilePath? filePath; FilePath? filePath;
Identifier identifier; Identifier identifier;
string[] directoryNames; List<Identifier> identifiers = [];
string rootDirectory = propertyConfiguration.RootDirectory.Replace('\\', '/'); string rootDirectory = propertyConfiguration.RootDirectory.Replace('\\', '/');
string bMetadataCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection); string bMetadataCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
if (!Directory.Exists(bMetadataCollectionDirectory)) if (!Directory.Exists(bMetadataCollectionDirectory))
@ -700,24 +710,31 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
break; break;
filePath = null; filePath = null;
} }
if (filePath?.Id is null) if (filePath is null)
{
filePath = keyValuePair.Value[0];
if (filePath.Id is null)
continue;
identifier = GetIdentifier(propertyConfiguration, filePath, keyValuePair);
identifiers.Add(identifier);
continue; continue;
directoryNames = keyValuePair.Value.Select(l => l.DirectoryFullPath.Replace('\\', '/')).ToArray(); }
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, index: null); else if (filePath.Id is null)
identifier = new(directoryNames, filePath.ExtensionLowered, filePath.HasDateTimeOriginal, filePath.Id.Value, filePath.Length, paddedId, filePath.LastWriteTicks); continue;
identifier = GetIdentifier(propertyConfiguration, filePath, keyValuePair);
identifiers.Add(identifier);
results.Add(keyValuePair.Key, identifier); results.Add(keyValuePair.Key, identifier);
} }
json = JsonSerializer.Serialize(results.Values.ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); json = JsonSerializer.Serialize(results.Values.ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(bMetadataCollectionDirectory, "!9.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(bMetadataCollectionDirectory, "!9.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
json = JsonSerializer.Serialize((from l in results orderby l.Value.PaddedId select l.Value).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); json = JsonSerializer.Serialize((from l in identifiers orderby l.PaddedId select l).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(bMetadataCollectionDirectory, ".json"), json.Replace(rootDirectory, string.Empty), updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(Path.Combine(bMetadataCollectionDirectory, ".json"), json.Replace(rootDirectory, string.Empty), updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiersAndHideSplatNine(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) private static ReadOnlyDictionary<int, Identifier> GetSplatNineIdentifiersAndHideSplatNine(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> keyValuePairs)
{ {
ReadOnlyDictionary<int, Identifier> results; ReadOnlyDictionary<int, Identifier> results;
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> keyValuePairs = FilePath.GetKeyValuePairs(filePathsCollection);
if (keyValuePairs.Count == 0) if (keyValuePairs.Count == 0)
results = new(new Dictionary<int, Identifier>()); results = new(new Dictionary<int, Identifier>());
else else
@ -730,7 +747,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return results; return results;
} }
private ReadOnlyCollection<Mapping> GetMappings(Property.Models.Configuration propertyConfiguration, string eDistanceContentDirectory, ReadOnlyCollection<Container> readOnlyContainers, MapLogic mapLogic, bool distinctItems) private ReadOnlyCollection<Mapping> GetMappings(Property.Models.Configuration propertyConfiguration, string eDistanceContentDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, MapLogic mapLogic, bool distinctItems)
{ {
List<Mapping> results = []; List<Mapping> results = [];
int count = 0; int count = 0;
@ -743,14 +760,14 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
DateTime[] containerDateTimes; DateTime[] containerDateTimes;
MappingFromItem mappingFromItem; MappingFromItem mappingFromItem;
ReadOnlyCollection<Item> filteredItems; ReadOnlyCollection<Item> filteredItems;
foreach (Container container in readOnlyContainers) foreach (Container.Models.Container container in readOnlyContainers)
{ {
if (container.Items.Count == 0) if (container.Items.Count == 0)
continue; continue;
filteredItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(propertyConfiguration, container); filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0) if (filteredItems.Count == 0)
continue; continue;
containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory)); focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory));
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)
@ -927,8 +944,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
private List<SaveContainer> GetSaveContainers(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, ProgressBarOptions options, MapLogic mapLogic, string outputResolution) private List<SaveContainer> GetSaveContainers(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, ProgressBarOptions options, MapLogic mapLogic, string outputResolution)
{ {
List<SaveContainer> results; List<SaveContainer> results;
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) = 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, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
if (mapped.Count == 0 && !_Configuration.SaveSortingWithoutPerson) if (mapped.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
@ -968,9 +986,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return results; return results;
} }
private void MapLogic(long ticks, ReadOnlyCollection<Container> containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) 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)
{ {
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution); IDlibDotNet dlibDotNet = this;
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContentCollection); string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContentCollection);
@ -1141,7 +1160,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string d2ResultsFullGroupDirectory, string d2ResultsFullGroupDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges, List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection, Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container, Container.Models.Container container,
Item item, Item item,
DateTime[] containerDateTimes, DateTime[] containerDateTimes,
bool? isFocusRelativePath) bool? isFocusRelativePath)
@ -1202,12 +1221,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
} }
if (resizedFileHolder.Exists && item.FilePath.HasIgnoreKeyword is not null && item.FilePath.HasIgnoreKeyword.Value != shouldIgnore.Value) if (resizedFileHolder.Exists && item.FilePath.HasIgnoreKeyword is not null && item.FilePath.HasIgnoreKeyword.Value != shouldIgnore.Value)
{ {
if (!item.FilePath.DirectoryFullPath.Contains("Results") || !item.FilePath.DirectoryFullPath.Contains("Resize")) if (item.FilePath.DirectoryFullPath.Contains("Results") && item.FilePath.DirectoryFullPath.Contains("Resize"))
throw new NotSupportedException($"Rename File! <{item.FilePath.FileNameFirstSegment}>");
else
{
File.Delete(resizedFileHolder.FullName); File.Delete(resizedFileHolder.FullName);
} else
throw new NotSupportedException($"Rename File! <{item.FilePath.FileNameFirstSegment}>");
} }
} }
if (property is null || item.Property is null) if (property is null || item.Property is null)
@ -1297,14 +1314,14 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string d2ResultsFullGroupDirectory, string d2ResultsFullGroupDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges, List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection, Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container, Container.Models.Container container,
ReadOnlyCollection<Item> filteredItems, ReadOnlyCollection<Item> filteredItems,
string message) string message)
{ {
int result = 0; int result = 0;
int exceptionsCount = 0; int exceptionsCount = 0;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
DateTime[] containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); DateTime[] containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
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);
@ -1340,7 +1357,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return (result, exceptionsCount > 0); return (result, exceptionsCount > 0);
} }
private (string, string) GetResultsFullGroupDirectories() (string, string) IDlibDotNet.GetResultsFullGroupDirectories()
{ {
string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration, _Configuration.PropertyConfiguration,
@ -1359,7 +1376,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory); return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory);
} }
private (string, string, string, string) GetResultsFullGroupDirectories(string outputResolution) (string, string, string, string) IDlibDotNet.GetResultsFullGroupDirectories(string outputResolution)
{ {
string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration, _Configuration.PropertyConfiguration,
@ -1503,8 +1520,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
private (string, ReadOnlyCollection<ReadOnlyCollection<FilePath>>, bool) GetFilesCollectionThenCopyOrMove(long ticks, string fileSearchFilter, string directorySearchFilter, ProgressBarOptions options, string outputResolution) private (string, ReadOnlyCollection<ReadOnlyCollection<FilePath>>, bool) GetFilesCollectionThenCopyOrMove(long ticks, string fileSearchFilter, string directorySearchFilter, ProgressBarOptions options, string outputResolution)
{ {
ProgressBar progressBar; ProgressBar progressBar;
IDlibDotNet dlibDotNet = this;
string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory; string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory;
(string cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); (string cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultContentCollection]); IReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, [_Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultContentCollection]);
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: false); ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: false);
int count = filePathsCollection.Select(l => l.Count).Sum(); int count = filePathsCollection.Select(l => l.Count).Sum();

View File

@ -51,6 +51,7 @@
<ProjectReference Include="..\FaceParts\FaceParts.csproj" /> <ProjectReference Include="..\FaceParts\FaceParts.csproj" />
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
<ProjectReference Include="..\Map\Map.csproj" /> <ProjectReference Include="..\Map\Map.csproj" />
<ProjectReference Include="..\Container\Container.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />
<ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" /> <ProjectReference Include="..\PhotoPrism\PhotoPrism.csproj" />
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" /> <ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />

View File

@ -41,6 +41,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\Container\Container.csproj" />
<ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -460,7 +460,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
private (long?, string?) GetDirectory(Configuration configuration, string by, string segmentB) private (long?, string?) GetDirectory(Configuration configuration, string by, LocationContainer _, string segmentB)
{ {
long? ticks = null; long? ticks = null;
const int zero = 0; const int zero = 0;
@ -537,22 +537,22 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
private Record Get(Configuration configuration, string by, long? personKey, string? displayDirectoryName, string segmentB) private Record Get(Configuration configuration, string by, LocationContainer locationContainer, string? displayDirectoryName, string segmentB)
{ {
long? ticks; long? ticks;
string? directory; string? directory;
string? debugDirectory; string? debugDirectory;
string? personDirectory; string? personDirectory;
if (personKey is null || string.IsNullOrEmpty(displayDirectoryName)) if (locationContainer.PersonKey is null || string.IsNullOrEmpty(displayDirectoryName))
{ {
debugDirectory = null; debugDirectory = null;
(ticks, directory) = GetDirectory(configuration, by, segmentB); (ticks, directory) = GetDirectory(configuration, by, locationContainer, segmentB);
personDirectory = directory is null ? null : Path.Combine(directory, $"X+{ticks}"); personDirectory = directory is null ? null : Path.Combine(directory, $"X+{ticks}");
} }
else else
{ {
ticks = null; ticks = null;
string personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey.Value); string personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, locationContainer.PersonKey.Value);
debugDirectory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, displayDirectoryName); debugDirectory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, displayDirectoryName);
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB); directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
personDirectory = Path.Combine(directory, displayDirectoryName, "lnk"); personDirectory = Path.Combine(directory, displayDirectoryName, "lnk");
@ -880,7 +880,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
displayDirectoryName = GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer, personKeyToPersonContainer); displayDirectoryName = GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer, personKeyToPersonContainer);
isCounterPersonYear = locationContainer.PersonKey is not null && IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKey.Value); isCounterPersonYear = locationContainer.PersonKey is not null && IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKey.Value);
(by, _, isBySorting) = Stateless.MapLogic.Get(useFiltersCounter, _Configuration.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKey, displayDirectoryName); (by, _, isBySorting) = Stateless.MapLogic.Get(useFiltersCounter, _Configuration.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKey, displayDirectoryName);
record = Get(_Configuration, by, locationContainer.PersonKey, displayDirectoryName, segmentB); record = Get(_Configuration, by, locationContainer, displayDirectoryName, segmentB);
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory)) if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
continue; continue;
directory = record.Directory; directory = record.Directory;
@ -1406,14 +1406,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return new(directoriesAndDateTimes, collection); return new(directoriesAndDateTimes, collection);
} }
public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) public void SaveShortcutsForOutputResolutionsDuringMapLogic(ReadOnlyCollection<Container.Models.Container> containers, ReadOnlyDictionary<long, List<int>> personKeyToIds, string dFacesContentDirectory, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
WindowsShortcut windowsShortcut; WindowsShortcut windowsShortcut;
List<(string, DateTime[])> directoriesAndDateTimes; List<(string, DateTime[])> directoriesAndDateTimes;
List<SaveShortcutsForOutputResolutions> collection; List<SaveShortcutsForOutputResolutions> collection;
ReadOnlyCollection<Item> validImageItems = IContainer.GetValidImageItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true); ReadOnlyCollection<Item> validImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_PropertyConfiguration, containers, distinctItems: true, filterItems: true);
(directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, validImageItems, distinctValidImageMappingCollection); (directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutionsDuringMapLogic(personKeyToIds, dFacesContentDirectory, validImageItems, distinctValidImageMappingCollection);
string[] directories = (from l in collection select l.Directory).Distinct().ToArray(); string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
foreach (string directory in directories) foreach (string directory in directories)
@ -1499,14 +1499,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) => public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages); IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
{ {
string[] directories; string[] directories;
string? directoryName; string? directoryName;
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers); List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
LookForAbandoned(propertyConfiguration, distinctFilteredIds); LookForAbandoned(propertyConfiguration, distinctFilteredIds);
dlibDotNet.Tick(); dlibDotNet.Tick();
List<string> distinctFilteredFileNameFirstSegments = 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(); dlibDotNet.Tick();
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);

View File

@ -22,7 +22,6 @@ internal abstract class DistanceLogic
internal record TicksDirectory(DateTime AlternateDirectoryDateTime, internal record TicksDirectory(DateTime AlternateDirectoryDateTime,
string Directory, string Directory,
DateTime DirectoryDateTime, DateTime DirectoryDateTime,
string DirectoryName,
bool? IsLocationContainerDebugDirectory, bool? IsLocationContainerDebugDirectory,
float? TotalDays); float? TotalDays);
@ -86,53 +85,55 @@ internal abstract class DistanceLogic
float? totalDays; float? totalDays;
long? next = null; long? next = null;
string? checkDirectory; string? checkDirectory;
string ticksDirectoryName;
DateTime directoryDateTime; DateTime directoryDateTime;
DirectoryInfo directoryInfo; DirectoryInfo directoryInfo;
TicksDirectory ticksDirectory;
long? lastDirectoryTicks = null; long? lastDirectoryTicks = null;
DateTime dateTime = DateTime.Now; DateTime dateTime = DateTime.Now;
DateTime alternateDirectoryDateTime; DateTime alternateDirectoryDateTime;
string ticksDirectoryNameFirstSegment;
bool? isLocationContainerDebugDirectory; bool? isLocationContainerDebugDirectory;
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks; long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
for (int i = 1; i < 5; i++) for (int i = 1; i < 5; i++)
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
if (!Directory.Exists(eDistanceContentDirectory)) if (!Directory.Exists(eDistanceContentDirectory))
_ = Directory.CreateDirectory(eDistanceContentDirectory); _ = Directory.CreateDirectory(eDistanceContentDirectory);
string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string ticksDirectory in ticksDirectories) foreach (string ticksFullPath in ticksFullPaths)
{ {
ticksDirectoryName = Path.GetFileName(ticksDirectory); ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
if (ticksDirectoryName.Length < 3) if (ticksDirectoryNameFirstSegment.Length < 3)
continue; continue;
if (!long.TryParse(ticksDirectoryName, out long directoryTicks)) if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
throw new NotSupportedException(); throw new NotSupportedException();
if (next is null) if (next is null)
next = new DateTime(directoryTicks).Ticks; next = new DateTime(directoryTicks).Ticks;
else else
{ {
next += month; next += month;
checkDirectory = Path.GetDirectoryName(ticksDirectory); checkDirectory = Path.GetDirectoryName(ticksFullPath);
if (string.IsNullOrEmpty(checkDirectory)) if (string.IsNullOrEmpty(checkDirectory))
{ {
if (string.IsNullOrEmpty(checkDirectory)) if (string.IsNullOrEmpty(checkDirectory))
continue; continue;
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString()); checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
if (ticksDirectory == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern)) if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(configuration.LocationContainerDirectoryPattern))
continue; continue;
Directory.Move(ticksDirectory, checkDirectory); Directory.Move(ticksFullPath, checkDirectory);
continue; continue;
} }
} }
directoryInfo = new(ticksDirectory); directoryInfo = new(ticksFullPath);
directoryDateTime = new DateTime(directoryTicks); directoryDateTime = new DateTime(directoryTicks);
if (directoryInfo.CreationTime.Ticks != directoryTicks) if (directoryInfo.CreationTime.Ticks != directoryTicks)
Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
if (directoryInfo.LastWriteTime.Ticks != directoryTicks) if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1); alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryName.EndsWith(configuration.LocationContainerDebugDirectory); isLocationContainerDebugDirectory = configuration.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(configuration.LocationContainerDebugDirectory);
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays; totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
results.Add(new(alternateDirectoryDateTime, ticksDirectory, new(directoryTicks), ticksDirectoryName, isLocationContainerDebugDirectory, totalDays)); ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
results.Add(ticksDirectory);
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0) if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
continue; continue;
lastDirectoryTicks = directoryTicks; lastDirectoryTicks = directoryTicks;
@ -216,9 +217,37 @@ internal abstract class DistanceLogic
} }
} }
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName) private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
{
string result;
string checkDirectory;
string directory = file;
List<string> collection = [];
for (int i = 0; i < file.Length; i++)
{
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
if (directory == ticksDirectory.Directory)
break;
collection.Add(Path.GetFileName(directory));
}
collection.Reverse();
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
foreach (string directoryName in collection)
checkDirectory = Path.Combine(checkDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
result = Path.Combine(checkDirectory, fileName);
if (File.Exists(result))
throw new Exception($"File <{fileName}> already exists!");
File.Move(file, result);
return result;
}
private static List<Record> GetRecords(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
{ {
List<Record> results = []; List<Record> results = [];
string @enum;
Record record;
string fileName; string fileName;
string checkFile; string checkFile;
FilePath filePath; FilePath filePath;
@ -244,8 +273,26 @@ internal abstract class DistanceLogic
File.Move(file, checkFile); File.Move(file, checkFile);
continue; continue;
} }
if (file.StartsWith(ticksDirectory.Directory))
{
@enum = IPath.GetEnum(filePath).ToString();
if (!ticksDirectory.Directory.EndsWith(@enum))
{
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
fileHolder = IFileHolder.Get(checkFile);
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
if (filePath.Id is null)
continue;
}
}
distinct.Add(fileName); distinct.Add(fileName);
results.Add(new(directoryNumber, isDefault, linksCount, filePath, personDisplayDirectoryName, personKeyFormatted)); record = new(DirectoryNumber: directoryNumber,
IsDefault: isDefault,
LinksCount: linksCount,
MappedFaceFilePath: filePath,
PersonDisplayDirectoryName: personDisplayDirectoryName,
PersonKeyFormatted: personKeyFormatted);
results.Add(record);
} }
return results; return results;
} }
@ -311,6 +358,7 @@ internal abstract class DistanceLogic
DateTime dateTime; DateTime dateTime;
TimeSpan timeSpan; TimeSpan timeSpan;
int directoryNumber; int directoryNumber;
List<Record> records;
string? checkDirectory; string? checkDirectory;
ProgressBar progressBar; ProgressBar progressBar;
string[] yearDirectories; string[] yearDirectories;
@ -340,8 +388,7 @@ internal abstract class DistanceLogic
progressBar = new(ticksDirectories.Count, message, options); progressBar = new(ticksDirectories.Count, message, options);
foreach (TicksDirectory ticksDirectory in ticksDirectories) foreach (TicksDirectory ticksDirectory in ticksDirectories)
{ {
if (i == 1) progressBar.Tick();
progressBar.Tick();
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly); personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories) foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
{ {
@ -368,23 +415,6 @@ internal abstract class DistanceLogic
linksCount = null; linksCount = null;
else else
linksCount = GetLinksCount(yearDirectory); linksCount = GetLinksCount(yearDirectory);
if (ticksDirectory.DirectoryName != configuration.LocationContainerDebugDirectory)
{
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
File.Delete(file);
}
if (ticksDirectory.DirectoryName == configuration.LocationContainerDebugDirectory)
{
isDefault = null;
personDisplayDirectoryName = null;
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
files = Directory.GetFiles(yearDirectory, "*.lnk", SearchOption.AllDirectories);
foreach (string file in files)
File.Delete(file);
continue;
}
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
if (personNameDirectories.Length > 1) if (personNameDirectories.Length > 1)
throw new NotSupportedException("Try deleting *.lnk files!"); throw new NotSupportedException("Try deleting *.lnk files!");
@ -467,7 +497,9 @@ internal abstract class DistanceLogic
Directory.Move(personNameDirectory, personFirstInitialDirectory); Directory.Move(personNameDirectory, personFirstInitialDirectory);
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
} }
results.AddRange(GetRecords(propertyConfiguration, configuration, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName)); records = GetRecords(propertyConfiguration, configuration, ticksDirectory, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName);
if (records.Count > 0)
results.AddRange(records);
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personNameLinkDirectory in personNameLinkDirectories) foreach (string personNameLinkDirectory in personNameLinkDirectories)
{ {

View File

@ -13,17 +13,17 @@ namespace View_by_Distance.Map.Models.Stateless;
internal abstract class MapLogic internal abstract class MapLogic
{ {
internal record Duplicate(long PersonKey,
int Id,
FilePath FilePath,
float? Percent);
internal record MappedFile(long PersonKey, internal record MappedFile(long PersonKey,
string PersonKeyFormatted, string PersonKeyFormatted,
string? PersonDisplayDirectoryName, string? PersonDisplayDirectoryName,
int? DirectoryNumber, int? DirectoryNumber,
FilePath FilePath); FilePath FilePath);
internal record Duplicate(long PersonKey,
int Id,
FilePath FilePath,
float? Percent);
internal record PersonKeyFormattedIdThenWholePercentages(string PersonKeyFormatted, internal record PersonKeyFormattedIdThenWholePercentages(string PersonKeyFormatted,
string? PersonDisplayDirectoryName, string? PersonDisplayDirectoryName,
bool? IsDefault, bool? IsDefault,
@ -188,6 +188,7 @@ internal abstract class MapLogic
private static List<MappedFile> GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, ReadOnlyCollection<PersonContainer> personContainers) private static List<MappedFile> GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, ReadOnlyCollection<PersonContainer> personContainers)
{ {
List<MappedFile> results = []; List<MappedFile> results = [];
MappedFile mappedFile;
string personKeyFormatted; string personKeyFormatted;
List<string> distinct = []; List<string> distinct = [];
foreach (PersonContainer personContainer in personContainers) foreach (PersonContainer personContainer in personContainers)
@ -202,7 +203,12 @@ internal abstract class MapLogic
continue; continue;
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name); distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value); personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value);
results.Add(new(personContainer.Key.Value, personKeyFormatted, personContainer.DisplayDirectoryName, null, personContainer.DisplayDirectoryAllFilePaths[i])); mappedFile = new(PersonKey: personContainer.Key.Value,
PersonKeyFormatted: personKeyFormatted,
PersonDisplayDirectoryName: personContainer.DisplayDirectoryName,
DirectoryNumber: null,
FilePath: personContainer.DisplayDirectoryAllFilePaths[i]);
results.Add(mappedFile);
} }
} }
return results; return results;
@ -462,6 +468,7 @@ internal abstract class MapLogic
string checkFile; string checkFile;
FilePath filePath; FilePath filePath;
FileHolder fileHolder; FileHolder fileHolder;
MappedFile mappedFile;
List<string> distinct = []; List<string> distinct = [];
PersonBirthday? personBirthday; PersonBirthday? personBirthday;
PersonContainer? personContainer; PersonContainer? personContainer;
@ -481,7 +488,12 @@ internal abstract class MapLogic
personDisplayDirectoryName = record.PersonDisplayDirectoryName; personDisplayDirectoryName = record.PersonDisplayDirectoryName;
else else
personDisplayDirectoryName = personContainer.DisplayDirectoryName; personDisplayDirectoryName = personContainer.DisplayDirectoryName;
results.Add(new(personKey, record.PersonKeyFormatted, personDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath)); mappedFile = new(PersonKey: personKey,
PersonKeyFormatted: record.PersonKeyFormatted,
PersonDisplayDirectoryName: personDisplayDirectoryName,
DirectoryNumber: record.DirectoryNumber,
FilePath: record.MappedFaceFilePath);
results.Add(mappedFile);
} }
for (int i = results.Count - 1; i > -1; i--) for (int i = results.Count - 1; i > -1; i--)
{ {
@ -501,7 +513,11 @@ internal abstract class MapLogic
File.Move(filePath.FullName, checkFile); File.Move(filePath.FullName, checkFile);
fileHolder = IFileHolder.Get(checkFile); fileHolder = IFileHolder.Get(checkFile);
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null); filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
results[i] = new(results[i].PersonKey, results[i].PersonKeyFormatted, results[i].PersonDisplayDirectoryName, results[i].DirectoryNumber, filePath); results[i] = new(PersonKey: results[i].PersonKey,
PersonKeyFormatted: results[i].PersonKeyFormatted,
PersonDisplayDirectoryName: results[i].PersonDisplayDirectoryName,
DirectoryNumber: results[i].DirectoryNumber,
FilePath: filePath);
} }
return results; return results;
} }
@ -791,6 +807,7 @@ internal abstract class MapLogic
int? wholePercentages; int? wholePercentages;
List<int> wholePercentagesCollection; List<int> wholePercentagesCollection;
Dictionary<int, List<int>> idToWholePercentagesCollection = []; Dictionary<int, List<int>> idToWholePercentagesCollection = [];
PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") {records.Count:000} join from ticks Director(ies) - C - {totalSeconds} total second(s)"; string message = $") {records.Count:000} join from ticks Director(ies) - C - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
@ -808,7 +825,14 @@ internal abstract class MapLogic
wholePercentagesCollection = idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value]; wholePercentagesCollection = idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value];
wholePercentagesCollection.Add(wholePercentages.Value); wholePercentagesCollection.Add(wholePercentages.Value);
idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value].Add(wholePercentages.Value); idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value].Add(wholePercentages.Value);
results.Add(new(record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.IsDefault, record.LinksCount, record.MappedFaceFilePath, record.MappedFaceFilePath.Id.Value, wholePercentages.Value)); personKeyFormattedIdThenWholePercentages = new(PersonKeyFormatted: record.PersonKeyFormatted,
PersonDisplayDirectoryName: record.PersonDisplayDirectoryName,
IsDefault: record.IsDefault,
LinksCount: record.LinksCount,
MappedFaceFilePath: record.MappedFaceFilePath,
Id: record.MappedFaceFilePath.Id.Value,
WholePercentages: wholePercentages.Value);
results.Add(personKeyFormattedIdThenWholePercentages);
} }
return results.AsReadOnly(); return results.AsReadOnly();
} }

View File

@ -34,10 +34,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MetadataExtractor" Version="2.8.1" /> <PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
<PackageReference Include="System.Text.Json" Version="9.0.2" /> <PackageReference Include="System.Text.Json" Version="9.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -148,7 +148,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
DateTime? result = null; DateTime? result = null;
DateTime? dateTime; DateTime? dateTime;
DateTime checkDateTime; DateTime checkDateTime;
string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat(); string dateTimeFormat = Stateless.Methods.IMetadata.DateTimeFormat();
MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault(); MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType<MetadataExtractor.Formats.Exif.ExifDirectoryBase>().FirstOrDefault();
results.Add(new DateTime(filePath.CreationTicks)); results.Add(new DateTime(filePath.CreationTicks));
results.Add(new DateTime(filePath.LastWriteTicks)); results.Add(new DateTime(filePath.LastWriteTicks));
@ -158,7 +158,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
results.Add(checkDateTime); results.Add(checkDateTime);
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime));
if (dateTime is not null) if (dateTime is not null)
results.Add(dateTime.Value); results.Add(dateTime.Value);
} }
@ -166,7 +166,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
results.Add(checkDateTime); results.Add(checkDateTime);
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized));
if (dateTime is not null) if (dateTime is not null)
results.Add(dateTime.Value); results.Add(dateTime.Value);
} }
@ -177,7 +177,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
} }
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal));
if (dateTime is not null) if (dateTime is not null)
{ {
result ??= dateTime.Value; result ??= dateTime.Value;
@ -195,7 +195,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
} }
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
if (dateTime is not null) if (dateTime is not null)
{ {
result ??= dateTime.Value; result ??= dateTime.Value;
@ -213,7 +213,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
} }
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
if (dateTime is not null) if (dateTime is not null)
{ {
result ??= dateTime.Value; result ??= dateTime.Value;
@ -231,7 +231,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
} }
else else
{ {
dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated)); dateTime = Stateless.Methods.IMetadata.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
if (dateTime is not null) if (dateTime is not null)
{ {
result ??= dateTime.Value; result ??= dateTime.Value;

View File

@ -1,3 +1,4 @@
using System.Globalization;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless.Methods; namespace View_by_Distance.Metadata.Models.Stateless.Methods;
@ -47,4 +48,23 @@ internal static class Base
return result; 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
} }

View File

@ -64,4 +64,14 @@ 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);
} }

View File

@ -239,7 +239,7 @@ public class A_Property
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
} }
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container container, ReadOnlyCollection<Item> items, string message) private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container.Models.Container container, ReadOnlyCollection<Item> items, string message)
{ {
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = []; List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
@ -268,14 +268,14 @@ public class A_Property
}); });
} }
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container[] containers) public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container.Models.Container[] containers)
{ {
int total = 0; int total = 0;
string message; string message;
int totalSeconds; int totalSeconds;
Container container;
bool anyNullOrNoIsUniqueFileName; bool anyNullOrNoIsUniqueFileName;
List<Exception> exceptions = []; List<Exception> exceptions = [];
Container.Models.Container container;
int containersLength = containers.Length; int containersLength = containers.Length;
const string outputResolution = "Original"; const string outputResolution = "Original";
List<Tuple<string, DateTime>> sourceDirectoryChanges = []; List<Tuple<string, DateTime>> sourceDirectoryChanges = [];

View File

@ -55,4 +55,24 @@ public interface IProperty
static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) => static (DateTime?, DateTime[], int?, string?) Get(IPropertyConfiguration propertyConfiguration, bool populateId, IMetadata<MetadataExtractor.Directory>? metadata, FileHolder fileHolder, bool isIgnoreExtension, bool isValidImageFormatExtension, ASCIIEncoding asciiEncoding) =>
Property.Get(populateId, metadata, FilePath.Get(propertyConfiguration, fileHolder, index: null), isIgnoreExtension, isValidImageFormatExtension, asciiEncoding); Property.Get(populateId, metadata, FilePath.Get(propertyConfiguration, fileHolder, index: null), isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container) =>
GetThreeStandardDeviationHigh(minimum, container);
static TimeSpan GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container) =>
Property.GetThreeStandardDeviationHigh(minimum, container);
(int, List<DateTime>, List<Shared.Models.Item>) TestStatic_Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Get(container, threeStandardDeviationHigh, i);
static (int, List<DateTime>, List<Shared.Models.Item>) Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Property.Get(container, threeStandardDeviationHigh, i);
bool TestStatic_Any(Container.Models.Container[] propertyHolderCollections) =>
Any(propertyHolderCollections);
static bool Any(Container.Models.Container[] propertyHolderCollections) =>
Property.Any(propertyHolderCollections);
double TestStatic_GetStandardDeviation(List<long> values, double average) =>
GetStandardDeviation(values, average);
static double GetStandardDeviation(List<long> values, double average) =>
Property.GetStandardDeviation(values, average);
} }

View File

@ -366,4 +366,112 @@ internal partial class Property
return new(property?.DateTimeOriginal, dateTimes, property?.Id, message); return new(property?.DateTimeOriginal, dateTimes, property?.Id, message);
} }
internal static double GetStandardDeviation(List<long> values, double average)
{
double result = 0;
if (values.Count == 0)
throw new Exception("Collection must have at least one value!");
double sum = values.Sum(l => (l - average) * (l - average));
result = Math.Sqrt(sum / values.Count);
return result;
}
private static long GetThreeStandardDeviationHigh(ref List<long> ticksCollection, long min)
{
long result;
ticksCollection = (from l in ticksCollection select l - min).ToList();
double sum = ticksCollection.Sum();
double average = sum / ticksCollection.Count;
double standardDeviation = GetStandardDeviation(ticksCollection, average);
result = (long)Math.Ceiling(average + min + (standardDeviation * 3));
return result;
}
internal static TimeSpan GetThreeStandardDeviationHigh(int minimum, Container.Models.Container container)
{
TimeSpan result;
DateTime? minimumDateTime;
List<long> ticksCollection = [];
foreach (Shared.Models.Item item in container.Items)
{
if (item.Property is null)
continue;
minimumDateTime = Shared.Models.Methods.IProperty.GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
ticksCollection.Add(minimumDateTime.Value.Ticks);
}
long threeStandardDeviationHigh;
long min;
if (ticksCollection.Count == 0)
min = 0;
else
min = ticksCollection.Min();
if (ticksCollection.Count < minimum)
threeStandardDeviationHigh = long.MaxValue;
else
threeStandardDeviationHigh = GetThreeStandardDeviationHigh(ref ticksCollection, min);
result = new TimeSpan(threeStandardDeviationHigh - min);
return result;
}
internal static (int, List<DateTime>, List<Shared.Models.Item>) Get(Container.Models.Container container, TimeSpan threeStandardDeviationHigh, int i)
{
List<Shared.Models.Item> results = [];
int j = i;
long? ticks;
TimeSpan timeSpan;
Shared.Models.Item item;
DateTime? minimumDateTime;
Shared.Models.Item nextItem;
DateTime? nextMinimumDateTime;
List<DateTime> dateTimes = [];
for (; j < container.Items.Count; j++)
{
ticks = null;
item = container.Items[j];
if (item.Property is null)
continue;
minimumDateTime = Shared.Models.Methods.IProperty.GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
for (int k = j + 1; k < container.Items.Count; k++)
{
nextItem = container.Items[k];
if (nextItem.Property is null)
continue;
nextMinimumDateTime = Shared.Models.Methods.IProperty.GetMinimumDateTime(nextItem.Property);
if (nextMinimumDateTime is null)
continue;
ticks = nextMinimumDateTime.Value.Ticks;
break;
}
results.Add(item);
dateTimes.Add(minimumDateTime.Value);
if (ticks.HasValue)
{
timeSpan = new(ticks.Value - minimumDateTime.Value.Ticks);
if (timeSpan > threeStandardDeviationHigh)
break;
}
}
return new(j, dateTimes, results);
}
internal static bool Any(Container.Models.Container[] containers)
{
bool result = false;
foreach (Container.Models.Container container in containers)
{
if (container.Items.Count == 0)
continue;
if ((from l in container.Items where l.Any() select true).Any())
{
result = true;
break;
}
}
return result;
}
} }

View File

@ -46,6 +46,7 @@
<PackageReference Include="System.Text.Json" Version="9.0.2" /> <PackageReference Include="System.Text.Json" Version="9.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Container\Container.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -315,7 +315,7 @@ public class C_Resize
throw new Exception(); throw new Exception();
} }
public void SaveResizedSubfile(Configuration configuration, string outputResolution, string cResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, Item item, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize) public void SaveResizedSubfile(Property.Models.Configuration configuration, string outputResolution, string cResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, Item item, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize)
{ {
if (mappingFromItem.ResizedFileHolder is null) if (mappingFromItem.ResizedFileHolder is null)
throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder)); throw new NullReferenceException(nameof(mappingFromItem.ResizedFileHolder));
@ -462,7 +462,7 @@ public class C_Resize
} }
} }
public Dictionary<string, int[]> GetResizeKeyValuePairs(Configuration configuration, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem) public Dictionary<string, int[]> GetResizeKeyValuePairs(Property.Models.Configuration configuration, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem)
{ {
Dictionary<string, int[]>? results; Dictionary<string, int[]>? results;
string json; string json;

View File

@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models; namespace View_by_Distance.Shared.Models;
internal record FilePair(string Path, public record FilePair(string Path,
bool IsUnique, bool IsUnique,
bool? IsNotUniqueAndNeedsReview, bool? IsNotUniqueAndNeedsReview,
List<string> Collection, List<string> Collection,
@ -20,6 +20,6 @@ internal record FilePair(string Path,
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(FilePair))] [JsonSerializable(typeof(FilePair))]
internal partial class FilePairSourceGenerationContext : JsonSerializerContext public partial class FilePairSourceGenerationContext : JsonSerializerContext
{ {
} }

View File

@ -1,8 +0,0 @@
namespace View_by_Distance.Shared.Models.Methods;
public interface IContainer : Stateless.Methods.IContainer
{ // ...
//
}

View File

@ -1,302 +0,0 @@
using System.Collections.ObjectModel;
using System.Text.Json;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Container
{
private record FilePair(bool IsUnique, List<string> Collection, FilePath FilePath, Models.Item Item) { }
internal static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Models.Item> items)
{
DateTime[] results;
long containerMinimumTicks = (from l in items select l.FilePath.LastWriteTicks).Min();
long containerMaximumTicks = (from l in items select l.FilePath.LastWriteTicks).Max();
results = [new(containerMinimumTicks), new(containerMaximumTicks)];
return results;
}
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container)
{
List<Models.Item> results = [];
foreach (Models.Item item in container.Items)
{
if (!item.IsValidImageFormatExtension || propertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered))
continue;
results.Add(item);
}
return container.Items.Count == results.Count ? container.Items : results.AsReadOnly();
}
private static List<Models.FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
{
int renamed;
const bool useCeilingAverage = true;
List<Models.FilePair>? filePairs = null;
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = XDirectory.GetFilesKeyValuePairs(filePathsCollection);
for (int i = 0; i < short.MaxValue; i++)
{
renamed = 0;
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension, useCeilingAverage);
compareFileNamesToFiles = XDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
renamed += XDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
filePairs = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
renamed += XDirectory.MaybeMove(propertyConfiguration, filePairs, aPropertySingletonDirectory, extension);
if (renamed == 0)
break;
if (i > 10)
throw new NotImplementedException();
}
if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
throw new NullReferenceException(nameof(filePairs));
return filePairs;
}
private static Models.Property? GetProperty(Models.FilePair filePair)
{
Models.Property? result;
if (filePair.Match is null)
result = null;
else
{
string json = File.ReadAllText(filePair.Match);
if (string.IsNullOrEmpty(json))
result = null;
else
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
}
return result;
}
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
{
string[] segments = directory.Split(cei.Combined);
string? checkDirectory = segments.Length == 1 ?
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
segments.Length == 2 ?
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
null;
if (checkDirectory is not null && Directory.Exists(checkDirectory))
{
string checkFile = Path.Combine(checkDirectory, fileName);
if (File.Exists(checkFile))
File.Move(checkFile, fullFileName);
}
}
private static void ParallelFor(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int rootDirectoryLength, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, Models.FilePair filePair, List<FilePair> results)
{
dlibDotNet?.Tick();
bool abandoned = false;
Models.FileHolder sourceDirectoryFileHolder;
Models.Property? property = GetProperty(filePair);
Models.FileHolder imageFileHolder = IFileHolder.Get(filePair.Path);
FilePath filePath = FilePath.Get(propertyConfiguration, imageFileHolder, index: null);
bool? fileSizeChanged = property is not null ? property.FileSize != filePath.Length : null;
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(filePath.ExtensionLowered);
bool? shouldIgnore = property is null || property.Keywords is null ? null : propertyConfiguration.IgnoreRulesKeyWords.Any(l => property.Keywords.Contains(l));
bool? isArchive = filePath.Id is null || splatNineIdentifiers is null ? null : splatNineIdentifiers.TryGetValue(filePath.Id.Value, out Identifier? identifier);
if (shouldIgnore is not null)
{
if (shouldIgnore.Value)
{
FileInfo fileInfo = new(filePath.FullName);
if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden))
File.SetAttributes(imageFileHolder.FullName, FileAttributes.Hidden);
}
if (filePath.HasIgnoreKeyword is not null && filePath.HasIgnoreKeyword.Value != shouldIgnore.Value)
{
if (filePath.DirectoryFullPath.Contains("Results") && filePath.DirectoryFullPath.Contains("Resize"))
File.Delete(filePath.FullName);
else
throw new NotSupportedException($"Rename File! <{filePath.FileNameFirstSegment}>");
}
}
string relativePath = IPath.GetRelativePath(filePair.Path, rootDirectoryLength, forceExtensionToLower: true);
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime.Ticks != filePath.LastWriteTicks : null;
if (filePair.Match is not null)
sourceDirectoryFileHolder = IFileHolder.Get(filePair.Match);
else if (!filePair.IsUnique)
sourceDirectoryFileHolder = IFileHolder.Get(Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath, extension)));
else
{
string fileName = Path.GetFileName(filePair.Path);
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
string directory = Path.Combine(aPropertySingletonDirectory, cei.Combined);
string jsonFileName = $"{fileName}{extension}";
string fullFileName = Path.Combine(directory, jsonFileName);
MoveIf(jsonFileName, cei, directory, fullFileName);
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
}
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
{
File.SetCreationTime(sourceDirectoryFileHolder.FullName, new(filePath.LastWriteTicks));
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
}
Models.Item item = Models.Item.Get(filePath, sourceDirectoryFileHolder, relativePath, isArchive, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
lock (results)
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
}
private static List<FilePair> GetFilePairs(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
{
List<FilePair> results = [];
const string extension = ".json";
int maxDegreeOfParallelism = Environment.ProcessorCount;
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
List<Models.FilePair> filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filePathsCollection);
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, extension, filesCollectionDirectoryLength, splatNineIdentifiers, filePairs[i], results));
return results;
}
private static (int, Models.Container[]) GetContainers(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, string directorySearchFilter)
{
List<Models.Container> results = [];
string directory;
List<Models.Item>? items;
Models.Container container;
List<string> directories = [];
Dictionary<string, List<Models.Item>> directoryToItems = [];
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{
if (filePaths.Count == 0)
continue;
directory = filePaths[0].DirectoryFullPath;
if (directory is null)
continue;
if (!directories.Contains(directory))
directories.Add(directory);
if (!directoryToItems.TryGetValue(directory, out items))
{
directoryToItems.Add(directory, []);
if (!directoryToItems.TryGetValue(directory, out items))
throw new Exception();
}
}
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
foreach (FilePair filePair in filePairs)
{
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
{
directoryToItems.Add(filePair.FilePath.DirectoryFullPath, []);
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
throw new Exception();
}
items.Add(filePair.Item);
}
foreach (KeyValuePair<string, List<Models.Item>> keyValuePair in directoryToItems)
{
if (keyValuePair.Value.Count == 0)
continue;
container = new(keyValuePair.Key, new(keyValuePair.Value));
results.Add(container);
}
return (filePairs.Count, results.ToArray());
}
internal static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
{
Models.Container[] results;
const string directorySearchFilter = "*";
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
return results.AsReadOnly();
}
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory)
{
int count;
Models.Container[] results;
IDlibDotNet? dlibDotNet = null;
const bool useCeilingAverage = true;
const string fileSearchFilter = "*";
const string directorySearchFilter = "*";
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, propertyConfiguration.RootDirectory, splatNineIdentifiers, filePathsCollection, directorySearchFilter);
return (count, results);
}
internal static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
{
List<int> results = [];
ReadOnlyCollection<Models.Item> filteredItems;
foreach (Models.Container container in readOnlyContainers)
{
if (container.Items.Count == 0)
continue;
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
foreach (Models.Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (results.Contains(item.Property.Id.Value))
continue;
results.Add(item.Property.Id.Value);
}
}
return results;
}
internal static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
{
List<string> results = [];
ReadOnlyCollection<Models.Item> filteredItems;
foreach (Models.Container container in readOnlyContainers)
{
if (container.Items.Count == 0)
continue;
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
foreach (Models.Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (results.Contains(item.FilePath.FileNameFirstSegment))
continue;
results.Add(item.FilePath.FileNameFirstSegment);
}
}
return results;
}
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
{
List<Models.Item> results = [];
List<int> distinct = [];
ReadOnlyCollection<Models.Item> filteredItems;
foreach (Models.Container container in containers)
{
if (container.Items.Count == 0)
continue;
if (!filterItems)
filteredItems = container.Items;
else
{
filteredItems = GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
}
foreach (Models.Item item in filteredItems)
{
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (distinctItems)
{
if (distinct.Contains(item.Property.Id.Value))
continue;
distinct.Add(item.Property.Id.Value);
}
results.Add(item);
}
}
return results.AsReadOnly();
}
}

View File

@ -1,48 +0,0 @@
using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IContainer
{
DateTime[] TestStatic_GetContainerDateTimes(ReadOnlyCollection<Models.Item> items) =>
GetContainerDateTimes(items);
static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Models.Item> items) =>
Container.GetContainerDateTimes(items);
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container) =>
GetValidImageItems(propertyConfiguration, container);
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container) =>
Container.GetValidImageItems(propertyConfiguration, container);
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory);
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) =>
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory);
ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection);
static ReadOnlyCollection<Models.Container> GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
Container.GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, splatNineIdentifiers, filePathsCollection);
List<int> TestStatic_GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
Container.GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
}

View File

@ -50,4 +50,14 @@ public interface IDirectory
static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) => static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection) =>
XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection); XDirectory.GetFilePathCollections(propertyConfiguration, filesCollection);
List<FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
int TestStatic_MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
XDirectory.MaybeMove(propertyConfiguration, filePairs, jsonGroupDirectory, extension);
} }

View File

@ -4,5 +4,7 @@ public interface IDlibDotNet
{ {
void Tick(); void Tick();
(string, string) GetResultsFullGroupDirectories();
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
} }

View File

@ -23,29 +23,16 @@ public interface IId
static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => static string GetPaddedId(Properties.IPropertyConfiguration propertyConfiguration, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
Id.GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index); Id.GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
string TestStatic_GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
GetIgnoreFullPath(filePath, fileHolder);
static string GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
fileHolder.DirectoryFullPath is null ?
throw new NotSupportedException() :
filePath.Id > -1 ?
fileHolder.NameWithoutExtension[^1] == '9' ?
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}8{fileHolder.ExtensionLowered}") :
throw new NotSupportedException("High") :
fileHolder.NameWithoutExtension[^1] == '1' ?
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}2{fileHolder.ExtensionLowered}") :
throw new NotSupportedException("Low");
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) => bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment); NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
static bool NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) => static bool NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber); fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment); NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment);
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1 fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
&& fileNameFirstSegment[^1] is '1' or '2' or '8' or '9' && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9'
&& fileNameFirstSegment.All(char.IsNumber); && fileNameFirstSegment.All(char.IsNumber);
bool TestStatic_NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) => bool TestStatic_NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
@ -58,4 +45,19 @@ public interface IId
static int GetDeterministicHashCode(byte[] value) => static int GetDeterministicHashCode(byte[] value) =>
Id.GetDeterministicHashCode(value); Id.GetDeterministicHashCode(value);
int TestStatic_GetHasIgnoreKeyword(FilePath filePath) =>
GetHasIgnoreKeyword(filePath);
static int GetHasIgnoreKeyword(FilePath filePath) =>
Id.GetHasIgnoreKeyword(filePath);
int TestStatic_GetMissingDateTimeOriginal(FilePath filePath) =>
GetMissingDateTimeOriginal(filePath);
static int GetMissingDateTimeOriginal(FilePath filePath) =>
Id.GetMissingDateTimeOriginal(filePath);
int TestStatic_GetHasDateTimeOriginal(FilePath filePath) =>
GetHasDateTimeOriginal(filePath);
static int GetHasDateTimeOriginal(FilePath filePath) =>
Id.GetHasDateTimeOriginal(filePath);
} }

View File

@ -72,4 +72,9 @@ public interface IPath
static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) => static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
XPath.GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups); XPath.GetKeyValuePairs(propertyConfiguration, resultsFullGroupDirectory, jsonGroups);
byte TestStatic_GetEnum(FilePath filePath) =>
GetEnum(filePath);
static byte GetEnum(FilePath filePath) =>
XPath.GetEnum(filePath);
} }

View File

@ -23,11 +23,6 @@ public interface IProperty
static string GetDiffRootDirectory(string diffPropertyDirectory) => static string GetDiffRootDirectory(string diffPropertyDirectory) =>
Property.GetDiffRootDirectory(diffPropertyDirectory); Property.GetDiffRootDirectory(diffPropertyDirectory);
bool TestStatic_Any(Models.Container[] propertyHolderCollections) =>
Any(propertyHolderCollections);
static bool Any(Models.Container[] propertyHolderCollections) =>
Property.Any(propertyHolderCollections);
(bool?, string[]) TestStatic_IsWrongYear(string[] segments, string year) => (bool?, string[]) TestStatic_IsWrongYear(string[] segments, string year) =>
IsWrongYear(segments, year); IsWrongYear(segments, year);
static (bool?, string[]) IsWrongYear(string[] segments, string year) => static (bool?, string[]) IsWrongYear(string[] segments, string year) =>
@ -43,21 +38,6 @@ public interface IProperty
static List<DateTime> GetDateTimes(Models.Property property) => static List<DateTime> GetDateTimes(Models.Property property) =>
Property.GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp); Property.GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp);
double TestStatic_GetStandardDeviation(List<long> values, double average) =>
GetStandardDeviation(values, average);
static double GetStandardDeviation(List<long> values, double average) =>
Property.GetStandardDeviation(values, average);
TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
GetThreeStandardDeviationHigh(minimum, container);
static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
Property.GetThreeStandardDeviationHigh(minimum, container);
(int, List<DateTime>, List<Models.Item>) TestStatic_Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Get(container, threeStandardDeviationHigh, i);
static (int, List<DateTime>, List<Models.Item>) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Property.Get(container, threeStandardDeviationHigh, i);
List<DateTime> TestStatic_GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) => List<DateTime> TestStatic_GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>
GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, gpsDateStamp); GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, gpsDateStamp);
static List<DateTime> GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) => static List<DateTime> GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>

View File

@ -28,13 +28,22 @@ internal abstract class Id
_ = results.Append(intelligentId[i]); _ = results.Append(intelligentId[i]);
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]); _ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
result = int.Parse(results.ToString()); result = int.Parse(results.ToString());
if (intelligentId[^1] is '1' or '2') if (intelligentId[^1] is '1' or '2' or '3')
result *= -1; result *= -1;
else if (intelligentId[^1] is not '9' and not '8') else if (intelligentId[^1] is not '9' and not '8' and not '7')
throw new NotSupportedException(); throw new NotSupportedException();
return result; return result;
} }
internal static int GetHasIgnoreKeyword(FilePath filePath) =>
filePath.Id > -1 ? 8 : 2;
internal static int GetMissingDateTimeOriginal(FilePath filePath) =>
filePath.Id > -1 ? 7 : 3;
internal static int GetHasDateTimeOriginal(FilePath filePath) =>
filePath.Id > -1 ? 9 : 1;
internal static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) internal static string GetIntelligentId(Properties.IPropertyConfiguration propertyConfiguration, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
{ {
string result; string result;
@ -48,12 +57,12 @@ internal abstract class Id
List<char> resultAllInOneSubdirectoryChars = []; List<char> resultAllInOneSubdirectoryChars = [];
if (id > -1) if (id > -1)
{ {
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : 9; key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 9 : 7;
value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0'); value = id.ToString().PadLeft(propertyConfiguration.IntMinValueLength, '0');
} }
else else
{ {
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : 1; key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 1 : 3;
value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0'); value = id.ToString()[1..].PadLeft(propertyConfiguration.IntMinValueLength, '0');
} }
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--) for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)

View File

@ -171,112 +171,4 @@ internal abstract class Property
return result; return result;
} }
internal static double GetStandardDeviation(List<long> values, double average)
{
double result = 0;
if (values.Count == 0)
throw new Exception("Collection must have at least one value!");
double sum = values.Sum(l => (l - average) * (l - average));
result = Math.Sqrt(sum / values.Count);
return result;
}
private static long GetThreeStandardDeviationHigh(ref List<long> ticksCollection, long min)
{
long result;
ticksCollection = (from l in ticksCollection select l - min).ToList();
double sum = ticksCollection.Sum();
double average = sum / ticksCollection.Count;
double standardDeviation = GetStandardDeviation(ticksCollection, average);
result = (long)Math.Ceiling(average + min + (standardDeviation * 3));
return result;
}
internal static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container)
{
TimeSpan result;
DateTime? minimumDateTime;
List<long> ticksCollection = [];
foreach (Models.Item item in container.Items)
{
if (item.Property is null)
continue;
minimumDateTime = GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
ticksCollection.Add(minimumDateTime.Value.Ticks);
}
long threeStandardDeviationHigh;
long min;
if (ticksCollection.Count == 0)
min = 0;
else
min = ticksCollection.Min();
if (ticksCollection.Count < minimum)
threeStandardDeviationHigh = long.MaxValue;
else
threeStandardDeviationHigh = GetThreeStandardDeviationHigh(ref ticksCollection, min);
result = new TimeSpan(threeStandardDeviationHigh - min);
return result;
}
internal static (int, List<DateTime>, List<Models.Item>) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i)
{
List<Models.Item> results = [];
int j = i;
long? ticks;
Models.Item item;
TimeSpan timeSpan;
Models.Item nextItem;
DateTime? minimumDateTime;
DateTime? nextMinimumDateTime;
List<DateTime> dateTimes = [];
for (; j < container.Items.Count; j++)
{
ticks = null;
item = container.Items[j];
if (item.Property is null)
continue;
minimumDateTime = GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
for (int k = j + 1; k < container.Items.Count; k++)
{
nextItem = container.Items[k];
if (nextItem.Property is null)
continue;
nextMinimumDateTime = GetMinimumDateTime(nextItem.Property);
if (nextMinimumDateTime is null)
continue;
ticks = nextMinimumDateTime.Value.Ticks;
break;
}
results.Add(item);
dateTimes.Add(minimumDateTime.Value);
if (ticks.HasValue)
{
timeSpan = new(ticks.Value - minimumDateTime.Value.Ticks);
if (timeSpan > threeStandardDeviationHigh)
break;
}
}
return new(j, dateTimes, results);
}
internal static bool Any(Models.Container[] containers)
{
bool result = false;
foreach (Models.Container container in containers)
{
if (container.Items.Count == 0)
continue;
if ((from l in container.Items where l.Any() select true).Any())
{
result = true;
break;
}
}
return result;
}
} }

View File

@ -33,6 +33,7 @@ internal abstract partial class XDirectory
internal static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) internal static ReadOnlyCollection<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage)
{ {
List<string[]> results = []; List<string[]> results = [];
string[] files;
if (!fileSearchFilter.Contains('*')) if (!fileSearchFilter.Contains('*'))
fileSearchFilter = string.Concat('*', fileSearchFilter); fileSearchFilter = string.Concat('*', fileSearchFilter);
if (!directorySearchFilter.Contains('*')) if (!directorySearchFilter.Contains('*'))
@ -44,7 +45,12 @@ internal abstract partial class XDirectory
foreach (string innerDirectory in directories) foreach (string innerDirectory in directories)
{ {
try try
{ results.Add(Directory.GetFiles(innerDirectory, fileSearchFilter, SearchOption.AllDirectories)); } {
files = Directory.GetFiles(innerDirectory, fileSearchFilter, SearchOption.AllDirectories);
if (files.Length == 0)
continue;
results.Add(files);
}
catch (UnauthorizedAccessException) catch (UnauthorizedAccessException)
{ continue; } { continue; }
} }
@ -62,77 +68,6 @@ internal abstract partial class XDirectory
return results; return results;
} }
internal static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<string[]> filesCollection)
{
Dictionary<string, List<string>> results = [];
string fileName;
List<string>? collection;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
fileName = Path.GetFileName(file);
if (!results.TryGetValue(fileName, out collection))
{
results.Add(fileName, []);
if (!results.TryGetValue(fileName, out collection))
throw new Exception();
}
collection.Add(file);
}
}
return results;
}
internal static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
{
Dictionary<string, List<string>> results = [];
List<string>? collection;
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{
foreach (FilePath filePath in filePaths)
{
if (!results.TryGetValue(filePath.Name, out collection))
{
results.Add(filePath.Name, []);
if (!results.TryGetValue(filePath.Name, out collection))
throw new Exception();
}
collection.Add(filePath.FullName);
}
}
return results;
}
internal static int LookForAbandoned(ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension)
{
string fileName;
string fileNameWith;
List<string>? collection;
string fileNameUpperExtension;
int length = extension.Length;
List<string> renameCollection = [];
foreach (string[] files in jsonFilesCollection)
{
foreach (string file in files)
{
fileNameWith = Path.GetFileName(file);
if (fileNameWith.Length < length || !fileNameWith.EndsWith(extension))
throw new Exception();
fileName = fileNameWith[..^length];
if (!fileNamesToFiles.TryGetValue(fileName, out collection))
{
fileNameUpperExtension = string.Concat(Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName).ToUpper());
if (fileName == fileNameUpperExtension || !fileNamesToFiles.TryGetValue(fileNameUpperExtension, out collection))
renameCollection.Add(file);
}
}
}
if (renameCollection.Count > 0)
IDirectory.MoveFiles(renameCollection, "{}", "{abd}");
return renameCollection.Count;
}
private static bool GetIsNotUniqueAndNeedsReview(string file, List<string> collection) private static bool GetIsNotUniqueAndNeedsReview(string file, List<string> collection)
{ {
bool result = false; bool result = false;
@ -175,13 +110,15 @@ internal abstract partial class XDirectory
return result; return result;
} }
internal static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) internal static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles)
{ {
List<FilePair> results = []; List<FilePair> results = [];
string? match; string? match;
FilePair filePair;
bool uniqueFileName; bool uniqueFileName;
List<string>? collection; List<string>? collection;
bool? isNotUniqueAndNeedsReview; bool? isNotUniqueAndNeedsReview;
string fileNameWithoutExtensionMinusOne;
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection) foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{ {
foreach (FilePath filePath in filePaths) foreach (FilePath filePath in filePaths)
@ -189,25 +126,43 @@ internal abstract partial class XDirectory
isNotUniqueAndNeedsReview = null; isNotUniqueAndNeedsReview = null;
if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered)) if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered))
continue; continue;
if (!fileNamesToFiles.TryGetValue(filePath.Name, out collection)) fileNameWithoutExtensionMinusOne = filePath.NameWithoutExtension[..^1];
if (!fileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
throw new Exception(); throw new Exception();
uniqueFileName = collection.Count == 1; uniqueFileName = collection.Count == 1;
if (!uniqueFileName) if (!uniqueFileName)
isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath.FullName, collection); isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath.FullName, collection);
if (!compareFileNamesToFiles.TryGetValue(string.Concat(filePath.Name, extension), out collection)) if (!compareFileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, [], null)); filePair = new(Path: filePath.FullName,
IsUnique: uniqueFileName,
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
Collection: [],
Match: null);
else else
{ {
if (collection.Count == 0) if (collection.Count == 0)
results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, null)); filePair = new(Path: filePath.FullName,
IsUnique: uniqueFileName,
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
Collection: collection,
Match: null);
else if (uniqueFileName && collection.Count == 1) else if (uniqueFileName && collection.Count == 1)
results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, collection.First())); filePair = new(Path: filePath.FullName,
IsUnique: uniqueFileName,
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
Collection: collection,
Match: collection.First());
else else
{ {
match = GetMatch(filePath.FullName, collection); match = GetMatch(filePath.FullName, collection);
results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, match)); filePair = new(Path: filePath.FullName,
IsUnique: uniqueFileName,
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
Collection: collection,
Match: match);
} }
} }
results.Add(filePair);
} }
} }
return results; return results;
@ -458,6 +413,7 @@ internal abstract partial class XDirectory
{ {
List<string> results = []; List<string> results = [];
FileInfo fileInfo; FileInfo fileInfo;
List<string> distinctExtensions = [];
foreach ((FilePath filePath, string to) in toDoCollection) foreach ((FilePath filePath, string to) in toDoCollection)
{ {
tick?.Invoke(); tick?.Invoke();
@ -471,6 +427,8 @@ internal abstract partial class XDirectory
results.Add(filePath.NameWithoutExtension); results.Add(filePath.NameWithoutExtension);
try try
{ {
if (!distinctExtensions.Contains(filePath.ExtensionLowered))
distinctExtensions.Add(filePath.ExtensionLowered);
if (move || moveBack) if (move || moveBack)
File.Move(filePath.FullName, to); File.Move(filePath.FullName, to);
else else

View File

@ -292,6 +292,9 @@ internal abstract class XPath
return result; return result;
} }
internal static byte GetEnum(FilePath filePath) =>
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileName) internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileName)
{ {
CombinedEnumAndIndex result; CombinedEnumAndIndex result;