diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9adfc96..53e75a2 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -628,5 +628,19 @@ ], "problemMatcher": "$msCompile" }, + { + "label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20", + "type": "shell", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "X", + "L:/Git/AA", + "Day-Helper-2025-03-20", + "false", + "4" + ], + "problemMatcher": [] + } ] } \ No newline at end of file diff --git a/Compare/Compare.cs b/Compare/Compare.cs index 4791912..8114729 100644 --- a/Compare/Compare.cs +++ b/Compare/Compare.cs @@ -17,6 +17,21 @@ public partial class Compare : ICompare, IDisposable private ProgressBar? _ProgressBar; private readonly ProgressBarOptions _ProgressBarOptions; + void ICompare.Tick() => + _ProgressBar?.Tick(); + + void IDisposable.Dispose() + { + _ProgressBar?.Dispose(); + GC.SuppressFinalize(this); + } + + void ICompare.ConstructProgressBar(int maxTicks, string message) + { + _ProgressBar?.Dispose(); + _ProgressBar = new(maxTicks, message, _ProgressBarOptions); + } + public Compare(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) { if (isSilent) @@ -31,19 +46,46 @@ public partial class Compare : ICompare, IDisposable CompareWork(logger, appSettings, compare, ticks); } - void ICompare.Tick() => - _ProgressBar?.Tick(); - - void ICompare.ConstructProgressBar(int maxTicks, string message) + private void CompareWork(ILogger? logger, AppSettings appSettings, ICompare compare, long ticks) { - _ProgressBar?.Dispose(); - _ProgressBar = new(maxTicks, message, _ProgressBarOptions); - } - - void IDisposable.Dispose() - { - _ProgressBar?.Dispose(); - GC.SuppressFinalize(this); + const int updated = 0; + DistanceLimits? distanceLimits; + logger?.LogInformation("{Ticks}", ticks); + ReadOnlyCollection matrix; + ReadOnlyCollection saveContainers; + ReadOnlyCollection exifDirectories; + ReadOnlyCollection preFiltered; + ReadOnlyCollection postFiltered; + ReadOnlyDictionary onlyOne; + bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks); + ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings); + ReadOnlyCollection mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections); + ReadOnlyDictionary> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding); + foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions) + { + if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber)) + continue; + _ProgressBar?.Dispose(); + logger?.LogInformation("{outputResolution}", outputResolution); + exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution); + preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); + if (preFiltered.Count == 0) + continue; + distanceLimits = new(appSettings.DistanceSettings); + postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits); + if (postFiltered.Count == 0) + continue; + matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); + if (matrix.Count == 0) + continue; + onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix); + if (onlyOne.Count == 0) + continue; + saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne); + if (saveContainers.Count == 0) + continue; + IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers); + } } private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks) @@ -123,46 +165,4 @@ public partial class Compare : ICompare, IDisposable return results; } - private void CompareWork(ILogger? logger, AppSettings appSettings, ICompare compare, long ticks) - { - const int updated = 0; - DistanceLimits? distanceLimits; - logger?.LogInformation("{Ticks}", ticks); - ReadOnlyCollection matrix; - ReadOnlyCollection saveContainers; - ReadOnlyCollection exifDirectories; - ReadOnlyCollection preFiltered; - ReadOnlyCollection postFiltered; - ReadOnlyDictionary onlyOne; - bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks); - ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings); - ReadOnlyCollection mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections); - ReadOnlyDictionary> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding); - foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions) - { - if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber)) - continue; - _ProgressBar?.Dispose(); - logger?.LogInformation("{outputResolution}", outputResolution); - exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution); - preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); - if (preFiltered.Count == 0) - continue; - distanceLimits = new(appSettings.DistanceSettings); - postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits); - if (postFiltered.Count == 0) - continue; - matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); - if (matrix.Count == 0) - continue; - onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix); - if (onlyOne.Count == 0) - continue; - saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne); - if (saveContainers.Count == 0) - continue; - IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers); - } - } - } \ No newline at end of file diff --git a/Compare/Models/CompareSettings.cs b/Compare/Models/CompareSettings.cs index bc559be..98214cd 100644 --- a/Compare/Models/CompareSettings.cs +++ b/Compare/Models/CompareSettings.cs @@ -8,11 +8,8 @@ public record CompareSettings(string Company, string FacesFileNameExtension, string FacesHiddenFileNameExtension, string FacesPartsFileNameExtension, - string[] IgnoreExtensions, int MaxDegreeOfParallelism, - string[] OutputResolutions, - string[] ValidImageFormatExtensions, - string[] ValidVideoFormatExtensions) : Shared.Models.Properties.ICompareSettings + string[] OutputResolutions) : Shared.Models.Properties.ICompareSettings { public override string ToString() diff --git a/Distance/Models/Stateless/FilterLogicD.cs b/Distance/Models/Stateless/FilterLogicD.cs index 020e12c..8402781 100644 --- a/Distance/Models/Stateless/FilterLogicD.cs +++ b/Distance/Models/Stateless/FilterLogicD.cs @@ -11,11 +11,21 @@ namespace View_by_Distance.Distance.Models.Stateless; internal static class FilterLogicD { - internal record RecordA(long? Ticks, string? Directory); + internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath) + { + string result; + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); + result = Path.Combine(cContentDirectory, cei.Combined); + return result; + } - internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting); - - internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory); + internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath) + { + string result; + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); + result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension); + return result; + } internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName) { @@ -39,141 +49,12 @@ internal static class FilterLogicD else if (isBySorting && useFiltersCounter.HasValue) byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}"; else - { - byValue = $"{by.Value switch - { - IMapLogic.Mapping => nameof(IMapLogic.Mapping), - IMapLogic.Sorting => saveIndividually ? nameof(IMapLogic.Individually) : nameof(IMapLogic.Sorting), - IMapLogic.ForceSingleImage => forceSingleImageHumanized, - _ => throw new NotImplementedException() - }}{(!isDefaultName ? "-A" : "-Z")}"; - } + byValue = IDistance.Get(saveIndividually, forceSingleImageHumanized, by.Value, isDefaultName); } result = new(byValue, isByMapping, isBySorting); return result; } - private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) => - Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName); - - private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB) - { - RecordC result; - if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName)) - throw new NotImplementedException(); - long? ticks = null; - string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName); - string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB); - string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk"); - result = new(debugDirectory, directory, ticks, personDirectory); - return result; - } - - internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath) - { - string result; - CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); - result = Path.Combine(cContentDirectory, cei.Combined); - return result; - } - - internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath) - { - string result; - CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); - result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension); - return result; - } - - internal static ReadOnlyCollection GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) - { - List results = []; - RecordB recordB; - RecordC recordC; - string segmentB; - string checkFile; - string? directory; - string shortcutFile; - string facesDirectory; - bool isCounterPersonYear; - string facePartsDirectory; - FileHolder? faceFileHolder; - SaveContainer? saveContainer; - FileHolder? resizedFileHolder; - int? useFiltersCounter = null; - string resizeContentDirectory; - FileHolder? facePartsFileHolder; - FileHolder? hiddenFaceFileHolder; - LocationContainer locationContainer; - bool sortingContainersAny = onlyOne.Count > 0; - string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings, - nameof(E_Distance), - resultSettings.ResultContent); - string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings, - nameof(C_Resize), - outputResolution, - includeResizeGroup: true, - includeModel: false, - includePredictorModel: false); - string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings, - nameof(D2_FaceParts), - outputResolution, - includeResizeGroup: true, - includeModel: true, - includePredictorModel: true); - string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent); - if (!Directory.Exists(cContentDirectory)) - _ = Directory.CreateDirectory(cContentDirectory); - string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString()); - if (!Directory.Exists(eDistanceContentTicksDirectory)) - _ = Directory.CreateDirectory(eDistanceContentTicksDirectory); - string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent); - if (!Directory.Exists(d2FacePartsContentDirectory)) - _ = Directory.CreateDirectory(d2FacePartsContentDirectory); - string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); - string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; - compare.ConstructProgressBar(onlyOne.Count, message); - foreach (KeyValuePair keyValuePair in onlyOne) - { - if (distanceSettings.SaveIndividually) - break; - locationContainer = keyValuePair.Value; - if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null) - continue; - segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2]; - if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null) - continue; - isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks); - recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName); - recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB); - if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory)) - continue; - directory = recordC.Directory; - if (!string.IsNullOrEmpty(recordC.DebugDirectory)) - results.Add(SaveContainer.Get(recordC.DebugDirectory)); - if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null) - { - if (!distanceSettings.SaveSortingWithoutPerson) - throw new NotSupportedException(); - if (recordC.Ticks is null) - continue; - } - results.Add(SaveContainer.Get(recordC.PersonDirectory)); - facesDirectory = locationContainer.LengthSource.DirectoryFullPath; - faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName); - checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}"); - shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk"); - resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource); - facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource); - hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}")); - facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}")); - resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}")); - saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile); - results.Add(saveContainer); - } - return results.AsReadOnly(); - } - internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection saveContainers) { string fileName; @@ -285,4 +166,115 @@ internal static class FilterLogicD } } + internal static ReadOnlyCollection GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) + { + List results = []; + RecordB recordB; + RecordC recordC; + string segmentB; + string checkFile; + string? directory; + string shortcutFile; + string facesDirectory; + bool isCounterPersonYear; + string facePartsDirectory; + FileHolder? faceFileHolder; + SaveContainer? saveContainer; + FileHolder? resizedFileHolder; + int? useFiltersCounter = null; + string resizeContentDirectory; + FileHolder? facePartsFileHolder; + FileHolder? hiddenFaceFileHolder; + LocationContainer locationContainer; + bool sortingContainersAny = onlyOne.Count > 0; + string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings, + nameof(E_Distance), + resultSettings.ResultContent); + string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings, + nameof(C_Resize), + outputResolution, + includeResizeGroup: true, + includeModel: false, + includePredictorModel: false); + string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings, + nameof(D2_FaceParts), + outputResolution, + includeResizeGroup: true, + includeModel: true, + includePredictorModel: true); + string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent); + if (!Directory.Exists(cContentDirectory)) + _ = Directory.CreateDirectory(cContentDirectory); + string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString()); + if (!Directory.Exists(eDistanceContentTicksDirectory)) + _ = Directory.CreateDirectory(eDistanceContentTicksDirectory); + string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent); + if (!Directory.Exists(d2FacePartsContentDirectory)) + _ = Directory.CreateDirectory(d2FacePartsContentDirectory); + string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); + string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; + compare.ConstructProgressBar(onlyOne.Count, message); + foreach (KeyValuePair keyValuePair in onlyOne) + { + if (distanceSettings.SaveIndividually) + break; + locationContainer = keyValuePair.Value; + if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null) + continue; + segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2]; + if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null) + continue; + isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks); + recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName); + recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB); + if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory)) + continue; + directory = recordC.Directory; + if (!string.IsNullOrEmpty(recordC.DebugDirectory)) + results.Add(SaveContainer.Get(recordC.DebugDirectory)); + if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null) + { + if (!distanceSettings.SaveSortingWithoutPerson) + throw new NotSupportedException(); + if (recordC.Ticks is null) + continue; + } + results.Add(SaveContainer.Get(recordC.PersonDirectory)); + facesDirectory = locationContainer.LengthSource.DirectoryFullPath; + faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName); + checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}"); + shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk"); + resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource); + facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource); + hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}")); + facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}")); + resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}")); + saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile); + results.Add(saveContainer); + } + return results.AsReadOnly(); + } + + private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) => + Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName); + + private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB) + { + RecordC result; + if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName)) + throw new NotImplementedException(); + long? ticks = null; + string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName); + string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB); + string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk"); + result = new(debugDirectory, directory, ticks, personDirectory); + return result; + } + + internal record RecordA(long? Ticks, string? Directory); + + internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting); + + internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory); + } \ No newline at end of file diff --git a/Distance/Models/Stateless/IDistance.cs b/Distance/Models/Stateless/IDistance.cs index eac1a4e..9189845 100644 --- a/Distance/Models/Stateless/IDistance.cs +++ b/Distance/Models/Stateless/IDistance.cs @@ -9,49 +9,69 @@ namespace View_by_Distance.Distance.Models.Stateless; public interface IDistance { - static ReadOnlyCollection TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => - GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); - static ReadOnlyCollection GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => - MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); + static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) => + $"{by switch + { + IMapLogic.Mapping => nameof(IMapLogic.Mapping), + IMapLogic.Sorting => saveIndividually ? + nameof(IMapLogic.Individually) : + nameof(IMapLogic.Sorting), + IMapLogic.ForceSingleImage => forceSingleImageHumanized, + _ => throw new NotImplementedException() + }}{(!isDefaultName ? "-A" : "-Z")}"; - static ReadOnlyDictionary> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) => - Extract(compareSettings, exifDirectories); - static ReadOnlyDictionary> Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) => - MappedLogicA.Extract(compareSettings, exifDirectories); - - static ReadOnlyCollection TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection exifDirectories) => - GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories); - static ReadOnlyCollection GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection exifDirectories) => - FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories); - - static ReadOnlyCollection TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary> keyValuePairs, ReadOnlyCollection exifDirectories) => - GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); - static ReadOnlyCollection GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary> keyValuePairs, ReadOnlyCollection exifDirectories) => - FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); - - static ReadOnlyCollection TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection preFiltered, DistanceLimits distanceLimits) => - GetPostFilterLocationContainer(preFiltered, distanceLimits); - static ReadOnlyCollection GetPostFilterLocationContainer(ReadOnlyCollection preFiltered, DistanceLimits distanceLimits) => - FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits); - - static ReadOnlyCollection TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection postFiltered) => - GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); - static ReadOnlyCollection GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection postFiltered) => - FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); - - static ReadOnlyDictionary TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection matrix) => - GetOnlyOne(distanceSettings, matrix); - static ReadOnlyDictionary GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection matrix) => + public static ReadOnlyDictionary GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection matrix) => FilterLogicC.GetOnlyOne(distanceSettings, matrix); - static ReadOnlyCollection TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) => - GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne); - static ReadOnlyCollection GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) => - FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne); + public static ReadOnlyCollection GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection exifDirectories) => + FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories); - static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection saveContainers) => - SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers); - static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection saveContainers) => + public static ReadOnlyCollection GetPostFilterLocationContainer(ReadOnlyCollection preFiltered, DistanceLimits distanceLimits) => + FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits); + + public static ReadOnlyDictionary> Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) => + MappedLogicA.Extract(compareSettings, exifDirectories); + + public static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection saveContainers) => FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers); + public static ReadOnlyCollection GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) => + FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne); + + public static ReadOnlyCollection GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => + MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); + + public static ReadOnlyCollection GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection postFiltered) => + FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); + + public static ReadOnlyCollection GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary> keyValuePairs, ReadOnlyCollection exifDirectories) => + FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); + + internal static ReadOnlyDictionary TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection matrix) => + GetOnlyOne(distanceSettings, matrix); + + internal static ReadOnlyCollection TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection exifDirectories) => + GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories); + + internal static ReadOnlyCollection TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection preFiltered, DistanceLimits distanceLimits) => + GetPostFilterLocationContainer(preFiltered, distanceLimits); + + internal static ReadOnlyDictionary> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) => + Extract(compareSettings, exifDirectories); + + internal static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection saveContainers) => + SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers); + + internal static ReadOnlyCollection TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary onlyOne) => + GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne); + + internal static ReadOnlyCollection TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => + GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); + + internal static ReadOnlyCollection TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection postFiltered) => + GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered); + + internal static ReadOnlyCollection TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary> keyValuePairs, ReadOnlyCollection exifDirectories) => + GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories); + } \ No newline at end of file diff --git a/Distance/Models/Stateless/MappedLogicA.cs b/Distance/Models/Stateless/MappedLogicA.cs index e9c5534..1d95016 100644 --- a/Distance/Models/Stateless/MappedLogicA.cs +++ b/Distance/Models/Stateless/MappedLogicA.cs @@ -14,33 +14,53 @@ internal static class MappedLogicA string? PersonDisplayDirectoryName, FilePath FilePath); - private static List GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections) + internal static ReadOnlyDictionary> Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) { - List results = []; - FilePath filePath; - MappedFile mappedFile; - string personKeyFormatted; - List distinct = []; - PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName; - foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers) + Dictionary> results = []; + int? wholePercentages; + Dictionary? keyValues; + Dictionary> keyValuePairs = []; + foreach (ExifDirectory exifDirectory in exifDirectories) { - if (personContainer.Key is null) + if (exifDirectory.FilePath.Id is null) continue; - for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--) + if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues)) { - filePath = personContainer.DisplayDirectoryAllFilePaths[i]; - if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension) - continue; - if (distinct.Contains(filePath.Name)) - continue; - distinct.Add(filePath.Name); - personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value); - personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name); - mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath); - results.Add(mappedFile); + keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []); + if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues)) + throw new Exception(); } + wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath); + if (wholePercentages is null) + continue; + keyValues.Add(wholePercentages.Value, exifDirectory.FilePath); } - return results; + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly()); + return results.AsReadOnly(); + } + + internal static ReadOnlyCollection GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) + { + List results = []; + string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent)); + ReadOnlyCollection records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections); + ReadOnlyCollection mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records); + if (mappedFiles.Count > 0) + { + int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism; + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)"; + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; + ReadOnlyDictionary> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection; + compare.ConstructProgressBar(mappedFiles.Count, message); + _ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) => + { + compare.Tick(); + MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]); + }); + } + return results.AsReadOnly(); } private static ReadOnlyCollection GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection records) @@ -102,6 +122,35 @@ internal static class MappedLogicA return results.AsReadOnly(); } + private static List GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections) + { + List results = []; + FilePath filePath; + MappedFile mappedFile; + string personKeyFormatted; + List distinct = []; + PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName; + foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers) + { + if (personContainer.Key is null) + continue; + for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--) + { + filePath = personContainer.DisplayDirectoryAllFilePaths[i]; + if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension) + continue; + if (distinct.Contains(filePath.Name)) + continue; + distinct.Add(filePath.Name); + personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value); + personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name); + mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath); + results.Add(mappedFile); + } + } + return results; + } + private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List exifDirectories, ReadOnlyDictionary> skipCollection, MappedFile mappedFile) { int? id; @@ -152,53 +201,4 @@ internal static class MappedLogicA exifDirectories.Add(exifDirectory); } - internal static ReadOnlyCollection GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) - { - List results = []; - string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent)); - ReadOnlyCollection records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections); - ReadOnlyCollection mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records); - if (mappedFiles.Count > 0) - { - int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism; - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)"; - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - ReadOnlyDictionary> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection; - compare.ConstructProgressBar(mappedFiles.Count, message); - _ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) => - { - compare.Tick(); - MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]); - }); - } - return results.AsReadOnly(); - } - - internal static ReadOnlyDictionary> Extract(ICompareSettings compareSettings, ReadOnlyCollection exifDirectories) - { - Dictionary> results = []; - int? wholePercentages; - Dictionary? keyValues; - Dictionary> keyValuePairs = []; - foreach (ExifDirectory exifDirectory in exifDirectories) - { - if (exifDirectory.FilePath.Id is null) - continue; - if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues)) - { - keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []); - if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues)) - throw new Exception(); - } - wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath); - if (wholePercentages is null) - continue; - keyValues.Add(wholePercentages.Value, exifDirectory.FilePath); - } - foreach (KeyValuePair> keyValuePair in keyValuePairs) - results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly()); - return results.AsReadOnly(); - } - } \ No newline at end of file diff --git a/Distance/Models/Stateless/MappedLogicB.cs b/Distance/Models/Stateless/MappedLogicB.cs index aef7c3e..1ba5f00 100644 --- a/Distance/Models/Stateless/MappedLogicB.cs +++ b/Distance/Models/Stateless/MappedLogicB.cs @@ -24,327 +24,6 @@ internal static class MappedLogicB bool? IsLocationContainerDebugDirectory, float? TotalDays); - private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames) - { - string checkFile; - string actionDirectoryName = Path.GetFileName(actionDirectory); - string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - foreach (string file in files) - { - if (facesFileNames.Contains(file)) - { - checkFile = Path.Combine(checkDirectory, Path.GetFileName(file)); - if (File.Exists(checkFile)) - continue; - File.Move(file, checkFile); - continue; - } - File.Delete(file); - } - } - - private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory) - { - string[] files; - string checkFile; - string? checkDirectory; - string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory)); - if (!Directory.Exists(checkDirectory)) - Directory.Move(directory, checkDirectory); - else - { - files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); - foreach (string file in files) - { - if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted)) - continue; - checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted); - checkDirectory = Path.GetDirectoryName(checkFile); - if (checkDirectory is null) - continue; - if (File.Exists(checkFile)) - continue; - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - File.Move(file, checkFile); - } - } - } - _ = IPath.DeleteEmptyDirectories(personKeyDirectory); - } - - private static List UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory) - { - List results = []; - float? totalDays; - long? next = null; - string? checkDirectory; - DateTime directoryDateTime; - DirectoryInfo directoryInfo; - TicksDirectory ticksDirectory; - long? lastDirectoryTicks = null; - DateTime dateTime = DateTime.Now; - DateTime alternateDirectoryDateTime; - string ticksDirectoryNameFirstSegment; - bool? isLocationContainerDebugDirectory; - long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks; - for (int i = 1; i < 5; i++) - _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); - if (!Directory.Exists(eDistanceContentDirectory)) - _ = Directory.CreateDirectory(eDistanceContentDirectory); - string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string ticksFullPath in ticksFullPaths) - { - ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0]; - if (ticksDirectoryNameFirstSegment.Length < 3) - continue; - if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks)) - throw new NotSupportedException(); - if (next is null) - next = new DateTime(directoryTicks).Ticks; - else - { - next += month; - checkDirectory = Path.GetDirectoryName(ticksFullPath); - if (string.IsNullOrEmpty(checkDirectory)) - { - if (string.IsNullOrEmpty(checkDirectory)) - continue; - checkDirectory = Path.Combine(checkDirectory, next.Value.ToString()); - if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern)) - continue; - Directory.Move(ticksFullPath, checkDirectory); - continue; - } - } - directoryInfo = new(ticksFullPath); - directoryDateTime = new DateTime(directoryTicks); - if (directoryInfo.CreationTime.Ticks != directoryTicks) - Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks)); - if (directoryInfo.LastWriteTime.Ticks != directoryTicks) - Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks)); - alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1); - isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory); - totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays; - ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays); - results.Add(ticksDirectory); - if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0) - continue; - lastDirectoryTicks = directoryTicks; - } - string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray(); - if (compare.Length > 0 && distanceSettings.ReMap) - throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); - return results; - } - - private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory) - { - bool isDefault; - string[] files; - FileInfo[] collection; - string[] facesFileNames; - string yearDirectoryName; - string[] yearDirectories; - string alphaDirectoryName; - string matchDirectoryName; - string personKeyFormatted; - string[] alphaDirectories; - string[] matchDirectories; - string[] actionDirectories; - string personDisplayDirectory; - string[] personKeyDirectories; - string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly); - foreach (string segmentCDirectory in segmentCDirectories) - { - personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string personKeyDirectory in personKeyDirectories) - { - personKeyFormatted = Path.GetFileName(personKeyDirectory); - yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string yearDirectory in yearDirectories) - { - yearDirectoryName = Path.GetFileName(yearDirectory); - if (yearDirectoryName.StartsWith('=')) - Directory.Move(yearDirectory, yearDirectory.Replace('=', '~')); - } - yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string yearDirectory in yearDirectories) - { - yearDirectoryName = Path.GetFileName(yearDirectory); - matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); - alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray(); - if (alphaDirectories.Length == 0) - continue; - alphaDirectoryName = Path.GetFileName(alphaDirectories[0]); - foreach (string matchDirectory in matchDirectories) - { - matchDirectoryName = Path.GetFileName(matchDirectory); - files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly); - if (files.Length != 4) - continue; - collection = files.Select(l => new FileInfo(l)).ToArray(); - isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); - if (isDefault) - facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray(); - else - facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray(); - if (facesFileNames.Length == 0) - continue; - personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName); - if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory)) - continue; - _ = Process.Start("explorer", matchDirectory); - for (int i = 0; i < int.MaxValue; i++) - { - Thread.Sleep(500); - actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray(); - if (actionDirectories.Length > 0) - { - MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames); - break; - } - } - } - } - } - } - } - - private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file) - { - string result; - string checkDirectory; - string directory = file; - List collection = []; - for (int i = 0; i < file.Length; i++) - { - directory = Path.GetDirectoryName(directory) ?? throw new Exception(); - if (directory == ticksDirectory.Directory) - break; - collection.Add(Path.GetFileName(directory)); - } - collection.Reverse(); - checkDirectory = $"{ticksDirectory.Directory}.{@enum}"; - foreach (string directoryName in collection) - checkDirectory = Path.Combine(checkDirectory, directoryName); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - result = Path.Combine(checkDirectory, fileName); - if (File.Exists(result)) - throw new Exception($"File <{fileName}> already exists!"); - File.Move(file, result); - return result; - } - - private static List GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List distinct, string? personDisplayDirectoryName) - { - List results = []; - string @enum; - Record record; - string fileName; - string checkFile; - FilePath filePath; - FileHolder fileHolder; - int? wholePercentages; - foreach (string file in files) - { - if (file.EndsWith(".lnk")) - continue; - fileHolder = FileHolder.Get(file); - filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); - if (filePath.Id is null) - continue; - wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath); - if (wholePercentages is null) - continue; - fileName = Path.GetFileName(file); - if (distinct.Contains(fileName)) - { - checkFile = $"{file}.dup"; - if (File.Exists(checkFile)) - continue; - File.Move(file, checkFile); - continue; - } - if (file.StartsWith(ticksDirectory.Directory)) - { - @enum = IPath.GetEnum(filePath).ToString(); - if (!ticksDirectory.Directory.EndsWith(@enum)) - { - checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file); - fileHolder = FileHolder.Get(checkFile); - filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); - if (filePath.Id is null) - continue; - } - } - distinct.Add(fileName); - record = new(DirectoryNumber: directoryNumber, - IsDefault: isDefault, - LinksCount: linksCount, - MappedFaceFilePath: filePath, - PersonDisplayDirectoryName: personDisplayDirectoryName, - PersonKeyFormatted: personKeyFormatted); - results.Add(record); - } - return results; - } - - private static string[] RenameBirth(string[] files) - { - List results = []; - string checkFile; - foreach (string file in files) - { - if (file.EndsWith(".brt")) - { - results.Add(file); - continue; - } - checkFile = $"{file}.brt"; - if (File.Exists(checkFile)) - { - results.Add(file); - continue; - } - File.Move(file, checkFile); - results.Add(checkFile); - } - return results.ToArray(); - } - - private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory) - { - string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted); - if (Directory.Exists(newestPersonKeyDirectory)) - MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory); - else - Directory.Move(personKeyDirectory, newestPersonKeyDirectory); - } - - private static int? GetLinksCount(string yearDirectory) - { - int? result; - string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-'); - if (yearDirectoryNameSegments.Length != 3) - result = null; - else - { - string lastSegment = yearDirectoryNameSegments[^1]; - if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0])) - result = null; - else - result = lastSegment[0] - 65; - } - return result; - } - internal static ReadOnlyCollection DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections) { List results = []; @@ -526,4 +205,325 @@ internal static class MappedLogicB return results.AsReadOnly(); } + private static List UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory) + { + List results = []; + float? totalDays; + long? next = null; + string? checkDirectory; + DateTime directoryDateTime; + DirectoryInfo directoryInfo; + TicksDirectory ticksDirectory; + long? lastDirectoryTicks = null; + DateTime dateTime = DateTime.Now; + DateTime alternateDirectoryDateTime; + string ticksDirectoryNameFirstSegment; + bool? isLocationContainerDebugDirectory; + long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks; + for (int i = 1; i < 5; i++) + _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); + if (!Directory.Exists(eDistanceContentDirectory)) + _ = Directory.CreateDirectory(eDistanceContentDirectory); + string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string ticksFullPath in ticksFullPaths) + { + ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0]; + if (ticksDirectoryNameFirstSegment.Length < 3) + continue; + if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks)) + throw new NotSupportedException(); + if (next is null) + next = new DateTime(directoryTicks).Ticks; + else + { + next += month; + checkDirectory = Path.GetDirectoryName(ticksFullPath); + if (string.IsNullOrEmpty(checkDirectory)) + { + if (string.IsNullOrEmpty(checkDirectory)) + continue; + checkDirectory = Path.Combine(checkDirectory, next.Value.ToString()); + if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern)) + continue; + Directory.Move(ticksFullPath, checkDirectory); + continue; + } + } + directoryInfo = new(ticksFullPath); + directoryDateTime = new DateTime(directoryTicks); + if (directoryInfo.CreationTime.Ticks != directoryTicks) + Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks)); + if (directoryInfo.LastWriteTime.Ticks != directoryTicks) + Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks)); + alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1); + isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory); + totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays; + ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays); + results.Add(ticksDirectory); + if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0) + continue; + lastDirectoryTicks = directoryTicks; + } + string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray(); + if (compare.Length > 0 && distanceSettings.ReMap) + throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); + return results; + } + + private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory) + { + bool isDefault; + string[] files; + FileInfo[] collection; + string[] facesFileNames; + string yearDirectoryName; + string[] yearDirectories; + string alphaDirectoryName; + string matchDirectoryName; + string personKeyFormatted; + string[] alphaDirectories; + string[] matchDirectories; + string[] actionDirectories; + string personDisplayDirectory; + string[] personKeyDirectories; + string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly); + foreach (string segmentCDirectory in segmentCDirectories) + { + personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string personKeyDirectory in personKeyDirectories) + { + personKeyFormatted = Path.GetFileName(personKeyDirectory); + yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string yearDirectory in yearDirectories) + { + yearDirectoryName = Path.GetFileName(yearDirectory); + if (yearDirectoryName.StartsWith('=')) + Directory.Move(yearDirectory, yearDirectory.Replace('=', '~')); + } + yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string yearDirectory in yearDirectories) + { + yearDirectoryName = Path.GetFileName(yearDirectory); + matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); + alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray(); + if (alphaDirectories.Length == 0) + continue; + alphaDirectoryName = Path.GetFileName(alphaDirectories[0]); + foreach (string matchDirectory in matchDirectories) + { + matchDirectoryName = Path.GetFileName(matchDirectory); + files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly); + if (files.Length != 4) + continue; + collection = files.Select(l => new FileInfo(l)).ToArray(); + isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]); + if (isDefault) + facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray(); + else + facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray(); + if (facesFileNames.Length == 0) + continue; + personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName); + if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory)) + continue; + _ = Process.Start("explorer", matchDirectory); + for (int i = 0; i < int.MaxValue; i++) + { + Thread.Sleep(500); + actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray(); + if (actionDirectories.Length > 0) + { + MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames); + break; + } + } + } + } + } + } + } + + private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames) + { + string checkFile; + string actionDirectoryName = Path.GetFileName(actionDirectory); + string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + foreach (string file in files) + { + if (facesFileNames.Contains(file)) + { + checkFile = Path.Combine(checkDirectory, Path.GetFileName(file)); + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + continue; + } + File.Delete(file); + } + } + + private static int? GetLinksCount(string yearDirectory) + { + int? result; + string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-'); + if (yearDirectoryNameSegments.Length != 3) + result = null; + else + { + string lastSegment = yearDirectoryNameSegments[^1]; + if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0])) + result = null; + else + result = lastSegment[0] - 65; + } + return result; + } + + private static string[] RenameBirth(string[] files) + { + List results = []; + string checkFile; + foreach (string file in files) + { + if (file.EndsWith(".brt")) + { + results.Add(file); + continue; + } + checkFile = $"{file}.brt"; + if (File.Exists(checkFile)) + { + results.Add(file); + continue; + } + File.Move(file, checkFile); + results.Add(checkFile); + } + return results.ToArray(); + } + + private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory) + { + string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted); + if (Directory.Exists(newestPersonKeyDirectory)) + MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory); + else + Directory.Move(personKeyDirectory, newestPersonKeyDirectory); + } + + private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory) + { + string[] files; + string checkFile; + string? checkDirectory; + string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory)); + if (!Directory.Exists(checkDirectory)) + Directory.Move(directory, checkDirectory); + else + { + files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); + foreach (string file in files) + { + if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted)) + continue; + checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted); + checkDirectory = Path.GetDirectoryName(checkFile); + if (checkDirectory is null) + continue; + if (File.Exists(checkFile)) + continue; + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + File.Move(file, checkFile); + } + } + } + _ = IPath.DeleteEmptyDirectories(personKeyDirectory); + } + + private static List GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List distinct, string? personDisplayDirectoryName) + { + List results = []; + string @enum; + Record record; + string fileName; + string checkFile; + FilePath filePath; + FileHolder fileHolder; + int? wholePercentages; + foreach (string file in files) + { + if (file.EndsWith(".lnk")) + continue; + fileHolder = FileHolder.Get(file); + filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); + if (filePath.Id is null) + continue; + wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath); + if (wholePercentages is null) + continue; + fileName = Path.GetFileName(file); + if (distinct.Contains(fileName)) + { + checkFile = $"{file}.dup"; + if (File.Exists(checkFile)) + continue; + File.Move(file, checkFile); + continue; + } + if (file.StartsWith(ticksDirectory.Directory)) + { + @enum = IPath.GetEnum(filePath).ToString(); + if (!ticksDirectory.Directory.EndsWith(@enum)) + { + checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file); + fileHolder = FileHolder.Get(checkFile); + filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); + if (filePath.Id is null) + continue; + } + } + distinct.Add(fileName); + record = new(DirectoryNumber: directoryNumber, + IsDefault: isDefault, + LinksCount: linksCount, + MappedFaceFilePath: filePath, + PersonDisplayDirectoryName: personDisplayDirectoryName, + PersonKeyFormatted: personKeyFormatted); + results.Add(record); + } + return results; + } + + private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file) + { + string result; + string checkDirectory; + string directory = file; + List collection = []; + for (int i = 0; i < file.Length; i++) + { + directory = Path.GetDirectoryName(directory) ?? throw new Exception(); + if (directory == ticksDirectory.Directory) + break; + collection.Add(Path.GetFileName(directory)); + } + collection.Reverse(); + checkDirectory = $"{ticksDirectory.Directory}.{@enum}"; + foreach (string directoryName in collection) + checkDirectory = Path.Combine(checkDirectory, directoryName); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + result = Path.Combine(checkDirectory, fileName); + if (File.Exists(result)) + throw new Exception($"File <{fileName}> already exists!"); + File.Move(file, result); + return result; + } + } \ No newline at end of file diff --git a/Metadata/Models/Stateless/Get.cs b/Metadata/Models/Stateless/Get.cs index 42d105f..f9e0c7f 100644 --- a/Metadata/Models/Stateless/Get.cs +++ b/Metadata/Models/Stateless/Get.cs @@ -54,51 +54,7 @@ internal static class Get return results.AsReadOnly(); } - internal static Action SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List distinct, List metadataGroups) - { - return file => - { - rename.Tick(); - ExifDirectory exifDirectory; - MetadataGroup metadataGroup; - DeterministicHashCode deterministicHashCode; - FileHolder fileHolder = FileHolder.Get(file); - bool fastForwardMovingPictureExpertsGroupUsed; - MinimumYearAndPathCombined minimumYearAndPathCombined; - FilePath? fastForwardMovingPictureExpertsGroupFilePath; - ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; - FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); - string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}"; - if (distinct.Contains(key)) - throw new NotSupportedException("Turn off parallelism when sidecar files are present!"); - if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null)) - return; - if (filePath.Id is not null) - { - fastForwardMovingPictureExpertsGroupFiles = null; - deterministicHashCode = new(null, filePath.Id, null); - } - else - { - fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(renameSettings, filePath); - fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null); - deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath); - } - filePath = FilePath.Get(filePath, deterministicHashCode); - fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0; - (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath); - metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([])); - lock (metadataGroups) - metadataGroups.Add(metadataGroup); - if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null) - { - foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) - File.Delete(fastForwardMovingPictureExpertsGroupFile); - } - }; - } - - internal static Action SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List distinct, List metadataGroups) + internal static Action SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List distinct, List metadataGroups) { return file => { @@ -125,7 +81,7 @@ internal static class Get } else { - fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(windowsSettings, httpClient, filePath); + fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, httpClient, filePath); fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null); deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath); } @@ -145,4 +101,48 @@ internal static class Get }; } + internal static Action SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List distinct, List metadataGroups) + { + return file => + { + rename.Tick(); + ExifDirectory exifDirectory; + MetadataGroup metadataGroup; + DeterministicHashCode deterministicHashCode; + FileHolder fileHolder = FileHolder.Get(file); + bool fastForwardMovingPictureExpertsGroupUsed; + MinimumYearAndPathCombined minimumYearAndPathCombined; + FilePath? fastForwardMovingPictureExpertsGroupFilePath; + ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; + FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null); + string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}"; + if (distinct.Contains(key)) + throw new NotSupportedException("Turn off parallelism when sidecar files are present!"); + if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null)) + return; + if (filePath.Id is not null) + { + fastForwardMovingPictureExpertsGroupFiles = null; + deterministicHashCode = new(null, filePath.Id, null); + } + else + { + fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, filePath); + fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null); + deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath); + } + filePath = FilePath.Get(filePath, deterministicHashCode); + fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0; + (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath); + metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([])); + lock (metadataGroups) + metadataGroups.Add(metadataGroup); + if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null) + { + foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) + File.Delete(fastForwardMovingPictureExpertsGroupFile); + } + }; + } + } \ No newline at end of file diff --git a/Metadata/Models/Stateless/IMetadata.cs b/Metadata/Models/Stateless/IMetadata.cs index 6654e93..c673cb5 100644 --- a/Metadata/Models/Stateless/IMetadata.cs +++ b/Metadata/Models/Stateless/IMetadata.cs @@ -72,9 +72,9 @@ public interface IMetadata static ReadOnlyDictionary> GetKeyValuePairs(IEnumerable collection) => Get.GetKeyValuePairs(collection); - Action TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List distinct, List metadataGroups) => - SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups); - static Action SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List distinct, List metadataGroups) => - Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups); + Action TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List distinct, List metadataGroups) => + SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups); + static Action SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List distinct, List metadataGroups) => + Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups); } \ No newline at end of file diff --git a/Rename/Models/RenameSettings.cs b/Rename/Models/RenameSettings.cs index aed9aca..d4f2008 100644 --- a/Rename/Models/RenameSettings.cs +++ b/Rename/Models/RenameSettings.cs @@ -9,7 +9,6 @@ public record RenameSettings(string Company, Dictionary DirectoryDictionary, string? FirstPassFile, bool ForceNewId, - string[] IgnoreExtensions, bool InPlace, bool InPlaceMoveDirectory, bool InPlaceWithOriginalName, @@ -20,9 +19,7 @@ public record RenameSettings(string Company, string RelativePropertyCollectionFile, bool RequireRootDirectoryExists, string[] SidecarExtensions, - bool SkipIdFiles, - string[] ValidImageFormatExtensions, - string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameSettings + bool SkipIdFiles) : Shared.Models.Properties.IRenameSettings { public override string ToString() diff --git a/Rename/Rename.cs b/Rename/Rename.cs index 2ed8bb7..52adeea 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -11,7 +11,6 @@ using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models.Stateless; using View_by_Distance.Rename.Models; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Rename; @@ -35,39 +34,58 @@ public partial class Rename : IRename, IDisposable private ProgressBar? _ProgressBar; private readonly ProgressBarOptions _ProgressBarOptions; - public Rename(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) - { - if (isSilent) - { } - if (args is null) - throw new NullReferenceException(nameof(args)); - if (console is null) - throw new NullReferenceException(nameof(console)); - IRename rename = this; - long ticks = DateTime.Now.Ticks; - _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - RenameWork(logger, appSettings, rename, ticks); - } - void IRename.Tick() => _ProgressBar?.Tick(); - void IRename.ConstructProgressBar(int maxTicks, string message) - { - _ProgressBar?.Dispose(); - _ProgressBar = new(maxTicks, message, _ProgressBarOptions); - } - void IDisposable.Dispose() { _ProgressBar?.Dispose(); GC.SuppressFinalize(this); } - ReadOnlyCollection IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath) + void IRename.ConstructProgressBar(int maxTicks, string message) + { + _ProgressBar?.Dispose(); + _ProgressBar = new(maxTicks, message, _ProgressBarOptions); + } + + DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath) + { + DeterministicHashCode result; + int? id; + int? width; + int? height; + try + { +#pragma warning disable CA1416 + using Image image = Image.FromFile(filePath.FullName); + width = image.Width; + height = image.Height; + using Bitmap bitmap = new(image); + Rectangle rectangle = new(0, 0, image.Width, image.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + byte[] bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + bitmap.UnlockBits(bitmapData); +#pragma warning restore CA1416 + id = IId.GetDeterministicHashCode(bytes); + } + catch (Exception) + { + id = null; + width = null; + height = null; + } + result = new(height, id, width); + return result; + } + + ReadOnlyCollection IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath) { List results = []; - bool isValidVideoFormatExtensions = renameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); + bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); if (isValidVideoFormatExtensions) { bool check; @@ -97,40 +115,241 @@ public partial class Rename : IRename, IDisposable return results.AsReadOnly(); } -#pragma warning disable CA1416 - - DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath) + public Rename(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) { - DeterministicHashCode result; - int? id; - int? width; - int? height; - try - { - using Image image = Image.FromFile(filePath.FullName); - width = image.Width; - height = image.Height; - using Bitmap bitmap = new(image); - Rectangle rectangle = new(0, 0, image.Width, image.Height); - BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); - IntPtr intPtr = bitmapData.Scan0; - int length = bitmapData.Stride * bitmap.Height; - byte[] bytes = new byte[length]; - Marshal.Copy(intPtr, bytes, 0, length); - bitmap.UnlockBits(bitmapData); - id = IId.GetDeterministicHashCode(bytes); - } - catch (Exception) - { - id = null; - width = null; - height = null; - } - result = new(height, id, width); - return result; + if (isSilent) + { } + if (args is null) + throw new NullReferenceException(nameof(args)); + if (console is null) + throw new NullReferenceException(nameof(console)); + IRename rename = this; + long ticks = DateTime.Now.Ticks; + _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + RenameWork(logger, appSettings, rename, ticks); } -#pragma warning restore CA1416 + private void RenameWork(ILogger? logger, AppSettings appSettings, IRename rename, long ticks) + { + ReadOnlyCollection ids = GetIds(appSettings.RenameSettings); + string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory); + if (!Directory.Exists(sourceDirectory)) + _ = Directory.CreateDirectory(sourceDirectory); + logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory); + ReadOnlyCollection files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly(); + if (files.Count > 0) + _ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory); + ReadOnlyCollection recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files); + SaveIdentifiersToDisk(ticks, appSettings, recordCollection); + if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName) + { + if (recordCollection.Count > 0) + recordCollection = new([]); + string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata)); + _ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory); + } + if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk) + { + DirectoryInfo directoryInfo = new(sourceDirectory); + ReadOnlyCollection toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection); + ReadOnlyCollection lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection); + if (lines.Count != 0) + { + File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines); + _ = IPath.DeleteEmptyDirectories(directoryInfo.FullName); + } + } + } + + private static ReadOnlyCollection GetIds(RenameSettings renameSettings) + { + ReadOnlyCollection results; + string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile; + string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile); + Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); + if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile)) + throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}"); + results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray()); + return results; + } + + private ReadOnlyCollection GetRecordCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, string sourceDirectory, ReadOnlyCollection files) + { + ReadOnlyCollection results; + List collection; + string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile); + if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile)) + collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile); + else + { + string json = File.ReadAllText(checkFile); + collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception(); + } + if (appSettings.RenameSettings.JustMediaDate) + results = new([]); + else + results = GetRecordCollection(appSettings, collection); + return results; + } + + private List GetRecordCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, string sourceDirectory, ReadOnlyCollection files, string? checkFile) + { + List results; + FirstPass firstPass; + A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings); + int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism; + int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000; + rename.ConstructProgressBar(filesCount, "EnumerateFiles load"); + if (appSettingsMaxDegreeOfParallelism == 1) + { + ReadOnlyDictionary> keyValuePairs = IMetadata.GetKeyValuePairs(files); + results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs); + } + else + { + results = []; + List distinct = []; + List metadataGroups = []; + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; + files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups)); + Thread.Sleep(500); + foreach (MetadataGroup metadataGroup in metadataGroups) + { + if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered)) + firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); + else + firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); + results.Add(firstPass); + } + } + if (!string.IsNullOrEmpty(checkFile)) + { + string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); + File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); + } + + return results; + } + + private List GetFirstPassCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, A_Metadata metadata, ReadOnlyDictionary> keyValuePairs) + { + List results = []; + int index = -1; + TimeSpan timeSpan; + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + index += 1; + rename.Tick(); + if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId) + { + if (appSettings.RenameSettings.InPlaceMoveDirectory) + continue; + throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!"); + } + if (keyValuePair.Value.Count > 2) + throw new NotSupportedException("Too many sidecar files!"); + SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results); + timeSpan = new(DateTime.Now.Ticks - ticks); + if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall) + break; + } + return results; + } + + private void SetFirstPassCollection(ILogger? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection ids, A_Metadata metadata, int index, KeyValuePair> keyValuePair, List results) + { + FilePath filePath; + FirstPass firstPass; + string directoryName; + ExifDirectory exifDirectory; + List sidecarFiles; + DeterministicHashCode deterministicHashCode; + bool fastForwardMovingPictureExpertsGroupUsed; + MinimumYearAndPathCombined minimumYearAndPathCombined; + FilePath? fastForwardMovingPictureExpertsGroupFilePath; + ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; + foreach (FileHolder fileHolder in keyValuePair.Value) + { + if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) + continue; + if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) + continue; + filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index); + if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) + continue; + if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null) + { + fastForwardMovingPictureExpertsGroupFiles = null; + deterministicHashCode = new(null, filePath.Id, null); + directoryName = Path.GetFileName(filePath.DirectoryFullPath); + if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString()))) + continue; + } + else + { + fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, filePath); + fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index); + deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath); + } + sidecarFiles = []; + filePath = FilePath.Get(filePath, deterministicHashCode); + for (int i = 0; i < keyValuePair.Value.Count; i++) + { + if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value) + JustMediaDate(logger, appSettings, metadata, filePath); + if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered) + continue; + sidecarFiles.Add(keyValuePair.Value[i]); + } + try + { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); } + catch (Exception) + { + logger?.LogWarning("<{filePath}>", filePath.FullName); + continue; + } + fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0; + if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null) + { + foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) + File.Delete(fastForwardMovingPictureExpertsGroupFile); + } + if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName) + NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray()); + if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) + fastForwardMovingPictureExpertsGroupUsed = true; + firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); + results.Add(firstPass); + } + } + + private void JustMediaDate(ILogger? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath) + { + ExifDirectory? exifDirectory; + MinimumYearAndPathCombined? minimumYearAndPathCombined; + try + { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); } + catch (Exception) + { + exifDirectory = null; + minimumYearAndPathCombined = null; + logger?.LogWarning("<{filePath}>", filePath.FullName); + } + if (exifDirectory is null || minimumYearAndPathCombined is null) + logger?.LogWarning("<{filePath}>", filePath.FullName); + else + { + DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory); + if (dateTime is null) + logger?.LogWarning("<{filePath}>", filePath.FullName); + else + { + File.SetCreationTime(filePath.FullName, dateTime.Value); + Thread.Sleep(500); + File.SetLastWriteTime(filePath.FullName, dateTime.Value); + } + } + } private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles) { @@ -189,126 +408,6 @@ public partial class Rename : IRename, IDisposable } } - private void JustMediaDate(ILogger? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath) - { - ExifDirectory? exifDirectory; - MinimumYearAndPathCombined? minimumYearAndPathCombined; - try - { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); } - catch (Exception) - { - exifDirectory = null; - minimumYearAndPathCombined = null; - logger?.LogWarning("<{filePath}>", filePath.FullName); - } - if (exifDirectory is null || minimumYearAndPathCombined is null) - logger?.LogWarning("<{filePath}>", filePath.FullName); - else - { - DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory); - if (dateTime is null) - logger?.LogWarning("<{filePath}>", filePath.FullName); - else - { - File.SetCreationTime(filePath.FullName, dateTime.Value); - Thread.Sleep(500); - File.SetLastWriteTime(filePath.FullName, dateTime.Value); - } - } - } - - private void SetFirstPassCollection(ILogger? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection ids, A_Metadata metadata, int index, KeyValuePair> keyValuePair, List results) - { - FilePath filePath; - FirstPass firstPass; - string directoryName; - ExifDirectory exifDirectory; - List sidecarFiles; - DeterministicHashCode deterministicHashCode; - bool fastForwardMovingPictureExpertsGroupUsed; - MinimumYearAndPathCombined minimumYearAndPathCombined; - FilePath? fastForwardMovingPictureExpertsGroupFilePath; - ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; - foreach (FileHolder fileHolder in keyValuePair.Value) - { - if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index); - if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) - continue; - if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null) - { - fastForwardMovingPictureExpertsGroupFiles = null; - deterministicHashCode = new(null, filePath.Id, null); - directoryName = Path.GetFileName(filePath.DirectoryFullPath); - if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString()))) - continue; - } - else - { - fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath); - fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index); - deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath); - } - sidecarFiles = []; - filePath = FilePath.Get(filePath, deterministicHashCode); - for (int i = 0; i < keyValuePair.Value.Count; i++) - { - if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value) - JustMediaDate(logger, appSettings, metadata, filePath); - if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered) - continue; - sidecarFiles.Add(keyValuePair.Value[i]); - } - try - { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); } - catch (Exception) - { - logger?.LogWarning("<{filePath}>", filePath.FullName); - continue; - } - fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0; - if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null) - { - foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) - File.Delete(fastForwardMovingPictureExpertsGroupFile); - } - if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName) - NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray()); - if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) - fastForwardMovingPictureExpertsGroupUsed = true; - firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); - results.Add(firstPass); - } - } - - private List GetFirstPassCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, A_Metadata metadata, ReadOnlyDictionary> keyValuePairs) - { - List results = []; - int index = -1; - TimeSpan timeSpan; - foreach (KeyValuePair> keyValuePair in keyValuePairs) - { - index += 1; - rename.Tick(); - if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId) - { - if (appSettings.RenameSettings.InPlaceMoveDirectory) - continue; - throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!"); - } - if (keyValuePair.Value.Count > 2) - throw new NotSupportedException("Too many sidecar files!"); - SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results); - timeSpan = new(DateTime.Now.Ticks - ticks); - if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall) - break; - } - return results; - } - private static ReadOnlyCollection GetRecordCollection(AppSettings appSettings, List collection) { List results = []; @@ -336,172 +435,22 @@ public partial class Rename : IRename, IDisposable return results.AsReadOnly(); } - private List GetRecordCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, string sourceDirectory, ReadOnlyCollection files, string? checkFile) - { - List results; - FirstPass firstPass; - A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings); - int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism; - int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000; - rename.ConstructProgressBar(filesCount, "EnumerateFiles load"); - if (appSettingsMaxDegreeOfParallelism == 1) - { - ReadOnlyDictionary> keyValuePairs = IMetadata.GetKeyValuePairs(files); - results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs); - } - else - { - results = []; - List distinct = []; - List metadataGroups = []; - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; - files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups)); - Thread.Sleep(500); - foreach (MetadataGroup metadataGroup in metadataGroups) - { - if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered)) - firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); - else - firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); - results.Add(firstPass); - } - } - if (!string.IsNullOrEmpty(checkFile)) - { - string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); - File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); - } - - return results; - } - - private ReadOnlyCollection GetRecordCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, string sourceDirectory, ReadOnlyCollection files) - { - ReadOnlyCollection results; - List collection; - string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile); - if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile)) - collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile); - else - { - string json = File.ReadAllText(checkFile); - collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception(); - } - if (appSettings.RenameSettings.JustMediaDate) - results = new([]); - else - results = GetRecordCollection(appSettings, collection); - return results; - } - - private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection recordCollection) + private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection recordCollection) { + string paddedId; + Identifier identifier; + List identifiers = []; + string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection); foreach (Record record in recordCollection) { if (record.ExifDirectory.FilePath.Id is null) continue; - if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length) - throw new NotSupportedException(); + paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null); + identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks); + identifiers.Add(identifier); } - } - - private static string GetTFW(Record record, bool? isWrongYear) => - string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I"); - - private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) => - splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}"; - - private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection ids, bool multipleDirectoriesWithFiles, string paddedId) - { - string? result; - string year = record.DateTime.Year.ToString(); - string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath); - if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year)) - result = null; - else - { - (bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory); - if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId)) - result = null; - else - { - if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2]) - isWrongYear = null; - string directoryName; - string tfw = GetTFW(record, isWrongYear); - string? maker = IMetadata.GetMaker(record.ExifDirectory); - string rootDirectory = appSettings.ResultSettings.RootDirectory; - string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None); - (int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear); - string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null; - string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _"; - string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}"; - if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2) - directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit); - else - { - directoryName = record.DateTime.ToString("yyyy-MM-dd"); - if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value)) - directoryName = value; - } - result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName)); - } - } - return result; - } - - private static List GetSidecarFiles(AppSettings appSettings, Record record, List distinct, string checkDirectory, string paddedId) - { - List results = []; - ToDo toDo; - string checkFile; - FilePath filePath; - string checkFileExtension; - foreach (FileHolder fileHolder in record.SidecarFiles) - { - checkFileExtension = fileHolder.ExtensionLowered; - filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null); - checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); - if (checkFile == filePath.FullName) - continue; - if (File.Exists(checkFile)) - { - checkFile = string.Concat(checkFile, ".del"); - if (File.Exists(checkFile)) - continue; - } - if (distinct.Contains(checkFile)) - continue; - distinct.Add(checkFile); - toDo = new(Directory: checkDirectory, - FileInfo: new(filePath.FullName), - File: checkFile, - JsonFile: false); - results.Add(toDo); - } - return results; - } - - private static bool? GetDirectoryCheck(ResultSettings resultSettings) - { - bool? result = null; - IEnumerable files; - string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories); - foreach (string _ in files) - { - if (result is null) - result = false; - else if (result.Value) - result = true; - break; - } - if (result is not null && result.Value) - break; - } - return result; + string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); + _ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); } private static ReadOnlyCollection GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection ids, ReadOnlyCollection files, ReadOnlyCollection recordCollection) @@ -589,17 +538,114 @@ public partial class Rename : IRename, IDisposable return results.AsReadOnly(); } - private static void VerifyDirectories(ReadOnlyCollection toDoCollection) + private static bool? GetDirectoryCheck(ResultSettings resultSettings) { - List distinct = []; - foreach (ToDo toDo in toDoCollection) + bool? result = null; + IEnumerable files; + string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) { - if (toDo.Directory is null || distinct.Contains(toDo.Directory)) - continue; - if (!Directory.Exists(toDo.Directory)) - _ = Directory.CreateDirectory(toDo.Directory); - distinct.Add(toDo.Directory); + files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories); + foreach (string _ in files) + { + if (result is null) + result = false; + else if (result.Value) + result = true; + break; + } + if (result is not null && result.Value) + break; } + return result; + } + + private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection recordCollection) + { + foreach (Record record in recordCollection) + { + if (record.ExifDirectory.FilePath.Id is null) + continue; + if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length) + throw new NotSupportedException(); + } + } + + private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection ids, bool multipleDirectoriesWithFiles, string paddedId) + { + string? result; + string year = record.DateTime.Year.ToString(); + string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath); + if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year)) + result = null; + else + { + (bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory); + if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId)) + result = null; + else + { + if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2]) + isWrongYear = null; + string directoryName; + string tfw = GetTFW(record, isWrongYear); + string? maker = IMetadata.GetMaker(record.ExifDirectory); + string rootDirectory = appSettings.ResultSettings.RootDirectory; + string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None); + (int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear); + string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null; + string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _"; + string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}"; + if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2) + directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit); + else + { + directoryName = record.DateTime.ToString("yyyy-MM-dd"); + if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value)) + directoryName = value; + } + result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName)); + } + } + return result; + } + + private static string GetTFW(Record record, bool? isWrongYear) => + string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I"); + + private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) => + splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}"; + + private static List GetSidecarFiles(AppSettings appSettings, Record record, List distinct, string checkDirectory, string paddedId) + { + List results = []; + ToDo toDo; + string checkFile; + FilePath filePath; + string checkFileExtension; + foreach (FileHolder fileHolder in record.SidecarFiles) + { + checkFileExtension = fileHolder.ExtensionLowered; + filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null); + checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); + if (checkFile == filePath.FullName) + continue; + if (File.Exists(checkFile)) + { + checkFile = string.Concat(checkFile, ".del"); + if (File.Exists(checkFile)) + continue; + } + if (distinct.Contains(checkFile)) + continue; + distinct.Add(checkFile); + toDo = new(Directory: checkDirectory, + FileInfo: new(filePath.FullName), + File: checkFile, + JsonFile: false); + results.Add(toDo); + } + return results; } private ReadOnlyCollection RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection toDoCollection) @@ -642,65 +688,16 @@ public partial class Rename : IRename, IDisposable return results.AsReadOnly(); } - private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection recordCollection) + private static void VerifyDirectories(ReadOnlyCollection toDoCollection) { - string paddedId; - Identifier identifier; - List identifiers = []; - string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection); - foreach (Record record in recordCollection) + List distinct = []; + foreach (ToDo toDo in toDoCollection) { - if (record.ExifDirectory.FilePath.Id is null) + if (toDo.Directory is null || distinct.Contains(toDo.Directory)) continue; - paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null); - identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks); - identifiers.Add(identifier); - } - string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); - _ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - } - - private static ReadOnlyCollection GetIds(RenameSettings renameSettings) - { - ReadOnlyCollection results; - string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile; - string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile); - Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); - if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile)) - throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}"); - results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray()); - return results; - } - - private void RenameWork(ILogger? logger, AppSettings appSettings, IRename rename, long ticks) - { - ReadOnlyCollection ids = GetIds(appSettings.RenameSettings); - string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory); - if (!Directory.Exists(sourceDirectory)) - _ = Directory.CreateDirectory(sourceDirectory); - logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory); - ReadOnlyCollection files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly(); - if (files.Count > 0) - _ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory); - ReadOnlyCollection recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files); - SaveIdentifiersToDisk(ticks, appSettings, recordCollection); - if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName) - { - if (recordCollection.Count > 0) - recordCollection = new([]); - string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata)); - _ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory); - } - if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk) - { - DirectoryInfo directoryInfo = new(sourceDirectory); - ReadOnlyCollection toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection); - ReadOnlyCollection lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection); - if (lines.Count != 0) - { - File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines); - _ = IPath.DeleteEmptyDirectories(directoryInfo.FullName); - } + if (!Directory.Exists(toDo.Directory)) + _ = Directory.CreateDirectory(toDo.Directory); + distinct.Add(toDo.Directory); } } diff --git a/Shared/Models/Properties/ICompareSettings.cs b/Shared/Models/Properties/ICompareSettings.cs index b574a13..27b990e 100644 --- a/Shared/Models/Properties/ICompareSettings.cs +++ b/Shared/Models/Properties/ICompareSettings.cs @@ -6,9 +6,6 @@ public interface ICompareSettings public string FacesFileNameExtension { init; get; } public string FacesHiddenFileNameExtension { init; get; } public string FacesPartsFileNameExtension { init; get; } - public string[] IgnoreExtensions { init; get; } public int MaxDegreeOfParallelism { init; get; } - public string[] ValidImageFormatExtensions { init; get; } - public string[] ValidVideoFormatExtensions { init; get; } } \ No newline at end of file diff --git a/Shared/Models/Properties/IRenameSettings.cs b/Shared/Models/Properties/IRenameSettings.cs index db8a21d..f4613df 100644 --- a/Shared/Models/Properties/IRenameSettings.cs +++ b/Shared/Models/Properties/IRenameSettings.cs @@ -3,9 +3,6 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IRenameSettings { - public string[] IgnoreExtensions { init; get; } public bool SkipIdFiles { init; get; } - public string[] ValidImageFormatExtensions { init; get; } - public string[] ValidVideoFormatExtensions { init; get; } } \ No newline at end of file diff --git a/Shared/Models/Properties/IWindowsSettings.cs b/Shared/Models/Properties/IWindowsSettings.cs index 0d63d8e..d04e74b 100644 --- a/Shared/Models/Properties/IWindowsSettings.cs +++ b/Shared/Models/Properties/IWindowsSettings.cs @@ -3,8 +3,4 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IWindowsSettings { - public string[] IgnoreExtensions { init; get; } - public string[] ValidImageFormatExtensions { init; get; } - public string[] ValidVideoFormatExtensions { init; get; } - } \ No newline at end of file diff --git a/Shared/Models/ResultSettings.cs b/Shared/Models/ResultSettings.cs index 29baf15..3304dcd 100644 --- a/Shared/Models/ResultSettings.cs +++ b/Shared/Models/ResultSettings.cs @@ -8,12 +8,15 @@ public record ResultSettings(string DateGroup, string ModelName, int NumberOfJitters, int NumberOfTimesToUpsample, + string[] IgnoreExtensions, string PredictorModelName, int ResultAllInOneSubdirectoryLength, string ResultCollection, string ResultContent, string ResultSingleton, - string RootDirectory) + string RootDirectory, + string[] ValidImageFormatExtensions, + string[] ValidVideoFormatExtensions) { public override string ToString() diff --git a/Shared/Models/Stateless/IId.cs b/Shared/Models/Stateless/IId.cs index 2c9464b..4d51de2 100644 --- a/Shared/Models/Stateless/IId.cs +++ b/Shared/Models/Stateless/IId.cs @@ -5,44 +5,69 @@ public interface IId const int DeterministicHashCode = 9876543; - static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) => - metadataSettings.Offset == DeterministicHashCode; - - string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => - GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal); - static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => - Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal); - - int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) => - GetId(resultSettings, metadataSettings, intelligentId); - static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) => - Id.GetId(resultSettings, metadataSettings, intelligentId); - - string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => - GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index); - static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => - Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index); - - bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) => - NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment); - static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) => - fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber); - - bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => - NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment); - static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => - fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1 - && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9' - && fileNameFirstSegment.All(char.IsNumber); - - bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) => - NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder); - static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) => - Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]); - - int TestStatic_GetDeterministicHashCode(byte[] value) => - GetDeterministicHashCode(value); - static int GetDeterministicHashCode(byte[] value) => + public static int GetDeterministicHashCode(byte[] value) => Id.GetDeterministicHashCode(value); + public static byte GetHasIgnoreKeyword(FilePath filePath) => + Id.GetHasIgnoreKeyword(filePath); + + public static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) => + metadataSettings.Offset == DeterministicHashCode; + + public static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + Id.GetHasDateTimeOriginal(resultSettings, filePath); + + public static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + Id.GetMissingDateTimeOriginal(resultSettings, filePath); + + public static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) => + Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]); + + public static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) => + Id.GetId(resultSettings, metadataSettings, intelligentId); + + public static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) => + fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber); + + public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => + fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1 + && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' + && fileNameFirstSegment.All(char.IsNumber); + + public static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => + Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal); + + public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => + Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index); + + internal int TestStatic_GetDeterministicHashCode(byte[] value) => + GetDeterministicHashCode(value); + + internal byte TestStatic_GetHasIgnoreKeyword(FilePath filePath) => + GetHasIgnoreKeyword(filePath); + + internal byte TestStatic_GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + GetHasDateTimeOriginal(resultSettings, filePath); + + internal byte TestStatic_GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + GetMissingDateTimeOriginal(resultSettings, filePath); + + internal bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) => + NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder); + + internal int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) => + GetId(resultSettings, metadataSettings, intelligentId); + + internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) => + NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment); + + internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) => + NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment); + + internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => + GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal); + + internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => + GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/IRename.cs b/Shared/Models/Stateless/IRename.cs index 0228dd6..cbb7313 100644 --- a/Shared/Models/Stateless/IRename.cs +++ b/Shared/Models/Stateless/IRename.cs @@ -1,12 +1,11 @@ using System.Collections.ObjectModel; -using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Shared.Models.Stateless; public interface IRename { - ReadOnlyCollection ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath); + ReadOnlyCollection ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath); DeterministicHashCode GetDeterministicHashCode(FilePath filePath); void ConstructProgressBar(int maxTicks, string message); void Tick(); diff --git a/Shared/Models/Stateless/IWindows.cs b/Shared/Models/Stateless/IWindows.cs index 971b1ed..db44a25 100644 --- a/Shared/Models/Stateless/IWindows.cs +++ b/Shared/Models/Stateless/IWindows.cs @@ -1,12 +1,11 @@ using System.Collections.ObjectModel; -using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Shared.Models.Stateless; public interface IWindows { - ReadOnlyCollection ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings windowsSettings, HttpClient? httpClient, FilePath filePath); + ReadOnlyCollection ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath); DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath); DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri); void ConstructProgressBar(int maxTicks, string message); diff --git a/Shared/Models/Stateless/Id.cs b/Shared/Models/Stateless/Id.cs index e3007ae..747d146 100644 --- a/Shared/Models/Stateless/Id.cs +++ b/Shared/Models/Stateless/Id.cs @@ -5,19 +5,34 @@ namespace View_by_Distance.Shared.Models.Stateless; internal abstract class Id { - internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) + internal static int GetDeterministicHashCode(byte[] value) { - bool result; - if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength) - result = false; - else + int result; + unchecked { - bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber); - result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0])); + int hash1 = (5381 << 16) + 5381; + int hash2 = hash1; + for (int i = 0; i < value.Length; i += 2) + { + hash1 = ((hash1 << 5) + hash1) ^ value[i]; + if (i == value.Length - 1) + break; + hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; + } + result = hash1 + (hash2 * 1566083941); } return result; } + internal static byte GetHasIgnoreKeyword(FilePath filePath) => + (byte)(filePath.Id > -1 ? 8 : 2); + + internal static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + (byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4); + + internal static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) => + (byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : 5); + internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) { int result; @@ -28,13 +43,26 @@ internal abstract class Id _ = results.Append(intelligentId[i]); _ = results.Append(intelligentId[^3]).Append(intelligentId[^2]); result = int.Parse(results.ToString()); - if (intelligentId[^1] is '1' or '2' or '3') + if (intelligentId[^1] is '1' or '2' or '3' or '4') result *= -1; - else if (intelligentId[^1] is not '9' and not '8' and not '7') + else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5') throw new NotSupportedException(); return result; } + internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) + { + bool result; + if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength) + result = false; + else + { + bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber); + result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0])); + } + return result; + } + #pragma warning disable IDE0060 internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) #pragma warning restore IDE0060 @@ -80,23 +108,4 @@ internal abstract class Id return result; } - internal static int GetDeterministicHashCode(byte[] value) - { - int result; - unchecked - { - int hash1 = (5381 << 16) + 5381; - int hash2 = hash1; - for (int i = 0; i < value.Length; i += 2) - { - hash1 = ((hash1 << 5) + hash1) ^ value[i]; - if (i == value.Length - 1) - break; - hash2 = ((hash2 << 5) + hash2) ^ value[i + 1]; - } - result = hash1 + (hash2 * 1566083941); - } - return result; - } - } \ No newline at end of file diff --git a/Shared/Models/Stateless/XPath.cs b/Shared/Models/Stateless/XPath.cs index 4986a0f..f1225d9 100644 --- a/Shared/Models/Stateless/XPath.cs +++ b/Shared/Models/Stateless/XPath.cs @@ -5,35 +5,29 @@ namespace View_by_Distance.Shared.Models.Stateless; internal abstract class XPath { - internal static string GetRelativePath(string path, int length, bool forceExtensionToLower) + private static ReadOnlyDictionary> Convert(List collection) { - string result; - if (forceExtensionToLower) + Dictionary> results = []; + List? c; + foreach (CombinedEnumAndIndex cei in collection) { - string extension = Path.GetExtension(path); - string extensionLowered = Path.GetExtension(path).ToLower(); - if (extension != extensionLowered) + if (!results.TryGetValue(cei.Enum, out c)) { - string? directoryName = Path.GetDirectoryName(path); - if (string.IsNullOrEmpty(directoryName)) - throw new NullReferenceException(directoryName); - string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); - if (string.IsNullOrEmpty(fileNameWithoutExtension)) - throw new NullReferenceException(fileNameWithoutExtension); - path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}"); + results.Add(cei.Enum, []); + if (!results.TryGetValue(cei.Enum, out c)) + throw new Exception(); } + c.Add(cei.Combined); } - result = path[length..].Replace(@"\", "/"); - return result; + return Convert(results); } - internal static bool DeleteEmptyDirectories(string rootDirectory) + private static ReadOnlyDictionary>>> Convert(Dictionary>>> keyValuePairs) { - bool result; - List results = []; - DeleteEmptyDirectories(rootDirectory, results); - result = results.Count > 0; - return result; + Dictionary>>> results = []; + foreach (KeyValuePair>>> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return results.AsReadOnly(); } internal static void DeleteEmptyDirectories(string rootDirectory, List deletedDirectories) @@ -71,45 +65,56 @@ internal abstract class XPath } } - internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches) + internal static byte GetEnum(FilePath filePath) => + GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); + + private static byte GetEnum(bool? ik, bool? dto) { - bool result; - string text; - if (!compareBeforeWrite) - result = true; + byte result; + if (ik is not null && ik.Value && dto is not null && dto.Value) + result = 11; + else if (ik is not null && ik.Value && dto is not null && !dto.Value) + result = 15; + else if (ik is not null && ik.Value && dto is null) + result = 19; + else if (ik is not null && !ik.Value && dto is not null && dto.Value) + result = 51; + else if (ik is not null && !ik.Value && dto is not null && !dto.Value) + result = 55; + else if (ik is not null && !ik.Value && dto is null) + result = 59; + else if (ik is null && dto is not null && dto.Value) + result = 91; + else if (ik is null && dto is not null && !dto.Value) + result = 95; + else if (ik is null && dto is null) + result = 99; else - { - if (!File.Exists(path)) - text = string.Empty; - else - text = File.ReadAllText(path); - result = text != contents; - if (!result && updateDateWhenMatches) - { - if (updateToWhenMatches is null) - File.SetLastWriteTime(path, DateTime.Now); - else - File.SetLastWriteTime(path, updateToWhenMatches.Value); - } - } - if (result) - { - if (path.Contains("()")) - File.WriteAllText(path, contents); - else if (path.Contains("{}") && !path.EndsWith(".json")) - File.WriteAllText(path, contents); - else if (path.Contains("[]") && !path.EndsWith(".json")) - File.WriteAllText(path, contents); - else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{') - File.WriteAllText(path, contents); - else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[') - File.WriteAllText(path, contents); - else - File.WriteAllText(path, contents); - } + throw new Exception(); return result; } + internal static List GetDirectories(string directory) + { + List results = []; + string? checkDirectory = directory; + string? pathRoot = Path.GetPathRoot(directory); + if (string.IsNullOrEmpty(pathRoot)) + throw new NullReferenceException(nameof(pathRoot)); + if (Directory.Exists(directory)) + results.Add(directory); + for (int i = 0; i < int.MaxValue; i++) + { + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot) + break; + results.Add(checkDirectory); + } + results.Add(pathRoot); + results.Reverse(); + return results; + } + internal static List GetDirectoryNames(string directory) { List results = []; @@ -146,83 +151,15 @@ internal abstract class XPath return results; } - internal static List GetDirectories(string directory) + internal static bool DeleteEmptyDirectories(string rootDirectory) { + bool result; List results = []; - string? checkDirectory = directory; - string? pathRoot = Path.GetPathRoot(directory); - if (string.IsNullOrEmpty(pathRoot)) - throw new NullReferenceException(nameof(pathRoot)); - if (Directory.Exists(directory)) - results.Add(directory); - for (int i = 0; i < int.MaxValue; i++) - { - checkDirectory = Path.GetDirectoryName(checkDirectory); - if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot) - break; - results.Add(checkDirectory); - } - results.Add(pathRoot); - results.Reverse(); - return results; - } - - internal static (int level, List directories) Get(string rootDirectory, string sourceDirectory) - { - int result = 0; - string? directory; - string? checkDirectory; - List results = []; - checkDirectory = sourceDirectory; - for (int i = 0; i < int.MaxValue; i++) - { - result += 1; - directory = Path.GetFileName(checkDirectory); - if (string.IsNullOrEmpty(directory)) - break; - results.Add(directory); - checkDirectory = Path.GetDirectoryName(checkDirectory); - if (checkDirectory == rootDirectory) - break; - } - results.Reverse(); - return new(result, results); - } - - internal static string GetDirectory(string sourceDirectory, int level, string directoryName) - { - string result; - string? checkDirectory; - checkDirectory = Path.GetDirectoryName(sourceDirectory); - for (int i = 0; i < level; i++) - checkDirectory = Path.GetDirectoryName(checkDirectory); - if (string.IsNullOrEmpty(checkDirectory)) - throw new Exception(); - checkDirectory = Path.Combine(checkDirectory, directoryName); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - result = checkDirectory; + DeleteEmptyDirectories(rootDirectory, results); + result = results.Count > 0; return result; } - internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) - { - DateTime dateTime = new(ticks); - IEnumerable fileSystemEntries; - string[] directories; - if (!Directory.Exists(rootDirectory)) - directories = []; - else - directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories); - foreach (string directory in directories) - { - fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly); - if (fileSystemEntries.Any()) - continue; - Directory.SetLastWriteTime(directory, dateTime); - } - } - internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) { bool check; @@ -265,49 +202,117 @@ internal abstract class XPath } } - private static byte GetEnum(bool? ik, bool? dto) + internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) { - byte result; - if (ik is not null && ik.Value && dto is not null && dto.Value) - result = 11; - else if (ik is not null && ik.Value && dto is not null && !dto.Value) - result = 15; - else if (ik is not null && ik.Value && dto is null) - result = 19; - else if (ik is not null && !ik.Value && dto is not null && dto.Value) - result = 51; - else if (ik is not null && !ik.Value && dto is not null && !dto.Value) - result = 55; - else if (ik is not null && !ik.Value && dto is null) - result = 59; - else if (ik is null && dto is not null && dto.Value) - result = 91; - else if (ik is null && dto is not null && !dto.Value) - result = 95; - else if (ik is null && dto is null) - result = 99; + DateTime dateTime = new(ticks); + IEnumerable fileSystemEntries; + string[] directories; + if (!Directory.Exists(rootDirectory)) + directories = []; else - throw new Exception(); + directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories); + foreach (string directory in directories) + { + fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly); + if (fileSystemEntries.Any()) + continue; + Directory.SetLastWriteTime(directory, dateTime); + } + } + + internal static string GetRelativePath(string path, int length, bool forceExtensionToLower) + { + string result; + if (forceExtensionToLower) + { + string extension = Path.GetExtension(path); + string extensionLowered = Path.GetExtension(path).ToLower(); + if (extension != extensionLowered) + { + string? directoryName = Path.GetDirectoryName(path); + if (string.IsNullOrEmpty(directoryName)) + throw new NullReferenceException(directoryName); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); + if (string.IsNullOrEmpty(fileNameWithoutExtension)) + throw new NullReferenceException(fileNameWithoutExtension); + path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}"); + } + } + result = path[length..].Replace(@"\", "/"); return result; } - internal static byte GetEnum(FilePath filePath) => - GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); + internal static string GetDirectory(string sourceDirectory, int level, string directoryName) + { + string result; + string? checkDirectory; + checkDirectory = Path.GetDirectoryName(sourceDirectory); + for (int i = 0; i < level; i++) + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory)) + throw new Exception(); + checkDirectory = Path.Combine(checkDirectory, directoryName); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + result = checkDirectory; + return result; + } - private static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileNameWithoutExtension) + internal static (int level, List directories) Get(string rootDirectory, string sourceDirectory) + { + int result = 0; + string? directory; + string? checkDirectory; + List results = []; + checkDirectory = sourceDirectory; + for (int i = 0; i < int.MaxValue; i++) + { + result += 1; + directory = Path.GetFileName(checkDirectory); + if (string.IsNullOrEmpty(directory)) + break; + results.Add(directory); + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (checkDirectory == rootDirectory) + break; + } + results.Reverse(); + return new(result, results); + } + + internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) { CombinedEnumAndIndex result; + if (filePath.Id is not null) + result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.Id.Value.ToString()); + else + result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.NameWithoutExtension); + return result; + } + + private static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath, string fileNameWithoutExtension) + { + CombinedEnumAndIndex result; + byte @enum; int converted; string combined; + byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(resultSettings, filePath); + if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null) + throw new NotImplementedException(); + if (filePath.HasIgnoreKeyword.Value) + @enum = IId.GetHasIgnoreKeyword(filePath); + else if (!filePath.HasDateTimeOriginal.Value) + @enum = missingDateTimeOriginal; + else + @enum = IId.GetHasDateTimeOriginal(resultSettings, filePath); string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0]; - byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); - string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ? - new('-', resultAllInOneSubdirectoryLength) : - fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..]; + string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ? + new('-', resultSettings.ResultAllInOneSubdirectoryLength) : + fileNameBeforeFirst[^resultSettings.ResultAllInOneSubdirectoryLength..]; if (check.Any(l => !char.IsNumber(l))) { - combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}"; - converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}"); + combined = $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}"; + converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}"); } else { @@ -318,16 +323,66 @@ internal abstract class XPath return result; } - internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) + internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches) { - CombinedEnumAndIndex result; - if (filePath.Id is not null) - result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString()); + bool result; + string text; + if (!compareBeforeWrite) + result = true; else - result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.NameWithoutExtension); + { + if (!File.Exists(path)) + text = string.Empty; + else + text = File.ReadAllText(path); + result = text != contents; + if (!result && updateDateWhenMatches) + { + if (updateToWhenMatches is null) + File.SetLastWriteTime(path, DateTime.Now); + else + File.SetLastWriteTime(path, updateToWhenMatches.Value); + } + } + if (result) + { + if (path.Contains("()")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("[]") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{') + File.WriteAllText(path, contents); + else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[') + File.WriteAllText(path, contents); + else + File.WriteAllText(path, contents); + } return result; } + internal static ReadOnlyDictionary>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) + { + Dictionary>>> results = []; + if (jsonGroups is not null) + { + DateTime dateTime = DateTime.Now; + ReadOnlyCollection years = GetYears(resultSettings); + Dictionary>>? k; + ReadOnlyDictionary>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime); + foreach (int year in years) + { + results.Add(year, []); + if (!results.TryGetValue(year, out k)) + throw new NullReferenceException(nameof(k)); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + k.Add(keyValuePair.Key, keyValuePair.Value); + } + } + return Convert(results); + } + private static ReadOnlyCollection GetYears(ResultSettings resultSettings) { List results = []; @@ -337,44 +392,6 @@ internal abstract class XPath return results.AsReadOnly(); } - private static byte[] GetBytes() => - [ - 11, - 15, - 19, - 51, - 55, - 59, - 91, - 95, - 99 - ]; - - private static ReadOnlyDictionary> Convert(Dictionary> keyValuePairs) - { - Dictionary> results = []; - foreach (KeyValuePair> keyValuePair in keyValuePairs) - results.Add(keyValuePair.Key, new(keyValuePair.Value)); - return results.AsReadOnly(); - } - - private static ReadOnlyDictionary> Convert(List collection) - { - Dictionary> results = []; - List? c; - foreach (CombinedEnumAndIndex cei in collection) - { - if (!results.TryGetValue(cei.Enum, out c)) - { - results.Add(cei.Enum, []); - if (!results.TryGetValue(cei.Enum, out c)) - throw new Exception(); - } - c.Add(cei.Combined); - } - return Convert(results); - } - private static ReadOnlyDictionary>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime) { Dictionary>> results = []; @@ -428,33 +445,25 @@ internal abstract class XPath return results.AsReadOnly(); } - private static ReadOnlyDictionary>>> Convert(Dictionary>>> keyValuePairs) + private static byte[] GetBytes() => + [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ]; + + private static ReadOnlyDictionary> Convert(Dictionary> keyValuePairs) { - Dictionary>>> results = []; - foreach (KeyValuePair>>> keyValuePair in keyValuePairs) + Dictionary> results = []; + foreach (KeyValuePair> keyValuePair in keyValuePairs) results.Add(keyValuePair.Key, new(keyValuePair.Value)); return results.AsReadOnly(); } - internal static ReadOnlyDictionary>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) - { - Dictionary>>> results = []; - if (jsonGroups is not null) - { - DateTime dateTime = DateTime.Now; - ReadOnlyCollection years = GetYears(resultSettings); - Dictionary>>? k; - ReadOnlyDictionary>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime); - foreach (int year in years) - { - results.Add(year, []); - if (!results.TryGetValue(year, out k)) - throw new NullReferenceException(nameof(k)); - foreach (KeyValuePair>> keyValuePair in keyValuePairs) - k.Add(keyValuePair.Key, keyValuePair.Value); - } - } - return Convert(results); - } - } \ No newline at end of file diff --git a/Windows/Models/WindowsSettings.cs b/Windows/Models/WindowsSettings.cs index da4d042..4efcda9 100644 --- a/Windows/Models/WindowsSettings.cs +++ b/Windows/Models/WindowsSettings.cs @@ -6,12 +6,9 @@ namespace View_by_Distance.Windows.Models; public record WindowsSettings(string Company, string? Host, - string[] IgnoreExtensions, int MaxDegreeOfParallelism, string? Page, string[] SidecarExtensions, - string[] ValidImageFormatExtensions, - string[] ValidVideoFormatExtensions, bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings { diff --git a/Windows/Windows.cs b/Windows/Windows.cs index 4a31a0d..c862ede 100644 --- a/Windows/Windows.cs +++ b/Windows/Windows.cs @@ -9,7 +9,6 @@ using System.Text.Json; using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models.Stateless; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Windows.Models; @@ -21,48 +20,93 @@ public partial class Windows : IWindows, IDisposable private ProgressBar? _ProgressBar; private readonly ProgressBarOptions _ProgressBarOptions; - public Windows(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) + DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) => + GetDeterministicHashCode(httpClient, uri); + + DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath) { - if (isSilent) - { } - if (args is null) - throw new NullReferenceException(nameof(args)); - if (console is null) - throw new NullReferenceException(nameof(console)); - IWindows windows = this; - long ticks = DateTime.Now.Ticks; - _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - WindowsWork(logger, appSettings, windows, ticks); + DeterministicHashCode result; + if (httpClient is not null) + result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName)); + else + { + Stream stream = File.OpenRead(filePath.FullName); + result = GetDeterministicHashCode(stream); + stream.Dispose(); + } + return result; + } + + private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri) + { + DeterministicHashCode result; + Stream stream = GetStream(httpClient, uri); + result = GetDeterministicHashCode(stream); + stream.Dispose(); + return result; + } + + private static Stream GetStream(HttpClient httpClient, Uri uri) + { + Stream result; + Task task = httpClient.GetStreamAsync(uri); + task.Wait(); + result = task.Result; + return result; + } + + private static DeterministicHashCode GetDeterministicHashCode(Stream stream) + { + DeterministicHashCode result; + int? id; + int? width; + int? height; + try + { +#pragma warning disable CA1416 + using Image image = Image.FromStream(stream); + width = image.Width; + height = image.Height; + using Bitmap bitmap = new(image); + Rectangle rectangle = new(0, 0, image.Width, image.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + byte[] bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + bitmap.UnlockBits(bitmapData); +#pragma warning restore CA1416 + id = IId.GetDeterministicHashCode(bytes); + } + catch (Exception) + { + id = null; + width = null; + height = null; + } + result = new(height, id, width); + return result; } void IWindows.Tick() => _ProgressBar?.Tick(); - void IWindows.ConstructProgressBar(int maxTicks, string message) - { - _ProgressBar?.Dispose(); - _ProgressBar = new(maxTicks, message, _ProgressBarOptions); - } - void IDisposable.Dispose() { _ProgressBar?.Dispose(); GC.SuppressFinalize(this); } - private static void DownloadFile(HttpClient httpClient, FilePath filePath) + void IWindows.ConstructProgressBar(int maxTicks, string message) { - FileStream fileStream = new(filePath.FullName, FileMode.Truncate); - Task httpResponseMessage = httpClient.GetAsync(filePath.FullName); - httpResponseMessage.Wait(); - Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream); - task.Wait(); + _ProgressBar?.Dispose(); + _ProgressBar = new(maxTicks, message, _ProgressBarOptions); } - ReadOnlyCollection IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath) + ReadOnlyCollection IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath) { List results = []; - bool isValidVideoFormatExtensions = WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); + bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); if (isValidVideoFormatExtensions) { bool check; @@ -94,75 +138,54 @@ public partial class Windows : IWindows, IDisposable return results.AsReadOnly(); } -#pragma warning disable CA1416 - - private static DeterministicHashCode GetDeterministicHashCode(Stream stream) + private static void DownloadFile(HttpClient httpClient, FilePath filePath) { - DeterministicHashCode result; - int? id; - int? width; - int? height; - try - { - using Image image = Image.FromStream(stream); - width = image.Width; - height = image.Height; - using Bitmap bitmap = new(image); - Rectangle rectangle = new(0, 0, image.Width, image.Height); - BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); - IntPtr intPtr = bitmapData.Scan0; - int length = bitmapData.Stride * bitmap.Height; - byte[] bytes = new byte[length]; - Marshal.Copy(intPtr, bytes, 0, length); - bitmap.UnlockBits(bitmapData); - id = IId.GetDeterministicHashCode(bytes); - } - catch (Exception) - { - id = null; - width = null; - height = null; - } - result = new(height, id, width); - return result; - } - - private static Stream GetStream(HttpClient httpClient, Uri uri) - { - Stream result; - Task task = httpClient.GetStreamAsync(uri); + FileStream fileStream = new(filePath.FullName, FileMode.Truncate); + Task httpResponseMessage = httpClient.GetAsync(filePath.FullName); + httpResponseMessage.Wait(); + Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream); task.Wait(); - result = task.Result; - return result; } - private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri) + public Windows(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) { - DeterministicHashCode result; - Stream stream = GetStream(httpClient, uri); - result = GetDeterministicHashCode(stream); - stream.Dispose(); - return result; + if (isSilent) + { } + if (args is null) + throw new NullReferenceException(nameof(args)); + if (console is null) + throw new NullReferenceException(nameof(console)); + IWindows windows = this; + long ticks = DateTime.Now.Ticks; + _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + WindowsWork(logger, appSettings, windows, ticks); } - DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) => - GetDeterministicHashCode(httpClient, uri); - - DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath) + private void WindowsWork(ILogger? logger, AppSettings appSettings, IWindows windows, long ticks) { - DeterministicHashCode result; - if (httpClient is not null) - result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName)); + if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page)) + Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page); else { - Stream stream = File.OpenRead(filePath.FullName); - result = GetDeterministicHashCode(stream); - stream.Dispose(); + string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory); + WindowsWork(logger, appSettings, windows, ticks, sourceDirectory); } - return result; } -#pragma warning restore CA1416 + private static void Verify(ILogger? logger, AppSettings appSettings, IWindows windows, string host, string page) + { + List messages = []; + HttpClient httpClient = new(); + int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism; + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; + ReadOnlyCollection collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception(); + windows.ConstructProgressBar(collection.Count, nameof(Verify)); + _ = Parallel.For(0, collection.Count, parallelOptions, (i, state) => + VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages)); + httpClient.Dispose(); + foreach (string message in messages) + logger?.LogWarning("{message}", message); + } private static ReadOnlyCollection? GetRecursiveCollection(HttpClient httpClient, string host, string page) { @@ -227,19 +250,46 @@ public partial class Windows : IWindows, IDisposable messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})"); } - private static void Verify(ILogger? logger, AppSettings appSettings, IWindows windows, string host, string page) + private void WindowsWork(ILogger? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory) { - List messages = []; - HttpClient httpClient = new(); + ReadOnlyCollection results; + if (!Directory.Exists(sourceDirectory)) + _ = Directory.CreateDirectory(sourceDirectory); + logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory); + ReadOnlyCollection files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly(); + if (files.Count > 0) + _ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory); + A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings); int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism; - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; - ReadOnlyCollection collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception(); - windows.ConstructProgressBar(collection.Count, nameof(Verify)); - _ = Parallel.For(0, collection.Count, parallelOptions, (i, state) => - VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages)); - httpClient.Dispose(); - foreach (string message in messages) - logger?.LogWarning("{message}", message); + int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000; + windows.ConstructProgressBar(filesCount, "EnumerateFiles load"); + if (appSettingsMaxDegreeOfParallelism == 1) + results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata); + else + results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism); + string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); + File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); + } + + private static ReadOnlyCollection WindowsSynchronousWork(ILogger? logger, AppSettings appSettings, IWindows windows, IEnumerable files, A_Metadata metadata) + { + List results = []; + int index = -1; + ReadOnlyDictionary> keyValuePairs; + if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page)) + keyValuePairs = IMetadata.GetKeyValuePairs(files); + else + { + ReadOnlyCollection collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page); + keyValuePairs = IMetadata.GetKeyValuePairs(collection); + } + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + if (keyValuePair.Value.Count > 2) + throw new NotSupportedException("Too many sidecar files!"); + index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair); + } + return results.AsReadOnly(); } private static ReadOnlyCollection GetRecursiveCollection(string host, string page) @@ -270,7 +320,7 @@ public partial class Windows : IWindows, IDisposable { if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) continue; - if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) + if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) continue; filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result); if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) @@ -285,7 +335,7 @@ public partial class Windows : IWindows, IDisposable } else { - fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath); + fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, httpClient, filePath); fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result); deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath); } @@ -310,7 +360,7 @@ public partial class Windows : IWindows, IDisposable foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) File.Delete(fastForwardMovingPictureExpertsGroupFile); } - if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) + if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) fastForwardMovingPictureExpertsGroupUsed = true; firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); results.Add(firstPass); @@ -318,27 +368,6 @@ public partial class Windows : IWindows, IDisposable return result; } - private static ReadOnlyCollection WindowsSynchronousWork(ILogger? logger, AppSettings appSettings, IWindows windows, IEnumerable files, A_Metadata metadata) - { - List results = []; - int index = -1; - ReadOnlyDictionary> keyValuePairs; - if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page)) - keyValuePairs = IMetadata.GetKeyValuePairs(files); - else - { - ReadOnlyCollection collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page); - keyValuePairs = IMetadata.GetKeyValuePairs(collection); - } - foreach (KeyValuePair> keyValuePair in keyValuePairs) - { - if (keyValuePair.Value.Count > 2) - throw new NotSupportedException("Too many sidecar files!"); - index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair); - } - return results.AsReadOnly(); - } - private ReadOnlyCollection WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism) { List results = []; @@ -346,12 +375,12 @@ public partial class Windows : IWindows, IDisposable List distinct = []; List metadataGroups = []; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; - files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups)); + files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, metadata, distinct, metadataGroups)); if (_ProgressBar?.CurrentTick != results.Count) throw new NotSupportedException(); foreach (MetadataGroup metadataGroup in metadataGroups) { - if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered)) + if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered)) firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); else firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); @@ -360,36 +389,4 @@ public partial class Windows : IWindows, IDisposable return results.AsReadOnly(); } - private void WindowsWork(ILogger? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory) - { - ReadOnlyCollection results; - if (!Directory.Exists(sourceDirectory)) - _ = Directory.CreateDirectory(sourceDirectory); - logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory); - ReadOnlyCollection files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly(); - if (files.Count > 0) - _ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory); - A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings); - int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism; - int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000; - windows.ConstructProgressBar(filesCount, "EnumerateFiles load"); - if (appSettingsMaxDegreeOfParallelism == 1) - results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata); - else - results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism); - string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); - File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); - } - - private void WindowsWork(ILogger? logger, AppSettings appSettings, IWindows windows, long ticks) - { - if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page)) - Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page); - else - { - string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory); - WindowsWork(logger, appSettings, windows, ticks, sourceDirectory); - } - } - } \ No newline at end of file