diff --git a/.gitignore b/.gitignore index 4a180e8..417772b 100644 --- a/.gitignore +++ b/.gitignore @@ -475,4 +475,4 @@ Rename/.vscode/.UserSecrets/secrets.json Rename/.vscode/.UserSecretsOld/rename.json Rename/.vscode/.UserSecretsOld/secrets.json Windows/.vscode/.UserSecrets/secrets.json -Windows/.vscode/.iCloudPhotos2025 \ No newline at end of file +Windows/.vscode/.7-Question \ No newline at end of file diff --git a/Compare/Models/AppSettings.cs b/Compare/Models/AppSettings.cs index d6a8bcb..1cf28b4 100644 --- a/Compare/Models/AppSettings.cs +++ b/Compare/Models/AppSettings.cs @@ -20,16 +20,16 @@ public record AppSettings(ResultSettings ResultSettings, private static void Verify(AppSettings appSettings) { - if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length != 3) + if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length is not 3 and not 6) throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDaysDeltaTolerance)); - if (appSettings.DistanceSettings.RangeDistanceTolerance.Length != 3) + if (appSettings.DistanceSettings.RangeDistanceTolerance.Length is not 3 and not 6) throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDistanceTolerance)); - if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length != 3) + if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length is not 3 and not 6) throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceAreaTolerance)); - if (appSettings.DistanceSettings.RangeFaceConfidence.Length != 3) + if (appSettings.DistanceSettings.RangeFaceConfidence.Length is not 3 and not 6) throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceConfidence)); _ = DateTime.Now.AddDays(-appSettings.DistanceSettings.RangeDaysDeltaTolerance[1]); - if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Length > 0) + if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any()) throw new Exception("Settings has SaveSortingWithoutPerson and JLinks!"); if (appSettings.DistanceSettings.SaveSortingWithoutPerson && !string.IsNullOrEmpty(appSettings.DistanceSettings.FocusModel)) throw new Exception("Settings has SaveSortingWithoutPerson and FocusModel!"); diff --git a/Distance/Models/Stateless/FilterLogicD.cs b/Distance/Models/Stateless/FilterLogicD.cs index 70cd99a..020e12c 100644 --- a/Distance/Models/Stateless/FilterLogicD.cs +++ b/Distance/Models/Stateless/FilterLogicD.cs @@ -72,16 +72,16 @@ internal static class FilterLogicD internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath) { string result; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath); - result = Path.Combine(cContentDirectory, directoryName); + 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; - (string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath); - result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); + result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension); return result; } diff --git a/Metadata/Models/A_Metadata.cs b/Metadata/Models/A_Metadata.cs index 8418421..959043b 100644 --- a/Metadata/Models/A_Metadata.cs +++ b/Metadata/Models/A_Metadata.cs @@ -11,7 +11,7 @@ public class A_Metadata private readonly ResultSettings _ResultSettings; private readonly MetadataSettings _MetadataSettings; - private readonly ReadOnlyDictionary> _FileGroups; + private readonly ReadOnlyDictionary>> _ResultSingletonFileGroups; public A_Metadata(ResultSettings resultSettings, MetadataSettings metadataSettings) { @@ -23,16 +23,28 @@ public class A_Metadata includeResizeGroup: false, includeModel: false, includePredictorModel: false); - _FileGroups = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]); + Dictionary>> results = []; + ReadOnlyDictionary>>> keyValuePairs = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]); + foreach (KeyValuePair>>> keyValuePair in keyValuePairs) + { + foreach (KeyValuePair>> keyValue in keyValuePair.Value) + { + if (keyValue.Key == resultSettings.ResultSingleton) + results.Add(keyValuePair.Key, keyValue.Value); + else + throw new Exception(); + } + } + _ResultSingletonFileGroups = new(results); } private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath) { MinimumYearAndPathCombined result; - (_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); DateTime minimumDateTime = new(filePath.CreationTicks < filePath.LastWriteTicks ? filePath.CreationTicks : filePath.LastWriteTicks); int minimumYear = minimumDateTime.Year < resultSettings.EpicYear ? resultSettings.EpicYear : minimumDateTime.Year; - result = new(minimumYear, Path.Combine(_FileGroups[minimumYear][_ResultSettings.ResultSingleton][directoryIndex], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json")); + result = new(minimumYear, Path.Combine(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json")); return result; } @@ -42,9 +54,9 @@ public class A_Metadata DateTime? dateTime; dateTime = IDate.GetDateTimeOriginal(exifDirectory); dateTime ??= IDate.GetMinimum(exifDirectory); - (_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year; - result = Path.Combine(_FileGroups[exifYear][_ResultSettings.ResultSingleton][directoryIndex], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"); + result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"); return new(exifYear, result); } diff --git a/Rename/Models/RenameSettings.cs b/Rename/Models/RenameSettings.cs index dcc6765..aed9aca 100644 --- a/Rename/Models/RenameSettings.cs +++ b/Rename/Models/RenameSettings.cs @@ -6,12 +6,14 @@ namespace View_by_Distance.Rename.Models; public record RenameSettings(string Company, string DefaultMaker, + Dictionary DirectoryDictionary, string? FirstPassFile, bool ForceNewId, string[] IgnoreExtensions, bool InPlace, bool InPlaceMoveDirectory, bool InPlaceWithOriginalName, + bool JustMediaDate, int MaxDegreeOfParallelism, int MaxMilliSecondsPerCall, bool OnlySaveIdentifiersToDisk, diff --git a/Rename/Rename.cs b/Rename/Rename.cs index 57f3573..2ed8bb7 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -176,7 +176,7 @@ public partial class Rename : IRename, IDisposable JsonFile: minimumYearAndPathCombined.PathCombined); toDoCollection.AddRange(GetSidecarFiles(appSettings, record, [], checkDirectory, paddedId)); } - _ = RenameFilesInDirectories(appSettings.RenameSettings, rename, new(toDoCollection)); + _ = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection.AsReadOnly()); string jsonFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}.json"); File.Move(minimumYearAndPathCombined.PathCombined, jsonFile, overwrite: true); if (appSettings.RenameSettings.InPlaceWithOriginalName && ids.Count > 0) @@ -189,12 +189,37 @@ public partial class Rename : IRename, IDisposable } } - private List GetFirstPassCollection(ILogger? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection ids, IEnumerable files, A_Metadata metadata) + 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) { - List results = []; - int index = -1; FilePath filePath; - TimeSpan timeSpan; FirstPass firstPass; string directoryName; ExifDirectory exifDirectory; @@ -204,7 +229,66 @@ public partial class Rename : IRename, IDisposable MinimumYearAndPathCombined minimumYearAndPathCombined; FilePath? fastForwardMovingPictureExpertsGroupFilePath; ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; - ReadOnlyDictionary> keyValuePairs = IMetadata.GetKeyValuePairs(files); + 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; @@ -217,57 +301,7 @@ public partial class Rename : IRename, IDisposable } if (keyValuePair.Value.Count > 2) throw new NotSupportedException("Too many sidecar files!"); - 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 (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); - } + SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results); timeSpan = new(DateTime.Now.Ticks - ticks); if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall) break; @@ -302,49 +336,61 @@ 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; - FirstPass firstPass; List collection; string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile); - if (!string.IsNullOrEmpty(checkFile) && File.Exists(checkFile)) + 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 - { - collection = []; - 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) - collection.AddRange(GetFirstPassCollection(logger, appSettings, rename, ticks, ids, files, metadata)); - else - { - 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()); - collection.Add(firstPass); - } - } - if (!string.IsNullOrEmpty(checkFile)) - { - string json = JsonSerializer.Serialize(collection, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); - File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); - } - } - results = GetRecordCollection(appSettings, collection); + results = GetRecordCollection(appSettings, collection); return results; } @@ -381,6 +427,7 @@ public partial class Rename : IRename, IDisposable { 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; @@ -389,7 +436,14 @@ public partial class Rename : IRename, IDisposable 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]}"; - string directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit); + 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)); } } @@ -460,9 +514,9 @@ public partial class Rename : IRename, IDisposable string checkFile; FilePath filePath; FileInfo[] matches; - string directoryName; FileHolder fileHolder; string? checkDirectory; + CombinedEnumAndIndex cei; const string jpg = ".jpg"; string checkFileExtension; List distinct = []; @@ -493,8 +547,8 @@ public partial class Rename : IRename, IDisposable if (File.Exists(checkFile)) continue; } - (directoryName, _) = IPath.GetDirectoryNameAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath); - jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json"); + cei = IPath.GetCombinedEnumAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath); + jsonFile = Path.Combine(jsonFileSubDirectory, cei.Combined, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json"); if (record.JsonFile != jsonFile) { fileHolder = FileHolder.Get(record.JsonFile); diff --git a/Shared/Models/CombinedEnumAndIndex.cs b/Shared/Models/CombinedEnumAndIndex.cs new file mode 100644 index 0000000..3b8e7d1 --- /dev/null +++ b/Shared/Models/CombinedEnumAndIndex.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public record CombinedEnumAndIndex(string Combined, + byte Enum, + int Index) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, CombinedEnumAndIndexSourceGenerationContext.Default.CombinedEnumAndIndex); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(CombinedEnumAndIndex))] +internal partial class CombinedEnumAndIndexSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Shared/Models/Stateless/IPath.cs b/Shared/Models/Stateless/IPath.cs index fdde4c0..5cfe754 100644 --- a/Shared/Models/Stateless/IPath.cs +++ b/Shared/Models/Stateless/IPath.cs @@ -61,14 +61,14 @@ public interface IPath static string GetDirectory(string sourceDirectory, int level, string directoryName) => XPath.GetDirectory(sourceDirectory, level, directoryName); - (string, int) TestStatic_GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) => - GetDirectoryNameAndIndex(resultSettings, filePath); - static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) => - XPath.GetDirectoryNameAndIndex(resultSettings, filePath); + CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) => + GetCombinedEnumAndIndex(resultSettings, filePath); + static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) => + XPath.GetCombinedEnumAndIndex(resultSettings, filePath); - ReadOnlyDictionary> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => + ReadOnlyDictionary>>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); - static ReadOnlyDictionary> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => + static ReadOnlyDictionary>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); } \ No newline at end of file diff --git a/Shared/Models/Stateless/XDate.cs b/Shared/Models/Stateless/XDate.cs index 7f98a79..caa8138 100644 --- a/Shared/Models/Stateless/XDate.cs +++ b/Shared/Models/Stateless/XDate.cs @@ -82,13 +82,15 @@ internal abstract class XDate for (int i = 0; i < int.MaxValue; i++) { check = Path.GetDirectoryName(check); - if (string.IsNullOrEmpty(check) || check == directoryInfo.FullName) + if (string.IsNullOrEmpty(check)) break; directoryName = Path.GetFileName(check); directorySegments = directoryName.Split(' '); (result, results) = IsWrongYear(directorySegments, year); if (result is not null) break; + if (check == directoryInfo.FullName) + break; } if (result is not null && !result.Value) break; diff --git a/Shared/Models/Stateless/XPath.cs b/Shared/Models/Stateless/XPath.cs index 585c00f..2985c3b 100644 --- a/Shared/Models/Stateless/XPath.cs +++ b/Shared/Models/Stateless/XPath.cs @@ -265,40 +265,64 @@ internal abstract class XPath } } - private static (string, int) GetDirectoryNameAndIndex(int resultAllInOneSubdirectoryLength, string fileNameWithoutExtension) + private static byte GetEnum(bool? ik, bool? dto) { + 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 + throw new Exception(); + return result; + } + + private static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileNameWithoutExtension) + { + CombinedEnumAndIndex result; int converted; - string result; + string combined; string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0]; - string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ? new('-', resultAllInOneSubdirectoryLength) : fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..]; + byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); + string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ? + new('-', resultAllInOneSubdirectoryLength) : + fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..]; if (check.Any(l => !char.IsNumber(l))) { - result = new('-', resultAllInOneSubdirectoryLength); + combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}"; converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}"); } else { - result = check; + combined = $"{@enum}{check}"; converted = int.Parse(check); } - return new(result, converted); + result = new(combined, @enum, converted); + return result; } - internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, int id) + internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) { - (string result, int converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, id.ToString()); - return new(result, converted); - } - - internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) - { - string result; - int converted; + CombinedEnumAndIndex result; if (filePath.Id is not null) - (result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.Id.Value.ToString()); + result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString()); else - (result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.NameWithoutExtension); - return new(result, converted); + result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.NameWithoutExtension); + return result; } private static ReadOnlyCollection GetYears(ResultSettings resultSettings) @@ -310,62 +334,121 @@ internal abstract class XPath return results.AsReadOnly(); } - private static ReadOnlyDictionary> Convert(Dictionary> collection) + 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 collection) + 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) + private static ReadOnlyDictionary> Convert(List collection) { - Dictionary> results = []; + 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 = []; + int plusOne; string directory; string checkDirectory; - Dictionary? keyValuePairs; - ReadOnlyCollection years = GetYears(resultSettings); + CombinedEnumAndIndex cei; + byte[] bytes = GetBytes(); + List collection = []; + ReadOnlyDictionary> keyValuePairs; int converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}"); - int plusOne = converted + 1; - List collection = []; - foreach (int year in years) + if (jsonGroups is not null) { - results.Add(year, []); - if (!results.TryGetValue(year, out keyValuePairs)) - throw new NullReferenceException(nameof(keyValuePairs)); - if (jsonGroups is not null) + plusOne = converted + 1; + foreach (string jsonGroup in jsonGroups) { - foreach (string jsonGroup in jsonGroups) + if (resultsFullGroupDirectory is null) + continue; + foreach (byte @enum in bytes) { - if (resultsFullGroupDirectory is null) - continue; - collection.Clear(); for (int i = 0; i < plusOne; i++) { if (string.IsNullOrEmpty(jsonGroup)) { if (i == converted) - checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, new('-', resultSettings.ResultAllInOneSubdirectoryLength))); + checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}")); else - checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0'))); + checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}")); } else { directory = Path.Combine(resultsFullGroupDirectory, jsonGroup); if (i == converted) - checkDirectory = Path.GetFullPath(Path.Combine(directory, new('-', resultSettings.ResultAllInOneSubdirectoryLength))); + checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}")); else - checkDirectory = Path.GetFullPath(Path.Combine(directory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0'))); + checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}")); } if (!Directory.Exists(checkDirectory)) _ = Directory.CreateDirectory(checkDirectory); - collection.Add(checkDirectory); + cei = new(Combined: checkDirectory, Enum: @enum, Index: -1); + collection.Add(cei); } - if (!string.IsNullOrEmpty(jsonGroup)) - keyValuePairs.Add(jsonGroup, collection.ToArray()); - else - keyValuePairs.Add(year.ToString(), collection.ToArray()); } + keyValuePairs = Convert(collection); + if (!string.IsNullOrEmpty(jsonGroup)) + results.Add(jsonGroup, keyValuePairs); + else + results.Add(dateTime.Ticks.ToString(), keyValuePairs); + } + } + return results.AsReadOnly(); + } + + private static ReadOnlyDictionary>>> Convert(Dictionary>>> 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); diff --git a/Windows/.vscode/11.http b/Windows/.vscode/11.http new file mode 100644 index 0000000..f1cd384 --- /dev/null +++ b/Windows/.vscode/11.http @@ -0,0 +1,5 @@ +@host = http://192.168.0.11:8080 + +GET {{host}}/iCloud%20Photos%202025 + +### diff --git a/Windows/.vscode/mklink.md b/Windows/.vscode/mklink.md new file mode 100644 index 0000000..7ae6523 --- /dev/null +++ b/Windows/.vscode/mklink.md @@ -0,0 +1,5 @@ +# mklink + +```bash 1741014465915 = 638766112659150000 = 2025-0.Winter = Mon Mar 03 2025 08:07:45 GMT-0700 (Mountain Standard Time) +mklink /J "L:\Git\AA\Windows\.vscode\.7-Question" "V:\7-Question" +```` diff --git a/Windows/Windows.cs b/Windows/Windows.cs index 1cf8739..4a31a0d 100644 --- a/Windows/Windows.cs +++ b/Windows/Windows.cs @@ -50,6 +50,15 @@ public partial class Windows : IWindows, IDisposable GC.SuppressFinalize(this); } + private static void DownloadFile(HttpClient httpClient, FilePath filePath) + { + FileStream fileStream = new(filePath.FullName, FileMode.Truncate); + Task httpResponseMessage = httpClient.GetAsync(filePath.FullName); + httpResponseMessage.Wait(); + Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream); + task.Wait(); + } + ReadOnlyCollection IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath) { List results = []; @@ -57,6 +66,8 @@ public partial class Windows : IWindows, IDisposable if (isValidVideoFormatExtensions) { bool check; + if (httpClient is not null) + DownloadFile(httpClient, filePath); try { CommandTask commandTask = Cli.Wrap("L:/Git/ffmpeg-2024-10-02-git-358fdf3083-full_build/bin/ffmpeg.exe") @@ -240,10 +251,10 @@ public partial class Windows : IWindows, IDisposable return results; } - private List GetCollection(ILogger? logger, AppSettings appSettings, IWindows windows, IEnumerable files, A_Metadata metadata) + private static int WindowsSynchronousWork(ILogger? logger, AppSettings appSettings, IWindows windows, A_Metadata metadata, List results, int index, KeyValuePair> keyValuePair) { - List results = []; - int index = -1; + int result = index + 1; + windows.Tick(); FilePath filePath; FirstPass firstPass; string directoryName; @@ -253,9 +264,65 @@ public partial class Windows : IWindows, IDisposable bool fastForwardMovingPictureExpertsGroupUsed; MinimumYearAndPathCombined minimumYearAndPathCombined; FilePath? fastForwardMovingPictureExpertsGroupFilePath; - ReadOnlyDictionary> keyValuePairs; ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; HttpClient? httpClient = string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page) ? null : new(); + foreach (FileHolder fileHolder in keyValuePair.Value) + { + if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) + continue; + if (appSettings.WindowsSettings.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)) + continue; + if (filePath.Id is not null) + { + fastForwardMovingPictureExpertsGroupFiles = null; + deterministicHashCode = new(null, filePath.Id, null); + directoryName = Path.GetFileName(filePath.DirectoryFullPath); + if (directoryName.EndsWith(filePath.Id.Value.ToString())) + continue; + } + else + { + fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, 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); + } + sidecarFiles = []; + filePath = FilePath.Get(filePath, deterministicHashCode); + for (int i = 0; i < keyValuePair.Value.Count; i++) + { + if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered) + continue; + sidecarFiles.Add(keyValuePair.Value[i]); + } + try + { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, 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 (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) + fastForwardMovingPictureExpertsGroupUsed = true; + firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); + results.Add(firstPass); + } + 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 @@ -265,61 +332,53 @@ public partial class Windows : IWindows, IDisposable } foreach (KeyValuePair> keyValuePair in keyValuePairs) { - index += 1; - windows.Tick(); if (keyValuePair.Value.Count > 2) throw new NotSupportedException("Too many sidecar files!"); - foreach (FileHolder fileHolder in keyValuePair.Value) - { - if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) - continue; - filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index); - if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) - continue; - if (filePath.Id is not null) - { - fastForwardMovingPictureExpertsGroupFiles = null; - deterministicHashCode = new(null, filePath.Id, null); - directoryName = Path.GetFileName(filePath.DirectoryFullPath); - if (directoryName.EndsWith(filePath.Id.Value.ToString())) - continue; - } - else - { - fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath); - fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index); - deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath); - } - sidecarFiles = []; - filePath = FilePath.Get(filePath, deterministicHashCode); - for (int i = 0; i < keyValuePair.Value.Count; i++) - { - if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered) - continue; - sidecarFiles.Add(keyValuePair.Value[i]); - } - try - { (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, 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 (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) - fastForwardMovingPictureExpertsGroupUsed = true; - firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); - results.Add(firstPass); - } + index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair); } - return results; + return results.AsReadOnly(); + } + + private ReadOnlyCollection WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism) + { + List results = []; + FirstPass firstPass; + List distinct = []; + List metadataGroups = []; + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; + files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, 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)) + 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); + } + 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) @@ -328,40 +387,8 @@ public partial class Windows : IWindows, IDisposable Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page); else { - FirstPass firstPass; - List results = []; 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); - 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.AddRange(GetCollection(logger, appSettings, windows, files, metadata)); - else - { - List distinct = []; - List metadataGroups = []; - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; - files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, 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)) - 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); - } - } - string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass); - File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json); + WindowsWork(logger, appSettings, windows, ticks, sourceDirectory); } }