diff --git a/Copy-Distinct/CopyDistinct.cs b/Copy-Distinct/CopyDistinct.cs index d4edf6c..b548cc3 100644 --- a/Copy-Distinct/CopyDistinct.cs +++ b/Copy-Distinct/CopyDistinct.cs @@ -92,9 +92,9 @@ public class CopyDistinct return (move, filesCollection, anyLenFiles, moveBack); } - private static (string[], List<(FileHolder, string)>) GetMoveBackToDoCollection(List filesCollection) + private static (string[], List<(FileHolder, string?, string)>) GetMoveBackToDoCollection(List filesCollection) { - List<(FileHolder, string)> results = new(); + List<(FileHolder, string?, string)> results = new(); string key; string? value; string fileName; @@ -146,7 +146,7 @@ public class CopyDistinct directory = Path.GetDirectoryName(value); if (string.IsNullOrEmpty(directory)) continue; - results.Add(new(new(file), value)); + results.Add(new(new(file), null, value)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); } @@ -161,7 +161,7 @@ public class CopyDistinct string[] distinctDirectories; ConsoleKey? consoleKey = null; string message = nameof(CopyDistinct); - List<(FileHolder, string)> toDoCollection; + List<(FileHolder, string?, string)> toDoCollection; int count = filesCollection.Select(l => l.Length).Sum(); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; if (moveBack) diff --git a/Duplicate-Search/DuplicateSearch.cs b/Duplicate-Search/DuplicateSearch.cs index df4452b..d207724 100644 --- a/Duplicate-Search/DuplicateSearch.cs +++ b/Duplicate-Search/DuplicateSearch.cs @@ -189,7 +189,7 @@ public class DuplicateSearch if (mappingFromItem is not null) { resizedFileHolder = new(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}")); - collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsWrongYear, item.Property.Keywords, mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder); + collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsWrongYear, item.Property.Keywords ?? Array.Empty(), mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder); } } resizedFileHolder = new(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath)); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 6d9159a..e947edd 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -1102,10 +1102,33 @@ public partial class DlibDotNet return result; } + private (string, List) GetFilesCollectionThenCopyOrMove(long ticks, string fileSearchFilter, string directorySearchFilter, ProgressBarOptions options, string outputResolution) + { + ProgressBar progressBar; + string filesCollectionRootDirectory = _Configuration.PropertyConfiguration.RootDirectory; + (string cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); + IReadOnlyDictionary fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, new string[] { _Configuration.PropertyConfiguration.ResultContent }); + List filesCollection = IDirectory.GetFilesCollection(filesCollectionRootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage: false); + int count = filesCollection.Select(l => l.Length).Sum(); + string message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + progressBar = new(count, message, options); + (string[] distinctDirectories, List<(FileHolder, string?, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filesCollection, fileGroups[_Configuration.PropertyConfiguration.ResultContent], () => progressBar.Tick()); + progressBar.Dispose(); + foreach (string distinctDirectory in distinctDirectories) + { + if (!Directory.Exists(distinctDirectory)) + _ = Directory.CreateDirectory(distinctDirectory); + } + message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + progressBar = new(count, message, options); + _ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick()); + progressBar.Dispose(); + return (filesCollectionRootDirectory, filesCollection); + } + private void Search(long ticks, ReadOnlyCollection personContainers, string argZero, string propertyRoot) { int t; - int count; string message; MapLogic? mapLogic; Container[] containers; @@ -1121,6 +1144,7 @@ public partial class DlibDotNet bool filesCollectionCountIsOne = false; List? filesCollection = null; const string directorySearchFilter = "*"; + string? filesCollectionRootDirectory = null; bool configurationOutputResolutionsHas = false; ReadOnlyDictionary> personKeyToIds; bool runToDoCollectionFirst = GetRunToDoCollectionFirst(ticks); @@ -1143,20 +1167,8 @@ public partial class DlibDotNet configurationOutputResolutionsHas = true; if (!runToDoCollectionFirst) break; - ProgressBar progressBar; - (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); - IReadOnlyDictionary fileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, new string[] { _Configuration.PropertyConfiguration.ResultContent }); - filesCollection = IDirectory.GetFilesCollection(_Configuration.PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage: false); - message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - count = filesCollection.Select(l => l.Length).Sum(); + (filesCollectionRootDirectory, filesCollection) = GetFilesCollectionThenCopyOrMove(ticks, fileSearchFilter, directorySearchFilter, options, outputResolution); filesCollectionCountIsOne = filesCollection.Count == 1; - progressBar = new(count, message, options); - (string[] distinctDirectories, List<(FileHolder, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filesCollection, fileGroups[_Configuration.PropertyConfiguration.ResultContent], () => progressBar.Tick()); - progressBar.Dispose(); - message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - progressBar = new(count, message, options); - _ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick()); - progressBar.Dispose(); break; } fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent); @@ -1184,17 +1196,19 @@ public partial class DlibDotNet } if (configurationOutputResolutionsHas) { + int count; foreach (string outputResolution in _Configuration.OutputResolutions) { if (outputResolution.Any(l => char.IsNumber(l))) continue; (cResultsFullGroupDirectory, _, _, _) = GetResultsFullGroupDirectories(outputResolution); - filesCollection = IDirectory.GetFilesCollection(Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultAllInOne), directorySearchFilter, fileSearchFilter, useCeilingAverage: true); + filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent, _Configuration.PropertyConfiguration.ResultAllInOne); + filesCollection = IDirectory.GetFilesCollection(filesCollectionRootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage: true); count = filesCollection.Select(l => l.Length).Sum(); break; } } - if (filesCollection is null) + if (filesCollectionRootDirectory is null || filesCollection is null) throw new NullReferenceException(nameof(filesCollection)); message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; using (ProgressBar progressBar = new(2, message, options)) @@ -1203,7 +1217,7 @@ public partial class DlibDotNet string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton); if (!Directory.Exists(aPropertySingletonDirectory)) _ = Directory.CreateDirectory(aPropertySingletonDirectory); - (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollection); + (t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, filesCollection); progressBar.Tick(); } fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 8f700d6..b070d20 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -281,7 +281,7 @@ internal abstract class MapLogic string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title); string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - for (int i = 1; i < 3; i++) + for (int i = 1; i < 6; i++) { check = false; results.Clear(); diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 4108f8e..cf8281f 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -99,7 +99,7 @@ public class A_Property if (item.Property is not null) result = item.Property; else - result = JsonSerializer.Deserialize(json); + result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property); if (result is not null && json.Contains("WrongYear")) { id = result.Id; diff --git a/Property/Models/Stateless/Result.cs b/Property/Models/Stateless/Result.cs index a554635..188f35b 100644 --- a/Property/Models/Stateless/Result.cs +++ b/Property/Models/Stateless/Result.cs @@ -13,7 +13,7 @@ internal class Result internal static string GetResultsGroupDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string description, bool create) { - string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace("_", ") ")); + string result = Path.Combine($"{propertyConfiguration.RootDirectory}-Results", description.Replace('_', ')')); if (create && !Directory.Exists(result)) _ = Directory.CreateDirectory(result); return result; diff --git a/Shared/.kanbn/index.md b/Shared/.kanbn/index.md index b637ae7..765e419 100644 --- a/Shared/.kanbn/index.md +++ b/Shared/.kanbn/index.md @@ -30,7 +30,6 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g - [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md) - [find-incorrectly-mapped-faces](tasks/find-incorrectly-mapped-faces.md) - [nef-support](tasks/nef-support.md) -- [reload-slideshow](tasks/reload-slideshow.md) - [set-date-taken-when-missing](tasks/set-date-taken-when-missing.md) - [triangle-over-person-in-full-image-for-some](tasks/triangle-over-person-in-full-image-for-some.md) @@ -47,6 +46,7 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g - [fix-random-logic](tasks/fix-random-logic.md) - [move-copy-manual-files-to-get-display-directory-all-files](tasks/move-copy-manual-files-to-get-display-directory-all-files.md) - [rename-files-to-padded-number-string](tasks/rename-files-to-padded-number-string.md) +- [reload-slideshow](tasks/reload-slideshow.md) - [genealogical-data-communication-as-golden](tasks/genealogical-data-communication-as-golden.md) - [look-for-family-from-jlink-in-x-mapped](tasks/look-for-family-from-jlink-in-x-mapped.md) - [move-over-2023-california-pictures](tasks/move-over-2023-california-pictures.md) diff --git a/Shared/.kanbn/tasks/reload-slideshow.md b/Shared/.kanbn/tasks/reload-slideshow.md index 39fdb54..fbf15cc 100644 --- a/Shared/.kanbn/tasks/reload-slideshow.md +++ b/Shared/.kanbn/tasks/reload-slideshow.md @@ -1,10 +1,11 @@ --- created: 2023-08-08T05:37:00.125Z -updated: 2023-08-08T05:37:14.241Z +updated: 2023-08-14T02:08:22.605Z assigned: "" progress: 0 tags: [] started: 2023-08-08T05:37:10.651Z +completed: 2023-08-14T02:08:22.605Z --- # Reload slideshow diff --git a/Shared/Models/Item.cs b/Shared/Models/Item.cs index f56a5bc..8d66cc6 100644 --- a/Shared/Models/Item.cs +++ b/Shared/Models/Item.cs @@ -6,6 +6,7 @@ namespace View_by_Distance.Shared.Models; public class Item : Properties.IItem { + protected readonly string[] _AlternateFileLines; protected List _Faces; protected readonly bool? _FileSizeChanged; protected readonly FileHolder _ImageFileHolder; @@ -18,6 +19,7 @@ public class Item : Properties.IItem protected readonly string _RelativePath; protected FileHolder? _ResizedFileHolder; protected readonly FileHolder _SourceDirectoryFileHolder; + public string[] AlternateFileLines => _AlternateFileLines; public List Faces => _Faces; public bool? FileSizeChanged => _FileSizeChanged; public FileHolder ImageFileHolder => _ImageFileHolder; @@ -32,8 +34,9 @@ public class Item : Properties.IItem public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder; [JsonConstructor] - public Item(List faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder) + public Item(string[] alternateFileLines, List faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder) { + _AlternateFileLines = alternateFileLines; _Faces = faces; _FileSizeChanged = fileSizeChanged; _ImageFileHolder = imageFileHolder; @@ -48,8 +51,8 @@ public class Item : Properties.IItem _SourceDirectoryFileHolder = sourceDirectoryFileHolder; } - public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) : - this(new(), fileSizeChanged, imageFileInfo, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder) + public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool? isNotUniqueAndNeedsReview, bool isUniqueFileName, bool isValidImageFormatExtension, Property? property, string[] alternateFileLines, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) : + this(alternateFileLines, new(), fileSizeChanged, imageFileInfo, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder) { if (relativePath.EndsWith(".json")) throw new ArgumentException("Can not be a *.json file!"); @@ -58,7 +61,7 @@ public class Item : Properties.IItem } public Item(FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) : - this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, null, false, isValidImageFormatExtension, null, null, null, null) + this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, null, false, isValidImageFormatExtension, null, Array.Empty(), null, null, null) { } public override string ToString() diff --git a/Shared/Models/MappingFromItem.cs b/Shared/Models/MappingFromItem.cs index a767ac1..11a5ec6 100644 --- a/Shared/Models/MappingFromItem.cs +++ b/Shared/Models/MappingFromItem.cs @@ -9,7 +9,7 @@ public record MappingFromItem(DateTime[] ContainerDateTimes, int Id, FileHolder ImageFileHolder, bool? IsWrongYear, - string[]? Keywords, + string[] Keywords, DateTime MinimumDateTime, string? Model, string RelativePath, @@ -35,7 +35,7 @@ public record MappingFromItem(DateTime[] ContainerDateTimes, List dateTimes = item.Property.GetDateTimes(); DateTime minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); (bool? isWrongYear, _) = Stateless.Methods.IProperty.IsWrongYear(item.ImageFileHolder, item.Property.DateTimeOriginal, dateTimes); - result = new(containerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, item.Property.Id.Value, item.ImageFileHolder, isWrongYear, item.Property.Keywords, minimumDateTime, item.Property.Model, item.RelativePath, resizedFileHolder); + result = new(containerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, item.Property.Id.Value, item.ImageFileHolder, isWrongYear, item.Property.Keywords ?? Array.Empty(), minimumDateTime, item.Property.Model, item.RelativePath, resizedFileHolder); return result; } diff --git a/Shared/Models/Properties/IItem.cs b/Shared/Models/Properties/IItem.cs index f073564..2e3c0c4 100644 --- a/Shared/Models/Properties/IItem.cs +++ b/Shared/Models/Properties/IItem.cs @@ -3,6 +3,7 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IItem { + public string[] AlternateFileLines { get; } public bool? FileSizeChanged { get; } public List Faces { get; } public FileHolder ImageFileHolder { get; } diff --git a/Shared/Models/Property.cs b/Shared/Models/Property.cs index bc423c9..af26ce5 100644 --- a/Shared/Models/Property.cs +++ b/Shared/Models/Property.cs @@ -28,6 +28,23 @@ public record Property(DateTime CreationTime, public List GetDateTimes() => Stateless.Methods.Property.GetDateTimes(CreationTime, LastWriteTime, DateTime, DateTimeDigitized, DateTimeFromName, DateTimeOriginal, GPSDateStamp); + public static Property GetProperty(Property property, string[] keywords) => + new(property.CreationTime, + property.DateTime, + property.DateTimeDigitized, + property.DateTimeFromName, + property.DateTimeOriginal, + property.FileSize, + property.GPSDateStamp, + property.Height, + property.Id, + keywords, + property.LastWriteTime, + property.Make, + property.Model, + property.Orientation, + property.Width); + } [JsonSourceGenerationOptions(WriteIndented = true)] diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs index 78df7bc..ed83fe4 100644 --- a/Shared/Models/Stateless/Methods/Container.cs +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -62,31 +62,59 @@ internal abstract class Container return filePairs; } - private static Models.Property? GetProperty(Models.FilePair filePair) + private static string[] GetAlternateFileLines(string? alternateFilesCollectionDirectory, Models.FilePair filePair) { - Models.Property? property; + string[]? results; + string pathDirectoryName = Path.GetFileName(Path.GetDirectoryName(filePair.Path) ?? filePair.Path); + string? alternateFile = alternateFilesCollectionDirectory is null ? null : Path.Combine(alternateFilesCollectionDirectory, pathDirectoryName, $"{Path.GetFileName(filePair.Path)}.tsv"); + if (!File.Exists(alternateFile)) + results = Array.Empty(); + else + results = File.ReadAllLines(alternateFile); + return results; + } + + private static (Models.Property?, string[]) GetProperty(Models.FilePair filePair, string? alternateFilesCollectionDirectory) + { + string[] results; + Models.Property? result; if (filePair.Match is null) - property = null; + (result, results) = (null, Array.Empty()); else { string json = File.ReadAllText(filePair.Match); if (string.IsNullOrEmpty(json)) - property = null; + (result, results) = (null, Array.Empty()); else - property = JsonSerializer.Deserialize(json); + { + result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property); + if (result is null) + results = Array.Empty(); + else + { + results = alternateFilesCollectionDirectory is null ? Array.Empty() : GetAlternateFileLines(alternateFilesCollectionDirectory, filePair); + if (results.Any(l => l.Contains('!'))) + { + if (result.Keywords is null) + result = Models.Property.GetProperty(result, new string[] { "!" }); + else + result = Models.Property.GetProperty(result, result.Keywords.Concat(new string[] { "!" }).ToArray()); + } + } + } } - return property; + return (result, results); } - private static void ParallelFor(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int length, Models.FilePair filePair, List results) + private static void ParallelFor(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int rootDirectoryLength, string? alternateFilesCollectionDirectory, Models.FilePair filePair, List results) { string fileName; bool abandoned = false; Models.FileHolder sourceDirectoryFileHolder; - Models.Property? property = GetProperty(filePair); Models.FileHolder imageFileInfo = new(filePair.Path); + (Models.Property? property, string[] alternateFileLines) = GetProperty(filePair, alternateFilesCollectionDirectory); bool? fileSizeChanged = property is not null ? property.FileSize != imageFileInfo.Length : null; - string relativePath = IPath.GetRelativePath(filePair.Path, length, forceExtensionToLower: true); + string relativePath = IPath.GetRelativePath(filePair.Path, rootDirectoryLength, forceExtensionToLower: true); bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(imageFileInfo.ExtensionLowered); bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime != imageFileInfo.LastWriteTime : null; if (filePair.Match is not null) @@ -104,22 +132,24 @@ internal abstract class Container File.SetCreationTime(sourceDirectoryFileHolder.FullName, imageFileInfo.LastWriteTime.Value); File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value); } - Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged); + Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsNotUniqueAndNeedsReview, filePair.IsUnique, isValidImageFormatExtension, property, alternateFileLines, abandoned, fileSizeChanged, lastWriteTimeChanged); lock (results) results.Add(new(filePair.Path, imageFileInfo.DirectoryName, filePair.IsUnique, filePair.Collection, item)); } - private static List GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, List filePairs) + private static List GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, string extension, List filePairs) { List results = new(); - int length = propertyConfiguration.RootDirectory.Length; int maxDegreeOfParallelism = Environment.ProcessorCount; + string? alternateResultAllInOne = !propertyConfiguration.ResultAllInOne.Contains(' ') ? null : propertyConfiguration.ResultAllInOne.Replace(' ', '-'); + string? alternateFilesCollectionDirectory = alternateResultAllInOne is null ? null : Path.Combine(Path.GetDirectoryName(filesCollectionDirectory) ?? filesCollectionDirectory, alternateResultAllInOne); + int filesCollectionDirectoryLength = filesCollectionDirectory.Length; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - _ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, length, filePairs[i], results)); + _ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, filesCollectionDirectoryLength, alternateFilesCollectionDirectory, filePairs[i], results)); return results; } - private static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string directorySearchFilter, List filesCollection) + private static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, List filesCollection, string directorySearchFilter) { List results = new(); string? directory; @@ -145,7 +175,7 @@ internal abstract class Container } } List filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection); - List collection = GetFilePairs(propertyConfiguration, aPropertySingletonDirectory, extension, filePairs); + List collection = GetFilePairs(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, extension, filePairs); foreach (FilePair filePair in collection) { if (filePair.Directory is null) @@ -168,12 +198,12 @@ internal abstract class Container return (collection.Count, results.ToArray()); } - internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, List filesCollection) + internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, List filesCollection) { int count; Models.Container[] results; const string directorySearchFilter = "*"; - (count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, directorySearchFilter, filesCollection); + (count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection, directorySearchFilter); return (count, results); } @@ -185,7 +215,7 @@ internal abstract class Container const string fileSearchFilter = "*"; const string directorySearchFilter = "*"; List filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage); - (count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, directorySearchFilter, filesCollection); + (count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, propertyConfiguration.RootDirectory, filesCollection, directorySearchFilter); return (count, results); } diff --git a/Shared/Models/Stateless/Methods/IContainer.cs b/Shared/Models/Stateless/Methods/IContainer.cs index fea54da..f34a751 100644 --- a/Shared/Models/Stateless/Methods/IContainer.cs +++ b/Shared/Models/Stateless/Methods/IContainer.cs @@ -25,10 +25,10 @@ public interface IContainer static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) => Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory); - (int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, List filesCollection) => - GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollection); - static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, List filesCollection) => - Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollection); + (int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, List filesCollection) => + GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection); + static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, List filesCollection) => + Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection); List TestStatic_GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, Models.Container[] containers) => GetFilteredDistinctIds(propertyConfiguration, containers); diff --git a/Shared/Models/Stateless/Methods/IDirectory.cs b/Shared/Models/Stateless/Methods/IDirectory.cs index 67c2e12..6d7ddf9 100644 --- a/Shared/Models/Stateless/Methods/IDirectory.cs +++ b/Shared/Models/Stateless/Methods/IDirectory.cs @@ -69,19 +69,19 @@ public interface IDirectory static void MoveFiles(List files, string find, string replace) => XDirectory.MoveFiles(files, find, replace); - (string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => + (string[], List<(Models.FileHolder, string?, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => GetToDoCollection(propertyConfiguration, filesCollection, directories, tick); - static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => + static (string[], List<(Models.FileHolder, string?, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, List filesCollection, string[] directories, Action? tick) => XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filesCollection, directories, tick); - (string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => + (string[], List<(Models.FileHolder, string?, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick); - static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => + static (string[], List<(Models.FileHolder, string?, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) => XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick); - List TestStatic_CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) => + List TestStatic_CopyOrMove(List<(Models.FileHolder, string?, string)> toDoCollection, bool move, bool moveBack, Action? tick) => CopyOrMove(toDoCollection, move, moveBack, tick); - static List CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) => + static List CopyOrMove(List<(Models.FileHolder, string?, string)> toDoCollection, bool move, bool moveBack, Action? tick) => XDirectory.CopyOrMove(toDoCollection, move, moveBack, tick); (bool, int?) TestStatic_GetId(int sortOrderOnlyLengthIndex, Models.FileHolder fileHolder) => diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index af16d46..2c91fa6 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -338,9 +338,9 @@ internal abstract partial class XDirectory return (from l in results orderby l.FileHolder.CreationTime, l.FileHolder.FullName.Length descending select l).ToArray(); } - internal static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) + internal static (string[], List<(Models.FileHolder, string?, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List filesCollection, string[] directories, Action? tick) { - List<(Models.FileHolder, string)> results = new(); + List<(Models.FileHolder, string?, string)> results = new(); string paddedId; string checkFile; string directory; @@ -350,7 +350,10 @@ internal abstract partial class XDirectory bool wrapped = false; string directoryName; bool paddedCheck = false; + string fileDirectoryName; SortedRecord sortedRecord; + string? alternateCheckFile; + string? alternateDirectory; Models.FileHolder fileHolder; List distinctIds = new(); List distinct = new(); @@ -358,6 +361,7 @@ internal abstract partial class XDirectory List distinctDirectories = new(); int intMinValueLength = int.MinValue.ToString().Length; SortedRecord[] sortedRecords = GetSortedRecords(filesCollection); + string? alternateResultAllInOne = !propertyConfiguration.ResultAllInOne.Contains(' ') ? null : propertyConfiguration.ResultAllInOne.Replace(' ', '-'); for (int i = 0; i < sortedRecords.Length; i++) { tick?.Invoke(); @@ -365,19 +369,24 @@ internal abstract partial class XDirectory fileHolder = sortedRecord.FileHolder; if (fileHolder.Name.EndsWith("len") || fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) continue; - (_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension); - directoryName = Path.GetFileName(fileHolder.DirectoryName); - if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(directoryName)) + (directoryName, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension); + fileDirectoryName = Path.GetFileName(fileHolder.DirectoryName); + if (fileDirectoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(fileDirectoryName)) { if (wrapped) continue; directory = directories[directoryIndex]; + if (alternateResultAllInOne is null) + alternateDirectory = null; + else + alternateDirectory = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(directory)) ?? directory, alternateResultAllInOne, directoryName); } else { if (!wrapped) wrapped = true; - directory = Path.Combine(directories[directoryIndex], directoryName); + alternateDirectory = null; + directory = Path.Combine(directories[directoryIndex], fileDirectoryName); } if (ifCanUseId && sortedRecord.NameWithoutExtensionIsIdFormat && sortedRecord.Id is not null && fileHolder.DirectoryName is not null) { @@ -401,6 +410,7 @@ internal abstract partial class XDirectory continue; if (!copyDuplicates) continue; + alternateDirectory = null; for (int j = 1; j < int.MaxValue; j++) { fileInfo = new(checkFile); @@ -416,8 +426,9 @@ internal abstract partial class XDirectory } if (distinct.Contains(checkFile)) continue; + alternateCheckFile = null; distinct.Add(checkFile); - results.Add(new(fileHolder, checkFile)); + results.Add(new(fileHolder, alternateCheckFile, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); break; @@ -427,7 +438,15 @@ internal abstract partial class XDirectory distinct.Add(checkFile); if (sortedRecord.Id is not null) distinctIds.Add(sortedRecord.Id.Value); - results.Add(new(fileHolder, checkFile)); + if (string.IsNullOrEmpty(alternateDirectory)) + alternateCheckFile = null; + else + { + alternateCheckFile = Path.Combine(alternateDirectory, $"{sortedRecord.Id}{fileHolder.ExtensionLowered}.tsv"); + if (!distinctDirectories.Contains(alternateDirectory)) + distinctDirectories.Add(alternateDirectory); + } + results.Add(new(fileHolder, alternateCheckFile, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); } @@ -436,13 +455,15 @@ internal abstract partial class XDirectory return (distinctDirectories.ToArray(), results); } - internal static List CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) + internal static List CopyOrMove(List<(Models.FileHolder, string?, string)> toDoCollection, bool move, bool moveBack, Action? tick) { List results = new(); FileInfo fileInfo; - foreach ((Models.FileHolder fileHolder, string to) in toDoCollection) + foreach ((Models.FileHolder fileHolder, string? alternateFile, string to) in toDoCollection) { tick?.Invoke(); + if (alternateFile is not null) + _ = XPath.WriteAllText(alternateFile, fileHolder.FullName, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); fileInfo = new(to); if (fileInfo.Exists) { diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index 9e55d0c..f98b742 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -141,6 +141,7 @@ public class UnitTestResize Shared.Models.Property? property = null; const bool isValidImageFormatExtension = true; List> subFileTuples = new(); + string[] alternateFileLines = Array.Empty(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; string[] changesFrom = new string[] { nameof(A_Property) }; @@ -173,7 +174,7 @@ public class UnitTestResize resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory); resize.Update(cResultsFullGroupDirectory); blurHasher.Update(cResultsFullGroupDirectory); - item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); + item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, alternateFileLines, false, false, false); Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) { diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 90b0842..60c4c6b 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -216,6 +216,7 @@ public class UnitTestFace Shared.Models.Property? property = null; const bool isValidImageFormatExtension = true; List> subFileTuples = new(); + string[] alternateFileLines = Array.Empty(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; string[] changesFrom = new string[] { nameof(A_Property) }; @@ -248,7 +249,7 @@ public class UnitTestFace resize.SetAngleBracketCollection(cResultsFullGroupDirectory, sourceDirectory); resize.Update(cResultsFullGroupDirectory); blurHasher.Update(cResultsFullGroupDirectory); - item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); + item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, alternateFileLines, false, false, false); Assert.IsNotNull(item.ImageFileHolder); if (item.Property is null) {