1404 lines
77 KiB
C#

using Humanizer;
using ShellProgressBar;
using System.Text;
using System.Text.Json;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods;
using WindowsShortcutFactory;
namespace View_by_Distance.Map.Models;
public class MapLogic
{
protected readonly Dictionary<int, List<int>> _SkipCollection;
protected readonly List<PersonContainer> _NotMappedPersonContainers;
protected readonly Dictionary<long, PersonContainer> _PersonKeyToPersonContainer;
protected Dictionary<long, (long LCL, long Minimum, long Maximum, long UCL)>? _PersonKeyToRanges;
protected readonly Dictionary<int, Dictionary<int, PersonContainer[]>> _IdThenNormalizedRectangleToPersonContainers;
public Dictionary<int, int[]> KeyValuePairs => throw new NotImplementedException();
public Dictionary<int, int[]> IndicesFromNew => throw new NotImplementedException();
private readonly long _Ticks;
private readonly Serilog.ILogger? _Log;
private readonly int _MaxDegreeOfParallelism;
private readonly Configuration? _Configuration;
private readonly string _EDistanceContentTicksDirectory;
private readonly Shared.Models.Methods.IMapLogicSupport? _MapLogicSupport;
private readonly Shared.Models.Properties.IPropertyConfiguration _PropertyConfiguration;
public MapLogic(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, long ticks, PersonContainer[] personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, Shared.Models.Methods.IMapLogicSupport? mapLogicSupport)
{
_Ticks = ticks;
_Configuration = configuration;
_MapLogicSupport = mapLogicSupport;
_Log = Serilog.Log.ForContext<MapLogic>();
_PropertyConfiguration = propertyConfiguration;
_MaxDegreeOfParallelism = maxDegreeOfParallelism;
if (_Log is null)
{ }
if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any())
throw new Exception();
if (_MaxDegreeOfParallelism == 0)
{ }
string json;
string fullPath;
List<KeyValuePair<int, int[]>>? collection;
Dictionary<int, List<int>> skipCollection = new();
List<PersonContainer> notMappedPersonContainers = new();
Dictionary<long, PersonContainer> personKeyToPersonContainer = new();
string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, $"({ticks})");
Dictionary<int, Dictionary<int, PersonContainer[]>> idThenNormalizedRectangleToPersonContainers = new();
for (int i = 1; i < 5; i++)
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
if (string.IsNullOrEmpty(rootDirectoryParent))
throw new NullReferenceException(nameof(rootDirectoryParent));
if (!Directory.Exists(eDistanceContentDirectory))
_ = Directory.CreateDirectory(eDistanceContentDirectory);
if (!Directory.Exists(eDistanceContentTicksDirectory))
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
if (configuration is not null && mapLogicSupport is not null)
{
List<PersonContainer> personContainerCollection = new(personContainers);
Stateless.MapLogic.Set(propertyConfiguration,
configuration,
ticks,
personContainerCollection,
a2PeopleSingletonDirectory,
eDistanceContentDirectory,
mapLogicSupport,
personKeyToPersonContainer,
notMappedPersonContainers,
skipCollection,
idThenNormalizedRectangleToPersonContainers);
if (personContainerCollection.Count == personContainers.Length)
throw new NotSupportedException();
}
foreach (string propertyContentCollectionFile in propertyConfiguration.PropertyContentCollectionFiles)
{
fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile));
if (fullPath.Contains(propertyConfiguration.RootDirectory))
continue;
if (!File.Exists(fullPath))
continue;
json = File.ReadAllText(fullPath);
collection = JsonSerializer.Deserialize<List<KeyValuePair<int, int[]>>>(json);
if (collection is null)
throw new NullReferenceException(nameof(collection));
}
_SkipCollection = skipCollection;
_PersonKeyToPersonContainer = personKeyToPersonContainer;
_EDistanceContentTicksDirectory = eDistanceContentTicksDirectory;
_IdThenNormalizedRectangleToPersonContainers = idThenNormalizedRectangleToPersonContainers;
_NotMappedPersonContainers = notMappedPersonContainers.OrderByDescending(l => l.Key).ToList();
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
public (Dictionary<long, int>, int) AddToMapping(Mapping[] mappingCollection)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
int result = 0;
long personKey;
const int zero = 0;
string mappingSegmentB;
PersonBirthday personBirthday;
PersonContainer[]? collection;
List<PersonContainer> personContainers = new();
Dictionary<long, int> personKeyToCount = new();
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
foreach (Mapping mapping in mappingCollection)
{
personContainers.Clear();
if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(mapping.MappingFromItem.Id, out normalizedRectangleToPersonContainers))
result += 1;
else
{
if (!normalizedRectangleToPersonContainers.TryGetValue(mapping.MappingFromLocation.NormalizedRectangle, out collection))
result += 1;
else
personContainers.AddRange(collection);
}
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKey = personBirthday.Value.Ticks;
if (!personKeyToCount.ContainsKey(personKey))
personKeyToCount.Add(personKey, 0);
personKeyToCount[personKey] += 1;
mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, mapping.MappingFromItem);
mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, personContainer.DisplayDirectoryName, personBirthday, mappingSegmentB);
}
}
return new(personKeyToCount, result);
}
public void SaveContainers(int totalNotMapped, int? updated, List<SaveContainer> saveContainers)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string checkFile;
string sourceFile;
WindowsShortcut windowsShortcut;
string[] directories = (from l in saveContainers select l.Directory).Distinct().ToArray();
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds);
string message;
if (updated is null)
message = $") {saveContainers.Count:000} save(s) - {totalNotMapped} Total not Mapped - {totalSeconds} total second(s)";
else
message = $") {saveContainers.Count:000} save(s) - {totalNotMapped} Total not Mapped - {updated} Updated - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
foreach (string directory in directories)
{
if (string.IsNullOrEmpty(directory))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
using ProgressBar progressBar = new(saveContainers.Count, message, options);
foreach (SaveContainer saveContainer in saveContainers)
{
if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.FaceFileHolder is null)
continue;
progressBar.Tick();
if (!saveContainer.FaceFileHolder.Exists && saveContainer.ResizedFileHolder is not null && saveContainer.ResizedFileHolder.Exists)
{
checkFile = saveContainer.CheckFile;
sourceFile = saveContainer.ResizedFileHolder.FullName;
}
else if (saveContainer.FaceFileHolder.Exists)
{
sourceFile = saveContainer.FaceFileHolder.FullName;
checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesFileNameExtension}";
}
else
continue;
if (File.Exists(checkFile))
continue;
File.Copy(sourceFile, checkFile);
if (saveContainer.MakeAllHidden)
File.SetAttributes(checkFile, FileAttributes.Hidden);
if (saveContainer.HiddenFaceFileHolder is not null && saveContainer.HiddenFaceFileHolder.Exists)
{
sourceFile = saveContainer.HiddenFaceFileHolder.FullName;
checkFile = $"{saveContainer.CheckFile}{_Configuration.FacesHiddenFileNameExtension}";
}
else if (saveContainer.FacePartsFileHolder is not null && saveContainer.FacePartsFileHolder.Exists)
{
sourceFile = saveContainer.FacePartsFileHolder.FullName;
checkFile = $"{saveContainer.CheckFile}{_Configuration.FacePartsFileNameExtension}";
}
if (File.Exists(checkFile))
continue;
File.Copy(sourceFile, checkFile);
if (saveContainer.MakeAllHidden)
File.SetAttributes(checkFile, FileAttributes.Hidden);
}
if (updated is null)
{
foreach (SaveContainer saveContainer in saveContainers)
{
if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists)
continue;
checkFile = saveContainer.CheckFile;
sourceFile = saveContainer.ResizedFileHolder.FullName;
if (File.Exists(checkFile))
continue;
File.Copy(sourceFile, checkFile);
if (saveContainer.MakeAllHidden)
File.SetAttributes(checkFile, FileAttributes.Hidden);
}
}
foreach (SaveContainer saveContainer in saveContainers)
{
if (string.IsNullOrEmpty(saveContainer.ShortcutFile) || saveContainer.ResizedFileHolder is null || !saveContainer.ResizedFileHolder.Exists)
continue;
try
{
string description = saveContainer.FaceFileHolder is not null ? saveContainer.FaceFileHolder.Name : string.Empty;
windowsShortcut = new() { Path = saveContainer.ResizedFileHolder.FullName, Description = description };
windowsShortcut.Save(saveContainer.ShortcutFile);
windowsShortcut.Dispose();
if (saveContainer.MakeAllHidden)
File.SetAttributes(saveContainer.ShortcutFile, FileAttributes.Hidden);
}
catch (Exception)
{ }
}
}
private static string? GetFacesDirectory(string dFacesContentDirectory, MappingFromItem mappingFromItem)
{
string? result;
string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath);
if (directoryName is null)
result = null;
else
result = Path.Combine($"{dFacesContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension);
return result;
}
private static string? GetFacePartsDirectory(string d2FacePartsContentDirectory, MappingFromItem mappingFromItem)
{
string? result;
string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath);
if (directoryName is null)
result = null;
else
result = Path.Combine($"{d2FacePartsContentDirectory}{directoryName}", mappingFromItem.ImageFileHolder.NameWithoutExtension);
return result;
}
private SaveContainer? GetMatchSaveContainer(string dFacesContentDirectory, string d2FacePartsContentDirectory, string directory, Mapping mapping)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
SaveContainer? result;
string shortcutFile = string.Empty;
string? facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem);
if (facesDirectory is null)
result = null;
else
{
FileHolder faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"));
if (!faceFileHolder.Exists)
result = null;
else
{
string? facePartsDirectory = GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem);
if (facePartsDirectory is null)
result = null;
else
{
string checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
FileHolder hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}"));
FileHolder facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}"));
result = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile);
}
}
}
return result;
}
private static (string, bool, bool) Get(int? useFiltersCounter, string forceSingleImageHumanized, Mapping mapping)
{
string by;
bool isByMapping;
bool isBySorting;
if (mapping.By is null)
{
isByMapping = false;
isBySorting = false;
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
}
else
{
isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping;
isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting;
if (isBySorting && mapping.MappingFromPerson is null)
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person";
else if (isBySorting && useFiltersCounter.HasValue)
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Modified Filters - {useFiltersCounter.Value}";
else
{
by = mapping.By.Value switch
{
Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping),
Shared.Models.Stateless.IMapLogic.Sorting => nameof(Shared.Models.Stateless.IMapLogic.Sorting),
Shared.Models.Stateless.IMapLogic.ForceSingleImage => forceSingleImageHumanized,
_ => throw new NotImplementedException()
};
}
}
return new(by, isByMapping, isBySorting);
}
private string GetDirectory(string by, MappingFromItem mappingFromItem, SortingContainer sortingContainer)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string result;
const int zero = 0;
string mappingSegmentB;
string personKeyFormatted;
PersonBirthday personBirthday;
PersonContainer personContainer;
result = Path.Combine(_EDistanceContentTicksDirectory, by, sortingContainer.Sorting.Id.ToString(), sortingContainer.Sorting.NormalizedRectangle.ToString());
for (int i = _NotMappedPersonContainers.Count - 1; i > 0; i--)
{
personContainer = _NotMappedPersonContainers[i];
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, mappingFromItem);
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
result = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mappingSegmentB);
_NotMappedPersonContainers.RemoveAt(i);
break;
}
return result;
}
private List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping, Dictionary<long, int> personKeyToCount, int? useFiltersCounter, bool saveNullPerson, bool saveMapped)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<SaveContainer> results = new();
string by;
long personKey;
bool isByMapping;
bool isBySorting;
string checkFile;
string directory;
string shortcutFile;
string? directoryName;
string personDirectory;
string? facesDirectory;
FileHolder faceFileHolder;
string personKeyFormatted;
List<int> distinct = new();
string? facePartsDirectory;
SaveContainer? saveContainer;
FileHolder facePartsFileHolder;
FileHolder hiddenFaceFileHolder;
Dictionary<int, Mapping>? normalizedRectangleToMapping;
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
foreach (Mapping mapping in mappingCollection)
{
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
if (directoryName is null)
throw new NotSupportedException();
(by, isByMapping, isBySorting) = Get(useFiltersCounter, forceSingleImageHumanized, mapping);
if (isByMapping && !saveMapped)
continue;
if (mapping.MappingFromPerson is null)
{
if (!saveNullPerson)
continue;
if (mapping.SortingContainer is null)
continue;
if (distinct.Contains(mapping.MappingFromItem.Id))
continue;
if (distinct.Contains(mapping.SortingContainer.Sorting.Id))
continue;
directory = GetDirectory(by, mapping.MappingFromItem, mapping.SortingContainer);
personDirectory = Path.Combine(directory, $"Z]{DateTime.Now.Ticks}");
distinct.Add(mapping.MappingFromItem.Id);
distinct.Add(mapping.SortingContainer.Sorting.Id);
}
else
{
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
throw new NotSupportedException();
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
throw new NotSupportedException();
personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday);
if (string.IsNullOrEmpty(mapping.SegmentC))
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mapping.MappingFromPerson.SegmentB);
else
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mapping.MappingFromPerson.SegmentB, mapping.SegmentC);
if (isByMapping)
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
else if (mapping.By is not null)
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, "lnk");
else
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName[..1], "lnk");
if (isByMapping && personKeyToCount.TryGetValue(personKey, out int count))
{
saveContainer = new(Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{count} Face(s)"));
results.Add(saveContainer);
}
}
saveContainer = new(personDirectory);
results.Add(saveContainer);
facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem);
if (facesDirectory is null)
continue;
faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"));
if (!faceFileHolder.Exists)
continue;
if (isByMapping)
{
checkFile = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
saveContainer = new(checkFile, directory, faceFileHolder);
}
else
{
facePartsDirectory = GetFacePartsDirectory(d2FacePartsContentDirectory, mapping.MappingFromItem);
if (facePartsDirectory is null)
continue;
// if (!isBySorting || mapping.MappingFromPerson is not null)
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
// else
// checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}-Source{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
shortcutFile = Path.Combine(personDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.lnk");
hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesHiddenFileNameExtension}"));
facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacePartsFileNameExtension}"));
saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, mapping.MappingFromItem.ResizedFileHolder, shortcutFile);
}
results.Add(saveContainer);
if (!isBySorting || mapping.SortingContainer is null)
continue;
if (!idToNormalizedRectangleToMapping.TryGetValue(mapping.SortingContainer.Sorting.Id, out normalizedRectangleToMapping))
continue;
if (!normalizedRectangleToMapping.ContainsKey(mapping.SortingContainer.Sorting.NormalizedRectangle))
continue;
if (isBySorting && mapping.MappingFromPerson is null)
{
saveContainer = GetMatchSaveContainer(dFacesContentDirectory, d2FacePartsContentDirectory, directory, normalizedRectangleToMapping[mapping.SortingContainer.Sorting.NormalizedRectangle]);
if (saveContainer is not null)
results.Add(saveContainer);
}
saveContainer = Stateless.MapLogic.GetDebugSaveContainer(directory, mapping.SortingContainer, normalizedRectangleToMapping[mapping.SortingContainer.Sorting.NormalizedRectangle]);
results.Add(saveContainer);
}
return results;
}
public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping, int? useFiltersCounter, bool saveNullPerson)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<SaveContainer> results;
bool saveMapped = false;
Dictionary<long, int> personKeyToCount = new();
results = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, useFiltersCounter, saveNullPerson, saveMapped);
return results;
}
public void SaveMapped(string dFacesContentDirectory, string d2FacePartsContentDirectory, Mapping[] mappingCollection, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping, Dictionary<long, int> personKeyToCount, int totalNotMapped)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
int? updated = null;
bool saveMapped = true;
bool saveNullPerson = false;
int? useFiltersCounter = null;
string mappingDirectory = Path.Combine(_EDistanceContentTicksDirectory, nameof(Shared.Models.Stateless.IMapLogic.Mapping));
List<SaveContainer> saveContainers = GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, useFiltersCounter, saveNullPerson, saveMapped);
SaveContainers(totalNotMapped, updated, saveContainers);
if (!string.IsNullOrEmpty(_EDistanceContentTicksDirectory) && Directory.Exists(mappingDirectory))
Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory);
}
private List<(long, long, long, long)> GetPersonKeysRangesCollection(PersonContainer[] personContainers)
{
if (_PersonKeyToRanges is null)
throw new NullReferenceException(nameof(_PersonKeyToRanges));
List<(long, long, long, long)> results = new();
(long, long, long, long) singleton;
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null)
continue;
if (!_PersonKeyToRanges.TryGetValue(personContainer.Key.Value, out singleton))
continue;
results.Add(singleton);
}
return results;
}
public bool Used(FaceDistance faceDistanceEncoding)
{
bool result = false;
if (faceDistanceEncoding.NormalizedRectangle is null)
throw new NotSupportedException();
List<int>? normalizedRectangles;
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
if (_SkipCollection.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangles))
{
if (normalizedRectangles.Contains(faceDistanceEncoding.NormalizedRectangle.Value))
result = true;
}
if (!result && _IdThenNormalizedRectangleToPersonContainers.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangleToPersonContainers))
{
if (normalizedRectangleToPersonContainers.ContainsKey(faceDistanceEncoding.NormalizedRectangle.Value))
result = true;
}
return result;
}
public List<Sorting> GetSortingCollection(int i, FaceDistance faceDistanceEncoding, List<FaceDistance> faceDistanceLengths)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<Sorting> results = new();
Sorting sorting;
FaceDistance faceDistanceLength;
List<int>? normalizedRectangles;
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
List<(long lcl, long minimum, long maximum, long ucl)> personKeysRangesCollection;
for (int j = 0; j < faceDistanceLengths.Count; j++)
{
if (faceDistanceEncoding.NormalizedRectangle is null)
throw new NotSupportedException();
if (j == i)
continue;
if (_SkipCollection.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangles))
{
if (normalizedRectangles.Contains(faceDistanceEncoding.NormalizedRectangle.Value))
continue;
}
if (_IdThenNormalizedRectangleToPersonContainers.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangleToPersonContainers))
{
if (normalizedRectangleToPersonContainers.ContainsKey(faceDistanceEncoding.NormalizedRectangle.Value))
continue;
}
faceDistanceLength = faceDistanceLengths[j];
if (faceDistanceLength.NormalizedRectangle is null || faceDistanceLength.Length is null)
throw new NotSupportedException();
if (faceDistanceLength.Length == 0)
continue;
if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(faceDistanceLength.Id, out normalizedRectangleToPersonContainers))
personKeysRangesCollection = new();
else
{
if (!normalizedRectangleToPersonContainers.ContainsKey(faceDistanceLength.NormalizedRectangle.Value))
personKeysRangesCollection = new();
else
personKeysRangesCollection = GetPersonKeysRangesCollection(normalizedRectangleToPersonContainers[faceDistanceLength.NormalizedRectangle.Value]);
}
sorting = ISorting.Get(_Configuration.FaceDistancePermyriad, _Configuration.RangeDistanceTolerance, faceDistanceEncoding, faceDistanceLength, personKeysRangesCollection);
if (sorting.DistancePermyriad == 0)
continue;
if (sorting.Id == faceDistanceEncoding.Id)
{
if (sorting.NormalizedRectangle == faceDistanceEncoding.NormalizedRectangle.Value)
continue;
continue;
}
results.Add(sorting);
}
return results;
}
public int UpdateFromSortingContainers(SortingContainer[] sortingContainers, bool saveNullPerson)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
if (_MapLogicSupport is not null)
{
string counts = _MapLogicSupport.GetCounts();
_ = Directory.CreateDirectory(Path.Combine(_EDistanceContentTicksDirectory, counts));
}
int result = 0;
string key;
const int zero = 0;
string mappingSegmentB;
string personKeyFormatted;
PersonBirthday personBirthday;
PersonContainer[]? personContainers;
Dictionary<string, int> keyToCount = new();
List<int> normalizedRectangleCollectionForA;
List<int> normalizedRectangleCollectionForB;
Dictionary<string, string> keyToSegmentC = new();
Dictionary<int, List<int>> idToNormalizedRectangleCollectionForA = new();
Dictionary<int, List<int>> idToNormalizedRectangleCollectionForB = new();
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds);
string message = $") {sortingContainers.Length:000} Update From Sorting Container(s) - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(sortingContainers.Length, message, options);
foreach (SortingContainer sortingContainer in sortingContainers)
{
progressBar.Tick();
if (sortingContainer.Mapping is null)
throw new NotSupportedException();
if (!idToNormalizedRectangleCollectionForA.ContainsKey(sortingContainer.Mapping.MappingFromItem.Id))
idToNormalizedRectangleCollectionForA.Add(sortingContainer.Mapping.MappingFromItem.Id, new());
normalizedRectangleCollectionForA = idToNormalizedRectangleCollectionForA[sortingContainer.Mapping.MappingFromItem.Id];
if (!idToNormalizedRectangleCollectionForB.ContainsKey(sortingContainer.Mapping.MappingFromItem.Id))
idToNormalizedRectangleCollectionForB.Add(sortingContainer.Mapping.MappingFromItem.Id, new());
normalizedRectangleCollectionForB = idToNormalizedRectangleCollectionForB[sortingContainer.Mapping.MappingFromItem.Id];
if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(sortingContainer.Sorting.Id, out normalizedRectangleToPersonContainers) || !normalizedRectangleToPersonContainers.TryGetValue(sortingContainer.Sorting.NormalizedRectangle, out personContainers))
{
if (!saveNullPerson)
continue;
if (normalizedRectangleCollectionForA.Contains(sortingContainer.Mapping.MappingFromLocation.NormalizedRectangle))
continue;
sortingContainer.Mapping.UpdateMappingFromUnknownPerson(sortingContainer);
normalizedRectangleCollectionForA.Add(sortingContainer.Mapping.MappingFromLocation.NormalizedRectangle);
result += 1;
}
else
{
if (normalizedRectangleCollectionForB.Contains(sortingContainer.Mapping.MappingFromLocation.NormalizedRectangle))
continue;
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, sortingContainer.Mapping.MappingFromItem);
key = string.Concat(personKeyFormatted, '\t', mappingSegmentB);
if (!keyToCount.ContainsKey(key))
keyToCount.Add(key, new());
if (!keyToCount.ContainsKey(key))
keyToCount.Add(key, 0);
if (!keyToSegmentC.ContainsKey(key))
keyToSegmentC.Add(key, string.Empty);
keyToCount[key]++;
if (keyToCount[key] > _Configuration.SortingMaximumPerKey)
{
keyToCount[key] = 0;
keyToSegmentC[key] = sortingContainer.Sorting.DistancePermyriad.ToString();
}
sortingContainer.Mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, personContainer.DisplayDirectoryName, personBirthday, mappingSegmentB, keyToSegmentC[key], sortingContainer);
normalizedRectangleCollectionForB.Add(sortingContainer.Mapping.MappingFromLocation.NormalizedRectangle);
result += 1;
break;
}
}
}
return result;
}
public void CopyManualFiles(string dFacesContentDirectory, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
int? id;
Mapping mapping;
string faceFile;
string checkFile;
string directory;
FileInfo fileInfo;
const int zero = 0;
string faceFileName;
string shortcutFile;
string? directoryName;
string mappingSegmentB;
string personDirectory;
string? facesDirectory;
string personKeyFormatted;
string personDisplayFileName;
PersonBirthday personBirthday;
string? personDisplayDirectory;
int? normalizedRectangle;
WindowsShortcut windowsShortcut;
Dictionary<int, Mapping>? normalizedRectangleToMapping;
string by = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy);
Dictionary<int, PersonContainer[]>? normalizedRectangleToPeronContainerCollection;
string successfull = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Successfull";
foreach (KeyValuePair<long, PersonContainer> keyValuePair in _PersonKeyToPersonContainer)
{
if (keyValuePair.Value.Key is null || keyValuePair.Value.Birthdays is null || !keyValuePair.Value.Birthdays.Any())
continue;
personBirthday = keyValuePair.Value.Birthdays[zero];
foreach (string personDisplayDirectoryAllFile in keyValuePair.Value.DisplayDirectoryAllFiles)
{
if (personDisplayDirectoryAllFile.Contains("-2318605"))
continue;
if (!personDisplayDirectoryAllFile.EndsWith(_Configuration.FacesFileNameExtension))
continue;
(id, normalizedRectangle) = IMapping.GetConverted(_Configuration.FacesFileNameExtension, personDisplayDirectoryAllFile);
if (id is null || normalizedRectangle is null)
continue;
fileInfo = new(personDisplayDirectoryAllFile);
if (!fileInfo.Exists)
continue;
personDisplayFileName = Path.GetFileName(personDisplayDirectoryAllFile);
personDisplayDirectory = Path.GetDirectoryName(personDisplayDirectoryAllFile);
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
mappingSegmentB = Stateless.MapLogic.GetMappingSegmentB(_Ticks, personBirthday, keyValuePair.Value.ApproximateYears, fileInfo.CreationTime, isWrongYear: null);
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, mappingSegmentB);
personDirectory = Path.Combine(directory, keyValuePair.Value.DisplayDirectoryName, "lnk");
if (!idToNormalizedRectangleToMapping.TryGetValue(id.Value, out normalizedRectangleToMapping))
continue;
if (!normalizedRectangleToMapping.ContainsKey(normalizedRectangle.Value))
continue;
mapping = normalizedRectangleToMapping[normalizedRectangle.Value];
if (string.IsNullOrEmpty(personDisplayDirectory))
throw new NotSupportedException();
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
if (string.IsNullOrEmpty(directoryName))
throw new NotSupportedException();
shortcutFile = Path.Combine(personDisplayDirectory, $"{personDisplayFileName}.lnk");
facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); // Path.Combine($"{dFacesContentDirectory}{directoryName}", mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension);
if (facesDirectory is null)
continue;
faceFileName = $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}";
checkFile = Path.Combine(directory, fileInfo.Name);
if (!_IdThenNormalizedRectangleToPersonContainers.TryGetValue(id.Value, out normalizedRectangleToPeronContainerCollection) || !normalizedRectangleToPeronContainerCollection.ContainsKey(normalizedRectangle.Value))
{
if (!Directory.Exists(personDirectory))
_ = Directory.CreateDirectory(personDirectory);
if (!File.Exists(checkFile))
File.Copy(personDisplayDirectoryAllFile, checkFile);
}
if (personDisplayDirectoryAllFile.Contains(successfull))
continue;
directoryName = Path.Combine(personDisplayDirectory, successfull);
if (!Directory.Exists(directoryName))
_ = Directory.CreateDirectory(directoryName);
checkFile = Path.Combine(directoryName, personDisplayFileName);
if (File.Exists(checkFile))
File.Delete(personDisplayDirectoryAllFile);
else
File.Move(personDisplayDirectoryAllFile, checkFile);
faceFile = Path.Combine(facesDirectory, faceFileName);
if (!File.Exists(faceFile))
continue;
if (File.Exists(shortcutFile))
continue;
windowsShortcut = new() { Path = faceFile };
windowsShortcut.Save(shortcutFile);
windowsShortcut.Dispose();
if (!File.Exists(shortcutFile))
continue;
File.SetLastWriteTime(shortcutFile, mapping.MappingFromItem.MinimumDateTime);
}
}
}
public void SaveNotMappedTicks()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
int updated = 0;
string directory;
const int zero = 0;
int totalNotMapped = 0;
string personKeyFormatted;
SaveContainer saveContainer;
PersonBirthday personBirthday;
List<SaveContainer> saveContainers = new();
const string facePopulatedKey = nameof(Shared.Models.Stateless.IMapLogic.Sorting);
foreach (PersonContainer personContainer in _NotMappedPersonContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
directory = Path.Combine(_EDistanceContentTicksDirectory, $"{facePopulatedKey}NotMapped", personKeyFormatted, _Configuration.MappingDefaultName);
saveContainer = new(directory);
saveContainers.Add(saveContainer);
}
SaveContainers(totalNotMapped, updated, saveContainers);
}
private (string, PersonBirthday?) GetPersonBirthday(string[] directoryNames)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
PersonBirthday? personBirthday = null;
string personKeyFormatted = string.Empty;
foreach (string directoryName in directoryNames)
{
personBirthday = IPersonBirthday.GetPersonBirthday(_Configuration.PersonBirthdayFormat, directoryName);
if (personBirthday is not null)
{
personKeyFormatted = directoryName;
break;
}
}
return new(personKeyFormatted, personBirthday);
}
private (string, PersonBirthday?) GetPersonBirthday(string windowsShortcutPath)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string[] directoryNames = IPath.GetDirectoryNames(windowsShortcutPath);
(string personKeyFormatted, PersonBirthday? personBirthday) = GetPersonBirthday(directoryNames);
if (personBirthday is null)
{
string[] directories = Directory.GetDirectories(windowsShortcutPath, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
directoryNames = IPath.GetDirectoryNames(directory);
(personKeyFormatted, personBirthday) = GetPersonBirthday(directoryNames);
if (personBirthday is not null)
break;
}
}
return new(personKeyFormatted, personBirthday);
}
private List<string> GetPersonKeyFormattedCollection(string[] jLinks, string a2PeopleSingletonDirectory, PersonContainer[] personContainers, Dictionary<long, int> personKeyToCount)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
if (_MapLogicSupport is null)
throw new NullReferenceException(nameof(_MapLogicSupport));
List<string> results = new();
string[] files;
string checkDirectory;
string[] checkDirectories;
string personKeyFormatted;
PersonContainer[] matches;
PersonBirthday? personBirthday;
string fileNameWithoutExtension;
WindowsShortcut windowsShortcut;
List<(long, string)> collection = new();
foreach (string directoryName in jLinks)
{
checkDirectory = Path.Combine(a2PeopleSingletonDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
continue;
checkDirectories = Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly);
files = Directory.GetFiles(checkDirectory, "*.lnk", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
collection.Clear();
windowsShortcut = WindowsShortcut.Load(file);
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
if (windowsShortcut.Path is null)
continue;
if (!Directory.Exists(windowsShortcut.Path))
{
if (files.Length != checkDirectories.Length)
throw new NotSupportedException(fileNameWithoutExtension);
continue;
}
(personKeyFormatted, personBirthday) = GetPersonBirthday(windowsShortcut.Path);
if (personBirthday is null)
throw new NotSupportedException(fileNameWithoutExtension);
if (!personKeyToCount.ContainsKey(personBirthday.Value.Ticks))
collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension)));
else
collection.Add(new(personBirthday.Value.Ticks, Path.Combine(checkDirectory, personKeyFormatted, fileNameWithoutExtension, $"{personKeyToCount[personBirthday.Value.Ticks]} Face(s)")));
foreach ((long personKey, string displayDirectoryName) in collection)
{
matches = (from l in personContainers where l.Key == personKey && l.ApproximateYears.HasValue select l).ToArray();
if (!matches.Any())
continue;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personKey);
if (!displayDirectoryName.Contains(personKeyFormatted))
continue;
if (!Directory.Exists(displayDirectoryName))
_ = Directory.CreateDirectory(displayDirectoryName);
results.Add(personKeyFormatted);
}
}
}
return results;
}
private (int, FileHolder, int, string, string, string, string)[] GetCollectionForSaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleSingletonDirectory, PersonContainer[] personContainers, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
(int, FileHolder, int, string, string, string, string)[] results;
string checkFile;
string directory;
string? directoryName;
string personDirectory;
string personKeyFormatted;
bool usePersonKeyAndDeterministicHashCodeKey = false;
List<string> personKeyFormattedCollection = GetPersonKeyFormattedCollection(jLinks, a2PeopleSingletonDirectory, personContainers, personKeyToCount);
List<(int Id, FileHolder ImageFileHolder, int ApproximateYears, string PersonKeyFormatted, string CheckFile, string Directory, string PersonDirectory)> collection = new();
foreach (Mapping mapping in mappingCollection)
{
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
if (directoryName is null)
throw new NotSupportedException();
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting)
continue;
if (mapping.MappingFromPerson?.ApproximateYears is null)
continue;
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
throw new NotSupportedException();
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
throw new NotSupportedException();
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday);
if (personKeyFormatted == "1501-04-10_00")
continue;
if (!personKeyFormattedCollection.Contains(personKeyFormatted))
continue;
if (!usePersonKeyAndDeterministicHashCodeKey)
{
directory = Path.Combine(_EDistanceContentTicksDirectory, "Images");
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
checkFile = Path.Combine(directory, $"{mapping.MappingFromItem.Id}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
}
else
{
directory = Path.Combine(_EDistanceContentTicksDirectory, "Images", personKeyFormatted);
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}");
}
collection.Add(new(mapping.MappingFromItem.Id, mapping.MappingFromItem.ImageFileHolder, mapping.MappingFromPerson.ApproximateYears.Value, personKeyFormatted, directory, personDirectory, checkFile));
}
results = (from l in collection orderby l.ApproximateYears descending, l.PersonKeyFormatted descending select l).ToArray();
return results;
}
public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleSingletonDirectory, PersonContainer[] personContainers, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount, int totalNotMapped)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
SaveContainer? saveContainer;
List<int> distinctCollection = new();
List<SaveContainer> saveContainers = new();
(int, FileHolder, int, string, string, string, string)[] collection = GetCollectionForSaveFilteredOriginalImagesFromJLinks(jLinks, a2PeopleSingletonDirectory, personContainers, mappingCollection, personKeyToCount);
foreach ((int id, FileHolder imageFileHolder, int approximateYears, string personKeyFormatted, string directory, string personDirectory, string checkFile) in collection)
{
if (distinctCollection.Contains(id))
continue;
distinctCollection.Add(id);
saveContainer = new(personDirectory);
saveContainers.Add(saveContainer);
saveContainer = new(imageFileHolder, checkFile, directory);
saveContainers.Add(saveContainer);
}
SaveContainers(totalNotMapped, null, saveContainers);
}
private (List<(string, DateTime[])>, List<(string, string, string, string)>) GetCollectionForSaveShortcutsForOutputResolutions(List<Item> filteredItems, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
long personKey;
string fileName;
string directory;
string? directoryName;
string personDirectory;
string personKeyFormatted;
List<string> distinct = new();
List<(string, string, string, string)> collection = new();
List<(string, DateTime[])> directoriesAndDateTimes = new();
foreach (Item item in filteredItems)
{
if (item.ResizedFileHolder is null)
continue;
foreach (Face face in item.Faces)
{
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null)
continue;
directoryName = Path.GetDirectoryName(face.Mapping.MappingFromItem.RelativePath);
if (directoryName is null)
throw new NotSupportedException();
if (item.ResizedFileHolder?.DirectoryName is null || !item.ResizedFileHolder.Exists)
continue;
directory = Path.Combine(item.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
personDirectory = Path.Combine(directory, "No Faces");
fileName = Path.Combine(personDirectory, $"{item.ResizedFileHolder.Name}.lnk");
collection.Add(new(item.ResizedFileHolder.FullName, personDirectory, fileName, face.Mapping.MappingFromItem.Id.ToString()));
if (face.Mapping.MappingFromItem.ContainerDateTimes.Any() && !distinct.Contains(item.ResizedFileHolder.DirectoryName))
{
distinct.Add(item.ResizedFileHolder.DirectoryName);
directoriesAndDateTimes.Add(new(item.ResizedFileHolder.DirectoryName, face.Mapping.MappingFromItem.ContainerDateTimes));
}
}
}
foreach (Mapping mapping in mappingCollection)
{
if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists)
continue;
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting || mapping.MappingFromPerson?.ApproximateYears is null)
continue;
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
throw new NotSupportedException();
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
throw new NotSupportedException();
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday);
}
foreach (Mapping mapping in mappingCollection)
{
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
if (directoryName is null)
throw new NotSupportedException();
if (mapping.MappingFromItem.ResizedFileHolder.DirectoryName is null || !mapping.MappingFromItem.ResizedFileHolder.Exists)
continue;
if (mapping.By is null or Shared.Models.Stateless.IMapLogic.Sorting || mapping.MappingFromPerson?.ApproximateYears is null)
{
if (mapping.MappingFromItem.ContainerDateTimes.Any() && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName))
{
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName);
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes));
}
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", _PropertyConfiguration.ResultAllInOne);
personDirectory = Path.Combine(directory, "Unknown");
fileName = Path.Combine(personDirectory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey));
}
else
{
if (string.IsNullOrEmpty(mapping.MappingFromPerson.SegmentB))
throw new NotSupportedException();
if (string.IsNullOrEmpty(mapping.MappingFromPerson.DisplayDirectoryName))
throw new NotSupportedException();
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, mapping.MappingFromPerson.PersonBirthday);
personKey = mapping.MappingFromPerson.PersonBirthday.Value.Ticks;
if (mapping.MappingFromItem.ContainerDateTimes.Any() && !distinct.Contains(mapping.MappingFromItem.ResizedFileHolder.DirectoryName))
{
distinct.Add(mapping.MappingFromItem.ResizedFileHolder.DirectoryName);
directoriesAndDateTimes.Add(new(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, mapping.MappingFromItem.ContainerDateTimes));
}
directory = Path.Combine(mapping.MappingFromItem.ResizedFileHolder.DirectoryName, $"{_PropertyConfiguration.ResultAllInOne}Shortcuts", personKeyFormatted);
if (!personKeyToCount.ContainsKey(personKey))
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName);
else
personDirectory = Path.Combine(directory, mapping.MappingFromPerson.DisplayDirectoryName, $"{personKeyToCount[personKey]} Face(s)");
fileName = Path.Combine(directory, $"{mapping.MappingFromItem.ResizedFileHolder.Name}.lnk");
collection.Add(new(mapping.MappingFromItem.ResizedFileHolder.FullName, personDirectory, fileName, mapping.MappingFromLocation.DeterministicHashCodeKey));
}
}
return new(directoriesAndDateTimes, collection);
}
public void SaveShortcutsForOutputResolutions(List<Item> filteredItems, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
WindowsShortcut windowsShortcut;
List<(string, DateTime[])> directoriesAndDateTimes;
List<(string, string Directory, string, string)> collection;
(directoriesAndDateTimes, collection) = GetCollectionForSaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount);
string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
foreach (string directory in directories)
{
if (string.IsNullOrEmpty(directory))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
foreach ((string fullName, string directory, string fileName, string description) in collection)
{
if (File.Exists(fileName))
continue;
try
{
windowsShortcut = new() { Path = fullName, Description = description };
windowsShortcut.Save(fileName);
windowsShortcut.Dispose();
}
catch (Exception)
{ }
}
foreach ((string directory, DateTime[] dateTimes) in directoriesAndDateTimes)
{
if (!dateTimes.Any())
continue;
Directory.SetCreationTime(directory, dateTimes[0]);
Directory.SetLastWriteTime(directory, dateTimes[1]);
}
}
private List<(string, FileHolder, string)> GetCollection(string dFacesContentDirectory, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<(string, FileHolder, string)> results = new();
Mapping mapping;
string checkFile;
string directory;
string? directoryName;
string? facesDirectory;
FileHolder faceFileHolder;
List<int>? normalizedRectangles;
string by = nameof(Shared.Models.Stateless.IMapLogic.CopyNotMappedFaces);
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
foreach (KeyValuePair<int, Dictionary<int, Mapping>> keyValuePair in idToNormalizedRectangleToMapping)
{
_ = _IdThenNormalizedRectangleToPersonContainers.TryGetValue(keyValuePair.Key, out normalizedRectangleToPersonContainers);
foreach (KeyValuePair<int, Mapping> normalizedRectangleAndMapping in keyValuePair.Value)
{
mapping = normalizedRectangleAndMapping.Value;
if (normalizedRectangleToPersonContainers is not null && normalizedRectangleToPersonContainers.ContainsKey(mapping.MappingFromLocation.NormalizedRectangle))
continue;
_ = _SkipCollection.TryGetValue(keyValuePair.Key, out normalizedRectangles);
if (normalizedRectangles is not null && normalizedRectangles.Contains(mapping.MappingFromLocation.NormalizedRectangle))
continue;
directoryName = Path.GetDirectoryName(mapping.MappingFromItem.RelativePath);
facesDirectory = GetFacesDirectory(dFacesContentDirectory, mapping.MappingFromItem); // Path.Combine($"{dFacesContentDirectory}{directoryName}", mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension);
if (facesDirectory is null)
continue;
faceFileHolder = new(Path.Combine(facesDirectory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}"));
if (directoryName is null || !faceFileHolder.Exists)
continue;
directory = Path.Combine(_EDistanceContentTicksDirectory, by, $"{mapping.MappingFromLocation.AreaPermille:0000}A{mapping.MappingFromItem.MinimumDateTime.ToString("yyyy")[..3]}#");
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_Configuration.FacesFileNameExtension}");
results.Add(new(directory, faceFileHolder, checkFile));
}
}
return results;
}
public void CopyNotMappedFaces(int[] rangeFaceAreaPermilleTolerance, string dFacesContentDirectory, Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
List<(string Directory, FileHolder FaceFileHolder, string CheckFile)> collection = GetCollection(dFacesContentDirectory, idToNormalizedRectangleToMapping);
string[] directories = (from l in collection select l.Directory).Distinct().ToArray();
foreach (string directory in directories)
{
if (string.IsNullOrEmpty(directory))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
foreach ((string directory, FileHolder faceFileHolder, string checkFile) in collection)
{
if (File.Exists(checkFile))
continue;
File.Copy(faceFileHolder.FullName, checkFile);
}
}
private DatabaseFileRoot GetDatabaseFileRoot()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "files.json");
string json = File.ReadAllText(file);
DatabaseFileRoot? databaseFileRoot = JsonSerializer.Deserialize<DatabaseFileRoot>(json);
if (databaseFileRoot is null)
throw new NullReferenceException(nameof(databaseFileRoot));
return databaseFileRoot;
}
private Marker[] GetMarkers()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "markers.json");
string json = File.ReadAllText(file);
Marker[]? markerRoot = JsonSerializer.Deserialize<Marker[]>(json);
if (markerRoot is null)
throw new NullReferenceException(nameof(markerRoot));
return markerRoot;
}
private static Dictionary<string, DatabaseFile> Get(DatabaseFileRoot databaseFileRoot)
{
Dictionary<string, DatabaseFile> fileUidToFile = new();
for (int i = 0; i < databaseFileRoot.Files.Count; i++)
fileUidToFile.Add(databaseFileRoot.Files[i].FileUid, databaseFileRoot.Files[i]);
return fileUidToFile;
}
private static MarkerWith GetMarkerWith(int? dlib, DatabaseFile databaseFile, Marker marker, int? count, double? percent, int? normalizedRectangle, long? personKey, string personKeyFormatted)
{
return new(marker.MarkerUid,
marker.FileUid,
marker.MarkerType,
marker.MarkerSrc,
marker.MarkerName,
marker.MarkerReview,
marker.MarkerInvalid,
marker.SubjUid,
marker.SubjSrc,
marker.FaceId,
marker.FaceDist,
marker.EmbeddingsJson,
marker.LandmarksJson,
marker.X,
marker.Y,
marker.W,
marker.H,
marker.Q,
marker.Size,
marker.Score,
marker.Thumb,
marker.MatchedAt,
marker.CreatedAt,
marker.UpdatedAt,
databaseFile.Id,
databaseFile.FileName,
dlib,
count,
percent,
normalizedRectangle,
personKey,
personKeyFormatted);
}
private static Dictionary<string, List<Face>> GetFacesByFileName(List<Item> filteredItems)
{
Dictionary<string, List<Face>> results = new();
string key;
foreach (Item item in filteredItems)
{
foreach (Face face in item.Faces)
{
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null)
continue;
key = Path.GetFileNameWithoutExtension(face.Mapping.MappingFromItem.RelativePath);
if (!results.ContainsKey(key))
results.Add(key, new());
results[key].Add(face);
}
}
return results;
}
public void FindMatch(List<Item> filteredItems)
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
int? dlib;
double? percent;
long? personKey;
const int zero = 0;
List<Face>? matches;
MarkerWith markerWith;
int? normalizedRectangle;
string personKeyFormatted;
DatabaseFile? databaseFile;
PersonBirthday personBirthday;
Marker[] markers = GetMarkers();
string fileNameWithoutExtension;
PersonContainer[]? personContainers;
System.Drawing.Rectangle dlibRectangle;
System.Drawing.Rectangle prismRectangle;
System.Drawing.Rectangle intersectRectangle;
(Face Face, double Percent)[] sortedCollection;
List<(Face Face, double Percent)> collection = new();
DatabaseFileRoot databaseFileRoot = GetDatabaseFileRoot();
Dictionary<string, DatabaseFile> fileUidToFile = Get(databaseFileRoot);
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
Dictionary<string, List<Face>> keyValuePairs = GetFacesByFileName(filteredItems);
foreach (Marker marker in markers)
{
dlib = null;
personKey = null;
collection.Clear();
normalizedRectangle = null;
personKeyFormatted = string.Empty;
normalizedRectangleToPersonContainers = null;
if (!fileUidToFile.TryGetValue(marker.FileUid, out databaseFile))
continue;
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.Combine("C:", databaseFile.FileName));
prismRectangle = new((int)(marker.X * databaseFile.FileWidth), (int)(marker.Y * databaseFile.FileHeight), (int)(marker.W * databaseFile.FileWidth), (int)(marker.H * databaseFile.FileHeight));
if (!keyValuePairs.TryGetValue(fileNameWithoutExtension, out matches) || !int.TryParse(fileNameWithoutExtension, out int id))
percent = null;
else
{
dlib = id;
_ = _IdThenNormalizedRectangleToPersonContainers.TryGetValue(dlib.Value, out normalizedRectangleToPersonContainers);
foreach (Face face in matches)
{
if (face.Location is null || face.OutputResolution is null)
continue;
dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
intersectRectangle = System.Drawing.Rectangle.Intersect(prismRectangle, dlibRectangle);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (dlibRectangle.Width * dlibRectangle.Height);
if (percent < 0.000001)
continue;
collection.Add(new(face, percent.Value));
}
}
if (!collection.Any())
percent = null;
else
{
sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray();
percent = sortedCollection[zero].Percent;
normalizedRectangle = sortedCollection[zero].Face.Mapping?.MappingFromLocation.NormalizedRectangle;
if (normalizedRectangleToPersonContainers is null || normalizedRectangle is null || !normalizedRectangleToPersonContainers.TryGetValue(normalizedRectangle.Value, out personContainers))
personContainers = null;
else
{
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKey = personBirthday.Value.Ticks;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
break;
}
}
}
markerWith = GetMarkerWith(dlib, databaseFile, marker, collection.Count, percent, normalizedRectangle, personKey, personKeyFormatted);
string json = JsonSerializer.Serialize(markerWith, new JsonSerializerOptions() { WriteIndented = true });
if (IPath.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "With", $"{marker.MarkerUid}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true))
continue;
}
}
public void SaveMarkers()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
double[]? encoding;
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "markers.json");
string json = File.ReadAllText(file);
Marker[]? markers = JsonSerializer.Deserialize<Marker[]>(json);
if (markers is null)
throw new NullReferenceException(nameof(markers));
foreach (Marker marker in markers)
{
encoding = JsonSerializer.Deserialize<double[]>(marker.EmbeddingsJson[1..^1]);
File.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "EmbeddingsJson", $"{marker.MarkerUid}.json"), marker.EmbeddingsJson);
if (encoding is null)
continue;
}
}
public void LoadMatches()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string json;
MarkerWith? markerWith;
List<MarkerWith> collection = new();
StringBuilder stringBuilder = new();
List<(int Count, MarkerWith MarkerWith)> countCollection = new();
List<(double Percent, MarkerWith MarkerWith)> percentCollection = new();
string[] files = Directory.GetFiles(Path.Combine(_Configuration.PhotoPrismDirectory, "With"), "*.json", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
json = File.ReadAllText(file);
markerWith = JsonSerializer.Deserialize<MarkerWith>(json);
if (markerWith is null || markerWith.DlibId is null)
continue;
collection.Add(markerWith);
if (markerWith.Count is null || markerWith.Count.Value == 0)
continue;
countCollection.Add(new(markerWith.Count.Value, markerWith));
if (markerWith.Percent is null)
continue;
percentCollection.Add(new(markerWith.Percent.Value, markerWith));
if (string.IsNullOrEmpty(markerWith.PersonKeyFormatted))
continue;
_ = stringBuilder.
Append("update `markers` set subj_src = 'manual' marker_name = '").
Append(markerWith.PersonKeyFormatted).
Append("' where marker_uid = '").
Append(markerWith.MarkerUid).
AppendLine("';");
}
(int, MarkerWith)[] countSorted = countCollection.OrderByDescending(l => l.Count).ToArray();
(double, MarkerWith)[] percentSorted = percentCollection.OrderBy(l => l.Percent).ToArray();
if (collection.Any())
{ }
File.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "marker_name_update.sql"), stringBuilder.ToString());
}
public Dictionary<int, Dictionary<int, PersonContainer[]>> GetMissing(Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping)
{
Dictionary<int, Dictionary<int, PersonContainer[]>> results = new();
foreach (KeyValuePair<int, Dictionary<int, PersonContainer[]>> normalizedRectangleToPersonContainers in _IdThenNormalizedRectangleToPersonContainers)
{
if (idToNormalizedRectangleToMapping.ContainsKey(normalizedRectangleToPersonContainers.Key))
continue;
results.Add(normalizedRectangleToPersonContainers.Key, normalizedRectangleToPersonContainers.Value);
}
return results;
}
public void UpdatedPersonKeyToRanges(Configuration configuration, long ticks, Mapping[] mappingCollection)
{
Dictionary<long, (long LCL, long Minimum, long Maximum, long UCL)> personKeyToRanges = new();
Stateless.MapLogic.SetPersonTicks(configuration, ticks, mappingCollection, personKeyToRanges, _IdThenNormalizedRectangleToPersonContainers);
_PersonKeyToRanges = personKeyToRanges;
}
}