259 lines
12 KiB
C#
259 lines
12 KiB
C#
using System.Drawing;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using View_by_Distance.Shared.Models;
|
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
|
|
|
namespace View_by_Distance.PhotoPrism.Models;
|
|
|
|
public class F_PhotoPrism
|
|
{
|
|
|
|
private static JsonProperty[] GetJsonProperty(string fileName)
|
|
{
|
|
JsonProperty[] results;
|
|
if (!File.Exists(fileName))
|
|
results = Array.Empty<JsonProperty>();
|
|
else
|
|
{
|
|
string json = File.ReadAllText(fileName);
|
|
JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json);
|
|
if (jsonElements is null || !jsonElements.Any())
|
|
results = Array.Empty<JsonProperty>();
|
|
else
|
|
{
|
|
JsonElement jsonElement = jsonElements.Last();
|
|
if (jsonElement.ValueKind != JsonValueKind.Object)
|
|
results = Array.Empty<JsonProperty>();
|
|
else
|
|
results = jsonElement.EnumerateObject().ToArray();
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static Marker[]? GetMarkers(string fPhotoPrismSingletonDirectory)
|
|
{
|
|
Marker[]? results;
|
|
string file = Path.Combine(fPhotoPrismSingletonDirectory, "markers.json");
|
|
JsonProperty[] jsonProperties = GetJsonProperty(file);
|
|
if (!jsonProperties.Any())
|
|
results = null;
|
|
else
|
|
results = JsonSerializer.Deserialize<Marker[]>(jsonProperties.Last().Value);
|
|
return results;
|
|
}
|
|
|
|
private static Dictionary<string, List<Shared.Models.Marker>> GetFileUIdToMarkers(string fPhotoPrismSingletonDirectory)
|
|
{
|
|
Dictionary<string, List<Shared.Models.Marker>> results = new();
|
|
string fileUid;
|
|
Marker[]? markers = GetMarkers(fPhotoPrismSingletonDirectory);
|
|
if (markers is null)
|
|
throw new NullReferenceException(nameof(markers));
|
|
foreach (Marker marker in markers)
|
|
{
|
|
fileUid = HexStringToString(marker.FileUid);
|
|
if (!results.ContainsKey(fileUid))
|
|
results.Add(fileUid, new());
|
|
results[fileUid].Add(Marker.Map(marker));
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static Dictionary<int, List<MappingFromPhotoPrism>>? GetCollectionFile(string fileName)
|
|
{
|
|
Dictionary<int, List<MappingFromPhotoPrism>>? results;
|
|
if (!File.Exists(fileName))
|
|
results = null;
|
|
else
|
|
{
|
|
string json = File.ReadAllText(fileName);
|
|
results = JsonSerializer.Deserialize<Dictionary<int, List<MappingFromPhotoPrism>>>(json);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<Shared.Models.DatabaseFile>? GetDatabaseFiles(string fPhotoPrismSingletonDirectory)
|
|
{
|
|
List<Shared.Models.DatabaseFile>? results;
|
|
string file = Path.Combine(fPhotoPrismSingletonDirectory, "files.json");
|
|
JsonProperty[] jsonProperties = GetJsonProperty(file);
|
|
if (!jsonProperties.Any())
|
|
results = null;
|
|
else
|
|
{
|
|
results = new();
|
|
DatabaseFile[]? databaseFiles = JsonSerializer.Deserialize<DatabaseFile[]>(jsonProperties.Last().Value);
|
|
if (databaseFiles is null)
|
|
results = null;
|
|
else
|
|
{
|
|
foreach (DatabaseFile databaseFile in databaseFiles)
|
|
results.Add(DatabaseFile.Map(databaseFile));
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
public static Dictionary<int, List<MappingFromPhotoPrism>> GetFileNameToCollection(string fPhotoPrismSingletonDirectory)
|
|
{
|
|
Dictionary<int, List<MappingFromPhotoPrism>>? results;
|
|
string fileName = Path.Combine(fPhotoPrismSingletonDirectory, "collection.json");
|
|
results = GetCollectionFile(fileName);
|
|
if (results is null)
|
|
{
|
|
int id;
|
|
results = new();
|
|
string fileNameWithoutExtension;
|
|
List<Shared.Models.Marker>? makers;
|
|
MappingFromPhotoPrism mappingFromPhotoPrism;
|
|
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
|
|
List<Shared.Models.DatabaseFile>? databaseFiles = GetDatabaseFiles(fPhotoPrismSingletonDirectory);
|
|
if (databaseFiles is not null)
|
|
{
|
|
Dictionary<string, List<Shared.Models.Marker>> fileUIdToMarkers = GetFileUIdToMarkers(fPhotoPrismSingletonDirectory);
|
|
foreach (Shared.Models.DatabaseFile databaseFile in databaseFiles)
|
|
{
|
|
if (databaseFile.FileName is null || databaseFile.FileUid is null)
|
|
continue;
|
|
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(databaseFile.FileName);
|
|
if (!int.TryParse(fileNameWithoutExtension, out id))
|
|
continue;
|
|
|
|
if (!results.TryGetValue(id, out mappingFromPhotoPrismCollection))
|
|
{
|
|
results.Add(id, new());
|
|
if (!results.TryGetValue(id, out mappingFromPhotoPrismCollection))
|
|
throw new Exception();
|
|
}
|
|
if (!fileUIdToMarkers.TryGetValue(databaseFile.FileUid, out makers))
|
|
mappingFromPhotoPrism = new(databaseFile, new());
|
|
else
|
|
mappingFromPhotoPrism = new(databaseFile, makers);
|
|
mappingFromPhotoPrismCollection.Add(mappingFromPhotoPrism);
|
|
}
|
|
}
|
|
string json = JsonSerializer.Serialize(results);
|
|
_ = IPath.WriteAllText(fileName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static void PopulateSubjects(string mappingDefaultName, string personBirthdayFormat, List<string> subjects, StringBuilder stringBuilder, PersonContainer[] personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection)
|
|
{
|
|
long? personKey;
|
|
const int zero = 0;
|
|
string personKeyFormatted;
|
|
PersonBirthday personBirthday;
|
|
foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Shared.Models.Marker marker, float percent) in sortedCollection)
|
|
{
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
|
|
continue;
|
|
if (IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName))
|
|
continue;
|
|
personBirthday = personContainer.Birthdays[zero];
|
|
personKey = personBirthday.Value.Ticks;
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday);
|
|
subjects.Add($"update `subjects` set subj_alias = '{personKeyFormatted}' where subj_name = '{personContainer.DisplayDirectoryName}';");
|
|
_ = stringBuilder.
|
|
Append("update `markers` set subj_src = 'manual', marker_name = '").
|
|
Append(personContainer.DisplayDirectoryName).
|
|
Append("' where marker_uid = '").
|
|
Append(marker.MarkerUid).
|
|
AppendLine("';");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void WriteMatches(string fPhotoPrismContentDirectory, string mappingDefaultName, string personBirthdayFormat, float[] rectangleIntersectMinimums, long ticks, List<Face> distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic)
|
|
{
|
|
string file;
|
|
string text;
|
|
float dlibArea;
|
|
float? percent;
|
|
string directory;
|
|
int width, height;
|
|
int? wholePercentages;
|
|
RectangleF? prismRectangle;
|
|
List<string> subjects = new();
|
|
DateTime dateTime = new(ticks);
|
|
int dlibLocationWholePercentages;
|
|
PersonContainer[]? personContainers;
|
|
StringBuilder stringBuilder = new();
|
|
RectangleF? dlibPercentagesRectangle;
|
|
float rectangleIntersectMinimum = rectangleIntersectMinimums.Min();
|
|
Dictionary<int, PersonContainer[]>? wholePercentagesToPersonContainers;
|
|
(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection;
|
|
List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)> collection = new();
|
|
foreach (Face face in distinctFilteredFaces)
|
|
{
|
|
collection.Clear();
|
|
wholePercentages = face.Mapping?.MappingFromLocation?.WholePercentages;
|
|
if (wholePercentages is null)
|
|
continue;
|
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null)
|
|
continue;
|
|
if (face.Mapping.MappingFromPhotoPrismCollection is null)
|
|
continue;
|
|
(_, wholePercentagesToPersonContainers) = mapLogic.GetWholePercentagesToPersonContainers(face.Mapping.MappingFromItem.Id);
|
|
if (wholePercentagesToPersonContainers is null || !wholePercentagesToPersonContainers.TryGetValue(wholePercentages.Value, out personContainers))
|
|
continue;
|
|
(width, height) = IOutputResolution.Get(face.OutputResolution);
|
|
dlibLocationWholePercentages = ILocation.GetWholePercentages(height, face.Location, Shared.Models.Stateless.ILocation.Digits, width);
|
|
dlibPercentagesRectangle = ILocation.GetPercentagesRectangle(Shared.Models.Stateless.ILocation.Digits, dlibLocationWholePercentages);
|
|
if (dlibPercentagesRectangle is null)
|
|
continue;
|
|
dlibArea = dlibPercentagesRectangle.Value.Width * dlibPercentagesRectangle.Value.Height;
|
|
foreach (MappingFromPhotoPrism mappingFromPhotoPrism in face.Mapping.MappingFromPhotoPrismCollection)
|
|
{
|
|
foreach (Shared.Models.Marker marker in mappingFromPhotoPrism.Markers)
|
|
{
|
|
prismRectangle = ILocation.GetPercentagesRectangle(mappingFromPhotoPrism.DatabaseFile, marker, face.OutputResolution);
|
|
if (prismRectangle is null)
|
|
continue;
|
|
percent = ILocation.GetIntersectPercent(dlibPercentagesRectangle.Value, dlibArea, prismRectangle.Value);
|
|
if (percent is null || percent < rectangleIntersectMinimum)
|
|
continue;
|
|
collection.Add(new(mappingFromPhotoPrism, marker, percent.Value));
|
|
}
|
|
}
|
|
if (!collection.Any())
|
|
continue;
|
|
sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray();
|
|
PopulateSubjects(mappingDefaultName, personBirthdayFormat, subjects, stringBuilder, personContainers, sortedCollection);
|
|
}
|
|
if (subjects.Any())
|
|
{
|
|
directory = Path.Combine(fPhotoPrismContentDirectory, dateTime.ToString("yyyy-MM-dd"));
|
|
if (!Directory.Exists(directory))
|
|
_ = Directory.CreateDirectory(directory);
|
|
file = Path.Combine(directory, $"{ticks}-{rectangleIntersectMinimum}-subject_alias_update.sql");
|
|
text = string.Join(Environment.NewLine, subjects.Distinct());
|
|
_ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
file = Path.Combine(directory, $"{ticks}-{rectangleIntersectMinimum}-marker_name_update.sql");
|
|
text = stringBuilder.ToString();
|
|
_ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
}
|
|
}
|
|
|
|
internal static string HexStringToString(string text)
|
|
{
|
|
string result;
|
|
if (text.Length < 2 || text[0] != '0' || text[1] != 'x')
|
|
result = text;
|
|
else
|
|
{
|
|
string after = text[2..];
|
|
byte[] bytes = Enumerable.Range(0, after.Length)
|
|
.Where(x => x % 2 == 0)
|
|
.Select(x => Convert.ToByte(after.Substring(x, 2), 16))
|
|
.ToArray();
|
|
result = Encoding.UTF8.GetString(bytes);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} |