Files
.config
.vscode
Compare
Date-Group
Delete-By-Distinct
Delete-By-Relative
Distance
Drag-Drop-Explorer
Drag-Drop-Search
Duplicate-Search
Face
FaceParts
FaceRecognitionDotNet
Instance
Map
Metadata
Move-By-Id
Person
PhotoPrism
PrepareForOld
Property
Property-Compare
Rename
Resize
Shared
.vscode
Models
Methods
Properties
Stateless
Methods
%ClassName%.cs .ai
Age.cs
Container.cs
DistanceHolder.cs
Face.cs
FaceDistance.cs
FaceDistanceContainer.cs
FaceFileSystem.cs
FacePoint.cs
FileHolder.cs
FileSystem.cs
I%ClassName%.cs .ai
IAge.cs
IBackgroundPage.cs
IContainer.cs
IDirectory.cs
IDirectoryFileSystem.cs
IDistanceHolder.cs
IFace.cs
IFaceDistance.cs
IFaceDistanceContainer.cs
IFaceFileSystem.cs
IFacePoint.cs
IFileHolder.cs
IFileSystem.cs
IIndex.cs
IItem.cs
ILocation.cs
IMapping.cs
IMappingFromItem.cs
IMetadataFile.cs
IMetadataFileCollection.cs
IMetadataFileId.cs
IMethodName.cs
IOutputResolution.cs
IPath.cs
IPerson.cs
IPersonAddress.cs
IPersonAddressCity.cs
IPersonAddressState.cs
IPersonAddressStreet.cs
IPersonAddressZipCode.cs
IPersonBirthday.cs
IPersonComment.cs
IPersonContainer.cs
IPersonEmail.cs
IPersonId.cs
IPersonName.cs
IPersonNameAlias.cs
IPersonNameFirst.cs
IPersonNameLast.cs
IPersonNameMiddle.cs
IPersonNumber.cs
IPersonURL.cs
IProperty.cs
IRelativePaths.cs
ISorting.cs
ISortingContainer.cs
IStorage.cs
IWorkingDirectory.cs
ImageHelper.cs
Index.cs
Item.cs
Location.cs
Mapping.cs
MetadataFile.cs
MetadataFileCollection.cs
MetadataFileId.cs
OutputResolution.cs
Person.cs
PersonAddress.cs
PersonAddressCity.cs
PersonAddressState.cs
PersonAddressStreet.cs
PersonAddressZipCode.cs
PersonBirthday.cs
PersonComment.cs
PersonContainer.cs
PersonEmail.cs
PersonId.cs
PersonName.cs
PersonNameAlias.cs
PersonNameFirst.cs
PersonNameLast.cs
PersonNameMiddle.cs
PersonNumber.cs
PersonURL.cs
Property.cs
RelativePaths.cs
Sorting.cs
SortingContainer.cs
Storage.cs
WorkingDirectory.cs
XDirectory.cs
XPath.cs
FacePart.cs
IExif.cs
ILocation.cs
IMapLogic.cs
ImageFormat.cs
Mode.cs
Model.cs
PredictorModel.cs
%ClassName%.cs .ai
Console.cs
Container.cs
DatabaseFile.cs
DirectoryFileSystem.cs
DistanceHolder.cs
Face.cs
FaceDistance.cs
FaceDistanceContainer.cs
FaceEncoding.cs
FaceFileSystem.cs
FacePoint.cs
FileHolder.cs
FilePair.cs
FileSystem.cs
Item.cs
Location.cs
LocationContainer.cs
Mapping.cs
Marker.cs
MatchNginx.cs
MetadataFile.cs
MetadataFileCollection.cs
MetadataFileId.cs
OutputResolution.cs
Person.cs
PersonAddress.cs
PersonAddressCity.cs
PersonAddressState.cs
PersonAddressStreet.cs
PersonAddressZipCode.cs
PersonBirthday.cs
PersonComment.cs
PersonContainer.cs
PersonEmail.cs
PersonId.cs
PersonImport.cs
PersonName.cs
PersonNameAlias.cs
PersonNameFirst.cs
PersonNameLast.cs
PersonNameMiddle.cs
PersonNumber.cs
PersonURL.cs
Property.cs
RelativeLocation.cs
RelativePaths.cs
SaveContainer.cs
SaveShortcutsForOutputResolutions.cs
Sorting.cs
SortingContainer.cs
Storage.cs
XPath.cs
Phares
Sample-Data
View-by-Distance.Shared.csproj
Tests
TestsWithFaceRecognitionDotNet
.editorconfig
.gitattributes
.gitignore
.txt
View-by-Distance-MKLink-Console.sln
package.json
view-by-distance-mklink-con…/Shared/Models/Stateless/Methods/Container.cs
2023-02-25 23:01:08 -07:00

