diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 93bf17a..8f6b8e5 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -25,11 +25,14 @@ public partial class DlibDotNet private readonly C_Resize _Resize; private readonly F_Random _Random; private readonly IConsole _Console; + private readonly string? _GEDCOMFile; private readonly E_Distance _Distance; private readonly Serilog.ILogger? _Log; private readonly D2_FaceParts _FaceParts; private readonly AppSettings _AppSettings; private readonly List _Exceptions; + private readonly string[]? _GEDCOMFooterLines; + private readonly string[]? _GEDCOMHeaderLines; private readonly IsEnvironment _IsEnvironment; private readonly bool _PropertyRootExistedBefore; private readonly PersonContainer[] _PersonContainers; @@ -101,7 +104,12 @@ public partial class DlibDotNet _MapConfiguration = Get(configuration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, _FaceParts.FileNameExtension); _Distance = new(configuration.DistanceMoveUnableToMatch, configuration.DistanceRenameToMatch, _Configuration.FaceConfidencePercent, configuration.RangeFaceConfidence); if (_PropertyRootExistedBefore || !_ArgZeroIsConfigurationRootDirectory) + { + _GEDCOMFile = null; + _GEDCOMFooterLines = null; + _GEDCOMHeaderLines = null; _PersonContainers = Array.Empty(); + } else { int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); @@ -115,8 +123,10 @@ public partial class DlibDotNet if (rootResultsDirectory is null) throw new Exception(); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); + _GEDCOMFile = Path.GetFullPath(string.Concat(peopleRootDirectory, configuration.GEDCOMFile)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, "{}")); - _PersonContainers = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension); + (_GEDCOMHeaderLines, Dictionary> individuals, _GEDCOMFooterLines) = Shared.Models.Stateless.Methods.IPerson.GetIndividuals(_GEDCOMFile); + _PersonContainers = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals); } { (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple( @@ -182,7 +192,7 @@ public partial class DlibDotNet return result; } - private void Verify(Models.Configuration configuration) + private static void Verify(Models.Configuration configuration) { if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0])) throw new NullReferenceException($"{nameof(configuration.OutputResolutions)} must be fileNameToCollection valid outputResolution!"); @@ -1044,66 +1054,6 @@ public partial class DlibDotNet } } - private void CreateTree(PersonContainer[] personContainers, long ticks, string a2PeopleContentDirectory, Dictionary> personKeyToIds) - { - string by; - string[] matches; - const int zero = 0; - string[] pGedFiles; - string[] pGedLines; - string personKeyFormatted; - List distinct = new(); - PersonBirthday personBirthday; - string rootDirectory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-Tree"); - List lines = new() - { - "0 HEAD", - "1 SOUR DlibDotNet", - $"1 FILE {ticks}", - $"1 DATE {new DateTime(ticks):dd MMM yyyy}", - "1 DEST ANSTFILE", - "1 GEDC", - "2 VERS 5.5.1", - "2 FORM LINEAGE-LINKED", - "1 SUBM @1980-01-17_05@", - "2 NAME Mike Phares Jr", - "1 SUBN", - }; - foreach (PersonContainer personContainer in personContainers) - { - if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any()) - continue; - if (personContainer.DisplayDirectoryName == _Configuration.MappingDefaultName || personContainer.Person.Name.Alias.Value == "Z") - continue; - if (distinct.Contains(personContainer.Key.Value)) - continue; - distinct.Add(personContainer.Key.Value); - if (!personKeyToIds.ContainsKey(personContainer.Key.Value)) - continue; - personBirthday = personContainer.Birthdays[zero]; - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); - by = Shared.Models.Stateless.Methods.IPersonBirthday.IsCounterPersonBirthday(personBirthday) ? _Configuration.PropertyConfiguration.ResultAllInOne : "People"; - matches = (from l in personContainer.DisplayDirectoryAllFiles where !string.IsNullOrEmpty(personKeyFormatted) && l.Contains(personKeyFormatted) select l).ToArray(); - if (!matches.Any()) - continue; - pGedFiles = (from l in matches where l.EndsWith(".pged") select l).ToArray(); - if (!pGedFiles.Any()) - continue; - pGedLines = File.ReadAllLines(pGedFiles[0]); - lines.AddRange(pGedLines); - // segments = personContainer.DisplayDirectoryName.Split(_Configuration.PersonCharacters.ToArray()); - // if (segments.Length < 2) - // directory = Path.Combine(rootDirectory, $"000 {personKeyFormatted} {personContainer.DisplayDirectoryName}"); - // else - // directory = Path.Combine(rootDirectory, $"{segments[1].PadLeft(3, '0')} {personKeyFormatted} {personContainer.DisplayDirectoryName}"); - // if (Directory.Exists(directory)) - // continue; - // _ = Directory.CreateDirectory(directory); - } - lines.Add("0 TRLR"); - File.WriteAllLines(Path.Combine(a2PeopleContentDirectory, $"{ticks}.ged"), lines); - } - private void Search(long ticks, string argZero, string propertyRoot) { int t; @@ -1162,8 +1112,8 @@ public partial class DlibDotNet containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _PersonContainers, ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); personKeyToIds = mapLogic.GetPersonKeyToIds(); - if (a2PeopleContentDirectory is not null) - CreateTree(_PersonContainers, ticks, a2PeopleContentDirectory, personKeyToIds); + if (!string.IsNullOrEmpty(_GEDCOMFile) && !string.IsNullOrEmpty(a2PeopleContentDirectory) && _GEDCOMHeaderLines is not null && _GEDCOMFooterLines is not null) + Shared.Models.Stateless.Methods.IPerson.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GEDCOMHeaderLines, _GEDCOMFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); Dictionary>> idToLocationContainers = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, eDistanceContentDirectory, fileNameToCollection, idToLocationContainers, mapLogic); diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 514dc34..bee728a 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -28,6 +28,7 @@ public class Configuration [Display(Name = "Force Face Last Write Time to Creation Time"), Required] public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } + [Display(Name = "GEDCOM File"), Required] public string GEDCOMFile { get; set; } [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } [Display(Name = "Ignore Relative Paths"), Required] public string[] IgnoreRelativePaths { get; set; } [Display(Name = "Julie Phares Copy Birthdays"), Required] public string[] JLinks { get; set; } @@ -133,6 +134,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); if (configuration.ForceResizeLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); + if (configuration.GEDCOMFile is null) + throw new NullReferenceException(nameof(configuration.GEDCOMFile)); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreRelativePaths is null) @@ -243,6 +246,7 @@ public class Configuration configuration.ForceFaceLastWriteTimeToCreationTime.Value, configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.ForceResizeLastWriteTimeToCreationTime.Value, + configuration.GEDCOMFile, configuration.IgnoreExtensions, configuration.IgnoreRelativePaths, configuration.JLinks, diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 26e689f..13d833f 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -27,6 +27,7 @@ public class Configuration public bool ForceFaceLastWriteTimeToCreationTime { init; get; } public bool ForceMetadataLastWriteTimeToCreationTime { init; get; } public bool ForceResizeLastWriteTimeToCreationTime { init; get; } + public string GEDCOMFile { init; get; } public string[] IgnoreExtensions { init; get; } public string[] IgnoreRelativePaths { init; get; } public string[] JLinks { init; get; } @@ -101,6 +102,7 @@ public class Configuration bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, + string gedCOMFile, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] jLinks, @@ -174,6 +176,7 @@ public class Configuration ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + GEDCOMFile = gedCOMFile; IgnoreExtensions = ignoreExtensions; IgnoreRelativePaths = ignoreRelativePaths; JLinks = jLinks; diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 444c337..a9dbe77 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -20,6 +20,7 @@ "xFocusDirectory": "/Hawaii 2022", "FocusModel": "", "xFocusModel": "NIKON D3400", + "GEDCOMFile": "/([])/638158579618344864/638158579618344864-Export.ged", "PersonCharactersCopyCount": 0, "xPersonCharactersCopyCount": 2, "xRootDirectory": "D:/Tmp/phares/Pictures", diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 01715ed..e38a674 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -70,6 +70,7 @@ "ForceResizeLastWriteTimeToCreationTime": false, "FocusDirectory": "", "FocusModel": "", + "GEDCOMFile": "", "LocationDigits": 9, "LocationFactor": 10000, "MappingDefaultName": "John Doe~25", diff --git a/Shared/Models/PersonContainer.cs b/Shared/Models/PersonContainer.cs index 92c0ed0..5af1a7d 100644 --- a/Shared/Models/PersonContainer.cs +++ b/Shared/Models/PersonContainer.cs @@ -13,9 +13,10 @@ public class PersonContainer : Properties.IPersonContainer public string DisplayDirectoryName { init; get; } public long? Key { init; get; } public char? Char { init; get; } + public string[]? FilteredIndividualsLines { init; get; } [JsonConstructor] - public PersonContainer(int? approximateYears, char? @char, Person? person, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, long? key) + public PersonContainer(int? approximateYears, char? @char, Person? person, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, long? key, string[]? filteredIndividualsLines) { ApproximateYears = approximateYears; Char = @char; @@ -24,26 +25,27 @@ public class PersonContainer : Properties.IPersonContainer DisplayDirectoryAllFiles = displayDirectoryAllFiles; DisplayDirectoryName = displayDirectoryName; Key = key; + FilteredIndividualsLines = filteredIndividualsLines; } public PersonContainer(char[] personCharacters, PersonBirthday birthday, string displayDirectoryName) : - this(Stateless.Methods.IAge.GetApproximateYears(personCharacters, displayDirectoryName), null, Stateless.Methods.IPerson.GetPerson(personCharacters, displayDirectoryName, birthday.Value.Ticks, birthday), new PersonBirthday[] { birthday }, Array.Empty(), displayDirectoryName, birthday.Value.Ticks) + this(Stateless.Methods.IAge.GetApproximateYears(personCharacters, displayDirectoryName), null, Stateless.Methods.IPerson.GetPerson(personCharacters, displayDirectoryName, birthday.Value.Ticks, birthday), new PersonBirthday[] { birthday }, Array.Empty(), displayDirectoryName, birthday.Value.Ticks, null) { } public PersonContainer(int? approximateYears, PersonBirthday birthdays, string displayDirectoryName, long key) : - this(approximateYears, null, null, new PersonBirthday[] { birthdays }, Array.Empty(), displayDirectoryName, key) + this(approximateYears, null, null, new PersonBirthday[] { birthdays }, Array.Empty(), displayDirectoryName, key, null) { } public PersonContainer(int? approximateYears, PersonBirthday birthdays, char? @char, string displayDirectoryName, long key) : - this(approximateYears, @char, null, new PersonBirthday[] { birthdays }, Array.Empty(), displayDirectoryName, key) + this(approximateYears, @char, null, new PersonBirthday[] { birthdays }, Array.Empty(), displayDirectoryName, key, null) { } public PersonContainer(int? approximateYears, char @char, string[] displayDirectoryAllFiles, string displayDirectoryName) : - this(approximateYears, @char, null, null, displayDirectoryAllFiles, displayDirectoryName, null) + this(approximateYears, @char, null, null, displayDirectoryAllFiles, displayDirectoryName, null, null) { } public PersonContainer(int? approximateYears, Person? person, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, long? key) : - this(approximateYears, null, person, birthdays, displayDirectoryAllFiles, displayDirectoryName, key) + this(approximateYears, null, person, birthdays, displayDirectoryAllFiles, displayDirectoryName, key, null) { } public override string ToString() diff --git a/Shared/Models/Properties/IPersonContainer.cs b/Shared/Models/Properties/IPersonContainer.cs index fed6c4e..58bbccf 100644 --- a/Shared/Models/Properties/IPersonContainer.cs +++ b/Shared/Models/Properties/IPersonContainer.cs @@ -9,5 +9,6 @@ public interface IPersonContainer public string[] DisplayDirectoryAllFiles { init; get; } public string DisplayDirectoryName { init; get; } public long? Key { init; get; } + public string[]? FilteredIndividualsLines { init; get; } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPerson.cs b/Shared/Models/Stateless/Methods/IPerson.cs index 6cecc7f..416acb7 100644 --- a/Shared/Models/Stateless/Methods/IPerson.cs +++ b/Shared/Models/Stateless/Methods/IPerson.cs @@ -13,11 +13,26 @@ public interface IPerson Models.Person TestStatic_GetPerson(char[] personCharacters, string personDisplayDirectoryName, long personKey, Models.PersonBirthday personBirthday) => GetPerson(personCharacters, personDisplayDirectoryName, personKey, personBirthday); static Models.Person GetPerson(char[] personCharacters, string personDisplayDirectoryName, long personKey, Models.PersonBirthday personBirthday) => - Person.GetPerson(Array.Empty(), null, personKey, personBirthday, personDisplayDirectoryName.Split(personCharacters)); + Person.GetPerson(Array.Empty(), null, personKey, personBirthday, personDisplayDirectoryName.Split(personCharacters), null); - Models.Person TestStatic_GetPerson(string[] personDisplayDirectoryAllFiles, string personKeyFormatted, long personKey, string[] segments) => - GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, segments); - static Models.Person GetPerson(string[] personDisplayDirectoryAllFiles, string personKeyFormatted, long personKey, string[] segments) => - Person.GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, IPersonBirthday.GetPersonBirthday(personKey), segments); + Models.Person TestStatic_GetPerson(string[] personDisplayDirectoryAllFiles, string personKeyFormatted, long personKey, string[] segments, string[]? filteredIndividualsLines) => + GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, segments, filteredIndividualsLines); + static Models.Person GetPerson(string[] personDisplayDirectoryAllFiles, string personKeyFormatted, long personKey, string[] segments, string[]? filteredIndividualsLines) => + Person.GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, IPersonBirthday.GetPersonBirthday(personKey), segments, filteredIndividualsLines); + + (string[] headerLines, Dictionary> individuals, string[] footerLines) TestStatic_GetIndividuals(string gedCOMFile) => + GetIndividuals(gedCOMFile); + static (string[] headerLines, Dictionary> individuals, string[] footerLines) GetIndividuals(string gedCOMFile) => + Person.GetIndividuals(gedCOMFile); + + string[] TestStatic_GetFiltered(List individualsLines) => + GetFiltered(individualsLines); + static string[] GetFiltered(List individualsLines) => + Person.GetFiltered(individualsLines); + + void TestStatic_CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, Models.PersonContainer[] personContainers, string[] gedCOMHeaderLines, string[] gedCOMFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary> personKeyToIds) => + CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, gedCOMHeaderLines, gedCOMFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); + static void CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, Models.PersonContainer[] personContainers, string[] gedCOMHeaderLines, string[] gedCOMFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary> personKeyToIds) => + Person.CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, gedCOMHeaderLines, gedCOMFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonContainer.cs b/Shared/Models/Stateless/Methods/IPersonContainer.cs index 817dc24..6b0f525 100644 --- a/Shared/Models/Stateless/Methods/IPersonContainer.cs +++ b/Shared/Models/Stateless/Methods/IPersonContainer.cs @@ -5,10 +5,10 @@ public interface IPersonContainer // ... - Models.PersonContainer[] TestStatic_GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension) => - GetPersonContainers(storage, personBirthdayFormat, personCharacters, facesFileNameExtension); - static Models.PersonContainer[] GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension) => - PersonContainer.GetPersonContainers(storage, personBirthdayFormat, personCharacters, facesFileNameExtension); + Models.PersonContainer[] TestStatic_GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary> individuals) => + GetPersonContainers(storage, personBirthdayFormat, personCharacters, facesFileNameExtension, individuals); + static Models.PersonContainer[] GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary> individuals) => + PersonContainer.GetPersonContainers(storage, personBirthdayFormat, personCharacters, facesFileNameExtension, individuals); List<(long?, string)> TestStatic_GetDisplay(string personBirthdayFormat, Models.PersonContainer personContainer) => GetDisplay(personBirthdayFormat, personContainer); diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs index 8c891e3..c9a0de4 100644 --- a/Shared/Models/Stateless/Methods/Person.cs +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -15,110 +15,280 @@ internal abstract class Person return new(personBirthday, personKeyFormatted); } - private static void WriteGedFile(string personKeyFormatted, Models.PersonBirthday personBirthday, Models.PersonName name, string[] matches) + private static void CleanExport() { - string[] pGedFiles = (from l in matches where l.EndsWith(".pged") select l).ToArray(); - if (!pGedFiles.Any()) + List cleanLines = new(); + string exportFile = "xD:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/FamilyEcho/638157228251558818-RootsMagic-Export-Copy.ged"; + string[] sourceLines = File.ReadAllLines(exportFile); + for (int i = 0; i < sourceLines.Length; i++) { - string? directory = Path.GetDirectoryName(matches[0]); - if (directory is null) - throw new Exception(); - string? sexLine; - string? deathLine = null; - string nameLine = $"1 NAME {name.First.Value} /{name.Last.Value}/"; - if (personKeyFormatted[^2..] is "23" or "21" or "19" or "17" or "15") + if (sourceLines[i].StartsWith("1 _UID")) + continue; + else if (sourceLines[i].StartsWith("1 SEX")) + continue; + else if (sourceLines[i].StartsWith("1 DEAT")) + continue; + else if (sourceLines[i].StartsWith("2 GIVN")) + continue; + // else if (sourceLines[i].StartsWith("2 NICK")) + // continue; + else if (sourceLines[i].StartsWith("2 SURN")) + continue; + else if (sourceLines[i] == "1 BIRT") { - sexLine = "1 SEX M"; - deathLine = "1 DEAT Y"; + i += 1; + continue; } - else if (personKeyFormatted[^2..] is "22" or "20" or "18" or "16" or "14") + else if (sourceLines[i] == "1 CHAN") { - sexLine = "1 SEX F"; - deathLine = "1 DEAT Y"; + i += 1; + continue; } - else if (personKeyFormatted[^2..] is "13" or "11" or "09" or "07" or "05") - sexLine = "1 SEX M"; - else if (personKeyFormatted[^2..] is "12" or "10" or "08" or "06" or "04") - sexLine = "1 SEX F"; - else - { - sexLine = null; - // string[] sourceLines = File.ReadAllLines("D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/FamilyEcho/638157228251558818-RootsMagic-Export.ged"); - string[] sourceLines = File.ReadAllLines("D:/1) Images A/Images-9b89679-Results/A2) People/9b89679/([])/638157314010628679.ged"); - for (int i = 0; i < sourceLines.Length; i++) - { - if (sourceLines[i] != nameLine) - continue; - for (int j = i + 1; j < sourceLines.Length; j++) - { - i = j; - if (sourceLines[j].StartsWith("0 @I")) - break; - if (sourceLines[j].StartsWith("1 SEX ")) - sexLine = sourceLines[j]; - else if (sourceLines[j].StartsWith("1 DEAT ")) - deathLine = sourceLines[j]; - } - } - if (sexLine is null) - sexLine = "1 SEX U"; - else - { - string sex; - if (deathLine is null or not "1 DEAT Y") - sex = sexLine[6] is 'M' ? "05" : sexLine[6] is 'F' ? "04" : sexLine[6] is 'U' ? "02" : throw new NotImplementedException(); - else - sex = sexLine[6] is 'M' ? "15" : sexLine[6] is 'F' ? "14" : sexLine[6] is 'U' ? "03" : throw new NotImplementedException(); - if (directory.EndsWith("00")) - directory = string.Concat(directory[..^2], sex); - else if (directory.EndsWith("01")) - directory = string.Concat(directory[..^2], sex); - // else if (directory.EndsWith("04")) // Cameran - // directory = string.Concat(directory[..^2], sex); - // else if (directory.EndsWith("05")) // Daisy - // directory = string.Concat(directory[..^2], sex); - // else if (directory.EndsWith("18")) // Meghan - // directory = string.Concat(directory[..^2], sex); - // else if (directory.EndsWith("20")) // Joey - // directory = string.Concat(directory[..^2], sex); - else - throw new NotImplementedException(); - personKeyFormatted = $"{personKeyFormatted[..^2]}{sex}"; - } - } - List pGedLines = new() - { - $"0 @I{personKeyFormatted}@ INDI", - nameLine - }; - if (!string.IsNullOrEmpty(name.First.Value)) - pGedLines.Add($"2 GIVN {name.First.Value}"); - if (!string.IsNullOrEmpty(name.Last.Value)) - pGedLines.Add($"2 SURN {name.Last.Value}"); - if (!string.IsNullOrEmpty(name.Alias.Value)) - { - pGedLines.Add($"2 NICK {name.Alias.Value}"); - if (name.Alias.Value.Contains(" Jr")) - pGedLines.Add("2 NSFX Jr"); - else if (name.Alias.Value.Contains(" Sr")) - pGedLines.Add("2 NSFX Sr"); - } - pGedLines.Add(sexLine); - if (!string.IsNullOrEmpty(deathLine)) - pGedLines.Add(deathLine); - if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday)) - { - pGedLines.Add("1 BIRT"); - pGedLines.Add($"2 DATE {personBirthday.Value:dd MMM yyyy}"); - } - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - string text = string.Join(Environment.NewLine, pGedLines); - _ = IPath.WriteAllText(Path.Combine(directory, $"{personKeyFormatted}.pged"), text, updateDateWhenMatches: false, compareBeforeWrite: true); + cleanLines.Add(sourceLines[i]); } + File.WriteAllLines(exportFile, cleanLines); } - internal static Models.Person GetPerson(string[] personDisplayDirectoryAllFiles, string? personKeyFormatted, long personKey, Models.PersonBirthday personBirthday, string[] segments) + internal static (string[] headerLines, Dictionary> individuals, string[] footerLines) GetIndividuals(string gedCOMFile) + { + Dictionary> results = new(); + string? nick; + int startAt = 0; + List lines = new(); + List headerLines = new(); + List footerLines = new(); + string[] sourceLines = File.ReadAllLines(gedCOMFile); + for (int i = 0; i < sourceLines.Length; i++) + { + lines.Add(sourceLines[i]); + if (sourceLines[i].EndsWith("@ INDI")) + { + lines.RemoveAt(lines.Count - 1); + headerLines.AddRange(lines); + startAt = lines.Count; + lines.Clear(); + break; + } + } + for (int i = startAt; i < sourceLines.Length; i++) + { + if (!sourceLines[i].StartsWith("0 @")) + continue; + nick = null; + lines.Add(sourceLines[i]); + for (int j = i + 1; j < sourceLines.Length; j++) + { + if (sourceLines[j].StartsWith("0 @I")) + break; + lines.Add(sourceLines[j]); + if (!sourceLines[j].StartsWith("2 NICK ")) + continue; + nick = sourceLines[j][7..]; + } + if (string.IsNullOrEmpty(nick)) + { + if (lines[^1] != "0 TRLR") + throw new Exception(string.Join(Environment.NewLine, lines)); + else + { + footerLines.AddRange(lines); + break; + } + } + results.Add(nick, new()); + results[nick].AddRange(lines); + lines.Clear(); + } + return (headerLines.ToArray(), results, footerLines.ToArray()); + } + + private static void WriteGedFile(string personKeyFormatted, Models.PersonBirthday personBirthday, string[]? filteredIndividualsLines, Models.PersonName name, string[] matches) + { + string? directory = Path.GetDirectoryName(matches[0]); + if (directory is null) + throw new Exception(); + string? sexLine; + string? deathLine = null; + string jrOrSr; + if (string.IsNullOrEmpty(name.Alias.Value)) + jrOrSr = string.Empty; + else + { + if (name.Alias.Value.Contains(" Jr")) + jrOrSr = "Jr"; + else if (name.Alias.Value.Contains(" Sr")) + jrOrSr = "Sr"; + else + jrOrSr = string.Empty; + } + string nameLine = $"1 NAME {name.First.Value}/{name.Last.Value}/{jrOrSr}"; + if (personKeyFormatted[^2..] is "23" or "21" or "19" or "17" or "15") + { + sexLine = "1 SEX M"; + deathLine = "1 DEAT Y"; + } + else if (personKeyFormatted[^2..] is "22" or "20" or "18" or "16" or "14") + { + sexLine = "1 SEX F"; + deathLine = "1 DEAT Y"; + } + else if (personKeyFormatted[^2..] is "13" or "11" or "09" or "07" or "05") + sexLine = "1 SEX M"; + else if (personKeyFormatted[^2..] is "12" or "10" or "08" or "06" or "04") + sexLine = "1 SEX F"; + else if (filteredIndividualsLines is null) + sexLine = "1 SEX U"; + else + { + sexLine = null; + for (int i = 0; i < filteredIndividualsLines.Length; i++) + { + if (filteredIndividualsLines[i] != nameLine) + continue; + for (int j = i + 1; j < filteredIndividualsLines.Length; j++) + { + i = j; + if (filteredIndividualsLines[j].StartsWith("0 @I")) + break; + if (filteredIndividualsLines[j].StartsWith("1 SEX ")) + sexLine = filteredIndividualsLines[j]; + else if (filteredIndividualsLines[j].StartsWith("1 DEAT ")) + deathLine = filteredIndividualsLines[j]; + } + } + if (sexLine is null) + sexLine = "1 SEX U"; + else + { + string sex; + if (deathLine is null or not "1 DEAT Y") + sex = sexLine[6] is 'M' ? "05" : sexLine[6] is 'F' ? "04" : sexLine[6] is 'U' ? "02" : throw new NotImplementedException(); + else + sex = sexLine[6] is 'M' ? "15" : sexLine[6] is 'F' ? "14" : sexLine[6] is 'U' ? "03" : throw new NotImplementedException(); + if (directory.EndsWith("00")) + directory = string.Concat(directory[..^2], sex); + else if (directory.EndsWith("01")) + directory = string.Concat(directory[..^2], sex); + else + throw new NotImplementedException(); + personKeyFormatted = $"{personKeyFormatted[..^2]}{sex}"; + } + } + List pGedLines = new(); + if (filteredIndividualsLines is null || !filteredIndividualsLines.Any()) + pGedLines.Add($"0 @I{personKeyFormatted}@ INDI"); + else + { + if (!filteredIndividualsLines[0].StartsWith("0 @I")) + throw new NotSupportedException(); + pGedLines.Add(filteredIndividualsLines[0]); + } + pGedLines.Add(nameLine); + if (!string.IsNullOrEmpty(name.First.Value)) + pGedLines.Add($"2 GIVN {name.First.Value}"); + if (!string.IsNullOrEmpty(name.Last.Value)) + pGedLines.Add($"2 SURN {name.Last.Value}"); + pGedLines.Add($"2 NICK {personKeyFormatted}"); + pGedLines.Add(sexLine); + if (!string.IsNullOrEmpty(deathLine)) + pGedLines.Add(deathLine); + if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday)) + { + pGedLines.Add("1 BIRT"); + pGedLines.Add($"2 DATE {personBirthday.Value:dd MMM yyyy}"); + } + if (filteredIndividualsLines is not null) + { + for (int i = 1; i < filteredIndividualsLines.Length; i++) + pGedLines.Add(filteredIndividualsLines[i]); + } + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + string text = string.Join(Environment.NewLine, pGedLines); + _ = IPath.WriteAllText(Path.Combine(directory, $"{personKeyFormatted}.pged"), text, updateDateWhenMatches: false, compareBeforeWrite: true); + } + + internal static string[] GetFiltered(List individualsLines) + { + List results = new(); + for (int i = 0; i < individualsLines.Count; i++) + { + if (individualsLines[i].StartsWith("1 NAME")) + continue; + else if (individualsLines[i].StartsWith("2 GIVN")) + continue; + else if (individualsLines[i].StartsWith("2 SURN")) + continue; + else if (individualsLines[i].StartsWith("2 NICK")) + continue; + else if (individualsLines[i].StartsWith("1 SEX")) + continue; + else if (individualsLines[i].StartsWith("1 DEAT")) + continue; + else if (individualsLines[i] == "1 BIRT") + { + i += 1; + continue; + } + else if (individualsLines[i] == "1 CHAN") + { + i += 1; + continue; + } + results.Add(individualsLines[i]); + } + return results.ToArray(); + } + + internal static void CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, Models.PersonContainer[] personContainers, string[] gedCOMHeaderLines, string[] gedCOMFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary> personKeyToIds) + { + string by; + string[] matches; + const int zero = 0; + string[] pGedFiles; + string[] pGedLines; + string personKeyFormatted; + List lines = new(); + List distinct = new(); + lines.AddRange(gedCOMHeaderLines); + Models.PersonBirthday personBirthday; + string rootDirectory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-Tree"); + foreach (Models.PersonContainer personContainer in personContainers) + { + if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any()) + continue; + if (personContainer.DisplayDirectoryName == mappingDefaultName || personContainer.Person.Name.Alias.Value == "Z") + continue; + if (distinct.Contains(personContainer.Key.Value)) + continue; + distinct.Add(personContainer.Key.Value); + if (!personKeyToIds.ContainsKey(personContainer.Key.Value)) + continue; + personBirthday = personContainer.Birthdays[zero]; + personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); + by = IPersonBirthday.IsCounterPersonBirthday(personBirthday) ? resultAllInOne : "People"; + matches = (from l in personContainer.DisplayDirectoryAllFiles where !string.IsNullOrEmpty(personKeyFormatted) && l.Contains(personKeyFormatted) select l).ToArray(); + if (!matches.Any()) + continue; + pGedFiles = (from l in matches where l.EndsWith(".pged") select l).ToArray(); + if (!pGedFiles.Any()) + continue; + pGedLines = File.ReadAllLines(pGedFiles[0]); + lines.AddRange(pGedLines); + // segments = personContainer.DisplayDirectoryName.Split(_Configuration.PersonCharacters.ToArray()); + // if (segments.Length < 2) + // directory = Path.Combine(rootDirectory, $"000 {personKeyFormatted} {personContainer.DisplayDirectoryName}"); + // else + // directory = Path.Combine(rootDirectory, $"{segments[1].PadLeft(3, '0')} {personKeyFormatted} {personContainer.DisplayDirectoryName}"); + // if (Directory.Exists(directory)) + // continue; + // _ = Directory.CreateDirectory(directory); + } + lines.AddRange(gedCOMFooterLines); + File.WriteAllLines(Path.Combine(a2PeopleContentDirectory, $"{ticks}.ged"), lines); + } + + internal static Models.Person GetPerson(string[] personDisplayDirectoryAllFiles, string? personKeyFormatted, long personKey, Models.PersonBirthday personBirthday, string[] segments, string[]? filteredIndividualsLines) { Models.Person result; const int zero = 0; @@ -131,7 +301,7 @@ internal abstract class Person Models.PersonName name = PersonName.Create(segments[zero]); string[] matches = (from l in personDisplayDirectoryAllFiles where !string.IsNullOrEmpty(personKeyFormatted) && l.Contains(personKeyFormatted) select l).ToArray(); if (!string.IsNullOrEmpty(personKeyFormatted) && matches.Any()) - WriteGedFile(personKeyFormatted, personBirthday, name, matches); + WriteGedFile(personKeyFormatted, personBirthday, filteredIndividualsLines, name, matches); result = new(id, personBirthday, name, comments, urls, numbers, emails, addresses); return result; } diff --git a/Shared/Models/Stateless/Methods/PersonContainer.cs b/Shared/Models/Stateless/Methods/PersonContainer.cs index e4bf9e2..5835a12 100644 --- a/Shared/Models/Stateless/Methods/PersonContainer.cs +++ b/Shared/Models/Stateless/Methods/PersonContainer.cs @@ -33,13 +33,15 @@ internal abstract class PersonContainer return results; } - private static List<(long?, Models.PersonContainer)> GetPersonContainersCollections(string facesFileNameExtension, char[] personCharacters, char @char, char numberSign, string personDisplayDirectory, string personDisplayDirectoryName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection) + private static List<(long?, Models.PersonContainer)> GetPersonContainersCollections(string facesFileNameExtension, char[] personCharacters, Dictionary> individuals, char @char, char numberSign, string personDisplayDirectory, string personDisplayDirectoryName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection) { List<(long?, Models.PersonContainer)> results = new(); long personKey; string[] segments; const int zero = 0; Models.Person person; + List? individualsLines; + string[]? filteredIndividualsLines; Models.PersonContainer personContainer; Models.PersonBirthday[] orderedPersonBirthdays; string[] personDisplayDirectoryAllFiles = GetFiles(facesFileNameExtension, personDisplayDirectory); @@ -55,8 +57,10 @@ internal abstract class PersonContainer continue; personKey = orderedPersonBirthdays[zero].Value.Ticks; } - person = IPerson.GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, segments); - personContainer = new(approximateYears, @char, person, orderedPersonBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personKey); + _ = individuals.TryGetValue(personKeyFormatted, out individualsLines); + filteredIndividualsLines = individualsLines is null ? null : IPerson.GetFiltered(individualsLines); + person = IPerson.GetPerson(personDisplayDirectoryAllFiles, personKeyFormatted, personKey, segments, filteredIndividualsLines); + personContainer = new(approximateYears, @char, person, orderedPersonBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personKey, filteredIndividualsLines); results.Add(new(personKey, personContainer)); } return results; @@ -101,7 +105,7 @@ internal abstract class PersonContainer return result; } - private static List<(long?, Models.PersonContainer)> GetPersonContainersGroup(string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, char @char, string[] personDisplayDirectories) + private static List<(long?, Models.PersonContainer)> GetPersonContainersGroup(string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, Dictionary> individuals, char @char, string[] personDisplayDirectories) { List<(long?, Models.PersonContainer)> results = new(); string? minusOne; @@ -130,7 +134,7 @@ internal abstract class PersonContainer if (changes.Any(l => l is not null)) continue; if (collection.Any()) - results.AddRange(GetPersonContainersCollections(facesFileNameExtension, personCharacters, @char, numberSign, personDisplayDirectory, personDisplayDirectoryName, approximateYears, collection)); + results.AddRange(GetPersonContainersCollections(facesFileNameExtension, personCharacters, individuals, @char, numberSign, personDisplayDirectory, personDisplayDirectoryName, approximateYears, collection)); else { personContainer = GetPersonContainer(facesFileNameExtension, @char, personDisplayDirectory, personDisplayDirectoryName, approximateYears); @@ -142,7 +146,7 @@ internal abstract class PersonContainer return results; } - private static Models.PersonContainer[] GetPersonContainersGroups(string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, string[] groupDirectories) + private static Models.PersonContainer[] GetPersonContainersGroups(string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, Dictionary> individuals, string[] groupDirectories) { Models.PersonContainer[] results; const int zero = 0; @@ -156,14 +160,14 @@ internal abstract class PersonContainer if (!personCharacters.Contains(groupDirectoryName[zero])) continue; personDisplayDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly); - collection = GetPersonContainersGroup(personBirthdayFormat, facesFileNameExtension, personCharacters, groupDirectoryName[zero], personDisplayDirectories); + collection = GetPersonContainersGroup(personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, groupDirectoryName[zero], personDisplayDirectories); personContainers.AddRange(collection); } results = (from l in personContainers orderby l.PersonKey is not null, l.PersonKey select l.PersonContainer).ToArray(); return results; } - internal static Models.PersonContainer[] GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension) + internal static Models.PersonContainer[] GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary> individuals) { Models.PersonContainer[] results; string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); @@ -180,7 +184,7 @@ internal abstract class PersonContainer if (!groupDirectories.Any()) results = Array.Empty(); else - results = GetPersonContainersGroups(personBirthdayFormat, facesFileNameExtension, personCharacters, groupDirectories); + results = GetPersonContainersGroups(personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, groupDirectories); return results; } @@ -201,5 +205,5 @@ internal abstract class PersonContainer } return results; } - + } \ No newline at end of file