From 23256c8152f00020e7b2d561c5a5303fcfc9b828 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 6 Apr 2025 15:45:10 -0700 Subject: [PATCH] Alignment with Console --- Metadata/Models/A_Metadata.cs | 98 ++++----- Rename/Rename.cs | 41 +++- Shared/Models/Stateless/IDate.cs | 40 ++-- Shared/Models/Stateless/IId.cs | 20 +- Shared/Models/Stateless/IPath.cs | 159 ++++++++------ Shared/Models/Stateless/Id.cs | 27 ++- Shared/Models/Stateless/XDate.cs | 356 +++++++++++++++---------------- Shared/Models/Stateless/XPath.cs | 32 ++- Windows/Windows.cs | 28 ++- 9 files changed, 455 insertions(+), 346 deletions(-) diff --git a/Metadata/Models/A_Metadata.cs b/Metadata/Models/A_Metadata.cs index 959043b..ab2253c 100644 --- a/Metadata/Models/A_Metadata.cs +++ b/Metadata/Models/A_Metadata.cs @@ -36,45 +36,8 @@ public class A_Metadata } } _ResultSingletonFileGroups = new(results); - } - - private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath) - { - MinimumYearAndPathCombined result; - 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(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json")); - return result; - } - - private (int, string) GetJsonFile(ResultSettings resultSettings, FilePath filePath, ExifDirectory exifDirectory) - { - string? result; - DateTime? dateTime; - dateTime = IDate.GetDateTimeOriginal(exifDirectory); - dateTime ??= IDate.GetMinimum(exifDirectory); - CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); - int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year; - result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"); - return new(exifYear, result); - } - - private static (string, ExifDirectory?) Get(string jsonFile) - { - ExifDirectory? result; - string json = File.ReadAllText(jsonFile); - try - { - result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory); - if (result is null) - throw new Exception(); - } - catch (Exception) - { - result = null; - } - return new(json, result); + ReadOnlyCollection directories = new([Path.Combine(aResultsFullGroupDirectory, resultSettings.ResultSingleton)]); + IPath.CreateDirectories(directories); } public (MinimumYearAndPathCombined, ExifDirectory) GetMetadataCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, FilePath filePath) @@ -148,19 +111,45 @@ public class A_Metadata return new(minimumYearAndPathCombined, result); } - private static Stream GetStream(HttpClient httpClient, FilePath filePath) + private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath) { - Stream result; - Task httpResponseMessage = httpClient.GetAsync(filePath.FullName); - httpResponseMessage.Wait(); - Task task = httpResponseMessage.Result.Content.LoadIntoBufferAsync(); - task.Wait(); - Task stream = httpResponseMessage.Result.Content.ReadAsStreamAsync(); - stream.Wait(); - result = stream.Result; + MinimumYearAndPathCombined result; + 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(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json")); return result; } + private (int, string) GetJsonFile(ResultSettings resultSettings, FilePath filePath, ExifDirectory exifDirectory) + { + string? result; + DateTime? dateTime; + dateTime = IDate.GetDateTimeOriginal(exifDirectory); + dateTime ??= IDate.GetMinimum(exifDirectory); + CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath); + int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year; + result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"); + return new(exifYear, result); + } + + private static (string, ExifDirectory?) Get(string jsonFile) + { + ExifDirectory? result; + string json = File.ReadAllText(jsonFile); + try + { + result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory); + if (result is null) + throw new Exception(); + } + catch (Exception) + { + result = null; + } + return new(json, result); + } + public (MinimumYearAndPathCombined, ExifDirectory) GetMetadataCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, HttpClient? httpClient, FilePath filePath) { ExifDirectory result; @@ -178,4 +167,17 @@ public class A_Metadata return new(minimumYearAndPathCombined, result); } + private static Stream GetStream(HttpClient httpClient, FilePath filePath) + { + Stream result; + Task httpResponseMessage = httpClient.GetAsync(filePath.FullName); + httpResponseMessage.Wait(); + Task task = httpResponseMessage.Result.Content.LoadIntoBufferAsync(); + task.Wait(); + Task stream = httpResponseMessage.Result.Content.ReadAsStreamAsync(); + stream.Wait(); + result = stream.Result; + return result; + } + } \ No newline at end of file diff --git a/Rename/Rename.cs b/Rename/Rename.cs index 52adeea..e36c66f 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -124,11 +124,28 @@ public partial class Rename : IRename, IDisposable if (console is null) throw new NullReferenceException(nameof(console)); IRename rename = this; + LogNetToHoursSince(logger); long ticks = DateTime.Now.Ticks; _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; RenameWork(logger, appSettings, rename, ticks); } + private static void LogNetToHoursSince(ILogger? logger) + { + double secondsInAHour = 3600f; + long epoch = new DateTime(1970, 1, 1).Ticks; + long net8ReleaseDate = new DateTime(2023, 11, 14).Ticks; + long net9ReleaseDate = new DateTime(2024, 11, 12).Ticks; + double net8TotalSeconds = new TimeSpan(net8ReleaseDate - epoch).TotalSeconds; + double net9TotalSeconds = new TimeSpan(net9ReleaseDate - epoch).TotalSeconds; + logger?.LogInformation("It has been {net8TotalSeconds} seconds since net8 was released", net8TotalSeconds); + logger?.LogInformation("It has been {net9TotalSeconds} seconds since net9 was released", net9TotalSeconds); + double net8TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net8TotalSeconds) / secondsInAHour); + double net9TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net9TotalSeconds) / secondsInAHour); + logger?.LogInformation("It has been {net8TotalHours} hours since net8 was released", net8TotalHours); + logger?.LogInformation("It has been {net9TotalHours} hours since net9 was released", net9TotalHours); + } + private void RenameWork(ILogger? logger, AppSettings appSettings, IRename rename, long ticks) { ReadOnlyCollection ids = GetIds(appSettings.RenameSettings); @@ -365,7 +382,7 @@ public partial class Rename : IRename, IDisposable bool hasIgnoreKeyword = appSettings.MetadataSettings.IgnoreRulesKeyWords.Any(keywords.Contains); string checkFileExtension = exifDirectory.FilePath.ExtensionLowered == jpeg ? jpg : exifDirectory.FilePath.ExtensionLowered; bool hasDateTimeOriginal = dateTime is not null; - string paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, exifDirectory.FilePath.Id.Value, hasIgnoreKeyword, hasDateTimeOriginal, i); + string paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, exifDirectory.FilePath.Id.Value, exifDirectory.FilePath.ExtensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, i); string checkDirectory = appSettings.RenameSettings.InPlaceWithOriginalName ? Path.Combine(exifDirectory.FilePath.DirectoryFullPath, exifDirectory.FilePath.FileNameFirstSegment) : exifDirectory.FilePath.DirectoryFullPath; string checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); if (checkFile != exifDirectory.FilePath.FullName) @@ -445,7 +462,7 @@ public partial class Rename : IRename, IDisposable { if (record.ExifDirectory.FilePath.Id is null) continue; - paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null); + paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.ExtensionLowered, 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); } @@ -462,15 +479,19 @@ public partial class Rename : IRename, IDisposable string paddedId; string checkFile; FilePath filePath; + DateTime? dateTime; FileInfo[] matches; FileHolder fileHolder; + bool? hasIgnoreKeyword; string? checkDirectory; CombinedEnumAndIndex cei; + bool? hasDateTimeOriginal; const string jpg = ".jpg"; string checkFileExtension; List distinct = []; const string jpeg = ".jpeg"; string jsonFileSubDirectory; + ReadOnlyCollection keywords; bool? directoryCheck = GetDirectoryCheck(appSettings.ResultSettings); VerifyIntMinValueLength(appSettings.MetadataSettings, recordCollection); bool multipleDirectoriesWithFiles = directoryCheck is not null && directoryCheck.Value; @@ -481,7 +502,7 @@ public partial class Rename : IRename, IDisposable record = sorted[i]; if (record.ExifDirectory.FilePath.Id is null) continue; - paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, i); + paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.ExtensionLowered, record.HasIgnoreKeyword, record.HasDateTimeOriginal, i); checkDirectory = GetCheckDirectory(appSettings, directoryInfo, record, ids, multipleDirectoriesWithFiles, paddedId); if (string.IsNullOrEmpty(checkDirectory)) continue; @@ -496,6 +517,20 @@ public partial class Rename : IRename, IDisposable if (File.Exists(checkFile)) continue; } + if (record.ExifDirectory.FilePath.HasDateTimeOriginal is not null && record.ExifDirectory.FilePath.HasIgnoreKeyword is not null) + { + hasIgnoreKeyword = record.ExifDirectory.FilePath.HasIgnoreKeyword; + hasDateTimeOriginal = record.ExifDirectory.FilePath.HasDateTimeOriginal; + } + else + { + dateTime = IDate.GetDateTimeOriginal(record.ExifDirectory); + hasDateTimeOriginal = dateTime is not null; + if (dateTime is null && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(record.ExifDirectory.FilePath.ExtensionLowered)) + continue; + keywords = IMetadata.GetKeywords(record.ExifDirectory); + hasIgnoreKeyword = appSettings.MetadataSettings.IgnoreRulesKeyWords.Any(keywords.Contains); + } 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) diff --git a/Shared/Models/Stateless/IDate.cs b/Shared/Models/Stateless/IDate.cs index fc07b9d..da5e2cc 100644 --- a/Shared/Models/Stateless/IDate.cs +++ b/Shared/Models/Stateless/IDate.cs @@ -3,24 +3,28 @@ namespace View_by_Distance.Shared.Models.Stateless; public interface IDate { - (bool?, string[]) TestStatic_IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) => - IsWrongYear(directoryInfo, filePath, exifDirectory); - static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) => - XDate.IsWrongYear(directoryInfo, filePath, exifDirectory); - - (int Season, string seasonName) TestStatic_GetSeason(int dayOfYear) => - GetSeason(dayOfYear); - static (int Season, string seasonName) GetSeason(int dayOfYear) => - XDate.GetSeason(dayOfYear); - - DateTime? TestStatic_GetDateTimeOriginal(ExifDirectory exifDirectory) => - GetDateTimeOriginal(exifDirectory); - static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) => - XDate.GetDateTimeOriginal(exifDirectory); - - DateTime TestStatic_GetMinimum(ExifDirectory exifDirectory) => - GetMinimum(exifDirectory); - static DateTime GetMinimum(ExifDirectory exifDirectory) => + public static DateTime GetMinimum(ExifDirectory exifDirectory) => XDate.GetMinimum(exifDirectory); + public static (int Season, string seasonName) GetSeason(int dayOfYear) => + XDate.GetSeason(dayOfYear); + + public static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) => + XDate.GetDateTimeOriginal(exifDirectory); + + public static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) => + XDate.IsWrongYear(directoryInfo, filePath, exifDirectory); + + internal DateTime TestStatic_GetMinimum(ExifDirectory exifDirectory) => + GetMinimum(exifDirectory); + + internal (int Season, string seasonName) TestStatic_GetSeason(int dayOfYear) => + GetSeason(dayOfYear); + + internal DateTime? TestStatic_GetDateTimeOriginal(ExifDirectory exifDirectory) => + GetDateTimeOriginal(exifDirectory); + + internal (bool?, string[]) TestStatic_IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) => + IsWrongYear(directoryInfo, filePath, exifDirectory); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/IId.cs b/Shared/Models/Stateless/IId.cs index 4d51de2..79d4a1d 100644 --- a/Shared/Models/Stateless/IId.cs +++ b/Shared/Models/Stateless/IId.cs @@ -27,18 +27,18 @@ public interface IId 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); + fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '0' or '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[^1] is '0' or '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 GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => + Id.GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, 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); + public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => + Id.GetPaddedId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index); internal int TestStatic_GetDeterministicHashCode(byte[] value) => GetDeterministicHashCode(value); @@ -64,10 +64,10 @@ public interface IId 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_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, string extensionLowered, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) => + GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, 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); + internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) => + GetPaddedId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index); } \ No newline at end of file diff --git a/Shared/Models/Stateless/IPath.cs b/Shared/Models/Stateless/IPath.cs index e63ae5b..64b01de 100644 --- a/Shared/Models/Stateless/IPath.cs +++ b/Shared/Models/Stateless/IPath.cs @@ -3,77 +3,96 @@ using System.Collections.ObjectModel; namespace View_by_Distance.Shared.Models.Stateless; public interface IPath -{ // ... +{ - string TestStatic_GetRelativePath(string path, int length) => - GetRelativePath(path, length); - static string GetRelativePath(string path, int length) => - XPath.GetRelativePath(path, length, forceExtensionToLower: false); - - bool TestStatic_DeleteEmptyDirectories(string rootDirectory) => - DeleteEmptyDirectories(rootDirectory); - static bool DeleteEmptyDirectories(string rootDirectory) => - XPath.DeleteEmptyDirectories(rootDirectory); - - void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) => - ChangeDateForEmptyDirectories(rootDirectory, ticks); - static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) => - XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks); - - void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) => - MakeHiddenIfAllItemsAreHidden(rootDirectory); - static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) => - XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory); - - void TestStatic_DeleteEmptyDirectories(string rootDirectory, List deletedDirectories) => - DeleteEmptyDirectories(rootDirectory, deletedDirectories); - static void DeleteEmptyDirectories(string rootDirectory, List deletedDirectories) => - XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories); - // $dirs = gci "" -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName $dirs | Foreach-Object { Remove-Item $_ } - - string[] TestStatic_GetDirectoryNames(string directory) => - GetDirectoryNames(directory); - static string[] GetDirectoryNames(string directory) => - XPath.GetDirectoryNames(directory).ToArray(); - - string[] TestStatic_GetDirectories(string directory) => - GetDirectories(directory); - static string[] GetDirectories(string directory) => - XPath.GetDirectories(directory).ToArray(); - - string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) => - GetRelativePath(path, length, forceExtensionToLower); - static string GetRelativePath(string path, int length, bool forceExtensionToLower) => - XPath.GetRelativePath(path, length, forceExtensionToLower); - - bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => - WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); - static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => - XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); - - (int level, List directories) TestStatic_Get(string rootDirectory, string sourceDirectory) => - Get(rootDirectory, sourceDirectory); - static (int level, List directories) Get(string rootDirectory, string sourceDirectory) => - XPath.Get(rootDirectory, sourceDirectory); - - string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) => - GetDirectory(sourceDirectory, level, directoryName); - static string GetDirectory(string sourceDirectory, int level, string directoryName) => - XPath.GetDirectory(sourceDirectory, level, directoryName); - - 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) => - GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); - static ReadOnlyDictionary>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => - XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); - - byte TestStatic_GetEnum(FilePath filePath) => - GetEnum(filePath); - static byte GetEnum(FilePath filePath) => + public static byte GetEnum(FilePath filePath) => XPath.GetEnum(filePath); + public static string[] GetDirectories(string directory) => + XPath.GetDirectories(directory).ToArray(); + + public static string[] GetDirectoryNames(string directory) => + XPath.GetDirectoryNames(directory).ToArray(); + + public static string GetRelativePath(string path, int length) => + XPath.GetRelativePath(path, length, forceExtensionToLower: false); + + public static bool DeleteEmptyDirectories(string rootDirectory) => + XPath.DeleteEmptyDirectories(rootDirectory); + + public static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) => + XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory); + + public static void CreateDirectories(ReadOnlyCollection directories) => + XPath.CreateDirectories(directories); + + public static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) => + XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks); + + public static string GetRelativePath(string path, int length, bool forceExtensionToLower) => + XPath.GetRelativePath(path, length, forceExtensionToLower); + + public static string GetDirectory(string sourceDirectory, int level, string directoryName) => + XPath.GetDirectory(sourceDirectory, level, directoryName); + + public static void DeleteEmptyDirectories(string rootDirectory, List deletedDirectories) => + XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories); + + public static (int level, List directories) Get(string rootDirectory, string sourceDirectory) => + XPath.Get(rootDirectory, sourceDirectory); + + public static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) => + XPath.GetCombinedEnumAndIndex(resultSettings, filePath); + + public static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => + XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); + + public static ReadOnlyDictionary>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => + XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); + + internal byte TestStatic_GetEnum(FilePath filePath) => + GetEnum(filePath); + + internal string[] TestStatic_GetDirectories(string directory) => + GetDirectories(directory); + + internal string[] TestStatic_GetDirectoryNames(string directory) => + GetDirectoryNames(directory); + + internal string TestStatic_GetRelativePath(string path, int length) => + GetRelativePath(path, length); + + internal bool TestStatic_DeleteEmptyDirectories(string rootDirectory) => + DeleteEmptyDirectories(rootDirectory); + + internal void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) => + MakeHiddenIfAllItemsAreHidden(rootDirectory); + + internal void TestStatic_CreateDirectories(ReadOnlyCollection directories) => + CreateDirectories(directories); + + internal void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) => + ChangeDateForEmptyDirectories(rootDirectory, ticks); + + internal string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) => + GetRelativePath(path, length, forceExtensionToLower); + + internal string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) => + GetDirectory(sourceDirectory, level, directoryName); + + internal void TestStatic_DeleteEmptyDirectories(string rootDirectory, List deletedDirectories) => + DeleteEmptyDirectories(rootDirectory, deletedDirectories); + + internal (int level, List directories) TestStatic_Get(string rootDirectory, string sourceDirectory) => + Get(rootDirectory, sourceDirectory); + + internal CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) => + GetCombinedEnumAndIndex(resultSettings, filePath); + + internal bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => + WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); + + internal ReadOnlyDictionary>>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) => + GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Id.cs b/Shared/Models/Stateless/Id.cs index 747d146..bb18eee 100644 --- a/Shared/Models/Stateless/Id.cs +++ b/Shared/Models/Stateless/Id.cs @@ -31,7 +31,7 @@ internal abstract class Id (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); + (byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : filePath.Id > -1 ? 5 : 0); internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) { @@ -43,7 +43,7 @@ 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' or '4') + if (intelligentId[^1] is '0' or '1' or '2' or '3' or '4') result *= -1; else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5') throw new NotSupportedException(); @@ -64,7 +64,7 @@ internal abstract class Id } #pragma warning disable IDE0060 - internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) + internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) #pragma warning restore IDE0060 { string result; @@ -74,14 +74,25 @@ internal abstract class Id int key; string value; List resultAllInOneSubdirectoryChars = []; - if (id > -1) + if (hasDateTimeOriginal is null) { - key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 9 : 7; + key = 0; + value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0'); + } + else if (id > -1) + { + if (!resultSettings.ValidVideoFormatExtensions.Contains(extensionLowered)) + key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal.Value ? 9 : 7; + else + key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 6 : 5; value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0'); } else { - key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 1 : 3; + if (!resultSettings.ValidVideoFormatExtensions.Contains(extensionLowered)) + key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal.Value ? 1 : 3; + else + key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 4 : 0; value = id.ToString()[1..].PadLeft(metadataSettings.IntMinValueLength, '0'); } for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength - 1; i > -1; i--) @@ -92,14 +103,14 @@ internal abstract class Id return result; } - internal static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) + internal static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) { string result; if (metadataSettings.Offset < 0) result = Guid.NewGuid().ToString(); else { - string intelligentId = GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal); + string intelligentId = GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal); int check = GetId(resultSettings, metadataSettings, intelligentId); if (check != id) throw new NotSupportedException(); diff --git a/Shared/Models/Stateless/XDate.cs b/Shared/Models/Stateless/XDate.cs index caa8138..44d57e7 100644 --- a/Shared/Models/Stateless/XDate.cs +++ b/Shared/Models/Stateless/XDate.cs @@ -7,181 +7,11 @@ namespace View_by_Distance.Shared.Models.Stateless; internal abstract class XDate { - private record Record(bool? IsWrongYear, string[] Years); - - internal static (int Season, string seasonName) GetSeason(int dayOfYear) + internal static DateTime GetMinimum(ExifDirectory exifDirectory) { - (int Season, string seasonName) result = dayOfYear switch - { - < 78 => new(0, "Winter"), - < 124 => new(1, "Spring"), - < 171 => new(2, "Spring"), - < 217 => new(3, "Summer"), - < 264 => new(4, "Summer"), - < 309 => new(5, "Fall"), - < 354 => new(6, "Fall"), - _ => new(7, "Winter") - }; - return result; - } - - private static Record IsWrongYear(string[] segments, string year) - { - Record result; - bool? check; - string[] results = ( - from l - in segments - where l?.Length > 2 - && ( - l[..2] is "18" or "19" or "20" - || (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#')) - || (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.') - || (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.') - ) - select l - ).ToArray(); - string[] matches = ( - from l - in results - where l == year - || (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#')) - || (l.Length == 6 && l[..4] == year && l[4] == '.') - || (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.') - select l - ).ToArray(); - if (results.Length == 0) - check = null; - else - check = matches.Length == 0; - result = new(check, results); - return result; - } - - internal static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) - { - string[] results = []; - bool? result = null; - string year; - string directoryName; - string[] directorySegments; - List collection = []; - string? check = Path.GetFullPath(filePath.FullName); - DateTime? dateTimeOriginal = GetDateTimeOriginal(exifDirectory); - if (dateTimeOriginal is not null) - collection.Add(dateTimeOriginal.Value); - else - { - ReadOnlyCollection dateTimes = GetDateTimes(exifDirectory); - foreach (DateTime dateTime in dateTimes) - collection.Add(dateTime); - } - foreach (DateTime dateTime in collection) - { - year = dateTime.ToString("yyyy"); - for (int i = 0; i < int.MaxValue; i++) - { - check = Path.GetDirectoryName(check); - 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; - } - return new(result, results); - } - - internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) - { - DateTime? result; - List results = []; - foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories) - { - if (exifDirectoryBase.DateTimeOriginal is not null) - results.Add(exifDirectoryBase.DateTimeOriginal.Value); - } - foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories) - { - if (aviDirectory.DateTimeOriginal is not null) - results.Add(aviDirectory.DateTimeOriginal.Value); - } - foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories) - { - if (quickTimeMovieHeaderDirectory.Created is not null) - { - if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1) - continue; - results.Add(quickTimeMovieHeaderDirectory.Created.Value); - } - } - foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories) - { - if (quickTimeTrackHeaderDirectory.Created is not null) - { - if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1) - continue; - results.Add(quickTimeTrackHeaderDirectory.Created.Value); - } - } - result = results.Count == 0 ? null : results.Min(); - return result; - } - - private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension) - { - DateTime? result = null; - int length; - string format; - string fullFormat; - StringBuilder value = new(); - const string ticksExample = "##################"; - string[][] dateFormats = - [ - [string.Empty, "yyyyMMdd_HHmmss", string.Empty], - [string.Empty, "yyyyMMddHHmmssfff", string.Empty], - [string.Empty, "yyyyMMdd_", ticksExample], - [string.Empty, "yyyy-MM-dd_", ticksExample], - [string.Empty, "yyyy-MM-dd.", ticksExample], - // [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"], - [string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty], - [string.Empty, "yyyyMMdd_HHmmss", "_LLS"], - [string.Empty, "yyyyMMdd_HHmmss", "_HDR"], - ["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"], - ["IMG_", "yyyyMMdd_HHmmss", string.Empty], - ["IMG#####-", "yyyyMMdd-HHmm", string.Empty], - ["CameraZOOM-", "yyyyMMddHHmmss", string.Empty], - ["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty] - ]; - foreach (string[] dateFormat in dateFormats) - { - _ = value.Clear(); - if (dateFormat.Length != 3) - throw new Exception(); - fullFormat = string.Join(string.Empty, dateFormat); - if (fileNameWithoutExtension.Length != fullFormat.Length) - continue; - format = dateFormat[1]; - length = dateFormat[0].Length + dateFormat[1].Length; - for (int i = dateFormat[0].Length; i < length; i++) - _ = value.Append(fileNameWithoutExtension[i]); - if (value.Length != format.Length) - continue; - if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime)) - { - if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks)) - result = checkDateTime; - else - result = new DateTime(ticks); - break; - } - } + DateTime result; + ReadOnlyCollection results = GetDateTimes(exifDirectory); + result = results.Count == 0 ? DateTime.MinValue : results.Min(); return result; } @@ -241,12 +71,182 @@ internal abstract class XDate return results.AsReadOnly(); } - internal static DateTime GetMinimum(ExifDirectory exifDirectory) + private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension) { - DateTime result; - ReadOnlyCollection results = GetDateTimes(exifDirectory); - result = results.Count == 0 ? DateTime.MinValue : results.Min(); + DateTime? result = null; + int length; + string format; + string fullFormat; + StringBuilder value = new(); + const string ticksExample = "##################"; + string[][] dateFormats = + [ + [string.Empty, "yyyyMMdd_HHmmss", string.Empty], + [string.Empty, "yyyyMMddHHmmssfff", string.Empty], + [string.Empty, "yyyyMMdd_", ticksExample], + [string.Empty, "yyyy-MM-dd_", ticksExample], + [string.Empty, "yyyy-MM-dd.", ticksExample], + // [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"], + [string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty], + [string.Empty, "yyyyMMdd_HHmmss", "_LLS"], + [string.Empty, "yyyyMMdd_HHmmss", "_HDR"], + ["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"], + ["IMG_", "yyyyMMdd_HHmmss", string.Empty], + ["IMG#####-", "yyyyMMdd-HHmm", string.Empty], + ["CameraZOOM-", "yyyyMMddHHmmss", string.Empty], + ["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty] + ]; + foreach (string[] dateFormat in dateFormats) + { + _ = value.Clear(); + if (dateFormat.Length != 3) + throw new Exception(); + fullFormat = string.Join(string.Empty, dateFormat); + if (fileNameWithoutExtension.Length != fullFormat.Length) + continue; + format = dateFormat[1]; + length = dateFormat[0].Length + dateFormat[1].Length; + for (int i = dateFormat[0].Length; i < length; i++) + _ = value.Append(fileNameWithoutExtension[i]); + if (value.Length != format.Length) + continue; + if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime)) + { + if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks)) + result = checkDateTime; + else + result = new DateTime(ticks); + break; + } + } return result; } + internal static (int Season, string seasonName) GetSeason(int dayOfYear) + { + (int Season, string seasonName) result = dayOfYear switch + { + < 78 => new(0, "Winter"), + < 124 => new(1, "Spring"), + < 171 => new(2, "Spring"), + < 217 => new(3, "Summer"), + < 264 => new(4, "Summer"), + < 309 => new(5, "Fall"), + < 354 => new(6, "Fall"), + _ => new(7, "Winter") + }; + return result; + } + + internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) + { + DateTime? result; + List results = []; + foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories) + { + if (exifDirectoryBase.DateTimeOriginal is not null) + results.Add(exifDirectoryBase.DateTimeOriginal.Value); + } + foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories) + { + if (aviDirectory.DateTimeOriginal is not null) + results.Add(aviDirectory.DateTimeOriginal.Value); + } + foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories) + { + if (quickTimeMovieHeaderDirectory.Created is not null) + { + if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1) + continue; + results.Add(quickTimeMovieHeaderDirectory.Created.Value); + } + } + foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories) + { + if (quickTimeTrackHeaderDirectory.Created is not null) + { + if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1) + continue; + results.Add(quickTimeTrackHeaderDirectory.Created.Value); + } + } + result = results.Count == 0 ? null : results.Min(); + return result; + } + + internal static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) + { + string[] results = []; + bool? result = null; + string year; + string directoryName; + string[] directorySegments; + List collection = []; + string? check = Path.GetFullPath(filePath.FullName); + DateTime? dateTimeOriginal = GetDateTimeOriginal(exifDirectory); + if (dateTimeOriginal is not null) + collection.Add(dateTimeOriginal.Value); + else + { + ReadOnlyCollection dateTimes = GetDateTimes(exifDirectory); + foreach (DateTime dateTime in dateTimes) + collection.Add(dateTime); + } + foreach (DateTime dateTime in collection) + { + year = dateTime.ToString("yyyy"); + for (int i = 0; i < int.MaxValue; i++) + { + check = Path.GetDirectoryName(check); + 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; + } + return new(result, results); + } + + private static Record IsWrongYear(string[] segments, string year) + { + Record result; + bool? check; + string[] results = ( + from l + in segments + where l?.Length > 2 + && ( + l[..2] is "18" or "19" or "20" + || (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#')) + || (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.') + || (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.') + ) + select l + ).ToArray(); + string[] matches = ( + from l + in results + where l == year + || (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#')) + || (l.Length == 6 && l[..4] == year && l[4] == '.') + || (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.') + select l + ).ToArray(); + if (results.Length == 0) + check = null; + else + check = matches.Length == 0; + result = new(check, results); + return result; + } + + private record Record(bool? IsWrongYear, string[] Years); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/XPath.cs b/Shared/Models/Stateless/XPath.cs index f1225d9..5395e92 100644 --- a/Shared/Models/Stateless/XPath.cs +++ b/Shared/Models/Stateless/XPath.cs @@ -202,6 +202,20 @@ internal abstract class XPath } } + internal static void CreateDirectories(ReadOnlyCollection directories) + { + string checkDirectory; + foreach (string directory in directories) + { + for (int i = 0; i < 101; i++) + { + checkDirectory = Path.Combine(directory, i.ToString("000")); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + } + } + internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) { DateTime dateTime = new(ticks); @@ -297,14 +311,19 @@ internal abstract class XPath 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) + if (!filePath.IsIntelligentIdFormat) @enum = missingDateTimeOriginal; else - @enum = IId.GetHasDateTimeOriginal(resultSettings, filePath); + { + if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null) + throw new NotImplementedException("Chicken and Egg!"); + 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]; string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ? new('-', resultSettings.ResultAllInOneSubdirectoryLength) : @@ -447,6 +466,7 @@ internal abstract class XPath private static byte[] GetBytes() => [ + 0, 1, 2, 3, diff --git a/Windows/Windows.cs b/Windows/Windows.cs index c862ede..52cd8f5 100644 --- a/Windows/Windows.cs +++ b/Windows/Windows.cs @@ -156,11 +156,28 @@ public partial class Windows : IWindows, IDisposable if (console is null) throw new NullReferenceException(nameof(console)); IWindows windows = this; + LogNetToHoursSince(logger); long ticks = DateTime.Now.Ticks; _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; WindowsWork(logger, appSettings, windows, ticks); } + private static void LogNetToHoursSince(ILogger? logger) + { + double secondsInAHour = 3600f; + long epoch = new DateTime(1970, 1, 1).Ticks; + long net8ReleaseDate = new DateTime(2023, 11, 14).Ticks; + long net9ReleaseDate = new DateTime(2024, 11, 12).Ticks; + double net8TotalSeconds = new TimeSpan(net8ReleaseDate - epoch).TotalSeconds; + double net9TotalSeconds = new TimeSpan(net9ReleaseDate - epoch).TotalSeconds; + logger?.LogInformation("It has been {net8TotalSeconds} seconds since net8 was released", net8TotalSeconds); + logger?.LogInformation("It has been {net9TotalSeconds} seconds since net9 was released", net9TotalSeconds); + double net8TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net8TotalSeconds) / secondsInAHour); + double net9TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net9TotalSeconds) / secondsInAHour); + logger?.LogInformation("It has been {net8TotalHours} hours since net8 was released", net8TotalHours); + logger?.LogInformation("It has been {net9TotalHours} hours since net9 was released", net9TotalHours); + } + 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)) @@ -168,6 +185,9 @@ public partial class Windows : IWindows, IDisposable else { string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory); + if (!Directory.Exists(sourceDirectory)) + _ = Directory.CreateDirectory(sourceDirectory); + logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory); WindowsWork(logger, appSettings, windows, ticks, sourceDirectory); } } @@ -243,6 +263,7 @@ public partial class Windows : IWindows, IDisposable string paddedId = IId.GetPaddedId(resultSettings: appSettings.ResultSettings, metadataSettings: appSettings.MetadataSettings, id: deterministicHashCode.Id.Value, + extensionLowered: appSettings.ResultSettings.ValidImageFormatExtensions[0], hasIgnoreKeyword: null, hasDateTimeOriginal: null, index: null); @@ -253,12 +274,9 @@ public partial class Windows : IWindows, IDisposable 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(); + ReadOnlyCollection files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).AsReadOnly(); if (files.Count > 0) - _ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory); + _ = IPath.DeleteEmptyDirectories(sourceDirectory); A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings); int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism; int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;