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)
throw new Exception("Copy keyValuePairs-####.json file");
(int j, int f, int t, Shared.Models.Container[] containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
(int j, int f, int t, Shared.Models.Container[] containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(propertyConfiguration, propertyLogic);
if (propertyLogic.ExceptionsDirectories.Any())
throw new Exception();
if (propertyConfiguration.PopulatePropertyId && Shared.Models.Stateless.Methods.IProperty.Any(containers))

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.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)
{

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

View File

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

View File

@ -107,9 +107,9 @@ public partial class DragDropSearch : Form
private void LoadData()
{
Container[] containers;
Container.Models.Container[] containers;
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);
foreach (Item item in collection)
{

View File

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

View File

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

View File

@ -300,6 +300,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string message;
MapLogic? mapLogic;
A_Property propertyLogic;
IDlibDotNet dlibDotNet = this;
string eDistanceContentDirectory;
string? a2PeopleContentDirectory;
string aResultsFullGroupDirectory;
@ -314,15 +315,17 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
bool configurationOutputResolutionsHas = false;
ReadOnlyDictionary<long, List<int>> personKeyToIds;
ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers = null;
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs = null;
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = null;
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks);
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks);
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);
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)
mapLogic = null;
else
@ -335,7 +338,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
if (!runToDoCollectionFirst)
break;
(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;
}
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());
_Configuration.PropertyConfiguration.ChangeRootDirectory(argZero);
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false);
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))
continue;
(cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution);
(cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: true);
break;
@ -375,20 +379,17 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
}
if (filesCollectionRootDirectory is null || filePathsCollection is null)
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();
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
_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();
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
DeleteContinueFiles(personContainers);
if (!runToDoCollectionFirst)
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory, options);
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, count, readOnlyContainers, propertyLogic, mapLogic);
ReadOnlyCollection<Item> distinctValidImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, count, metadata, readOnlyContainers, propertyLogic, mapLogic);
ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
if (_Configuration.LookForAbandoned)
{
string dResultsFullGroupDirectory;
@ -396,7 +397,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
foreach (string outputResolution in _Configuration.OutputResolutions)
{
_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);
_ProgressBar.Dispose();
}
@ -437,7 +438,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory;
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(bResultsFullGroupDirectory, _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;
}
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 notMapped;
string message;
bool exceptions;
int totalSeconds;
Container container;
int totalNotMapped = 0;
IDlibDotNet dlibDotNet = this;
bool outputResolutionHasNumber;
bool anyNullOrNoIsUniqueFileName;
string cResultsFullGroupDirectory;
string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory;
Container.Models.Container container;
ReadOnlyCollection<Item> filteredItems;
int containersLength = readOnlyContainers.Count;
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism;
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));
B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
foreach (string outputResolution in _Configuration.OutputResolutions)
{
total = 0;
outputResolutionHasNumber = outputResolution.Any(char.IsNumber);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
_Faces.Update(dResultsFullGroupDirectory);
_Resize.Update(cResultsFullGroupDirectory);
_FaceParts.Update(d2ResultsFullGroupDirectory);
@ -587,13 +587,13 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
continue;
if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
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)
continue;
sourceDirectoryChanges.Clear();
anyNullOrNoIsUniqueFileName = filteredItems.Any(l => !l.IsUniqueFileName);
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);
if (outputResolutionHasNumber)
_Resize.SetAngleBracketCollection(cResultsFullGroupDirectory, container.SourceDirectory);
@ -629,7 +629,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
total += container.Items.Count;
}
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 };
using ProgressBar progressBar = new(1, message, options);
progressBar.Tick();
@ -678,14 +678,24 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
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)
{
Dictionary<int, Identifier> results = [];
string json;
string paddedId;
FilePath? filePath;
Identifier identifier;
string[] directoryNames;
List<Identifier> identifiers = [];
string rootDirectory = propertyConfiguration.RootDirectory.Replace('\\', '/');
string bMetadataCollectionDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultCollection);
if (!Directory.Exists(bMetadataCollectionDirectory))
@ -700,24 +710,31 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
break;
filePath = null;
}
if (filePath?.Id is null)
if (filePath is null)
{
filePath = keyValuePair.Value[0];
if (filePath.Id is null)
continue;
directoryNames = keyValuePair.Value.Select(l => l.DirectoryFullPath.Replace('\\', '/')).ToArray();
paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, index: null);
identifier = new(directoryNames, filePath.ExtensionLowered, filePath.HasDateTimeOriginal, filePath.Id.Value, filePath.Length, paddedId, filePath.LastWriteTicks);
identifier = GetIdentifier(propertyConfiguration, filePath, keyValuePair);
identifiers.Add(identifier);
continue;
}
else if (filePath.Id is null)
continue;
identifier = GetIdentifier(propertyConfiguration, filePath, keyValuePair);
identifiers.Add(identifier);
results.Add(keyValuePair.Key, identifier);
}
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);
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);
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, ReadOnlyCollection<FilePath>> keyValuePairs = FilePath.GetKeyValuePairs(filePathsCollection);
if (keyValuePairs.Count == 0)
results = new(new Dictionary<int, Identifier>());
else
@ -730,7 +747,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
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 = [];
int count = 0;
@ -743,14 +760,14 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
DateTime[] containerDateTimes;
MappingFromItem mappingFromItem;
ReadOnlyCollection<Item> filteredItems;
foreach (Container container in readOnlyContainers)
foreach (Container.Models.Container container in readOnlyContainers)
{
if (container.Items.Count == 0)
continue;
filteredItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(propertyConfiguration, container);
filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(propertyConfiguration, container);
if (filteredItems.Count == 0)
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));
isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
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)
{
List<SaveContainer> results;
IDlibDotNet dlibDotNet = this;
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);
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)
@ -968,9 +986,10 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
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 d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
string d2FacePartsContentCollectionDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContentCollection);
@ -1141,7 +1160,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string d2ResultsFullGroupDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container,
Container.Models.Container container,
Item item,
DateTime[] containerDateTimes,
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 (!item.FilePath.DirectoryFullPath.Contains("Results") || !item.FilePath.DirectoryFullPath.Contains("Resize"))
throw new NotSupportedException($"Rename File! <{item.FilePath.FileNameFirstSegment}>");
else
{
if (item.FilePath.DirectoryFullPath.Contains("Results") && item.FilePath.DirectoryFullPath.Contains("Resize"))
File.Delete(resizedFileHolder.FullName);
}
else
throw new NotSupportedException($"Rename File! <{item.FilePath.FileNameFirstSegment}>");
}
}
if (property is null || item.Property is null)
@ -1297,14 +1314,14 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string d2ResultsFullGroupDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container,
Container.Models.Container container,
ReadOnlyCollection<Item> filteredItems,
string message)
{
int result = 0;
int exceptionsCount = 0;
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 };
string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory));
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);
}
private (string, string) GetResultsFullGroupDirectories()
(string, string) IDlibDotNet.GetResultsFullGroupDirectories()
{
string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration,
@ -1359,7 +1376,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
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(
_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)
{
ProgressBar progressBar;
IDlibDotNet dlibDotNet = this;
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]);
ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useCeilingAverage: false);
int count = filePathsCollection.Select(l => l.Count).Sum();

