Sidecar
This commit is contained in:
parent
abbe2feac0
commit
30b8e2f5a9
@ -82,28 +82,50 @@ csharp_style_var_elsewhere = false:warning
|
|||||||
csharp_style_var_for_built_in_types = false:warning
|
csharp_style_var_for_built_in_types = false:warning
|
||||||
csharp_style_var_when_type_is_apparent = false:warning
|
csharp_style_var_when_type_is_apparent = false:warning
|
||||||
csharp_using_directive_placement = outside_namespace
|
csharp_using_directive_placement = outside_namespace
|
||||||
|
dotnet_analyzer_diagnostic.category-Design.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Documentation.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Globalization.severity = none
|
||||||
|
dotnet_analyzer_diagnostic.category-Interoperability.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Maintainability.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Naming.severity = none
|
||||||
|
dotnet_analyzer_diagnostic.category-Performance.severity = none
|
||||||
|
dotnet_analyzer_diagnostic.category-Reliability.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Security.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-SingleFile.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Style.severity = error
|
||||||
|
dotnet_analyzer_diagnostic.category-Usage.severity = error
|
||||||
dotnet_code_quality_unused_parameters = all
|
dotnet_code_quality_unused_parameters = all
|
||||||
dotnet_code_quality_unused_parameters = non_public # IDE0060: Remove unused parameter
|
dotnet_code_quality_unused_parameters = non_public # IDE0060: Remove unused parameter
|
||||||
dotnet_code_quality.CAXXXX.api_surface = private, internal
|
dotnet_code_quality.CAXXXX.api_surface = private, internal
|
||||||
|
dotnet_diagnostic.CA1001.severity = error # CA1001: Types that own disposable fields should be disposable
|
||||||
|
dotnet_diagnostic.CA1051.severity = error # CA1051: Do not declare visible instance fields
|
||||||
dotnet_diagnostic.CA1825.severity = warning # CA1823: Avoid zero-length array allocations
|
dotnet_diagnostic.CA1825.severity = warning # CA1823: Avoid zero-length array allocations
|
||||||
dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available
|
dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available
|
||||||
dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable
|
dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable
|
||||||
dotnet_diagnostic.CA1860.severity = error # CA1860: Prefer comparing 'Count' to 0 rather than using 'Any()', both for clarity and for performance
|
dotnet_diagnostic.CA1860.severity = error # CA1860: Prefer comparing 'Count' to 0 rather than using 'Any()', both for clarity and for performance
|
||||||
dotnet_diagnostic.CA1869.severity = none # CA1869: Avoid creating a new 'JsonSerializerOptions' instance for every serialization operation. Cache and reuse instances instead.
|
dotnet_diagnostic.CA1861.severity = error # CA1861: Prefer 'static readonly' fields over constant array arguments
|
||||||
dotnet_diagnostic.CA2254.severity = none # CA2254: The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'
|
dotnet_diagnostic.CA1869.severity = error # CA1869: Avoid creating a new 'JsonSerializerOptions' instance for every serialization operation. Cache and reuse instances instead.
|
||||||
|
dotnet_diagnostic.CA2201.severity = none # CA2201: Exception type System.NullReferenceException is reserved by the runtime
|
||||||
|
dotnet_diagnostic.CA2254.severity = error # CA2254: The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'
|
||||||
dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name
|
dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name
|
||||||
dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2");
|
dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2");
|
||||||
dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant.
|
dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant.
|
||||||
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
|
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
|
||||||
|
dotnet_diagnostic.IDE0010.severity = error # Add missing cases to switch statement (IDE0010)
|
||||||
dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified
|
dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified
|
||||||
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)
|
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)
|
||||||
dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed
|
dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed
|
||||||
|
dotnet_diagnostic.IDE0048.severity = error # Parentheses preferences (IDE0047 and IDE0048)
|
||||||
dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049)
|
dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049)
|
||||||
|
dotnet_diagnostic.IDE0051.severity = error # Private member '' is unused [, ]
|
||||||
dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter
|
dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter
|
||||||
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290)
|
dotnet_diagnostic.IDE0130.severity = error # Namespace does not match folder structure (IDE0130)
|
||||||
|
dotnet_diagnostic.IDE0230.severity = warning # IDE0230: Use UTF-8 string literal
|
||||||
|
dotnet_diagnostic.IDE0290.severity = error # Use primary constructor [Distance]csharp(IDE0290)
|
||||||
dotnet_diagnostic.IDE0300.severity = error # IDE0300: Collection initialization can be simplified
|
dotnet_diagnostic.IDE0300.severity = error # IDE0300: Collection initialization can be simplified
|
||||||
dotnet_diagnostic.IDE0301.severity = error #IDE0301: Collection initialization can be simplified
|
dotnet_diagnostic.IDE0301.severity = error #IDE0301: Collection initialization can be simplified
|
||||||
dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified
|
dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified
|
||||||
|
dotnet_diagnostic.JSON002.severity = warning # JSON002: Probable JSON string detected
|
||||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning
|
dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning
|
||||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case
|
dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case
|
||||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method
|
dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method
|
||||||
|
@ -2,7 +2,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using View_by_Distance.Metadata.Models.Stateless;
|
using View_by_Distance.Metadata.Models.Stateless;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Metadata.Models;
|
namespace View_by_Distance.Metadata.Models;
|
||||||
@ -132,42 +131,4 @@ public class A_Metadata
|
|||||||
return (fileInfo, result);
|
return (fileInfo, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Action<string> SetExifDirectoryCollection(IRename rename, IRenameConfiguration renameConfiguration, A_Metadata metadata, List<(FilePath, FileInfo, ExifDirectory)> exifDirectories)
|
|
||||||
{
|
|
||||||
return file =>
|
|
||||||
{
|
|
||||||
rename.Tick();
|
|
||||||
FileInfo fileInfo;
|
|
||||||
FilePath? ffmpegFilePath;
|
|
||||||
ExifDirectory exifDirectory;
|
|
||||||
FileHolder fileHolder = new(file);
|
|
||||||
ReadOnlyCollection<string>? ffmpegFiles;
|
|
||||||
DeterministicHashCode deterministicHashCode;
|
|
||||||
FilePath filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index: null);
|
|
||||||
if (!renameConfiguration.SkipIdFiles || filePath.Id is null || !filePath.IsIntelligentIdFormat && filePath.SortOrder is not null)
|
|
||||||
{
|
|
||||||
if (filePath.Id is not null)
|
|
||||||
{
|
|
||||||
ffmpegFiles = null;
|
|
||||||
deterministicHashCode = new(null, filePath.Id, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ffmpegFiles = rename.ConvertAndGetFfmpegFiles(renameConfiguration, filePath);
|
|
||||||
ffmpegFilePath = ffmpegFiles.Count == 0 ? null : FilePath.Get(renameConfiguration.MetadataConfiguration, new(ffmpegFiles[0]), index: null);
|
|
||||||
deterministicHashCode = ffmpegFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(ffmpegFilePath);
|
|
||||||
}
|
|
||||||
(fileInfo, exifDirectory) = metadata.GetMetadataCollection(renameConfiguration.MetadataConfiguration, filePath, deterministicHashCode);
|
|
||||||
lock (exifDirectories)
|
|
||||||
exifDirectories.Add(new(filePath, fileInfo, exifDirectory));
|
|
||||||
if (ffmpegFiles is not null)
|
|
||||||
{
|
|
||||||
foreach (string ffmpegFile in ffmpegFiles)
|
|
||||||
File.Delete(ffmpegFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
75
Metadata/Models/Stateless/Get.cs
Normal file
75
Metadata/Models/Stateless/Get.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
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.Metadata.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
internal static class Get
|
||||||
|
{
|
||||||
|
|
||||||
|
internal static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<string> files)
|
||||||
|
{
|
||||||
|
Dictionary<string, List<FileHolder>> results = [];
|
||||||
|
string key;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
List<FileHolder>? fileHolders;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
fileHolder = FileHolder.Get(file);
|
||||||
|
if (fileHolder.DirectoryName is null)
|
||||||
|
continue;
|
||||||
|
key = $"{Path.Combine(fileHolder.DirectoryName, fileHolder.NameWithoutExtension)}";
|
||||||
|
if (!results.TryGetValue(key, out fileHolders))
|
||||||
|
{
|
||||||
|
results.Add(key, []);
|
||||||
|
if (!results.TryGetValue(key, out fileHolders))
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
fileHolders.Add(fileHolder);
|
||||||
|
}
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Action<string> SetExifDirectoryCollection(IRename rename, IRenameConfiguration renameConfiguration, A_Metadata metadata, List<string> distinct, List<(FilePath, FileInfo, ExifDirectory, ReadOnlyCollection<FileHolder>)> collection)
|
||||||
|
{
|
||||||
|
return file =>
|
||||||
|
{
|
||||||
|
rename.Tick();
|
||||||
|
FileInfo fileInfo;
|
||||||
|
FilePath? ffmpegFilePath;
|
||||||
|
ExifDirectory exifDirectory;
|
||||||
|
ReadOnlyCollection<string>? ffmpegFiles;
|
||||||
|
DeterministicHashCode deterministicHashCode;
|
||||||
|
FileHolder fileHolder = FileHolder.Get(file);
|
||||||
|
FilePath filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index: null);
|
||||||
|
string key = $"{Path.Combine(fileHolder.DirectoryName ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
|
||||||
|
if (distinct.Contains(key))
|
||||||
|
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
|
||||||
|
if (!renameConfiguration.SkipIdFiles || filePath.Id is null || !filePath.IsIntelligentIdFormat && filePath.SortOrder is not null)
|
||||||
|
{
|
||||||
|
if (filePath.Id is not null)
|
||||||
|
{
|
||||||
|
ffmpegFiles = null;
|
||||||
|
deterministicHashCode = new(null, filePath.Id, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ffmpegFiles = rename.ConvertAndGetFfmpegFiles(renameConfiguration, filePath);
|
||||||
|
ffmpegFilePath = ffmpegFiles.Count == 0 ? null : FilePath.Get(renameConfiguration.MetadataConfiguration, FileHolder.Get(ffmpegFiles[0]), index: null);
|
||||||
|
deterministicHashCode = ffmpegFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(ffmpegFilePath);
|
||||||
|
}
|
||||||
|
(fileInfo, exifDirectory) = metadata.GetMetadataCollection(renameConfiguration.MetadataConfiguration, filePath, deterministicHashCode);
|
||||||
|
lock (collection)
|
||||||
|
collection.Add(new(filePath, fileInfo, exifDirectory, new([])));
|
||||||
|
if (ffmpegFiles is not null)
|
||||||
|
{
|
||||||
|
foreach (string ffmpegFile in ffmpegFiles)
|
||||||
|
File.Delete(ffmpegFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using MetadataExtractor;
|
using MetadataExtractor;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using View_by_Distance.Shared.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.Metadata.Models.Stateless.Methods;
|
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -55,4 +57,14 @@ public interface IMetadata
|
|||||||
static double? GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles) =>
|
static double? GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles) =>
|
||||||
GPS.GetDistance(originLatitude, originLongitude, destinationLatitude, destinationLongitude, decimalPlaces, distanceUnit);
|
GPS.GetDistance(originLatitude, originLongitude, destinationLatitude, destinationLongitude, decimalPlaces, distanceUnit);
|
||||||
|
|
||||||
|
Action<string> TestStatic_SetExifDirectoryCollection(IRename rename, IRenameConfiguration renameConfiguration, A_Metadata metadata, List<string> distinct, List<(FilePath, FileInfo, ExifDirectory, ReadOnlyCollection<FileHolder>)> collection) =>
|
||||||
|
SetExifDirectoryCollection(rename, renameConfiguration, metadata, distinct, collection);
|
||||||
|
static Action<string> SetExifDirectoryCollection(IRename rename, IRenameConfiguration renameConfiguration, A_Metadata metadata, List<string> distinct, List<(FilePath, FileInfo, ExifDirectory, ReadOnlyCollection<FileHolder>)> collection) =>
|
||||||
|
Get.SetExifDirectoryCollection(rename, renameConfiguration, metadata, distinct, collection);
|
||||||
|
|
||||||
|
ReadOnlyDictionary<string, List<FileHolder>> TestStatic_GetKeyValuePairs(IEnumerable<string> files) =>
|
||||||
|
GetKeyValuePairs(files);
|
||||||
|
static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<string> files) =>
|
||||||
|
Get.GetKeyValuePairs(files);
|
||||||
|
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ public class RenameConfiguration
|
|||||||
public bool? ForceNewId { get; set; }
|
public bool? ForceNewId { get; set; }
|
||||||
public string[]? IgnoreExtensions { get; set; }
|
public string[]? IgnoreExtensions { get; set; }
|
||||||
public string? RelativePropertyCollectionFile { get; set; }
|
public string? RelativePropertyCollectionFile { get; set; }
|
||||||
|
public string[]? SidecarExtensions { get; set; }
|
||||||
public bool? SkipIdFiles { get; set; }
|
public bool? SkipIdFiles { get; set; }
|
||||||
public string[]? ValidImageFormatExtensions { get; set; }
|
public string[]? ValidImageFormatExtensions { get; set; }
|
||||||
public string[]? ValidVideoFormatExtensions { get; set; }
|
public string[]? ValidVideoFormatExtensions { get; set; }
|
||||||
@ -53,6 +54,7 @@ public class RenameConfiguration
|
|||||||
if (configuration.ForceNewId is null) throw new NullReferenceException(nameof(configuration.ForceNewId));
|
if (configuration.ForceNewId is null) throw new NullReferenceException(nameof(configuration.ForceNewId));
|
||||||
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions));
|
||||||
if (configuration.RelativePropertyCollectionFile is null) throw new NullReferenceException(nameof(configuration.RelativePropertyCollectionFile));
|
if (configuration.RelativePropertyCollectionFile is null) throw new NullReferenceException(nameof(configuration.RelativePropertyCollectionFile));
|
||||||
|
if (configuration.SidecarExtensions is null) throw new NullReferenceException(nameof(configuration.SidecarExtensions));
|
||||||
if (configuration.SkipIdFiles is null) throw new NullReferenceException(nameof(configuration.SkipIdFiles));
|
if (configuration.SkipIdFiles is null) throw new NullReferenceException(nameof(configuration.SkipIdFiles));
|
||||||
if (configuration.ValidImageFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidImageFormatExtensions));
|
if (configuration.ValidImageFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidImageFormatExtensions));
|
||||||
if (configuration.ValidVideoFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidVideoFormatExtensions));
|
if (configuration.ValidVideoFormatExtensions is null) throw new NullReferenceException(nameof(configuration.ValidVideoFormatExtensions));
|
||||||
@ -62,6 +64,7 @@ public class RenameConfiguration
|
|||||||
configuration.ForceNewId.Value,
|
configuration.ForceNewId.Value,
|
||||||
configuration.IgnoreExtensions,
|
configuration.IgnoreExtensions,
|
||||||
configuration.RelativePropertyCollectionFile,
|
configuration.RelativePropertyCollectionFile,
|
||||||
|
configuration.SidecarExtensions,
|
||||||
configuration.SkipIdFiles.Value,
|
configuration.SkipIdFiles.Value,
|
||||||
configuration.ValidImageFormatExtensions,
|
configuration.ValidImageFormatExtensions,
|
||||||
configuration.ValidVideoFormatExtensions);
|
configuration.ValidVideoFormatExtensions);
|
||||||
|
@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace View_by_Distance.Rename.Models;
|
namespace View_by_Distance.Rename.Models;
|
||||||
|
|
||||||
internal record Identifier(int Id, string PaddedId)
|
internal sealed record Identifier(int Id, string PaddedId)
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -9,6 +9,7 @@ public record RenameConfiguration(Shared.Models.MetadataConfiguration MetadataCo
|
|||||||
bool ForceNewId,
|
bool ForceNewId,
|
||||||
string[] IgnoreExtensions,
|
string[] IgnoreExtensions,
|
||||||
string RelativePropertyCollectionFile,
|
string RelativePropertyCollectionFile,
|
||||||
|
string[] SidecarExtensions,
|
||||||
bool SkipIdFiles,
|
bool SkipIdFiles,
|
||||||
string[] ValidImageFormatExtensions,
|
string[] ValidImageFormatExtensions,
|
||||||
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameConfiguration
|
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameConfiguration
|
||||||
|
142
Rename/Rename.cs
142
Rename/Rename.cs
@ -17,11 +17,14 @@ using View_by_Distance.Shared.Models.Stateless.Methods;
|
|||||||
|
|
||||||
namespace View_by_Distance.Rename;
|
namespace View_by_Distance.Rename;
|
||||||
|
|
||||||
public partial class Rename : IRename
|
public partial class Rename : IRename, IDisposable
|
||||||
{
|
{
|
||||||
|
|
||||||
private record ToDo(string? Directory, FilePath FilePath, string File, bool JsonFile);
|
private sealed record ToDo(string? Directory, FilePath FilePath, string File, bool JsonFile);
|
||||||
private record Record(DateTime DateTime, ExifDirectory ExifDirectory, FilePath FilePath, bool HasDateTimeOriginal, bool HasIgnoreKeyword, string JsonFile);
|
|
||||||
|
private sealed record RecordA(ExifDirectory ExifDirectory, FileInfo FileInfo, FilePath FilePath, ReadOnlyCollection<FileHolder> SidecarFiles);
|
||||||
|
|
||||||
|
private sealed record RecordB(DateTime DateTime, ExifDirectory ExifDirectory, FilePath FilePath, ReadOnlyCollection<FileHolder> SidecarFiles, bool HasDateTimeOriginal, bool HasIgnoreKeyword, string JsonFile);
|
||||||
|
|
||||||
private ProgressBar? _ProgressBar;
|
private ProgressBar? _ProgressBar;
|
||||||
|
|
||||||
@ -44,6 +47,12 @@ public partial class Rename : IRename
|
|||||||
void IRename.Tick() =>
|
void IRename.Tick() =>
|
||||||
_ProgressBar?.Tick();
|
_ProgressBar?.Tick();
|
||||||
|
|
||||||
|
void IDisposable.Dispose()
|
||||||
|
{
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
ReadOnlyCollection<string> IRename.ConvertAndGetFfmpegFiles(IRenameConfiguration renameConfiguration, FilePath filePath)
|
ReadOnlyCollection<string> IRename.ConvertAndGetFfmpegFiles(IRenameConfiguration renameConfiguration, FilePath filePath)
|
||||||
{
|
{
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
@ -114,10 +123,11 @@ public partial class Rename : IRename
|
|||||||
|
|
||||||
private static void RenameUrl(FilePath filePath)
|
private static void RenameUrl(FilePath filePath)
|
||||||
{
|
{
|
||||||
|
FileHolder fileHolder;
|
||||||
string[] lines = File.ReadAllLines(filePath.FullName);
|
string[] lines = File.ReadAllLines(filePath.FullName);
|
||||||
if (lines.Length == 1)
|
if (lines.Length == 1)
|
||||||
{
|
{
|
||||||
FileHolder fileHolder = new(lines[0]);
|
fileHolder = FileHolder.Get(lines[0]);
|
||||||
if (fileHolder.Exists)
|
if (fileHolder.Exists)
|
||||||
{
|
{
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -130,22 +140,30 @@ public partial class Rename : IRename
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<(FilePath, FileInfo, ExifDirectory)> GetExifDirectoryCollection(IRename rename, RenameConfiguration renameConfiguration, IEnumerable<string> files, A_Metadata metadata)
|
private static List<RecordA> GetRecordACollection(IRename rename, RenameConfiguration renameConfiguration, IEnumerable<string> files, A_Metadata metadata)
|
||||||
{
|
{
|
||||||
List<(FilePath, FileInfo, ExifDirectory)> results = [];
|
List<RecordA> results = [];
|
||||||
int index = -1;
|
int index = -1;
|
||||||
FileInfo fileInfo;
|
FileInfo fileInfo;
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
FileHolder fileHolder;
|
|
||||||
FilePath? ffmpegFilePath;
|
FilePath? ffmpegFilePath;
|
||||||
ExifDirectory exifDirectory;
|
ExifDirectory exifDirectory;
|
||||||
|
List<FileHolder> sidecarFiles;
|
||||||
ReadOnlyCollection<string>? ffmpegFiles;
|
ReadOnlyCollection<string>? ffmpegFiles;
|
||||||
DeterministicHashCode deterministicHashCode;
|
DeterministicHashCode deterministicHashCode;
|
||||||
foreach (string file in files)
|
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||||
|
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||||
{
|
{
|
||||||
index += 1;
|
index += 1;
|
||||||
rename.Tick();
|
rename.Tick();
|
||||||
fileHolder = new(file);
|
if (keyValuePair.Value.Count > 1 && !renameConfiguration.ForceNewId)
|
||||||
|
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))
|
if (renameConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
continue;
|
continue;
|
||||||
filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index);
|
filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index);
|
||||||
@ -164,65 +182,77 @@ public partial class Rename : IRename
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ffmpegFiles = rename.ConvertAndGetFfmpegFiles(renameConfiguration, filePath);
|
ffmpegFiles = rename.ConvertAndGetFfmpegFiles(renameConfiguration, filePath);
|
||||||
ffmpegFilePath = ffmpegFiles.Count == 0 ? null : FilePath.Get(renameConfiguration.MetadataConfiguration, new(ffmpegFiles[0]), index);
|
ffmpegFilePath = ffmpegFiles.Count == 0 ? null : FilePath.Get(renameConfiguration.MetadataConfiguration, FileHolder.Get(ffmpegFiles[0]), index);
|
||||||
deterministicHashCode = ffmpegFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(ffmpegFilePath);
|
deterministicHashCode = ffmpegFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(ffmpegFilePath);
|
||||||
}
|
}
|
||||||
|
sidecarFiles = [];
|
||||||
|
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||||
|
{
|
||||||
|
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||||
|
continue;
|
||||||
|
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||||
|
}
|
||||||
(fileInfo, exifDirectory) = metadata.GetMetadataCollection(renameConfiguration.MetadataConfiguration, filePath, deterministicHashCode);
|
(fileInfo, exifDirectory) = metadata.GetMetadataCollection(renameConfiguration.MetadataConfiguration, filePath, deterministicHashCode);
|
||||||
results.Add(new(filePath, fileInfo, exifDirectory));
|
results.Add(new(exifDirectory, fileInfo, filePath, new(sidecarFiles)));
|
||||||
if (ffmpegFiles is not null)
|
if (ffmpegFiles is not null)
|
||||||
{
|
{
|
||||||
foreach (string ffmpegFile in ffmpegFiles)
|
foreach (string ffmpegFile in ffmpegFiles)
|
||||||
File.Delete(ffmpegFile);
|
File.Delete(ffmpegFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<Record> GetExifDirectoryCollection(MetadataConfiguration metadataConfiguration, List<(FilePath, FileInfo, ExifDirectory)> exifDirectories)
|
private static ReadOnlyCollection<RecordB> GetRecordBCollection(MetadataConfiguration metadataConfiguration, List<RecordA> recordACollection)
|
||||||
{
|
{
|
||||||
List<Record> results = [];
|
List<RecordB> results = [];
|
||||||
DateTime? dateTime;
|
DateTime? dateTime;
|
||||||
bool hasIgnoreKeyword;
|
bool hasIgnoreKeyword;
|
||||||
bool hasDateTimeOriginal;
|
bool hasDateTimeOriginal;
|
||||||
ReadOnlyCollection<string> keywords;
|
ReadOnlyCollection<string> keywords;
|
||||||
foreach ((FilePath filePath, FileInfo fileInfo, ExifDirectory exifDirectory) in exifDirectories)
|
foreach (RecordA recordA in recordACollection)
|
||||||
{
|
{
|
||||||
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
dateTime = IDate.GetDateTimeOriginal(recordA.ExifDirectory);
|
||||||
hasDateTimeOriginal = dateTime is not null;
|
hasDateTimeOriginal = dateTime is not null;
|
||||||
dateTime ??= IDate.GetMinimum(exifDirectory);
|
dateTime ??= IDate.GetMinimum(recordA.ExifDirectory);
|
||||||
keywords = IMetadata.GetKeywords(exifDirectory);
|
keywords = IMetadata.GetKeywords(recordA.ExifDirectory);
|
||||||
hasIgnoreKeyword = metadataConfiguration.IgnoreRulesKeyWords.Any(l => keywords.Contains(l));
|
hasIgnoreKeyword = metadataConfiguration.IgnoreRulesKeyWords.Any(l => keywords.Contains(l));
|
||||||
results.Add(new(dateTime.Value, exifDirectory, filePath, hasDateTimeOriginal, hasIgnoreKeyword, fileInfo.FullName));
|
results.Add(new(dateTime.Value, recordA.ExifDirectory, recordA.FilePath, recordA.SidecarFiles, hasDateTimeOriginal, hasIgnoreKeyword, recordA.FileInfo.FullName));
|
||||||
}
|
}
|
||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReadOnlyCollection<Record> GetExifDirectoryCollection(IRename rename, AppSettings appSettings, RenameConfiguration renameConfiguration, DirectoryInfo directoryInfo)
|
private ReadOnlyCollection<RecordB> GetRecordBCollection(IRename rename, AppSettings appSettings, RenameConfiguration renameConfiguration, DirectoryInfo directoryInfo)
|
||||||
{
|
{
|
||||||
ReadOnlyCollection<Record> results;
|
ReadOnlyCollection<RecordB> results;
|
||||||
List<(FilePath, FileInfo, ExifDirectory)> exifDirectories = [];
|
List<RecordA> recordACollection = [];
|
||||||
A_Metadata metadata = new(renameConfiguration.MetadataConfiguration);
|
A_Metadata metadata = new(renameConfiguration.MetadataConfiguration);
|
||||||
int appSettingsMaxDegreeOfParallelism = appSettings.MaxDegreeOfParallelism;
|
int appSettingsMaxDegreeOfParallelism = appSettings.MaxDegreeOfParallelism;
|
||||||
IEnumerable<string> files = appSettingsMaxDegreeOfParallelism == 1 ? Directory.GetFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories);
|
IEnumerable<string> files = appSettingsMaxDegreeOfParallelism == 1 ? Directory.GetFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(directoryInfo.FullName, "*", SearchOption.AllDirectories);
|
||||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count() : 123000;
|
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count() : 123000;
|
||||||
_ProgressBar = new(filesCount, "EnumerateFiles load", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
|
_ProgressBar = new(filesCount, "EnumerateFiles load", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
|
||||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||||
exifDirectories.AddRange(GetExifDirectoryCollection(rename, renameConfiguration, files, metadata));
|
recordACollection.AddRange(GetRecordACollection(rename, renameConfiguration, files, metadata));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
List<string> distinct = [];
|
||||||
|
List<(FilePath, FileInfo, ExifDirectory, ReadOnlyCollection<FileHolder>)> collection = [];
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||||
files.AsParallel().ForAll(A_Metadata.SetExifDirectoryCollection(rename, renameConfiguration, metadata, exifDirectories));
|
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, renameConfiguration, metadata, distinct, collection));
|
||||||
if (_ProgressBar.CurrentTick != exifDirectories.Count)
|
if (_ProgressBar.CurrentTick != recordACollection.Count)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
foreach ((FilePath filePath, FileInfo fileInfo, ExifDirectory exifDirectory, ReadOnlyCollection<FileHolder> sidecarFiles) in collection)
|
||||||
|
recordACollection.Add(new(exifDirectory, fileInfo, filePath, sidecarFiles));
|
||||||
}
|
}
|
||||||
_ProgressBar.Dispose();
|
_ProgressBar.Dispose();
|
||||||
results = GetExifDirectoryCollection(renameConfiguration.MetadataConfiguration, exifDirectories);
|
results = GetRecordBCollection(renameConfiguration.MetadataConfiguration, recordACollection);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void VerifyIntMinValueLength(MetadataConfiguration metadataConfiguration, ReadOnlyCollection<Record> exifDirectories)
|
private static void VerifyIntMinValueLength(MetadataConfiguration metadataConfiguration, ReadOnlyCollection<RecordB> recordBCollection)
|
||||||
{
|
{
|
||||||
foreach ((DateTime _, ExifDirectory exifDirectory, FilePath _, bool _, bool _, string _) in exifDirectories)
|
foreach ((DateTime _, ExifDirectory exifDirectory, FilePath _, ReadOnlyCollection<FileHolder> _, bool _, bool _, string _) in recordBCollection)
|
||||||
{
|
{
|
||||||
if (exifDirectory.Id is null)
|
if (exifDirectory.Id is null)
|
||||||
continue;
|
continue;
|
||||||
@ -231,7 +261,7 @@ public partial class Rename : IRename
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? GetCheckDirectory(RenameConfiguration renameConfiguration, Record record, FilePath filePath, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles)
|
private static string? GetCheckDirectory(RenameConfiguration renameConfiguration, RecordB record, FilePath filePath, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles)
|
||||||
{
|
{
|
||||||
string? result;
|
string? result;
|
||||||
if (filePath.DirectoryName is null)
|
if (filePath.DirectoryName is null)
|
||||||
@ -252,10 +282,37 @@ public partial class Rename : IRename
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<ToDo> GetToDoCollection(RenameConfiguration renameConfiguration, Identifier[]? identifiers, ReadOnlyCollection<Record> records)
|
private static List<ToDo> GetSidecarFiles(MetadataConfiguration metadataConfiguration, RecordB record, List<string> distinct, string checkDirectory, string paddedId)
|
||||||
{
|
{
|
||||||
List<ToDo> results = [];
|
List<ToDo> results = [];
|
||||||
Record record;
|
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 ReadOnlyCollection<ToDo> GetToDoCollection(RenameConfiguration renameConfiguration, Identifier[]? identifiers, ReadOnlyCollection<RecordB> recordBCollection)
|
||||||
|
{
|
||||||
|
List<ToDo> results = [];
|
||||||
|
RecordB record;
|
||||||
string jsonFile;
|
string jsonFile;
|
||||||
string paddedId;
|
string paddedId;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
@ -265,11 +322,11 @@ public partial class Rename : IRename
|
|||||||
string? checkDirectory;
|
string? checkDirectory;
|
||||||
const string jpg = ".jpg";
|
const string jpg = ".jpg";
|
||||||
string checkFileExtension;
|
string checkFileExtension;
|
||||||
bool multipleDirectoriesWithFiles;
|
|
||||||
List<string> distinct = [];
|
List<string> distinct = [];
|
||||||
bool? directoryCheck = null;
|
bool? directoryCheck = null;
|
||||||
const string jpeg = ".jpeg";
|
const string jpeg = ".jpeg";
|
||||||
string jsonFileSubDirectory;
|
string jsonFileSubDirectory;
|
||||||
|
bool multipleDirectoriesWithFiles;
|
||||||
foreach (string directory in Directory.GetDirectories(renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory, "*", SearchOption.TopDirectoryOnly))
|
foreach (string directory in Directory.GetDirectories(renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory, "*", SearchOption.TopDirectoryOnly))
|
||||||
{
|
{
|
||||||
foreach (string _ in Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories))
|
foreach (string _ in Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories))
|
||||||
@ -283,14 +340,14 @@ public partial class Rename : IRename
|
|||||||
if (directoryCheck is not null && directoryCheck.Value)
|
if (directoryCheck is not null && directoryCheck.Value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VerifyIntMinValueLength(renameConfiguration.MetadataConfiguration, records);
|
VerifyIntMinValueLength(renameConfiguration.MetadataConfiguration, recordBCollection);
|
||||||
multipleDirectoriesWithFiles = directoryCheck is not null && directoryCheck.Value;
|
multipleDirectoriesWithFiles = directoryCheck is not null && directoryCheck.Value;
|
||||||
ReadOnlyCollection<Record> collection = new((from l in records orderby l.DateTime select l).ToArray());
|
|
||||||
ResultConfiguration resultConfiguration = renameConfiguration.MetadataConfiguration.ResultConfiguration;
|
ResultConfiguration resultConfiguration = renameConfiguration.MetadataConfiguration.ResultConfiguration;
|
||||||
ReadOnlyCollection<int> ids = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
ReadOnlyCollection<int> ids = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
||||||
for (int i = 0; i < collection.Count; i++)
|
ReadOnlyCollection<RecordB> sorted = new((from l in recordBCollection orderby l.DateTime select l).ToArray());
|
||||||
|
for (int i = 0; i < sorted.Count; i++)
|
||||||
{
|
{
|
||||||
record = collection[i];
|
record = sorted[i];
|
||||||
if (record.ExifDirectory.Id is null)
|
if (record.ExifDirectory.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (record.FilePath.DirectoryName is null)
|
if (record.FilePath.DirectoryName is null)
|
||||||
@ -314,7 +371,7 @@ public partial class Rename : IRename
|
|||||||
jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.Id.Value}{checkFileExtension}.json");
|
jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.Id.Value}{checkFileExtension}.json");
|
||||||
if (record.JsonFile != jsonFile)
|
if (record.JsonFile != jsonFile)
|
||||||
{
|
{
|
||||||
fileHolder = new(record.JsonFile);
|
fileHolder = FileHolder.Get(record.JsonFile);
|
||||||
filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index: null);
|
filePath = FilePath.Get(renameConfiguration.MetadataConfiguration, fileHolder, index: null);
|
||||||
results.Add(new(null, filePath, jsonFile, JsonFile: true));
|
results.Add(new(null, filePath, jsonFile, JsonFile: true));
|
||||||
}
|
}
|
||||||
@ -322,6 +379,9 @@ public partial class Rename : IRename
|
|||||||
continue;
|
continue;
|
||||||
distinct.Add(checkFile);
|
distinct.Add(checkFile);
|
||||||
results.Add(new(checkDirectory, record.FilePath, checkFile, JsonFile: false));
|
results.Add(new(checkDirectory, record.FilePath, checkFile, JsonFile: false));
|
||||||
|
if (record.SidecarFiles.Count == 0)
|
||||||
|
continue;
|
||||||
|
results.AddRange(GetSidecarFiles(renameConfiguration.MetadataConfiguration, record, distinct, checkDirectory, paddedId));
|
||||||
}
|
}
|
||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
@ -370,11 +430,11 @@ public partial class Rename : IRename
|
|||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SaveIdentifiersToDisk(long ticks, RenameConfiguration renameConfiguration, string aMetadataCollectionDirectory, ReadOnlyCollection<Record> records)
|
private static void SaveIdentifiersToDisk(long ticks, RenameConfiguration renameConfiguration, string aMetadataCollectionDirectory, ReadOnlyCollection<RecordB> recordBCollection)
|
||||||
{
|
{
|
||||||
string paddedId;
|
string paddedId;
|
||||||
List<Identifier> identifiers = [];
|
List<Identifier> identifiers = [];
|
||||||
foreach (Record record in records)
|
foreach (RecordB record in recordBCollection)
|
||||||
{
|
{
|
||||||
if (record.ExifDirectory.Id is null)
|
if (record.ExifDirectory.Id is null)
|
||||||
continue;
|
continue;
|
||||||
@ -395,9 +455,9 @@ public partial class Rename : IRename
|
|||||||
throw new Exception($"Invalid {nameof(renameConfiguration.RelativePropertyCollectionFile)}");
|
throw new Exception($"Invalid {nameof(renameConfiguration.RelativePropertyCollectionFile)}");
|
||||||
DirectoryInfo directoryInfo = new(Path.GetFullPath(renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory));
|
DirectoryInfo directoryInfo = new(Path.GetFullPath(renameConfiguration.MetadataConfiguration.ResultConfiguration.RootDirectory));
|
||||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, directoryInfo.FullName);
|
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, directoryInfo.FullName);
|
||||||
ReadOnlyCollection<Record> records = GetExifDirectoryCollection(rename, appSettings, renameConfiguration, directoryInfo);
|
ReadOnlyCollection<RecordB> recordBCollection = GetRecordBCollection(rename, appSettings, renameConfiguration, directoryInfo);
|
||||||
SaveIdentifiersToDisk(ticks, renameConfiguration, aMetadataCollectionDirectory, records);
|
SaveIdentifiersToDisk(ticks, renameConfiguration, aMetadataCollectionDirectory, recordBCollection);
|
||||||
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(renameConfiguration, identifiers, records);
|
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(renameConfiguration, identifiers, recordBCollection);
|
||||||
ReadOnlyCollection<string> lines = RenameFilesInDirectories(toDoCollection);
|
ReadOnlyCollection<string> lines = RenameFilesInDirectories(toDoCollection);
|
||||||
if (lines.Count != 0)
|
if (lines.Count != 0)
|
||||||
{
|
{
|
||||||
|
@ -3,75 +3,97 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
public class FileHolder
|
public record FileHolder(DateTime? CreationTime,
|
||||||
|
string? DirectoryName,
|
||||||
|
bool Exists,
|
||||||
|
string ExtensionLowered,
|
||||||
|
string FullName,
|
||||||
|
int? Id,
|
||||||
|
DateTime? LastWriteTime,
|
||||||
|
long? Length,
|
||||||
|
string Name,
|
||||||
|
string NameWithoutExtension)
|
||||||
{
|
{
|
||||||
|
|
||||||
protected readonly DateTime? _CreationTime;
|
|
||||||
protected readonly string? _DirectoryName;
|
|
||||||
protected readonly bool _Exists;
|
|
||||||
protected readonly string _ExtensionLowered;
|
|
||||||
protected readonly string _FullName;
|
|
||||||
protected readonly int? _Id;
|
|
||||||
protected readonly DateTime? _LastWriteTime;
|
|
||||||
protected readonly long? _Length;
|
|
||||||
protected readonly string _Name;
|
|
||||||
protected readonly string _NameWithoutExtension;
|
|
||||||
public DateTime? CreationTime => _CreationTime;
|
|
||||||
public string? DirectoryName => _DirectoryName;
|
|
||||||
public bool Exists => _Exists;
|
|
||||||
public string ExtensionLowered => _ExtensionLowered;
|
|
||||||
public string FullName => _FullName;
|
|
||||||
public int? Id => _Id;
|
|
||||||
public DateTime? LastWriteTime => _LastWriteTime;
|
|
||||||
public long? Length => _Length;
|
|
||||||
public string Name => _Name;
|
|
||||||
public string NameWithoutExtension => _NameWithoutExtension;
|
|
||||||
|
|
||||||
public FileHolder(DateTime? creationTime, string? directoryName, bool exists, string extensionLowered, string fullName, int? id, DateTime? lastWriteTime, long? length, string name, string nameWithoutExtension)
|
|
||||||
{
|
|
||||||
_CreationTime = creationTime;
|
|
||||||
_DirectoryName = directoryName;
|
|
||||||
_Exists = exists;
|
|
||||||
_ExtensionLowered = extensionLowered;
|
|
||||||
_FullName = fullName;
|
|
||||||
_Id = id;
|
|
||||||
_LastWriteTime = lastWriteTime;
|
|
||||||
_Length = length;
|
|
||||||
_Name = name;
|
|
||||||
_NameWithoutExtension = nameWithoutExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileHolder(FileInfo fileInfo, int? id)
|
|
||||||
{
|
|
||||||
if (fileInfo.Exists)
|
|
||||||
{
|
|
||||||
_CreationTime = fileInfo.CreationTime;
|
|
||||||
_LastWriteTime = fileInfo.LastWriteTime;
|
|
||||||
_Length = fileInfo.Length;
|
|
||||||
}
|
|
||||||
_DirectoryName = fileInfo.DirectoryName;
|
|
||||||
_Exists = fileInfo.Exists;
|
|
||||||
_ExtensionLowered = fileInfo.Extension.ToLower();
|
|
||||||
_Id = id;
|
|
||||||
_FullName = fileInfo.FullName;
|
|
||||||
_Name = fileInfo.Name;
|
|
||||||
_NameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileHolder(string fileName) :
|
|
||||||
this(new FileInfo(fileName), null)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public FileHolder(string fileName, int? id) :
|
|
||||||
this(new FileInfo(fileName), id)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
string result = JsonSerializer.Serialize(this, FileHolderSourceGenerationContext.Default.FileHolder);
|
string result = JsonSerializer.Serialize(this, FileHolderSourceGenerationContext.Default.FileHolder);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FileHolder GetExisting(FileInfo fileInfo, int? id) =>
|
||||||
|
new(fileInfo.CreationTime,
|
||||||
|
fileInfo.DirectoryName,
|
||||||
|
fileInfo.Exists,
|
||||||
|
fileInfo.Extension.ToLower(),
|
||||||
|
fileInfo.FullName,
|
||||||
|
id,
|
||||||
|
fileInfo.LastWriteTime,
|
||||||
|
fileInfo.Length,
|
||||||
|
fileInfo.Name,
|
||||||
|
Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
||||||
|
|
||||||
|
private static FileHolder GetNonExisting(FileInfo fileInfo, int? id) =>
|
||||||
|
new(null,
|
||||||
|
fileInfo.DirectoryName,
|
||||||
|
fileInfo.Exists,
|
||||||
|
fileInfo.Extension.ToLower(),
|
||||||
|
fileInfo.FullName,
|
||||||
|
id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
fileInfo.Name,
|
||||||
|
Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
||||||
|
|
||||||
|
public static FileHolder Get(FileInfo fileInfo, int? id) =>
|
||||||
|
fileInfo.Exists ? GetExisting(fileInfo, id) : GetNonExisting(fileInfo, id);
|
||||||
|
|
||||||
|
public static FileHolder Get(FilePath filePath, int? id)
|
||||||
|
{
|
||||||
|
FileHolder result;
|
||||||
|
result = new(new(filePath.CreationTicks),
|
||||||
|
filePath.DirectoryName,
|
||||||
|
true,
|
||||||
|
filePath.ExtensionLowered,
|
||||||
|
filePath.FullName,
|
||||||
|
id,
|
||||||
|
new(filePath.LastWriteTicks),
|
||||||
|
filePath.Length,
|
||||||
|
filePath.Name,
|
||||||
|
Path.GetFileNameWithoutExtension(filePath.FullName));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileHolder GetExisting(FileHolder fileHolder) =>
|
||||||
|
new(fileHolder.CreationTime,
|
||||||
|
fileHolder.DirectoryName,
|
||||||
|
fileHolder.Exists,
|
||||||
|
fileHolder.ExtensionLowered,
|
||||||
|
fileHolder.FullName,
|
||||||
|
Id: null,
|
||||||
|
fileHolder.LastWriteTime,
|
||||||
|
fileHolder.Length,
|
||||||
|
fileHolder.Name,
|
||||||
|
Path.GetFileNameWithoutExtension(fileHolder.FullName));
|
||||||
|
|
||||||
|
private static FileHolder GetNonExisting(FileHolder fileHolder) =>
|
||||||
|
new(null,
|
||||||
|
fileHolder.DirectoryName,
|
||||||
|
fileHolder.Exists,
|
||||||
|
fileHolder.ExtensionLowered,
|
||||||
|
fileHolder.FullName,
|
||||||
|
Id: null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
fileHolder.Name,
|
||||||
|
Path.GetFileNameWithoutExtension(fileHolder.FullName));
|
||||||
|
|
||||||
|
public static FileHolder Get(FileHolder fileHolder) =>
|
||||||
|
fileHolder.Exists ? GetExisting(fileHolder) : GetNonExisting(fileHolder);
|
||||||
|
|
||||||
|
public static FileHolder Get(string file) =>
|
||||||
|
Get(new FileInfo(file), id: null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||||
|
@ -28,7 +28,7 @@ public record FilePath(long CreationTicks,
|
|||||||
public static FilePath Get(MetadataConfiguration metadataConfiguration, FileHolder fileHolder, int? index)
|
public static FilePath Get(MetadataConfiguration metadataConfiguration, FileHolder fileHolder, int? index)
|
||||||
{
|
{
|
||||||
if (fileHolder.CreationTime is null)
|
if (fileHolder.CreationTime is null)
|
||||||
fileHolder = new(fileHolder.FullName);
|
fileHolder = FileHolder.Get(fileHolder);
|
||||||
if (fileHolder.CreationTime is null)
|
if (fileHolder.CreationTime is null)
|
||||||
throw new NullReferenceException(nameof(fileHolder.CreationTime));
|
throw new NullReferenceException(nameof(fileHolder.CreationTime));
|
||||||
if (fileHolder.LastWriteTime is null)
|
if (fileHolder.LastWriteTime is null)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user