using CliWrap; using Microsoft.Extensions.Logging; using ShellProgressBar; using System.Collections.ObjectModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Text.Json; using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models.Stateless.Methods; using View_by_Distance.Rename.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless.Methods; namespace View_by_Distance.Rename; public partial class Rename : IRename, IDisposable { private sealed record ToDo(string? Directory, FilePath FilePath, string File, bool JsonFile); private sealed record RecordA(ExifDirectory ExifDirectory, bool FastForwardMovingPictureExpertsGroupUsed, FileInfo FileInfo, FilePath FilePath, ReadOnlyCollection SidecarFiles); private sealed record RecordB(DateTime DateTime, ExifDirectory ExifDirectory, bool FastForwardMovingPictureExpertsGroupUsed, FilePath FilePath, ReadOnlyCollection SidecarFiles, bool HasDateTimeOriginal, bool HasIgnoreKeyword, string JsonFile); private ProgressBar? _ProgressBar; public Rename(List args, ILogger? logger, AppSettings appSettings, bool isSilent, IConsole console) { if (isSilent) { } if (args is null) throw new NullReferenceException(nameof(args)); if (console is null) throw new NullReferenceException(nameof(console)); IRename rename = this; long ticks = DateTime.Now.Ticks; RenameWork(logger, appSettings, rename, ticks); } void IRename.Tick() => _ProgressBar?.Tick(); void IDisposable.Dispose() { _ProgressBar?.Dispose(); GC.SuppressFinalize(this); } ReadOnlyCollection IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameConfiguration renameConfiguration, FilePath filePath) { List results = []; bool isValidVideoFormatExtensions = renameConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); if (isValidVideoFormatExtensions) { bool check; try { CommandTask commandTask = Cli.Wrap("L:/Git/ffmpeg-2024-10-02-git-358fdf3083-full_build/bin/ffmpeg.exe") .WithArguments(new[] { "-i", filePath.FullName, "-vf", "select=eq(n\\,0)", "-q:v", "1", $"{filePath.Name}-%4d.jpg" }) .WithWorkingDirectory(filePath.DirectoryFullPath) .ExecuteAsync(); commandTask.Task.Wait(); check = true; } catch (Exception) { check = false; } if (check) { results.AddRange(Directory.GetFiles(filePath.DirectoryFullPath, $"{filePath.Name}-*.jpg", SearchOption.TopDirectoryOnly)); if (results.Count == 0) throw new Exception(); File.SetCreationTime(results[0], new(filePath.CreationTicks)); File.SetLastWriteTime(results[0], new(filePath.LastWriteTicks)); Thread.Sleep(100); } } return new(results); } #pragma warning disable CA1416 DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath) { DeterministicHashCode result; int? id; int? width; int? height; try { using Image image = Image.FromFile(filePath.FullName); width = image.Width; height = image.Height; using Bitmap bitmap = new(image); Rectangle rectangle = new(0, 0, image.Width, image.Height); BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); IntPtr intPtr = bitmapData.Scan0; int length = bitmapData.Stride * bitmap.Height; byte[] bytes = new byte[length]; Marshal.Copy(intPtr, bytes, 0, length); bitmap.UnlockBits(bitmapData); id = IId.GetDeterministicHashCode(bytes); } catch (Exception) { id = null; width = null; height = null; } result = new(height, id, width); return result; } #pragma warning restore CA1416 private void NonParallelismAndInPlace(RenameConfiguration renameConfiguration, ReadOnlyCollection ids, ExifDirectory exifDirectory, FileInfo fileInfo, FilePath filePath, bool fastForwardMovingPictureExpertsGroupUsed, ReadOnlyCollection sidecarFiles) { if (exifDirectory.Id is null) throw new NotImplementedException(); int i = 0; const string jpg = ".jpg"; const string jpeg = ".jpeg"; List toDoCollection = []; DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory); ReadOnlyCollection keywords = IMetadata.GetKeywords(exifDirectory); MetadataConfiguration metadataConfiguration = renameConfiguration.MetadataConfiguration; bool hasIgnoreKeyword = metadataConfiguration.IgnoreRulesKeyWords.Any(keywords.Contains); string checkFileExtension = filePath.ExtensionLowered == jpeg ? jpg : filePath.ExtensionLowered; bool hasDateTimeOriginal = dateTime is not null; string paddedId = IId.GetPaddedId(metadataConfiguration, exifDirectory.Id.Value, hasIgnoreKeyword, hasDateTimeOriginal, i); string checkDirectory = renameConfiguration.InPlaceWithOriginalName ? Path.Combine(filePath.DirectoryFullPath, filePath.FileNameFirstSegment) : filePath.DirectoryFullPath; string checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); if (checkFile != filePath.FullName) { if (File.Exists(checkFile)) { checkFile = string.Concat(checkFile, ".del"); if (File.Exists(checkFile)) throw new NotImplementedException(); } toDoCollection.Add(new(checkDirectory, filePath, checkFile, JsonFile: false)); if (sidecarFiles.Count != 0) { if (renameConfiguration.InPlace) throw new NotSupportedException($"Must use {nameof(renameConfiguration.InPlaceWithOriginalName)} when sidecar file(s) are present!"); dateTime ??= IDate.GetMinimum(exifDirectory); RecordB recordB = new(dateTime.Value, exifDirectory, fastForwardMovingPictureExpertsGroupUsed, filePath, sidecarFiles, hasDateTimeOriginal, hasIgnoreKeyword, fileInfo.FullName); toDoCollection.AddRange(GetSidecarFiles(metadataConfiguration, recordB, [], checkDirectory, paddedId)); } _ = RenameFilesInDirectories(renameConfiguration, new(toDoCollection)); string jsonFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}.json"); File.Move(fileInfo.FullName, jsonFile, overwrite: true); if (renameConfiguration.InPlaceWithOriginalName && ids.Count > 0) { string contains = ids.Contains(exifDirectory.Id.Value) ? "_ Exists _" : "_ New _"; string idCheck = Path.Combine(checkDirectory, contains, fastForwardMovingPictureExpertsGroupUsed ? "Video" : "Image"); if (!Directory.Exists(idCheck)) _ = Directory.CreateDirectory(idCheck); } } } private List GetRecordACollection(ILogger? logger, RenameConfiguration renameConfiguration, IRename rename, ReadOnlyCollection ids, IEnumerable files, A_Metadata metadata) { List results = []; int index = -1; FileInfo fileInfo; FilePath filePath; string directoryName; ExifDirectory exifDirectory; List sidecarFiles; DeterministicHashCode deterministicHashCode; bool fastForwardMovingPictureExpertsGroupUsed; FilePath? fastForwardMovingPictureExpertsGroupFilePath; ReadOnlyCollection? fastForwardMovingPictureExpertsGroupFiles; ReadOnlyDictionary> keyValuePairs = IMetadata.GetKeyValuePairs(files); foreach (KeyValuePair> keyValuePair in keyValuePairs) { index += 1; rename.Tick(); if (keyValuePair.Value.Count > 1 && !renameConfiguration.ForceNewId) { if (renameConfiguration.InPlaceMoveDirectory) continue; throw new NotSupportedException($"When sidecar files are present {nameof(renameConfiguration.ForceNewId)} must be true!"); } if (keyValuePair.Value.Count > 2) throw new NotSupportedException("Too many sidecar files!"); foreach (FileHolder fileHolder in keyValuePair.Value) { if (renameConfiguration.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) continue; if (renameConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) continue; filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index); if (renameConfiguration.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) continue; if (!renameConfiguration.ForceNewId && filePath.Id is not null) { fastForwardMovingPictureExpertsGroupFiles = null; deterministicHashCode = new(null, filePath.Id, null); directoryName = Path.GetFileName(filePath.DirectoryFullPath); if (renameConfiguration.InPlaceWithOriginalName || (renameConfiguration.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString()))) continue; } else { fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(renameConfiguration, filePath); fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(renameConfiguration.MetadataConfiguration, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index); deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath); } sidecarFiles = []; for (int i = 0; i < keyValuePair.Value.Count; i++) { if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered) continue; sidecarFiles.Add(keyValuePair.Value[i]); } try { (fileInfo, exifDirectory) = metadata.GetMetadataCollection(renameConfiguration.MetadataConfiguration, filePath, deterministicHashCode); } 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 (renameConfiguration.InPlace || renameConfiguration.InPlaceWithOriginalName) NonParallelismAndInPlace(renameConfiguration, ids, exifDirectory, fileInfo, filePath, fastForwardMovingPictureExpertsGroupUsed, new(sidecarFiles)); if (!fastForwardMovingPictureExpertsGroupUsed && renameConfiguration.InPlaceMoveDirectory && renameConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) fastForwardMovingPictureExpertsGroupUsed = true; results.Add(new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, fileInfo, filePath, new(sidecarFiles))); } } return results; } private static ReadOnlyCollection GetRecordBCollection(MetadataConfiguration metadataConfiguration, List recordACollection) { List results = []; DateTime? dateTime; bool hasIgnoreKeyword; bool hasDateTimeOriginal; ReadOnlyCollection keywords; foreach (RecordA recordA in recordACollection) { dateTime = IDate.GetDateTimeOriginal(recordA.ExifDirectory); hasDateTimeOriginal = dateTime is not null; dateTime ??= IDate.GetMinimum(recordA.ExifDirectory); keywords = IMetadata.GetKeywords(recordA.ExifDirectory); hasIgnoreKeyword = metadataConfiguration.IgnoreRulesKeyWords.Any(l => keywords.Contains(l)); results.Add(new(dateTime.Value, recordA.ExifDirectory, recordA.FastForwardMovingPictureExpertsGroupUsed, recordA.FilePath, recordA.SidecarFiles, hasDateTimeOriginal, hasIgnoreKeyword, recordA.FileInfo.FullName)); } return new(results); } private ReadOnlyCollection GetRecordBCollection(ILogger? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection ids, DirectoryInfo directoryInfo) { ReadOnlyCollection results; List recordACollection = []; RenameConfiguration renameConfiguration = appSettings.RenameConfiguration; A_Metadata metadata = new(renameConfiguration.MetadataConfiguration); int appSettingsMaxDegreeOfParallelism = appSettings.MaxDegreeOfParallelism; IEnumerable files = appSettingsMaxDegreeOfParallelism == 1 ? Directory.GetFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories); int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count() : 123000; _ProgressBar = new(filesCount, "EnumerateFiles load", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }); if (appSettingsMaxDegreeOfParallelism == 1) recordACollection.AddRange(GetRecordACollection(logger, renameConfiguration, rename, ids, files, metadata)); else { List distinct = []; List<(bool, FilePath, FileInfo, ExifDirectory, ReadOnlyCollection)> collection = []; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, renameConfiguration, metadata, distinct, collection)); if (_ProgressBar.CurrentTick != recordACollection.Count) throw new NotSupportedException(); foreach ((bool fastForwardMovingPictureExpertsGroupUsed, FilePath filePath, FileInfo fileInfo, ExifDirectory exifDirectory, ReadOnlyCollection sidecarFiles) in collection) { if (fastForwardMovingPictureExpertsGroupUsed || !renameConfiguration.InPlaceMoveDirectory || !renameConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) recordACollection.Add(new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, fileInfo, filePath, sidecarFiles)); else recordACollection.Add(new(exifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, fileInfo, filePath, sidecarFiles)); } } _ProgressBar.Dispose(); results = GetRecordBCollection(renameConfiguration.MetadataConfiguration, recordACollection); return results; } private static void VerifyIntMinValueLength(MetadataConfiguration metadataConfiguration, ReadOnlyCollection recordBCollection) { foreach (RecordB recordB in recordBCollection) { if (recordB.ExifDirectory.Id is null) continue; if (metadataConfiguration.IntMinValueLength < recordB.ExifDirectory.Id.Value.ToString().Length) throw new NotSupportedException(); } } private static string GetTFW(RecordB record, bool? isWrongYear) => string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I"); private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) => splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}"; private static string? GetCheckDirectory(RenameConfiguration renameConfiguration, RecordB record, ReadOnlyCollection ids, bool multipleDirectoriesWithFiles, string paddedId) { string? result; string year = record.DateTime.Year.ToString(); string checkDirectoryName = Path.GetFileName(record.FilePath.DirectoryFullPath); if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year)) result = null; else { (bool? isWrongYear, string[] years) = IDate.IsWrongYear(record.FilePath, record.ExifDirectory); if (renameConfiguration.InPlaceMoveDirectory && !record.FilePath.FileNameFirstSegment.Contains(paddedId)) result = null; else { string tfw = GetTFW(record, isWrongYear); string? maker = IMetadata.GetMaker(record.ExifDirectory); string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None); string? splat = checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null; (int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear); string rootDirectory = renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory; string contains = record.ExifDirectory.Id is null || ids.Contains(record.ExifDirectory.Id.Value) ? "_ Exists _" : "_ New-Destination _"; string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(renameConfiguration.DefaultMaker) ? string.Empty : renameConfiguration.DefaultMaker : $" {maker.Split(' ')[0]}"; string directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit); result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName)); } } return result; } private static List GetSidecarFiles(MetadataConfiguration metadataConfiguration, RecordB record, List distinct, string checkDirectory, string paddedId) { List results = []; string checkFile; FilePath filePath; string checkFileExtension; foreach (FileHolder fileHolder in record.SidecarFiles) { checkFileExtension = fileHolder.ExtensionLowered; filePath = FilePath.Get(metadataConfiguration, fileHolder, index: null); checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); if (checkFile == filePath.FullName) continue; if (File.Exists(checkFile)) { checkFile = string.Concat(checkFile, ".del"); if (File.Exists(checkFile)) continue; } if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); results.Add(new(checkDirectory, filePath, checkFile, JsonFile: false)); } return results; } private static bool? GetDirectoryCheck(RenameConfiguration renameConfiguration) { bool? result = null; IEnumerable files; string[] directories = Directory.GetDirectories(renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string directory in directories) { files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories); foreach (string _ in files) { if (result is null) result = false; else if (result.Value) result = true; break; } if (result is not null && result.Value) break; } return result; } private static ReadOnlyCollection GetToDoCollection(RenameConfiguration renameConfiguration, ReadOnlyCollection ids, ReadOnlyCollection recordBCollection) { List results = []; RecordB record; string jsonFile; string paddedId; string checkFile; FilePath filePath; string directoryName; FileHolder fileHolder; string? checkDirectory; const string jpg = ".jpg"; string checkFileExtension; List distinct = []; const string jpeg = ".jpeg"; string jsonFileSubDirectory; bool? directoryCheck = GetDirectoryCheck(renameConfiguration); MetadataConfiguration metadataConfiguration = renameConfiguration.MetadataConfiguration; VerifyIntMinValueLength(metadataConfiguration, recordBCollection); bool multipleDirectoriesWithFiles = directoryCheck is not null && directoryCheck.Value; ReadOnlyCollection sorted = new((from l in recordBCollection orderby l.DateTime select l).ToArray()); for (int i = 0; i < sorted.Count; i++) { record = sorted[i]; if (record.ExifDirectory.Id is null) continue; paddedId = IId.GetPaddedId(metadataConfiguration, record.ExifDirectory.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, i); checkDirectory = GetCheckDirectory(renameConfiguration, record, ids, multipleDirectoriesWithFiles, paddedId); if (string.IsNullOrEmpty(checkDirectory)) continue; checkFileExtension = record.FilePath.ExtensionLowered == jpeg ? jpg : record.FilePath.ExtensionLowered; jsonFileSubDirectory = Path.GetDirectoryName(Path.GetDirectoryName(record.JsonFile)) ?? throw new Exception(); checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}"); if (checkFile == record.FilePath.FullName) continue; if (File.Exists(checkFile)) { checkFile = string.Concat(checkFile, ".del"); if (File.Exists(checkFile)) continue; } (directoryName, _) = IPath.GetDirectoryNameAndIndex(metadataConfiguration.ResultConfiguration, record.ExifDirectory.Id.Value); jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.Id.Value}{checkFileExtension}.json"); if (record.JsonFile != jsonFile) { fileHolder = FileHolder.Get(record.JsonFile); filePath = FilePath.Get(metadataConfiguration, fileHolder, index: null); results.Add(new(null, filePath, jsonFile, JsonFile: true)); } if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); results.Add(new(checkDirectory, record.FilePath, checkFile, JsonFile: false)); if (record.SidecarFiles.Count == 0) continue; results.AddRange(GetSidecarFiles(metadataConfiguration, record, distinct, checkDirectory, paddedId)); } return new(results); } private static void VerifyDirectories(ReadOnlyCollection toDoCollection) { List distinct = []; foreach (ToDo toDo in toDoCollection) { if (toDo.Directory is null || distinct.Contains(toDo.Directory)) continue; if (!Directory.Exists(toDo.Directory)) _ = Directory.CreateDirectory(toDo.Directory); distinct.Add(toDo.Directory); } } private ReadOnlyCollection RenameFilesInDirectories(RenameConfiguration renameConfiguration, ReadOnlyCollection toDoCollection) { List results = []; VerifyDirectories(toDoCollection); bool useProgressBar = !renameConfiguration.InPlace && !renameConfiguration.InPlaceWithOriginalName; if (useProgressBar) _ProgressBar = new(toDoCollection.Count, "Move Files", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }); foreach (ToDo toDo in toDoCollection) { if (useProgressBar) _ProgressBar?.Tick(); if (toDo.JsonFile) { if (File.Exists(toDo.File)) File.Delete(toDo.File); try { File.Move(toDo.FilePath.FullName, toDo.File); } catch (Exception) { continue; } } else if (toDo.Directory is null) throw new NotSupportedException(); else { if (File.Exists(toDo.File)) File.Delete(toDo.File); try { File.Move(toDo.FilePath.FullName, toDo.File); } catch (Exception) { continue; } results.Add($"{toDo.FilePath.FullName}\t{toDo.File}"); } } if (useProgressBar) _ProgressBar?.Dispose(); return new(results); } private static void SaveIdentifiersToDisk(long ticks, RenameConfiguration renameConfiguration, ReadOnlyCollection recordBCollection) { string paddedId; Identifier identifier; List identifiers = []; MetadataConfiguration metadataConfiguration = renameConfiguration.MetadataConfiguration; string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(metadataConfiguration.ResultConfiguration, nameof(A_Metadata), metadataConfiguration.ResultConfiguration.ResultCollection); foreach (RecordB record in recordBCollection) { if (record.ExifDirectory.Id is null) continue; paddedId = IId.GetPaddedId(renameConfiguration.MetadataConfiguration, record.ExifDirectory.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null); identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.Id.Value, record.FilePath.Length, paddedId, record.DateTime.Ticks); identifiers.Add(identifier); } string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); _ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); } private static ReadOnlyCollection GetIds(RenameConfiguration renameConfiguration) { ReadOnlyCollection results; string? propertyCollectionFile = string.IsNullOrEmpty(renameConfiguration.RelativePropertyCollectionFile) ? null : renameConfiguration.RelativePropertyCollectionFile; string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile); Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray); if (identifiers is null && !string.IsNullOrEmpty(renameConfiguration.RelativePropertyCollectionFile)) throw new Exception($"Invalid {nameof(renameConfiguration.RelativePropertyCollectionFile)}"); results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray()); return results; } private void RenameWork(ILogger? logger, AppSettings appSettings, IRename rename, long ticks) { ReadOnlyCollection ids = GetIds(appSettings.RenameConfiguration); RenameConfiguration renameConfiguration = appSettings.RenameConfiguration; MetadataConfiguration metadataConfiguration = renameConfiguration.MetadataConfiguration; _ = IPath.DeleteEmptyDirectories(metadataConfiguration.ResultConfiguration.RootDirectory); DirectoryInfo directoryInfo = new(Path.GetFullPath(metadataConfiguration.ResultConfiguration.RootDirectory)); logger?.LogInformation("{Ticks} {RootDirectory}", ticks, directoryInfo.FullName); ReadOnlyCollection recordBCollection = GetRecordBCollection(logger, appSettings, rename, ids, directoryInfo); SaveIdentifiersToDisk(ticks, renameConfiguration, recordBCollection); if (renameConfiguration.InPlace || renameConfiguration.InPlaceWithOriginalName) { if (recordBCollection.Count > 0) recordBCollection = new([]); string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(metadataConfiguration.ResultConfiguration, nameof(A_Metadata)); _ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory); } if (!renameConfiguration.OnlySaveIdentifiersToDisk) { ReadOnlyCollection toDoCollection = GetToDoCollection(renameConfiguration, ids, recordBCollection); ReadOnlyCollection lines = RenameFilesInDirectories(renameConfiguration, toDoCollection); if (lines.Count != 0) { File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines); _ = IPath.DeleteEmptyDirectories(directoryInfo.FullName); } } } }