View File

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

View File

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

View File

@ -460,7 +460,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
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;
const int zero = 0;
@ -537,22 +537,22 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
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;
string? directory;
string? debugDirectory;
string? personDirectory;
if (personKey is null || string.IsNullOrEmpty(displayDirectoryName))
if (locationContainer.PersonKey is null || string.IsNullOrEmpty(displayDirectoryName))
{
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}");
}
else
{
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);
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
personDirectory = Path.Combine(directory, displayDirectoryName, "lnk");
@ -880,7 +880,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
displayDirectoryName = GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer, personKeyToPersonContainer);
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);
record = Get(_Configuration, by, locationContainer.PersonKey, displayDirectoryName, segmentB);
record = Get(_Configuration, by, locationContainer, displayDirectoryName, segmentB);
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
continue;
directory = record.Directory;
@ -1406,14 +1406,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
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)
throw new NullReferenceException(nameof(_Configuration));
WindowsShortcut windowsShortcut;
List<(string, DateTime[])> directoriesAndDateTimes;
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);
string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
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) =>
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? directoryName;
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
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);
dlibDotNet.Tick();
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);

View File

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

View File

@ -13,17 +13,17 @@ namespace View_by_Distance.Map.Models.Stateless;
internal abstract class MapLogic
{
internal record Duplicate(long PersonKey,
int Id,
FilePath FilePath,
float? Percent);
internal record MappedFile(long PersonKey,
string PersonKeyFormatted,
string? PersonDisplayDirectoryName,
int? DirectoryNumber,
FilePath FilePath);
internal record Duplicate(long PersonKey,
int Id,
FilePath FilePath,
float? Percent);
internal record PersonKeyFormattedIdThenWholePercentages(string PersonKeyFormatted,
string? PersonDisplayDirectoryName,
bool? IsDefault,
@ -188,6 +188,7 @@ internal abstract class MapLogic
private static List<MappedFile> GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, ReadOnlyCollection<PersonContainer> personContainers)
{
List<MappedFile> results = [];
MappedFile mappedFile;
string personKeyFormatted;
List<string> distinct = [];
foreach (PersonContainer personContainer in personContainers)
@ -202,7 +203,12 @@ internal abstract class MapLogic
continue;
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
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;
@ -462,6 +468,7 @@ internal abstract class MapLogic
string checkFile;
FilePath filePath;
FileHolder fileHolder;
MappedFile mappedFile;
List<string> distinct = [];
PersonBirthday? personBirthday;
PersonContainer? personContainer;
@ -481,7 +488,12 @@ internal abstract class MapLogic
personDisplayDirectoryName = record.PersonDisplayDirectoryName;
else
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--)
{
@ -501,7 +513,11 @@ internal abstract class MapLogic
File.Move(filePath.FullName, checkFile);
fileHolder = IFileHolder.Get(checkFile);
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;
}
@ -791,6 +807,7 @@ internal abstract class MapLogic
int? wholePercentages;
List<int> wholePercentagesCollection;
Dictionary<int, List<int>> idToWholePercentagesCollection = [];
PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages;
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)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
@ -808,7 +825,14 @@ internal abstract class MapLogic
wholePercentagesCollection = idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value];
wholePercentagesCollection.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();
}

