212 lines
11 KiB
C#
212 lines
11 KiB
C#
using ShellProgressBar;
|
|
using System.Collections.ObjectModel;
|
|
using System.Drawing;
|
|
using System.Text.Json;
|
|
using View_by_Distance.Shared.Models;
|
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
|
using static View_by_Distance.Map.Models.Stateless.MapLogic;
|
|
|
|
namespace View_by_Distance.Map.Models.Stateless;
|
|
|
|
internal abstract class FaceFileLogic
|
|
{
|
|
|
|
private static void MappedParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyDictionary<int, List<(string, int)>> skipCollection, List<LocationContainer> locationContainers, MappedFile mappedFile)
|
|
{
|
|
int? id;
|
|
string checkFile;
|
|
DateOnly dateOnly;
|
|
FilePath filePath;
|
|
string[] fileMatches;
|
|
FileHolder fileHolder;
|
|
int? wholePercentages;
|
|
const string lnk = ".lnk";
|
|
ExifDirectory? exifDirectory;
|
|
string personDisplayDirectoryName;
|
|
const bool fromDistanceContent = true;
|
|
List<(string File, int WholePercentages)>? wholePercentagesCollection;
|
|
if (!mappedFile.FilePath.Name.EndsWith(lnk))
|
|
{
|
|
if (mappedFile.FilePath.Id is null)
|
|
return;
|
|
id = mappedFile.FilePath.Id;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, mappedFile.FilePath);
|
|
}
|
|
else
|
|
{
|
|
fileHolder = IFileHolder.Get(mappedFile.FilePath.FullName[..^4]);
|
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
|
if (filePath.Id is null)
|
|
return;
|
|
id = filePath.Id;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
|
}
|
|
if (wholePercentages is null)
|
|
return;
|
|
if (configuration.LinkedAlpha is null && string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory) && skipCollection.TryGetValue(id.Value, out wholePercentagesCollection))
|
|
{
|
|
fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray();
|
|
foreach (string fileMatch in fileMatches)
|
|
{
|
|
if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch))
|
|
continue;
|
|
checkFile = $"{fileMatch}.dup";
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(fileMatch, checkFile);
|
|
continue;
|
|
}
|
|
}
|
|
dateOnly = DateOnly.FromDateTime(new DateTime(mappedFile.FilePath.CreationTicks));
|
|
if (mappedFile.FilePath.Name.EndsWith(lnk) || !File.Exists(mappedFile.FilePath.FullName))
|
|
exifDirectory = null;
|
|
else
|
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
|
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
|
lock (locationContainers)
|
|
locationContainers.Add(new(dateOnly,
|
|
exifDirectory,
|
|
mappedFile.DirectoryNumber,
|
|
personDisplayDirectoryName,
|
|
null,
|
|
null,
|
|
mappedFile.FilePath,
|
|
fromDistanceContent,
|
|
id.Value,
|
|
null,
|
|
null,
|
|
mappedFile.PersonKey,
|
|
rectangle,
|
|
wholePercentages.Value));
|
|
}
|
|
|
|
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetReadOnly(Dictionary<int, Dictionary<int, LocationContainer>> keyValuePairs)
|
|
{
|
|
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
|
|
foreach (KeyValuePair<int, Dictionary<int, LocationContainer>> keyValuePair in keyValuePairs)
|
|
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
|
return new(results);
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory)
|
|
{
|
|
Dictionary<int, Dictionary<int, LocationContainer>> results = [];
|
|
List<LocationContainer> locationContainers = [];
|
|
Dictionary<int, LocationContainer>? keyValuePairs;
|
|
Dictionary<int, List<(string, int)>> skipCollection = [];
|
|
Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
|
|
ReadOnlyCollection<string> readOnlyPersonKeyFormattedCollection;
|
|
ReadOnlyDictionary<string, string> readOnlyPersonKeyFormattedToNewestPersonKeyFormatted;
|
|
SetSkipCollections(configuration, personContainers, a2PeopleSingletonDirectory, skipCollection, skipNotSkipCollection);
|
|
{
|
|
List<string> personKeyFormattedCollection = [];
|
|
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
|
|
SetPersonCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
|
readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection);
|
|
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted);
|
|
}
|
|
List<Record> records = DistanceLogic.DeleteEmptyDirectoriesAndGetCollection(propertyConfiguration, configuration, ticks, eDistanceContentDirectory, readOnlyPersonKeyFormattedToNewestPersonKeyFormatted, readOnlyPersonKeyFormattedCollection);
|
|
List<MappedFile> mappedFiles = GetMappedFiles(propertyConfiguration, configuration, personContainers, records);
|
|
if (mappedFiles.Count > 0)
|
|
{
|
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
|
ReadOnlyDictionary<int, List<(string, int)>> readOnlySkipNotSkipCollection = new(skipCollection);
|
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
using ProgressBar progressBar = new(mappedFiles.Count, message, options);
|
|
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
|
{
|
|
progressBar.Tick();
|
|
MappedParallelFor(propertyConfiguration, configuration, readOnlySkipNotSkipCollection, locationContainers, mappedFiles[i]);
|
|
});
|
|
}
|
|
foreach (LocationContainer locationContainer in locationContainers)
|
|
{
|
|
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
|
|
{
|
|
results.Add(locationContainer.Id, []);
|
|
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
|
|
throw new Exception();
|
|
}
|
|
if (keyValuePairs.ContainsKey(locationContainer.WholePercentages))
|
|
continue;
|
|
keyValuePairs.Add(locationContainer.WholePercentages, locationContainer);
|
|
}
|
|
return GetReadOnly(results);
|
|
}
|
|
|
|
private static void MoveUnableToMatch(FilePath filePath)
|
|
{
|
|
string checkFile = $"{filePath.FullName}.unk";
|
|
if (File.Exists(filePath.FullName) && !File.Exists(checkFile))
|
|
File.Move(filePath.FullName, checkFile);
|
|
}
|
|
|
|
private static void AvailableParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, IFaceD dFace, List<LocationContainer> locationContainers, FilePath filePath)
|
|
{
|
|
string? json;
|
|
const bool fromDistanceContent = false;
|
|
if (filePath.Id is null)
|
|
return;
|
|
DateOnly dateOnly = DateOnly.FromDateTime(new DateTime(filePath.CreationTicks));
|
|
int? wholePercentages = IMapping.GetWholePercentages(dFace.FileNameExtension, filePath);
|
|
if (wholePercentages is null)
|
|
{
|
|
if (configuration.DistanceMoveUnableToMatch)
|
|
MoveUnableToMatch(filePath);
|
|
return;
|
|
}
|
|
ExifDirectory exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
|
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(exifDirectory);
|
|
if (json is null || !json.Contains(nameof(DateTime)))
|
|
{
|
|
if (configuration.DistanceMoveUnableToMatch)
|
|
MoveUnableToMatch(filePath);
|
|
return;
|
|
}
|
|
FaceFile? faceFile = JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
|
|
if (faceFile is null || faceFile.Location is null)
|
|
{
|
|
if (configuration.DistanceMoveUnableToMatch)
|
|
MoveUnableToMatch(filePath);
|
|
return;
|
|
}
|
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
|
if (rectangle is null)
|
|
return;
|
|
lock (locationContainers)
|
|
locationContainers.Add(new(dateOnly,
|
|
exifDirectory,
|
|
null,
|
|
null,
|
|
null,
|
|
faceFile,
|
|
filePath,
|
|
fromDistanceContent,
|
|
filePath.Id.Value,
|
|
null,
|
|
null,
|
|
null,
|
|
rectangle,
|
|
wholePercentages.Value));
|
|
}
|
|
|
|
internal static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, IFaceD dFace, long ticks, string dFacesContentDirectory, ReadOnlyCollection<FilePath> filePaths)
|
|
{
|
|
List<LocationContainer> results = [];
|
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
|
string message = $") Building Available Face Files Collection - {totalSeconds} total second(s)";
|
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
using ProgressBar progressBar = new(filePaths.Count, message, options);
|
|
_ = Parallel.For(0, filePaths.Count, parallelOptions, (i, state) =>
|
|
{
|
|
progressBar.Tick();
|
|
AvailableParallelFor(propertyConfiguration, configuration, dFace, results, filePaths[i]);
|
|
});
|
|
return results;
|
|
}
|
|
|
|
} |