diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 51d952b..d784604 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -379,7 +379,7 @@ public partial class DlibDotNet string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, List> sourceDirectoryChanges, - Dictionary> fileNameToCollection, + Dictionary> fileNameToCollection, Container container, int index, Item item, @@ -460,7 +460,7 @@ public partial class DlibDotNet collection = null; else _ = idToLocationContainers.TryGetValue(item.Property.Id.Value, out collection); - if (!fileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection)) + if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection)) mappingFromPhotoPrismCollection = null; faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, collection, mappingFromPhotoPrismCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) @@ -501,7 +501,7 @@ public partial class DlibDotNet string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, - Dictionary> fileNameToCollection, + Dictionary> fileNameToCollection, Container container, Item[] filteredItems, string message) @@ -638,7 +638,7 @@ public partial class DlibDotNet return new(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); } - private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, ReadOnlyDictionary>> idToLocationContainers, MapLogic mapLogic) + private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary> fileNameToCollection, ReadOnlyDictionary>> idToLocationContainers, MapLogic mapLogic) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -782,7 +782,7 @@ public partial class DlibDotNet } Dictionary> idToNormalizedRectangleToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToNormalizedRectangleToFace(distinctFilteredMappingCollection); if (Directory.Exists(fPhotoPrismContentDirectory)) - F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, ticks, distinctFilteredFaces, mapLogic); + F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, ticks, distinctFilteredFaces, mapLogic); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) mapLogic.SaveShortcutsForOutputResolutionsDuringMapLogic(containers, personKeyToIds, dFacesContentDirectory, distinctFilteredMappingCollection); if (!string.IsNullOrEmpty(_Configuration.PersonCharacters)) @@ -1099,7 +1099,7 @@ public partial class DlibDotNet string fPhotoPrismContentDirectory; string fPhotoPrismSingletonDirectory; Dictionary> personKeyToIds; - Dictionary> fileNameToCollection; + Dictionary> fileNameToCollection; (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); diff --git a/PhotoPrism/Models/DatabaseFile.cs b/PhotoPrism/Models/DatabaseFile.cs index 2cac083..95edf2f 100644 --- a/PhotoPrism/Models/DatabaseFile.cs +++ b/PhotoPrism/Models/DatabaseFile.cs @@ -52,7 +52,7 @@ public record DatabaseFile( [property: JsonPropertyName("updated_in")] string UpdatedIn, [property: JsonPropertyName("published_at")] object PublishedAt, [property: JsonPropertyName("deleted_at")] object DeletedAt) -{ +{ internal static Shared.Models.DatabaseFile Map(DatabaseFile databaseFile) { @@ -61,51 +61,51 @@ public record DatabaseFile( (int fileWidth, int fileHeight) = (int.Parse(databaseFile.FileWidth), int.Parse(databaseFile.FileHeight)); result = new(id, photoId, - databaseFile.PhotoUid, - databaseFile.PhotoTakenAt, - databaseFile.TimeIndex, - databaseFile.MediaId, - databaseFile.MediaUtc, - databaseFile.InstanceId, - databaseFile.FileUid, - databaseFile.FileName, - databaseFile.FileRoot, - databaseFile.OriginalName, - databaseFile.FileHash, - databaseFile.FileSize, - databaseFile.FileCodec, - databaseFile.FileType, - databaseFile.MediaType, - databaseFile.FileMime, - databaseFile.FilePrimary, - databaseFile.FileSidecar, - databaseFile.FileMissing, - databaseFile.FilePortrait, - databaseFile.FileVideo, - databaseFile.FileDuration, - databaseFile.FileFps, - databaseFile.FileFrames, + F_PhotoPrism.HexStringToString(databaseFile.PhotoUid), + F_PhotoPrism.HexStringToString(databaseFile.PhotoTakenAt), + F_PhotoPrism.HexStringToString(databaseFile.TimeIndex), + F_PhotoPrism.HexStringToString(databaseFile.MediaId), + F_PhotoPrism.HexStringToString(databaseFile.MediaUtc), + F_PhotoPrism.HexStringToString(databaseFile.InstanceId), + F_PhotoPrism.HexStringToString(databaseFile.FileUid), + F_PhotoPrism.HexStringToString(databaseFile.FileName), + F_PhotoPrism.HexStringToString(databaseFile.FileRoot), + F_PhotoPrism.HexStringToString(databaseFile.OriginalName), + F_PhotoPrism.HexStringToString(databaseFile.FileHash), + F_PhotoPrism.HexStringToString(databaseFile.FileSize), + F_PhotoPrism.HexStringToString(databaseFile.FileCodec), + F_PhotoPrism.HexStringToString(databaseFile.FileType), + F_PhotoPrism.HexStringToString(databaseFile.MediaType), + F_PhotoPrism.HexStringToString(databaseFile.FileMime), + F_PhotoPrism.HexStringToString(databaseFile.FilePrimary), + F_PhotoPrism.HexStringToString(databaseFile.FileSidecar), + F_PhotoPrism.HexStringToString(databaseFile.FileMissing), + F_PhotoPrism.HexStringToString(databaseFile.FilePortrait), + F_PhotoPrism.HexStringToString(databaseFile.FileVideo), + F_PhotoPrism.HexStringToString(databaseFile.FileDuration), + F_PhotoPrism.HexStringToString(databaseFile.FileFps), + F_PhotoPrism.HexStringToString(databaseFile.FileFrames), fileWidth, fileHeight, - databaseFile.FileOrientation, - databaseFile.FileOrientationSrc, - databaseFile.FileProjection, - databaseFile.FileAspectRatio, - databaseFile.FileHdr, - databaseFile.FileWatermark, - databaseFile.FileColorProfile, - databaseFile.FileMainColor, - databaseFile.FileColors, - databaseFile.FileLuminance, - databaseFile.FileDiff, - databaseFile.FileChroma, - databaseFile.FileSoftware, - databaseFile.FileError, - databaseFile.ModTime, - databaseFile.CreatedAt, - databaseFile.CreatedIn, - databaseFile.UpdatedAt, - databaseFile.UpdatedIn, + F_PhotoPrism.HexStringToString(databaseFile.FileOrientation), + F_PhotoPrism.HexStringToString(databaseFile.FileOrientationSrc), + F_PhotoPrism.HexStringToString(databaseFile.FileProjection), + F_PhotoPrism.HexStringToString(databaseFile.FileAspectRatio), + F_PhotoPrism.HexStringToString(databaseFile.FileHdr), + F_PhotoPrism.HexStringToString(databaseFile.FileWatermark), + F_PhotoPrism.HexStringToString(databaseFile.FileColorProfile), + F_PhotoPrism.HexStringToString(databaseFile.FileMainColor), + F_PhotoPrism.HexStringToString(databaseFile.FileColors), + F_PhotoPrism.HexStringToString(databaseFile.FileLuminance), + F_PhotoPrism.HexStringToString(databaseFile.FileDiff), + F_PhotoPrism.HexStringToString(databaseFile.FileChroma), + F_PhotoPrism.HexStringToString(databaseFile.FileSoftware), + F_PhotoPrism.HexStringToString(databaseFile.FileError), + F_PhotoPrism.HexStringToString(databaseFile.ModTime), + F_PhotoPrism.HexStringToString(databaseFile.CreatedAt), + F_PhotoPrism.HexStringToString(databaseFile.CreatedIn), + F_PhotoPrism.HexStringToString(databaseFile.UpdatedAt), + F_PhotoPrism.HexStringToString(databaseFile.UpdatedIn), databaseFile.PublishedAt, databaseFile.DeletedAt); return result; diff --git a/PhotoPrism/Models/Marker.cs b/PhotoPrism/Models/Marker.cs index feba59b..6c026f5 100644 --- a/PhotoPrism/Models/Marker.cs +++ b/PhotoPrism/Models/Marker.cs @@ -32,28 +32,28 @@ public record Marker( Shared.Models.Marker result; (double x, double y, double w, double h, double score) = (double.Parse(marker.X), double.Parse(marker.Y), double.Parse(marker.W), double.Parse(marker.H), double.Parse(marker.Score)); result = new( - marker.MarkerUid, - marker.FileUid, - marker.MarkerType, - marker.MarkerSrc, - marker.MarkerName, - marker.MarkerReview, - marker.MarkerInvalid, - marker.SubjUid, - marker.SubjSrc, - marker.FaceId, - marker.FaceDist, + F_PhotoPrism.HexStringToString(marker.MarkerUid), + F_PhotoPrism.HexStringToString(marker.FileUid), + F_PhotoPrism.HexStringToString(marker.MarkerType), + F_PhotoPrism.HexStringToString(marker.MarkerSrc), + F_PhotoPrism.HexStringToString(marker.MarkerName), + F_PhotoPrism.HexStringToString(marker.MarkerReview), + F_PhotoPrism.HexStringToString(marker.MarkerInvalid), + F_PhotoPrism.HexStringToString(marker.SubjUid), + F_PhotoPrism.HexStringToString(marker.SubjSrc), + F_PhotoPrism.HexStringToString(marker.FaceId), + F_PhotoPrism.HexStringToString(marker.FaceDist), x, y, w, h, - marker.Q, - marker.Size, + F_PhotoPrism.HexStringToString(marker.Q), + F_PhotoPrism.HexStringToString(marker.Size), score, - marker.Thumb, - marker.MatchedAt, - marker.CreatedAt, - marker.UpdatedAt); + F_PhotoPrism.HexStringToString(marker.Thumb), + F_PhotoPrism.HexStringToString(marker.MatchedAt), + F_PhotoPrism.HexStringToString(marker.CreatedAt), + F_PhotoPrism.HexStringToString(marker.UpdatedAt)); return result; } diff --git a/PhotoPrism/Models/_F_PhotoPrism.cs b/PhotoPrism/Models/_F_PhotoPrism.cs index c66d92c..9b0e83e 100644 --- a/PhotoPrism/Models/_F_PhotoPrism.cs +++ b/PhotoPrism/Models/_F_PhotoPrism.cs @@ -46,14 +46,29 @@ public class F_PhotoPrism private static Dictionary> GetFileUIdToMarkers(string fPhotoPrismSingletonDirectory) { Dictionary> results = new(); + string fileUid; Marker[]? markers = GetMarkers(fPhotoPrismSingletonDirectory); if (markers is null) throw new NullReferenceException(nameof(markers)); foreach (Marker marker in markers) { - if (!results.ContainsKey(marker.FileUid)) - results.Add(marker.FileUid, new()); - results[marker.FileUid].Add(Marker.Map(marker)); + fileUid = HexStringToString(marker.FileUid); + if (!results.ContainsKey(fileUid)) + results.Add(fileUid, new()); + results[fileUid].Add(Marker.Map(marker)); + } + return results; + } + + private static Dictionary>? GetCollectionFile(string fileName) + { + Dictionary>? results; + if (!File.Exists(fileName)) + results = null; + else + { + string json = File.ReadAllText(fileName); + results = JsonSerializer.Deserialize>>(json); } return results; } @@ -80,43 +95,86 @@ public class F_PhotoPrism return results; } - public static Dictionary> GetFileNameToCollection(string fPhotoPrismSingletonDirectory) + public static Dictionary> GetFileNameToCollection(string fPhotoPrismSingletonDirectory) { - Dictionary> results = new(); - List? makers; - MappingFromPhotoPrism mappingFromPhotoPrism; - List? mappingFromPhotoPrismCollection; - List? databaseFiles = GetDatabaseFiles(fPhotoPrismSingletonDirectory); - if (databaseFiles is not null) + Dictionary>? results; + string fileName = Path.Combine(fPhotoPrismSingletonDirectory, "collection.json"); + results = GetCollectionFile(fileName); + if (results is null) { - Dictionary> fileUIdToMarkers = GetFileUIdToMarkers(fPhotoPrismSingletonDirectory); - foreach (Shared.Models.DatabaseFile databaseFile in databaseFiles) + int id; + results = new(); + string fileNameWithoutExtension; + List? makers; + MappingFromPhotoPrism mappingFromPhotoPrism; + List? mappingFromPhotoPrismCollection; + List? databaseFiles = GetDatabaseFiles(fPhotoPrismSingletonDirectory); + if (databaseFiles is not null) { - if (!results.TryGetValue(databaseFile.FileName, out mappingFromPhotoPrismCollection)) + Dictionary> fileUIdToMarkers = GetFileUIdToMarkers(fPhotoPrismSingletonDirectory); + foreach (Shared.Models.DatabaseFile databaseFile in databaseFiles) { - results.Add(databaseFile.FileName, new()); - if (!results.TryGetValue(databaseFile.FileName, out mappingFromPhotoPrismCollection)) - throw new Exception(); + 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); } - 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; } - public static void WriteMatches(string fPhotoPrismContentDirectory, string personBirthdayFormat, long ticks, List distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic) + private static void PopulateSubjects(string mappingDefaultName, string personBirthdayFormat, List subjects, StringBuilder stringBuilder, PersonContainer[] personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, double Percent)[] sortedCollection) { long? personKey; + string personName; const int zero = 0; - int? normalizedRectangle; string personKeyFormatted; - List subjects = new(); PersonBirthday personBirthday; - string personDisplayDirectoryName; + foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Shared.Models.Marker marker, double percent) in sortedCollection) + { + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any()) + continue; + if (IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName) || IPerson.IsDefaultName(mappingDefaultName, personContainer.Person)) + continue; + personBirthday = personContainer.Birthdays[zero]; + personKey = personBirthday.Value.Ticks; + personName = personContainer.Person.GetFullName(); + personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); + subjects.Add($"update `subjects` set subj_alias = '{personKeyFormatted}' where subj_name = '{personName}';"); + _ = stringBuilder. + Append("update `markers` set subj_src = 'manual', marker_name = '"). + Append(personName). + Append("' where marker_uid = '"). + Append(marker.MarkerUid). + AppendLine("';"); + } + } + } + + public static void WriteMatches(string fPhotoPrismContentDirectory, string mappingDefaultName, string personBirthdayFormat, long ticks, List distinctFilteredFaces, Shared.Models.Methods.IMapLogic mapLogic) + { + string file; + string text; + int? normalizedRectangle; + List subjects = new(); StringBuilder stringBuilder = new(); PersonContainer[]? personContainers; System.Drawing.Rectangle dlibRectangle; @@ -158,28 +216,34 @@ public class F_PhotoPrism if (!collection.Any()) continue; sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray(); - foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Shared.Models.Marker marker, double percent) in sortedCollection) - { - 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; - personDisplayDirectoryName = personContainer.DisplayDirectoryName; - personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); - subjects.Add($"update `subjects` set subj_alias = '{personKeyFormatted}' where subj_name = '{personDisplayDirectoryName}';"); - _ = stringBuilder. - Append("update `markers` set subj_src = 'manual', marker_name = '"). - Append(personDisplayDirectoryName). - Append("' where marker_uid = '"). - Append(marker.MarkerUid). - AppendLine("';"); - } - } + PopulateSubjects(mappingDefaultName, personBirthdayFormat, subjects, stringBuilder, personContainers, sortedCollection); } - File.WriteAllLines(Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-subject_alias_update.sql"), subjects.Distinct()); - File.WriteAllText(Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-marker_name_update.sql"), stringBuilder.ToString()); + if (subjects.Any()) + { + file = Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-subject_alias_update.sql"); + text = string.Join(Environment.NewLine, subjects.Distinct()); + _ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); + file = Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-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; } } \ No newline at end of file diff --git a/Shared/Models/DatabaseFile.cs b/Shared/Models/DatabaseFile.cs index ba0d899..728613c 100644 --- a/Shared/Models/DatabaseFile.cs +++ b/Shared/Models/DatabaseFile.cs @@ -5,20 +5,20 @@ public record DatabaseFile( int PhotoId, string PhotoUid, string PhotoTakenAt, - string TimeIndex, - string MediaId, + string? TimeIndex, + string? MediaId, string MediaUtc, - string InstanceId, - string FileUid, - string FileName, - string FileRoot, - string OriginalName, - string FileHash, + string? InstanceId, + string? FileUid, + string? FileName, + string? FileRoot, + string? OriginalName, + string? FileHash, string FileSize, - string FileCodec, - string FileType, - string MediaType, - string FileMime, + string? FileCodec, + string? FileType, + string? MediaType, + string? FileMime, string FilePrimary, string FileSidecar, string FileMissing, @@ -30,19 +30,19 @@ public record DatabaseFile( int FileWidth, int FileHeight, string FileOrientation, - string FileOrientationSrc, + string? FileOrientationSrc, string FileProjection, string FileAspectRatio, string FileHdr, string FileWatermark, - string FileColorProfile, - string FileMainColor, - string FileColors, - string FileLuminance, + string? FileColorProfile, + string? FileMainColor, + string? FileColors, + string? FileLuminance, string FileDiff, string FileChroma, string FileSoftware, - string FileError, + string? FileError, string ModTime, string CreatedAt, string CreatedIn, diff --git a/Shared/Models/Marker.cs b/Shared/Models/Marker.cs index f661032..4d0af5a 100644 --- a/Shared/Models/Marker.cs +++ b/Shared/Models/Marker.cs @@ -1,16 +1,16 @@ namespace View_by_Distance.Shared.Models; public record Marker( - string MarkerUid, - string FileUid, - string MarkerType, - string MarkerSrc, - string MarkerName, + string? MarkerUid, + string? FileUid, + string? MarkerType, + string? MarkerSrc, + string? MarkerName, string MarkerReview, string MarkerInvalid, - string SubjUid, - string SubjSrc, - string FaceId, + string? SubjUid, + string? SubjSrc, + string? FaceId, string FaceDist, double X, double Y, @@ -19,7 +19,7 @@ public record Marker( string Q, string Size, double Score, - string Thumb, + string? Thumb, string MatchedAt, string CreatedAt, string UpdatedAt); \ No newline at end of file