Merge Kristy Files

This commit is contained in:
Mike Phares 2023-07-09 00:26:58 -07:00
parent 516e494928
commit d7ed5d89d9
12 changed files with 309 additions and 113 deletions

View File

@ -22,6 +22,7 @@ taskTemplate: '^+^_${overdue ? ''^R'' : ''''}${name}^: ${relations ? (''\n^-^/^g
- [photoview-in-docker-for-a-viewer-only](tasks/photoview-in-docker-for-a-viewer-only.md)
- [family-tree-as-markdown-files](tasks/family-tree-as-markdown-files.md)
- [image-size-distribution-per-exif-model-directory-when-no-model](tasks/image-size-distribution-per-exif-model-directory-when-no-model.md)
- [cluster-questioning](tasks/cluster-questioning.md)
## Todo

View File

@ -0,0 +1,13 @@
---
created: 2023-07-09T04:12:44.673Z
updated: 2023-07-09T04:12:44.667Z
assigned: ""
progress: 0
tags: []
---
# Cluster Questioning
Ask Logan for more details
- [ ] [k-means-clustering-introduction](https://www.geeksforgeeks.org/k-means-clustering-introduction/)

View File

@ -11,10 +11,16 @@ started: 2023-07-08T21:44:14.665Z
# Merge Kristy Files
```c#
string[] test = (from l in new string[] { "Mikes", "Mike", "Mik-e" } orderby l.EndsWith('s'), l.Contains('-') select l).ToArray();
return new(result, (from l in results orderby l.FileHolder.DirectoryName?.EndsWith('s'), l.FileHolder.DirectoryName?.Contains('-'), l.FileHolder.DirectoryName?.Length == 12 select l).ToArray());
```
## Sub-tasks
- [x] Convert .tiff to .jpg with Nikon Nx Studio at 100%
- [ ] Keep .tiff files in 2-Images-B
- [ ] Rotate the .jpg only
- [ ] Does original name matter to Kristy
- [ ] Use Rename console app to rename for storage
- [/] Keep .tiff files in 2-Images-B
- [ ] Copy to each backup from question
- [x] Rotate the .jpg only
- [x] Use Rename console app to rename for storage
- [ ] Move to production ...

View File

@ -87,6 +87,8 @@ public class CopyDistinct
}
}
}
if (move && _AppSettings.IfCanUseId)
throw new NotSupportedException("Not allowed because it would irreversible!");
return (move, filesCollection, anyLenFiles, moveBack);
}
@ -128,9 +130,6 @@ public class CopyDistinct
distinctFound.Add(file);
}
}
if (distinctNeeded.Count != distinctFound.Count)
continue;
break;
}
}
foreach (string[] files in filesCollection)
@ -176,7 +175,7 @@ public class CopyDistinct
progressBar = new(count, message, options);
string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey;
string[] directories = _FileGroups[key];
(distinctDirectories, toDoCollection) = Shared.Models.Stateless.Methods.IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, filesCollection, directories, () => progressBar.Tick());
(distinctDirectories, toDoCollection) = Shared.Models.Stateless.Methods.IDirectory.GetToDoCollection(_PropertyConfiguration, _AppSettings.CopyDuplicates, _AppSettings.IfCanUseId, filesCollection, directories, () => progressBar.Tick());
progressBar.Dispose();
}
foreach (string distinctDirectory in distinctDirectories)

View File

@ -1,10 +1,12 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Copy.Distinct.Models;
public record AppSettings(string Company,
bool CopyDuplicates,
string CopyTo,
bool IfCanUseId,
int MaxDegreeOfParallelism,
string ResultDirectoryKey,
string WorkingDirectoryName)
@ -12,8 +14,14 @@ public record AppSettings(string Company,
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(AppSettings))]
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,5 +1,6 @@
using Microsoft.Extensions.Configuration;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Copy.Distinct.Models.Binder;
@ -7,15 +8,16 @@ public class AppSettings
{
public string? Company { get; set; }
public int? MaxDegreeOfParallelism { get; set; }
public bool? CopyDuplicates { get; set; }
public string? CopyTo { get; set; }
public string? ResultDirectoryKey { init; get; }
public bool? IfCanUseId { get; set; }
public int? MaxDegreeOfParallelism { get; set; }
public string? ResultDirectoryKey { get; set; }
public string? WorkingDirectoryName { get; set; }
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
string result = JsonSerializer.Serialize(this, BinderAppSettingsSourceGenerationContext.Default.AppSettings);
return result;
}
@ -28,6 +30,8 @@ public class AppSettings
throw new NullReferenceException(nameof(appSettings.CopyDuplicates));
if (appSettings?.CopyTo is null)
throw new NullReferenceException(nameof(appSettings.CopyTo));
if (appSettings?.IfCanUseId is null)
throw new NullReferenceException(nameof(appSettings.IfCanUseId));
if (appSettings?.MaxDegreeOfParallelism is null)
throw new NullReferenceException(nameof(appSettings.MaxDegreeOfParallelism));
if (appSettings?.ResultDirectoryKey is null)
@ -38,6 +42,7 @@ public class AppSettings
appSettings.Company,
appSettings.CopyDuplicates.Value,
appSettings.CopyTo,
appSettings.IfCanUseId.Value,
appSettings.MaxDegreeOfParallelism.Value,
appSettings.ResultDirectoryKey,
appSettings.WorkingDirectoryName
@ -48,9 +53,17 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{
Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
result = Get(appSettings);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(AppSettings))]
internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -3,6 +3,7 @@
"Company": "Mike Phares",
"CopyDuplicates": true,
"CopyTo": "",
"IfCanUseId": true,
"Linux": {},
"Logging": {
"LogLevel": {

View File

@ -1,8 +1,10 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Rename.Models;
public record AppSettings(string Company,
string DefaultUnknownDirectoryName,
bool ForceIdName,
int MaxDegreeOfParallelism,
int MaxMinutesDelta,
@ -12,8 +14,14 @@ public record AppSettings(string Company,
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(AppSettings))]
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,5 +1,6 @@
using Microsoft.Extensions.Configuration;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Rename.Models.Binder;
@ -7,6 +8,7 @@ public class AppSettings
{
public string? Company { get; set; }
public string? DefaultUnknownDirectoryName { get; set; }
public bool? ForceIdName { get; set; }
public int? MaxDegreeOfParallelism { get; set; }
public int? MaxMinutesDelta { get; set; }
@ -15,7 +17,7 @@ public class AppSettings
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
string result = JsonSerializer.Serialize(this, BinderAppSettingsSourceGenerationContext.Default.AppSettings);
return result;
}
@ -24,6 +26,8 @@ public class AppSettings
Models.AppSettings result;
if (appSettings?.Company is null)
throw new NullReferenceException(nameof(appSettings.Company));
if (appSettings?.DefaultUnknownDirectoryName is null)
throw new NullReferenceException(nameof(appSettings.DefaultUnknownDirectoryName));
if (appSettings?.ForceIdName is null)
throw new NullReferenceException(nameof(appSettings.ForceIdName));
if (appSettings?.MaxDegreeOfParallelism is null)
@ -36,6 +40,7 @@ public class AppSettings
throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName));
result = new(
appSettings.Company,
appSettings.DefaultUnknownDirectoryName,
appSettings.ForceIdName.Value,
appSettings.MaxDegreeOfParallelism.Value,
appSettings.MaxMinutesDelta.Value,
@ -48,9 +53,17 @@ public class AppSettings
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{
Models.AppSettings result;
#pragma warning disable IL3050, IL2026
AppSettings? appSettings = configurationRoot.Get<AppSettings>();
#pragma warning restore IL3050, IL2026
result = Get(appSettings);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(AppSettings))]
internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -12,6 +12,15 @@ namespace View_by_Distance.Rename;
public class Rename
{
private record Record(int Index,
bool IsIgnoreExtension,
bool IsValidImageFormatExtension,
List<FileHolder> FileHolders,
bool FfmpegFilesPresent,
DateTime? DateTimeOriginal,
DateTime?[] DateTimes,
int? Id);
private readonly AppSettings _AppSettings;
private readonly string _WorkingDirectory;
private readonly Configuration _Configuration;
@ -90,44 +99,27 @@ public class Rename
return results;
}
private List<(FileHolder, string, string)> GetToDoCollection(ProgressBar progressBar, string[] files, bool nefPresent)
private List<Record> GetRecords(int offset, ProgressBar progressBar, string[] files)
{
List<(FileHolder, string, string)> results = new();
List<Record> results = new();
int? id;
int season;
string? message;
string checkFile;
DateTime dateTime;
bool? isWrongYear;
string seasonName;
string? directory;
TimeSpan? timeSpan;
string directoryName;
DateTime?[] dateTimes;
FileHolder fileHolder;
string[]? ffmpegFiles;
bool isIgnoreExtension;
string? seasonDirectory;
const string jpg = ".jpg";
DateTime? minimumDateTime;
string checkFileExtension;
DateTime? dateTimeFromName;
DateTime? dateTimeOriginal;
const string jpeg = ".jpeg";
DateTime?[] metadataDateTimes;
List<string> distinct = new();
string[] directoryNameSegments;
bool isValidImageFormatExtension;
DateTime? metadataDateTimeOriginal;
bool nameWithoutExtensionIsIdFormat;
IReadOnlyList<MetadataExtractor.Directory> directories;
foreach (string file in files)
for (int i = 0; i < files.Length; i++)
{
progressBar.Tick();
fileHolder = new(file);
fileHolder = new(files[i]);
if (!fileHolder.Exists)
continue;
directory = Path.GetDirectoryName(file);
directory = Path.GetDirectoryName(files[i]);
if (string.IsNullOrEmpty(directory))
continue;
if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
@ -137,7 +129,6 @@ public class Rename
nameWithoutExtensionIsIdFormat = Shared.Models.Stateless.Methods.IProperty.NameWithoutExtensionIsIdFormat(fileHolder);
if (nameWithoutExtensionIsIdFormat)
continue;
dateTimeFromName = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder);
isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered);
isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered);
if (!isIgnoreExtension && isValidImageFormatExtension)
@ -145,11 +136,11 @@ public class Rename
else
{
try
{ directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); }
{ directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(files[i]); }
catch (Exception) { continue; }
CommandTask<CommandResult> result = Cli.Wrap("ffmpeg.exe")
// .WithArguments(new[] { "-ss", "00:00:00", "-t", "00:00:00", "-i", file, "-qscale:v", "2", "-r", "0.01", $"{fileHolder.Name}-%4d.jpg" })
.WithArguments(new[] { "-i", file, "-vframes", "1", $"{fileHolder.Name}-%4d.jpg" })
// .WithArguments(new[] { "-ss", "00:00:00", "-t", "00:00:00", "-i", files[i], "-qscale:v", "2", "-r", "0.01", $"{fileHolder.Name}-%4d.jpg" })
.WithArguments(new[] { "-i", files[i], "-vframes", "1", $"{fileHolder.Name}-%4d.jpg" })
.WithWorkingDirectory(fileHolder.DirectoryName)
.ExecuteAsync();
result.Task.Wait();
@ -166,9 +157,57 @@ public class Rename
if (fileHolder.DirectoryName is null)
continue;
}
(dateTimeOriginal, dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, _PropertyConfiguration.PopulatePropertyId);
if (ffmpegFiles is not null)
{
fileHolder = new(files[i]);
foreach (string ffmpegFile in ffmpegFiles)
File.Delete(ffmpegFile);
}
if (message is not null)
throw new Exception(message);
results.Add(new(i + offset, isIgnoreExtension, isValidImageFormatExtension, new() { fileHolder }, ffmpegFiles is null, dateTimeOriginal, dateTimes, id));
}
return results;
}
private List<(FileHolder, string, string)> GetToDoCollection(ProgressBar progressBar, bool nefPresent, List<Record> records, int length)
{
List<(FileHolder, string, string)> results = new();
string id;
int season;
string checkFile;
bool? isWrongYear;
DateTime dateTime;
string seasonName;
TimeSpan? timeSpan;
string directoryName;
FileHolder fileHolder;
string? seasonDirectory;
const string jpg = ".jpg";
DateTime? minimumDateTime;
string checkFileExtension;
DateTime? dateTimeFromName;
const string jpeg = ".jpeg";
DateTime?[] metadataDateTimes;
List<string> distinct = new();
string[] directoryNameSegments;
DateTime? dateTimeOriginalByLogic;
DateTime? metadataDateTimeOriginal;
IReadOnlyList<MetadataExtractor.Directory> directories;
foreach (Record record in records)
{
progressBar.Tick();
if (record.FileHolders.Count != 1)
continue;
fileHolder = record.FileHolders.First();
if (!fileHolder.Exists)
continue;
if (string.IsNullOrEmpty(fileHolder.DirectoryName))
continue;
if (fileHolder.ExtensionLowered == jpeg)
{
if (!isIgnoreExtension && isValidImageFormatExtension)
if (!record.IsIgnoreExtension && record.IsValidImageFormatExtension)
{
if (File.Exists($"{fileHolder.FullName}.id"))
{
@ -178,7 +217,7 @@ public class Rename
if (distinct.Contains(checkFile))
continue;
distinct.Add(checkFile);
results.Add(new(new($"{fileHolder.FullName}.id"), directory, checkFile));
results.Add(new(new($"{fileHolder.FullName}.id"), fileHolder.DirectoryName, checkFile));
}
checkFile = Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}");
if (File.Exists(checkFile))
@ -186,11 +225,11 @@ public class Rename
if (distinct.Contains(checkFile))
continue;
distinct.Add(checkFile);
results.Add(new(fileHolder, directory, checkFile));
results.Add(new(fileHolder, fileHolder.DirectoryName, checkFile));
if (nefPresent)
results.Add(new(new($"{fileHolder.FullName[..^4]}.tif"), directory, $"{checkFile[..^4]}.tif"));
results.Add(new(new($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryName, $"{checkFile[..^4]}.tif"));
if (nefPresent)
results.Add(new(new($"{fileHolder.FullName[..^4]}.nef"), directory, $"{checkFile[..^4]}.nef"));
results.Add(new(new($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryName, $"{checkFile[..^4]}.nef"));
if (File.Exists(checkFile))
continue;
File.Move(fileHolder.FullName, checkFile);
@ -199,24 +238,16 @@ public class Rename
continue;
}
}
(dateTimeOriginal, dateTimes, id, message) = Shared.Models.Stateless.Methods.IProperty.Get(fileHolder, isIgnoreExtension, isValidImageFormatExtension, _PropertyConfiguration.PopulatePropertyId);
if (ffmpegFiles is not null)
{
fileHolder = new(file);
foreach (string ffmpegFile in ffmpegFiles)
File.Delete(ffmpegFile);
}
if (fileHolder.DirectoryName is null)
continue;
minimumDateTime = dateTimes.Min();
dateTimeFromName = Shared.Models.Stateless.Methods.IProperty.GetDateTimeFromName(fileHolder);
minimumDateTime = record.DateTimes.Min();
if (minimumDateTime is null)
throw new NotSupportedException();
if (dateTimeOriginal is null)
if (record.DateTimeOriginal is null)
timeSpan = null;
else
timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTimeOriginal.Value.Ticks));
timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - record.DateTimeOriginal.Value.Ticks));
if (timeSpan is not null && timeSpan.Value.TotalMinutes < _AppSettings.MaxMinutesDelta)
(metadataDateTimeOriginal, metadataDateTimes) = (null, Array.Empty<DateTime?>());
(dateTimeOriginalByLogic, metadataDateTimeOriginal, metadataDateTimes) = (record.DateTimeOriginal, null, Array.Empty<DateTime?>());
else
{
if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
@ -225,16 +256,21 @@ public class Rename
{ directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName); }
catch (Exception) { continue; }
(metadataDateTimeOriginal, metadataDateTimes) = Metadata.Models.Stateless.Methods.IMetadata.GetDateTimes(fileHolder, directories);
dateTimeOriginal ??= metadataDateTimeOriginal;
if (ffmpegFiles is not null && dateTimeOriginal is not null)
minimumDateTime = dateTimeOriginal.Value;
if (dateTimeOriginal is null)
dateTimeOriginalByLogic = record.DateTimeOriginal is not null ? record.DateTimeOriginal : metadataDateTimeOriginal;
if (record.FfmpegFilesPresent && dateTimeOriginalByLogic is not null)
minimumDateTime = dateTimeOriginalByLogic.Value;
if (dateTimeOriginalByLogic is null)
timeSpan = null;
else
timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTimeOriginal.Value.Ticks));
timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTimeOriginalByLogic.Value.Ticks));
}
if (timeSpan is null || timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta)
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : Path.Combine(fileHolder.DirectoryName, "Unknown"));
{
if (string.IsNullOrEmpty(_AppSettings.DefaultUnknownDirectoryName))
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : fileHolder.DirectoryName);
else
(isWrongYear, seasonDirectory) = (null, !_AppSettings.ForceIdName ? null : Path.Combine(fileHolder.DirectoryName, _AppSettings.DefaultUnknownDirectoryName));
}
else
{
directoryName = Path.GetFileName(fileHolder.DirectoryName);
@ -251,12 +287,10 @@ public class Rename
{
if (dateTimeFromName is not null && isWrongYear is not null && isWrongYear.Value)
minimumDateTime = dateTimeFromName.Value;
else if (dateTimeOriginal is not null)
minimumDateTime = dateTimeOriginal.Value;
else if (metadataDateTimeOriginal is not null)
minimumDateTime = metadataDateTimeOriginal.Value;
else if (dateTimeOriginalByLogic is not null)
minimumDateTime = dateTimeOriginalByLogic.Value;
else
minimumDateTime = new DateTime?[] { dateTimes.Where(l => l is not null).Min(), metadataDateTimes.Where(l => l is not null).Min() }.Min();
minimumDateTime = new DateTime?[] { record.DateTimes.Where(l => l is not null).Min(), metadataDateTimes.Where(l => l is not null).Min() }.Min();
if (minimumDateTime is null)
continue;
checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
@ -266,18 +300,19 @@ public class Rename
if (distinct.Contains(checkFile))
continue;
distinct.Add(checkFile);
results.Add(new(fileHolder, directory, checkFile));
results.Add(new(fileHolder, fileHolder.DirectoryName, checkFile));
if (nefPresent)
results.Add(new(new($"{fileHolder.FullName[..^4]}.tif"), directory, $"{checkFile[..^4]}.tif"));
results.Add(new(new($"{fileHolder.FullName[..^4]}.tif"), fileHolder.DirectoryName, $"{checkFile[..^4]}.tif"));
if (nefPresent)
results.Add(new(new($"{fileHolder.FullName[..^4]}.nef"), directory, $"{checkFile[..^4]}.nef"));
results.Add(new(new($"{fileHolder.FullName[..^4]}.nef"), fileHolder.DirectoryName, $"{checkFile[..^4]}.nef"));
}
else
{
if (id is null)
if (record.Id is null)
continue;
id = Shared.Models.Stateless.Methods.IDirectory.GetPaddedId(length, record.Index, record.Id.Value);
checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
checkFile = Path.Combine(seasonDirectory, $"{id.Value}{checkFileExtension}");
checkFile = Path.Combine(seasonDirectory, $"{id}{checkFileExtension}");
if (checkFile == fileHolder.FullName)
continue;
if (File.Exists(checkFile))
@ -317,13 +352,16 @@ public class Rename
{
List<string> results = new();
string message;
bool nefPresent;
bool nefPresentCheck;
bool nefPresent = false;
ProgressBar progressBar;
List<Record> records = new();
const string fileSearchFilter = "*";
const string directorySearchFilter = "*";
List<string> distinctDirectories = new();
List<(FileHolder, string)> verifiedToDoCollection = new();
List<(FileHolder, string, string)> toDoCollection = new();
int offset = Shared.Models.Stateless.Methods.IDirectory.GetOffset();
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
List<string[]> filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter);
int count = filesCollection.Select(l => l.Length).Sum();
@ -331,26 +369,50 @@ public class Rename
{
if (!files.Any())
continue;
// foreach (string file in files)
// foreach (string files[i] in files)
// {
// if (!file.EndsWith(".del"))
// if (!files[i].EndsWith(".del"))
// continue;
// File.Move(file, file[..^4]);
// File.Move(files[i], files[i][..^4]);
// }
// continue;
distinctDirectories.Clear();
message = $") Renaming files for <{files.FirstOrDefault()}>";
progressBar = new(files.Length, message, options);
if (_AppSettings.RenameUndo)
{
message = $") Undo renaming files for <{files.FirstOrDefault()}>";
progressBar = new(files.Length, message, options);
toDoCollection.AddRange(GetRenameUndoToDoCollection(progressBar, files));
}
else
{
nefPresent = files.Any(l => l.EndsWith(".NEF"));
if (!nefPresent)
toDoCollection.AddRange(GetToDoCollection(progressBar, files, nefPresent));
message = $"{records.Count:00000}) Gathering records for files next to <{files.FirstOrDefault()}>";
progressBar = new(files.Length, message, options);
nefPresentCheck = files.Any(l => l.EndsWith(".NEF"));
if (!nefPresentCheck)
records.AddRange(GetRecords(offset + records.Count, progressBar, files));
else
toDoCollection.AddRange(GetToDoCollection(progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray(), nefPresent));
{
if (!nefPresent)
nefPresent = true;
records.AddRange(GetRecords(offset + records.Count, progressBar, (from l in files where l.EndsWith(".JPG") select l).ToArray()));
}
}
progressBar.Dispose();
}
if (records.Any())
{
int length = 0;
foreach (Record record in records)
{
if (record.Id is null)
continue;
if (length > record.Id.Value.ToString().Length)
continue;
length = record.Id.Value.ToString().Length;
}
message = $"{length}) comparing records";
progressBar = new(records.Count, message, options);
toDoCollection.AddRange(GetToDoCollection(progressBar, nefPresent, records, length));
progressBar.Dispose();
}
foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection)
@ -372,10 +434,10 @@ public class Rename
File.WriteAllText($"{to}.id", $"{to}{Environment.NewLine}{fileHolder.FullName}");
}
ConsoleKey? consoleKey = null;
log.Information($"Ready to Move {verifiedToDoCollection.Count} file(s)?");
log.Information($"Ready to Move {verifiedToDoCollection.Count} files[i](s)?");
for (int y = 0; y < int.MaxValue; y++)
{
log.Information("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files");
log.Information("Press \"Y\" key to move files[i](s), \"N\" key to log files[i](s) or close console to not move files");
consoleKey = System.Console.ReadKey().Key;
if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
break;

View File

@ -3,6 +3,9 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IDirectory
{
static int GetOffset() =>
1000000;
char TestStatic_GetDirectory(string fileName) =>
GetDirectory(fileName);
static char GetDirectory(string fileName) =>
@ -13,6 +16,11 @@ public interface IDirectory
static int GetDirectory(char directory) =>
directory == '-' ? 10 : int.TryParse(directory.ToString(), out int value) ? value : 11;
string TestStatic_GetPaddedId(int length, int index, int id) =>
GetPaddedId(length, index, id);
static string GetPaddedId(int length, int index, int id) =>
id > -1 ? $"{index}070{id.ToString().PadLeft(length, '0')}" : $"{index}030{id.ToString()[1..].PadLeft(length, '0')}";
List<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) =>
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter);
static List<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) =>
@ -43,10 +51,10 @@ public interface IDirectory
static void MoveFiles(List<string> files, string find, string replace) =>
XDirectory.MoveFiles(files, find, replace);
(string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, List<string[]> filesCollection, string[] directories, Action? tick) =>
GetToDoCollection(propertyConfiguration, copyDuplicates, filesCollection, directories, tick);
static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, List<string[]> filesCollection, string[] directories, Action? tick) =>
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, filesCollection, directories, tick);
(string[], List<(Models.FileHolder, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick) =>
GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick);
static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick) =>
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filesCollection, directories, tick);
void TestStatic_CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick) =>
CopyOrMove(toDoCollection, move, moveBack, tick);

View File

@ -3,6 +3,8 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract partial class XDirectory
{
private record SortedRecord(int? Id, Models.FileHolder FileHolder);
private static int GetCeilingAverage(List<string[]> fileCollection)
{
List<int> counts = new();
@ -278,15 +280,59 @@ internal abstract partial class XDirectory
}
}
private static List<Models.FileHolder> GetFileHolders(List<string[]> filesCollection)
private static (bool, SortedRecord[]) GetSortedRecords(List<string[]> filesCollection)
{
List<Models.FileHolder> results = new();
bool result = true;
List<SortedRecord> results = new();
int? id;
short? multiplier;
char negativeMarker;
int absoluteValueOfId;
Models.FileHolder fileHolder;
int offset = IDirectory.GetOffset();
int offsetLength = offset.ToString().Length;
int sortOrderOnlyLengthIndex = offsetLength + 3;
foreach (string[] files in filesCollection)
results.AddRange(files.Select(l => new Models.FileHolder(l)));
return results;
{
foreach (string file in files)
{
fileHolder = new Models.FileHolder(file);
if (!result)
multiplier = null;
else
{
if (fileHolder.NameWithoutExtension.Length < sortOrderOnlyLengthIndex)
{
result = false;
multiplier = null;
}
else
{
negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2];
if (negativeMarker == '7')
multiplier = 1;
else if (negativeMarker == '3')
multiplier = -1;
else
{
result = false;
multiplier = null;
}
}
}
if (!result)
id = null;
else if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId))
id = null;
else
id = absoluteValueOfId * multiplier;
results.Add(new(id, fileHolder));
}
}
return new(result, (from l in results orderby l.FileHolder.LastWriteTime, l.FileHolder.FullName.Length descending select l).ToArray());
}
internal static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, List<string[]> filesCollection, string[] directories, Action? tick)
internal static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick)
{
List<(Models.FileHolder, string)> results = new();
string checkFile;
@ -295,18 +341,18 @@ internal abstract partial class XDirectory
int directoryIndex;
string directoryName;
bool wrapped = false;
List<int> distinctIds = new();
List<string> distinct = new();
List<string> distinctDirectories = new();
List<Models.FileHolder> fileHolders = GetFileHolders(filesCollection);
Models.FileHolder[] sortedFileHolders = (from l in fileHolders orderby l.LastWriteTime, l.FullName.Length descending select l).ToArray();
foreach (Models.FileHolder fileHolder in sortedFileHolders)
(bool all, SortedRecord[] sortedRecords) = GetSortedRecords(filesCollection);
foreach (SortedRecord sortedRecord in sortedRecords)
{
tick?.Invoke();
if (fileHolder.Name.EndsWith("len") || fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
if (sortedRecord.FileHolder.Name.EndsWith("len") || sortedRecord.FileHolder.ExtensionLowered == ".id" || sortedRecord.FileHolder.ExtensionLowered == ".lsv" || sortedRecord.FileHolder.DirectoryName is null)
continue;
(_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension);
directoryName = Path.GetFileName(fileHolder.DirectoryName);
if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(directoryName))
(_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, sortedRecord.FileHolder.NameWithoutExtension);
directoryName = Path.GetFileName(sortedRecord.FileHolder.DirectoryName);
if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !sortedRecord.FileHolder.Name.StartsWith(directoryName))
{
if (wrapped)
continue;
@ -318,22 +364,38 @@ internal abstract partial class XDirectory
wrapped = true;
directory = Path.Combine(directories[directoryIndex], directoryName);
}
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}{fileHolder.ExtensionLowered}");
if (distinct.Contains(checkFile))
if (all)
{
if (sortedRecord.Id is null || !sortedRecord.FileHolder.NameWithoutExtension.EndsWith(sortedRecord.Id.Value.ToString()[1..]))
throw new NotSupportedException();
}
if (all && ifCanUseId)
checkFile = Path.Combine(directory, $"{sortedRecord.Id}{sortedRecord.FileHolder.ExtensionLowered}");
else
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}{sortedRecord.FileHolder.ExtensionLowered}");
if ((sortedRecord.Id is not null && distinctIds.Contains(sortedRecord.Id.Value)) || distinct.Contains(checkFile))
{
if (string.IsNullOrEmpty(sortedRecord.FileHolder.DirectoryName))
continue;
if (!copyDuplicates)
continue;
for (int i = 1; i < int.MaxValue; i++)
{
fileInfo = new(checkFile);
if (!fileInfo.Exists || fileHolder.Length == fileInfo.Length && fileHolder.LastWriteTime == fileInfo.LastWriteTime)
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{i}dup{fileHolder.ExtensionLowered}");
if (!fileInfo.Exists || sortedRecord.FileHolder.Length == fileInfo.Length && sortedRecord.FileHolder.LastWriteTime == fileInfo.LastWriteTime)
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}dup{sortedRecord.FileHolder.ExtensionLowered}");
else
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{i}why{fileHolder.ExtensionLowered}");
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}why{sortedRecord.FileHolder.ExtensionLowered}");
if (sortedRecord.Id is not null)
{
if (distinctIds.Contains(sortedRecord.Id.Value))
continue;
distinctIds.Add(sortedRecord.Id.Value);
}
if (distinct.Contains(checkFile))
continue;
distinct.Add(checkFile);
results.Add(new(fileHolder, checkFile));
results.Add(new(sortedRecord.FileHolder, checkFile));
if (!distinctDirectories.Contains(directory))
distinctDirectories.Add(directory);
break;
@ -341,7 +403,9 @@ internal abstract partial class XDirectory
continue;
}
distinct.Add(checkFile);
results.Add(new(fileHolder, checkFile));
if (sortedRecord.Id is not null)
distinctIds.Add(sortedRecord.Id.Value);
results.Add(new(sortedRecord.FileHolder, checkFile));
if (!distinctDirectories.Contains(directory))
distinctDirectories.Add(directory);
}