View File

@ -34,10 +34,10 @@
</ItemGroup>
<ItemGroup>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup>
</Project>

View File

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

View File

@ -1,3 +1,4 @@
using System.Globalization;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
@ -47,4 +48,23 @@ internal static class Base
return result;
}
#pragma warning restore CA1416
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
{
DateTime? result;
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
result = dateTime;
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
result = dateTime;
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
result = dateTime;
else
result = null;
return result;
}
#pragma warning disable CA1416
}

View File

@ -64,4 +64,14 @@ public interface IMetadata
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
string TestStatic_DateTimeFormat() =>
DateTimeFormat();
static string DateTimeFormat() =>
"yyyy:MM:dd HH:mm:ss";
DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
GetDateTime(dateTimeFormat, value);
static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
Base.GetDateTime(dateTimeFormat, value);
}

View File

@ -239,7 +239,7 @@ public class A_Property
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 = [];
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;
string message;
int totalSeconds;
Container container;
bool anyNullOrNoIsUniqueFileName;
List<Exception> exceptions = [];
Container.Models.Container container;
int containersLength = containers.Length;
const string outputResolution = "Original";
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) =>
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);
}
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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Container\Container.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -315,7 +315,7 @@ public class C_Resize
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)
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;
string json;

View File

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

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) =>
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();
(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) =>
Id.GetPaddedId(propertyConfiguration, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
string TestStatic_GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
GetIgnoreFullPath(filePath, fileHolder);
static string GetIgnoreFullPath(FilePath filePath, Models.FileHolder fileHolder) =>
fileHolder.DirectoryFullPath is null ?
throw new NotSupportedException() :
filePath.Id > -1 ?
fileHolder.NameWithoutExtension[^1] == '9' ?
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}8{fileHolder.ExtensionLowered}") :
throw new NotSupportedException("High") :
fileHolder.NameWithoutExtension[^1] == '1' ?
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}2{fileHolder.ExtensionLowered}") :
throw new NotSupportedException("Low");
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
NameWithoutExtensionIsIntelligentIdFormat(propertyConfiguration, fileNameFirstSegment);
static bool NameWithoutExtensionIsIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameFirstSegment) =>
fileNameFirstSegment.Length - 1 == propertyConfiguration.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
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) =>
NameWithoutExtensionIsPaddedIntelligentIdFormat(propertyConfiguration, sortOrderOnlyLengthIndex, fileNameFirstSegment);
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(Properties.IPropertyConfiguration propertyConfiguration, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
fileNameFirstSegment.Length == propertyConfiguration.IntMinValueLength + sortOrderOnlyLengthIndex + 1
&& fileNameFirstSegment[^1] is '1' or '2' or '8' or '9'
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9'
&& fileNameFirstSegment.All(char.IsNumber);
bool TestStatic_NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, Models.FileHolder fileHolder) =>
@ -58,4 +45,19 @@ public interface IId
static int GetDeterministicHashCode(byte[] 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) =>
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) =>
Property.GetDiffRootDirectory(diffPropertyDirectory);
bool TestStatic_Any(Models.Container[] propertyHolderCollections) =>
Any(propertyHolderCollections);
static bool Any(Models.Container[] propertyHolderCollections) =>
Property.Any(propertyHolderCollections);
(bool?, string[]) TestStatic_IsWrongYear(string[] segments, string year) =>
IsWrongYear(segments, year);
static (bool?, string[]) IsWrongYear(string[] segments, string year) =>
@ -43,21 +38,6 @@ public interface IProperty
static List<DateTime> GetDateTimes(Models.Property property) =>
Property.GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeFromName, property.DateTimeOriginal, property.GPSDateStamp);
double TestStatic_GetStandardDeviation(List<long> values, double average) =>
GetStandardDeviation(values, average);
static double GetStandardDeviation(List<long> values, double average) =>
Property.GetStandardDeviation(values, average);
TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
GetThreeStandardDeviationHigh(minimum, container);
static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) =>
Property.GetThreeStandardDeviationHigh(minimum, container);
(int, List<DateTime>, List<Models.Item>) TestStatic_Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Get(container, threeStandardDeviationHigh, i);
static (int, List<DateTime>, List<Models.Item>) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) =>
Property.Get(container, threeStandardDeviationHigh, i);
List<DateTime> TestStatic_GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>
GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, gpsDateStamp);
static List<DateTime> GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) =>