214 lines
11 KiB
C#

using System.Text.Json;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Container
{
private record FilePair(string Path, string? Directory, bool IsUnique, List<string> Collection, Models.Item Item) { }
internal static DateTime[] GetContainerDateTimes(Models.Item[] filteredItems)
{
DateTime[] results;
DateTime? containerMinimumDateTime;
DateTime? containerMaximumDateTime;
containerMinimumDateTime = (from l in filteredItems select l.ImageFileHolder.LastWriteTime).Min();
if (containerMinimumDateTime is null)
containerMaximumDateTime = null;
else
containerMaximumDateTime = (from l in filteredItems select l.ImageFileHolder.LastWriteTime).Max();
if (containerMinimumDateTime is null || containerMaximumDateTime is null)
results = Array.Empty<DateTime>();
else
results = new DateTime[] { containerMinimumDateTime.Value, containerMaximumDateTime.Value };
return results;
}
internal static Models.Item[] GetFilterItems(Properties.IPropertyConfiguration propertyConfiguration, Models.Container container)
{
List<Models.Item> results = new();
foreach (Models.Item item in container.Items)
{
if (item.ImageFileHolder is not null
&& item.IsValidImageFormatExtension
&& !propertyConfiguration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered))
results.Add(item);
}
return results.ToArray();
}
internal static bool IsIgnoreRelativePath(Properties.IPropertyConfiguration propertyConfiguration, string[] ignoreRelativePaths, string directory)
{
bool result = false;
string? checkDirectory = Path.GetFullPath(directory);
for (int i = 0; i < int.MaxValue; i++)
{
if (ignoreRelativePaths.Contains(Path.GetFileName(checkDirectory)))
{
result = true;
break;
}
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == propertyConfiguration.RootDirectory)
break;
}
return result;
}
internal static Models.Container[] SortContainers(Properties.IPropertyConfiguration propertyConfiguration, string[] ignoreRelativePaths, bool argZeroIsConfigurationRootDirectory, string argZero, Models.Container[] containers)
{
List<Models.Container> results = new();
bool isIgnoreRelativePath;
for (int i = 1; i < 3; i++)
{
foreach (Models.Container container in containers)
{
if (!container.Items.Any())
continue;
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue;
isIgnoreRelativePath = ignoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && IsIgnoreRelativePath(propertyConfiguration, ignoreRelativePaths, container.SourceDirectory);
if (i == 1 && isIgnoreRelativePath)
continue;
if (i == 2 && !isIgnoreRelativePath)
continue;
results.Add(container);
}
}
return results.ToArray();
}
internal static List<Models.FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, List<string[]> filesCollection)
{
int renamed;
List<Models.FilePair>? filePairs = null;
List<string[]>? jsonFilesCollection = null;
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = IDirectory.GetFilesKeyValuePairs(filesCollection);
for (int i = 0; i < int.MaxValue; i++)
{
renamed = 0;
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension);
compareFileNamesToFiles = IDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
renamed += IDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
filePairs = IDirectory.GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
renamed += IDirectory.MaybeMove(propertyConfiguration.RootDirectory, propertyConfiguration.ResultAllInOne, filePairs, aPropertySingletonDirectory, extension);
if (renamed == 0)
{
_ = IPath.DeleteEmptyDirectories(aPropertySingletonDirectory);
break;
}
}
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? property;
if (filePair.Match is null)
property = null;
else
{
string json = File.ReadAllText(filePair.Match);
if (string.IsNullOrEmpty(json))
property = null;
else
property = JsonSerializer.Deserialize<Models.Property>(json);
}
return property;
}
private static void ParallelFor(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int length, Models.FilePair filePair, List<FilePair> results)
{
char directory;
string fileName;
bool abandoned = false;
Models.FileHolder sourceDirectoryFileHolder;
Models.Property? property = GetProperty(filePair);
Models.FileHolder imageFileInfo = new(filePair.Path);
bool? fileSizeChanged = property is not null ? property.FileSize != imageFileInfo.Length : null;
string relativePath = IPath.GetRelativePath(filePair.Path, length, forceExtensionToLower: true);
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(imageFileInfo.ExtensionLowered);
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime != imageFileInfo.LastWriteTime : null;
if (filePair.Match is not null)
sourceDirectoryFileHolder = new(filePair.Match);
else if (!filePair.IsUnique)
sourceDirectoryFileHolder = new(Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath, extension)));
else
{
fileName = Path.GetFileName(filePair.Path);
directory = IDirectory.GetDirectory(fileName);
sourceDirectoryFileHolder = new(Path.Combine(aPropertySingletonDirectory, propertyConfiguration.ResultAllInOne, directory.ToString(), $"{fileName}{extension}"));
}
if (imageFileInfo.LastWriteTime is not null && sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && imageFileInfo.LastWriteTime.Value != sourceDirectoryFileHolder.CreationTime.Value)
{
File.SetCreationTime(sourceDirectoryFileHolder.FullName, imageFileInfo.LastWriteTime.Value);
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
}
Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
lock (results)
results.Add(new(filePair.Path, imageFileInfo.DirectoryName, filePair.IsUnique, filePair.Collection, item));
}
private static List<FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, List<Models.FilePair> filePairs)
{
List<FilePair> results = new();
int length = propertyConfiguration.RootDirectory.Length;
int maxDegreeOfParallelism = Environment.ProcessorCount;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, length, filePairs[i], results));
return results;
}
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory)
{
List<Models.Container> results = new();
string? directory;
List<Models.Item>? items;
Models.Container container;
const string extension = ".json";
const string fileSearchFilter = "*";
const string directorySearchFilter = "*";
Dictionary<string, List<Models.Item>> directoryToItems = new();
List<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter);
foreach (string[] files in filesCollection)
{
if (!files.Any())
continue;
directory = Path.GetDirectoryName(files.First());
if (directory is null)
continue;
if (!directoryToItems.TryGetValue(directory, out items))
{
directoryToItems.Add(directory, new());
if (!directoryToItems.TryGetValue(directory, out items))
throw new Exception();
}
}
List<Models.FilePair> filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
List<FilePair> collection = GetFilePairs(propertyConfiguration, aPropertySingletonDirectory, extension, filePairs);
foreach (FilePair filePair in collection)
{
if (filePair.Directory is null)
continue;
if (!directoryToItems.TryGetValue(filePair.Directory, out items))
{
directoryToItems.Add(filePair.Directory, new());
if (!directoryToItems.TryGetValue(filePair.Directory, out items))
throw new Exception();
}
items.Add(filePair.Item);
}
foreach (KeyValuePair<string, List<Models.Item>> keyValuePair in directoryToItems)
{
if (!keyValuePair.Value.Any())
continue;
container = new(keyValuePair.Key, keyValuePair.Value);
results.Add(container);
}
return (collection.Count, results.ToArray());
}
}