281 lines
15 KiB
C#
281 lines
15 KiB
C#
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 : new(results);
|
|
}
|
|
|
|
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 ParallelFor(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int rootDirectoryLength, 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));
|
|
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);
|
|
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
|
sourceDirectoryFileHolder = IFileHolder.Get(Path.Combine(aPropertySingletonDirectory, directoryName, $"{fileName}{extension}"));
|
|
}
|
|
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 = new(filePath, sourceDirectoryFileHolder, relativePath, 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, 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, filePairs[i], results));
|
|
return results;
|
|
}
|
|
|
|
private static (int, Models.Container[]) GetContainers(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, 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, 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, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
|
{
|
|
Models.Container[] results;
|
|
const string directorySearchFilter = "*";
|
|
(_, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filePathsCollection, directorySearchFilter);
|
|
return new(results);
|
|
}
|
|
|
|
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, 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, 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 new(results);
|
|
}
|
|
|
|
} |