View File

@ -28,13 +28,22 @@ internal abstract class Id
_ = results.Append(intelligentId[i]);
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
result = int.Parse(results.ToString());
if (intelligentId[^1] is '1' or '2')
if (intelligentId[^1] is '1' or '2' or '3')
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();
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)
{
string result;
@ -48,12 +57,12 @@ internal abstract class Id
List<char> resultAllInOneSubdirectoryChars = [];
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');
}
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');
}
for (int i = value.Length - propertyConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)

View File

@ -171,112 +171,4 @@ internal abstract class Property
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)
{
List<string[]> results = [];
string[] files;
if (!fileSearchFilter.Contains('*'))
fileSearchFilter = string.Concat('*', fileSearchFilter);
if (!directorySearchFilter.Contains('*'))
@ -44,7 +45,12 @@ internal abstract partial class XDirectory
foreach (string innerDirectory in directories)
{
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)
{ continue; }
}
@ -62,77 +68,6 @@ internal abstract partial class XDirectory
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)
{
bool result = false;
@ -175,13 +110,15 @@ internal abstract partial class XDirectory
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 = [];
string? match;
FilePair filePair;
bool uniqueFileName;
List<string>? collection;
bool? isNotUniqueAndNeedsReview;
string fileNameWithoutExtensionMinusOne;
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
{
foreach (FilePath filePath in filePaths)
@ -189,25 +126,43 @@ internal abstract partial class XDirectory
isNotUniqueAndNeedsReview = null;
if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered))
continue;
if (!fileNamesToFiles.TryGetValue(filePath.Name, out collection))
fileNameWithoutExtensionMinusOne = filePath.NameWithoutExtension[..^1];
if (!fileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
throw new Exception();
uniqueFileName = collection.Count == 1;
if (!uniqueFileName)
isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath.FullName, collection);
if (!compareFileNamesToFiles.TryGetValue(string.Concat(filePath.Name, extension), out collection))
results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, [], null));
if (!compareFileNamesToFiles.TryGetValue(fileNameWithoutExtensionMinusOne, out collection))
filePair = new(Path: filePath.FullName,
IsUnique: uniqueFileName,
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
Collection: [],
Match: null);
else
{
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)
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
{
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;
@ -458,6 +413,7 @@ internal abstract partial class XDirectory
{
List<string> results = [];
FileInfo fileInfo;
List<string> distinctExtensions = [];
foreach ((FilePath filePath, string to) in toDoCollection)
{
tick?.Invoke();
@ -471,6 +427,8 @@ internal abstract partial class XDirectory
results.Add(filePath.NameWithoutExtension);
try
{
if (!distinctExtensions.Contains(filePath.ExtensionLowered))
distinctExtensions.Add(filePath.ExtensionLowered);
if (move || moveBack)
File.Move(filePath.FullName, to);
else

View File

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