Mostly Sorting

Video Merge as 4, 5, and 6

Enum change to last character
This commit is contained in:
Mike Phares 2025-03-22 17:18:30 -07:00
parent ae23e803fa
commit 9fb6f0fa05
22 changed files with 1578 additions and 1533 deletions

14
.vscode/tasks.json vendored
View File

@ -628,5 +628,19 @@
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
"type": "shell",
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
"args": [
"s",
"X",
"L:/Git/AA",
"Day-Helper-2025-03-20",
"false",
"4"
],
"problemMatcher": []
}
] ]
} }

View File

@ -17,6 +17,21 @@ public partial class Compare : ICompare, IDisposable
private ProgressBar? _ProgressBar; private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions; private readonly ProgressBarOptions _ProgressBarOptions;
void ICompare.Tick() =>
_ProgressBar?.Tick();
void IDisposable.Dispose()
{
_ProgressBar?.Dispose();
GC.SuppressFinalize(this);
}
void ICompare.ConstructProgressBar(int maxTicks, string message)
{
_ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
}
public Compare(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console) public Compare(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
{ {
if (isSilent) if (isSilent)
@ -31,19 +46,46 @@ public partial class Compare : ICompare, IDisposable
CompareWork(logger, appSettings, compare, ticks); CompareWork(logger, appSettings, compare, ticks);
} }
void ICompare.Tick() => private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
_ProgressBar?.Tick();
void ICompare.ConstructProgressBar(int maxTicks, string message)
{ {
_ProgressBar?.Dispose(); const int updated = 0;
_ProgressBar = new(maxTicks, message, _ProgressBarOptions); DistanceLimits? distanceLimits;
} logger?.LogInformation("{Ticks}", ticks);
ReadOnlyCollection<LocationContainer> matrix;
void IDisposable.Dispose() ReadOnlyCollection<SaveContainer> saveContainers;
{ ReadOnlyCollection<ExifDirectory> exifDirectories;
_ProgressBar?.Dispose(); ReadOnlyCollection<LocationContainer> preFiltered;
GC.SuppressFinalize(this); ReadOnlyCollection<LocationContainer> postFiltered;
ReadOnlyDictionary<string, LocationContainer> onlyOne;
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
{
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
continue;
_ProgressBar?.Dispose();
logger?.LogInformation("{outputResolution}", outputResolution);
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
if (preFiltered.Count == 0)
continue;
distanceLimits = new(appSettings.DistanceSettings);
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
if (postFiltered.Count == 0)
continue;
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
if (matrix.Count == 0)
continue;
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
if (onlyOne.Count == 0)
continue;
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
if (saveContainers.Count == 0)
continue;
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
}
} }
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks) private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks)
@ -123,46 +165,4 @@ public partial class Compare : ICompare, IDisposable
return results; return results;
} }
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
{
const int updated = 0;
DistanceLimits? distanceLimits;
logger?.LogInformation("{Ticks}", ticks);
ReadOnlyCollection<LocationContainer> matrix;
ReadOnlyCollection<SaveContainer> saveContainers;
ReadOnlyCollection<ExifDirectory> exifDirectories;
ReadOnlyCollection<LocationContainer> preFiltered;
ReadOnlyCollection<LocationContainer> postFiltered;
ReadOnlyDictionary<string, LocationContainer> onlyOne;
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
{
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
continue;
_ProgressBar?.Dispose();
logger?.LogInformation("{outputResolution}", outputResolution);
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
if (preFiltered.Count == 0)
continue;
distanceLimits = new(appSettings.DistanceSettings);
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
if (postFiltered.Count == 0)
continue;
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
if (matrix.Count == 0)
continue;
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
if (onlyOne.Count == 0)
continue;
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
if (saveContainers.Count == 0)
continue;
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
}
}
} }

View File

@ -8,11 +8,8 @@ public record CompareSettings(string Company,
string FacesFileNameExtension, string FacesFileNameExtension,
string FacesHiddenFileNameExtension, string FacesHiddenFileNameExtension,
string FacesPartsFileNameExtension, string FacesPartsFileNameExtension,
string[] IgnoreExtensions,
int MaxDegreeOfParallelism, int MaxDegreeOfParallelism,
string[] OutputResolutions, string[] OutputResolutions) : Shared.Models.Properties.ICompareSettings
string[] ValidImageFormatExtensions,
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.ICompareSettings
{ {
public override string ToString() public override string ToString()

View File

@ -11,11 +11,21 @@ namespace View_by_Distance.Distance.Models.Stateless;
internal static class FilterLogicD internal static class FilterLogicD
{ {
internal record RecordA(long? Ticks, string? Directory); internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
{
string result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
result = Path.Combine(cContentDirectory, cei.Combined);
return result;
}
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting); internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
{
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory); string result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
return result;
}
internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName) internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
{ {
@ -39,141 +49,12 @@ internal static class FilterLogicD
else if (isBySorting && useFiltersCounter.HasValue) else if (isBySorting && useFiltersCounter.HasValue)
byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}"; byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
else else
{ byValue = IDistance.Get(saveIndividually, forceSingleImageHumanized, by.Value, isDefaultName);
byValue = $"{by.Value switch
{
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
IMapLogic.Sorting => saveIndividually ? nameof(IMapLogic.Individually) : nameof(IMapLogic.Sorting),
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
_ => throw new NotImplementedException()
}}{(!isDefaultName ? "-A" : "-Z")}";
}
} }
result = new(byValue, isByMapping, isBySorting); result = new(byValue, isByMapping, isBySorting);
return result; return result;
} }
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
{
RecordC result;
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
throw new NotImplementedException();
long? ticks = null;
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
result = new(debugDirectory, directory, ticks, personDirectory);
return result;
}
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
{
string result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
result = Path.Combine(cContentDirectory, cei.Combined);
return result;
}
internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
{
string result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
return result;
}
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
{
List<SaveContainer> results = [];
RecordB recordB;
RecordC recordC;
string segmentB;
string checkFile;
string? directory;
string shortcutFile;
string facesDirectory;
bool isCounterPersonYear;
string facePartsDirectory;
FileHolder? faceFileHolder;
SaveContainer? saveContainer;
FileHolder? resizedFileHolder;
int? useFiltersCounter = null;
string resizeContentDirectory;
FileHolder? facePartsFileHolder;
FileHolder? hiddenFaceFileHolder;
LocationContainer locationContainer;
bool sortingContainersAny = onlyOne.Count > 0;
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
nameof(E_Distance),
resultSettings.ResultContent);
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
nameof(C_Resize),
outputResolution,
includeResizeGroup: true,
includeModel: false,
includePredictorModel: false);
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
nameof(D2_FaceParts),
outputResolution,
includeResizeGroup: true,
includeModel: true,
includePredictorModel: true);
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
if (!Directory.Exists(cContentDirectory))
_ = Directory.CreateDirectory(cContentDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
if (!Directory.Exists(eDistanceContentTicksDirectory))
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
if (!Directory.Exists(d2FacePartsContentDirectory))
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
compare.ConstructProgressBar(onlyOne.Count, message);
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
{
if (distanceSettings.SaveIndividually)
break;
locationContainer = keyValuePair.Value;
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
continue;
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
continue;
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
continue;
directory = recordC.Directory;
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
results.Add(SaveContainer.Get(recordC.DebugDirectory));
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
{
if (!distanceSettings.SaveSortingWithoutPerson)
throw new NotSupportedException();
if (recordC.Ticks is null)
continue;
}
results.Add(SaveContainer.Get(recordC.PersonDirectory));
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
results.Add(saveContainer);
}
return results.AsReadOnly();
}
internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers)
{ {
string fileName; string fileName;
@ -285,4 +166,115 @@ internal static class FilterLogicD
} }
} }
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
{
List<SaveContainer> results = [];
RecordB recordB;
RecordC recordC;
string segmentB;
string checkFile;
string? directory;
string shortcutFile;
string facesDirectory;
bool isCounterPersonYear;
string facePartsDirectory;
FileHolder? faceFileHolder;
SaveContainer? saveContainer;
FileHolder? resizedFileHolder;
int? useFiltersCounter = null;
string resizeContentDirectory;
FileHolder? facePartsFileHolder;
FileHolder? hiddenFaceFileHolder;
LocationContainer locationContainer;
bool sortingContainersAny = onlyOne.Count > 0;
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
nameof(E_Distance),
resultSettings.ResultContent);
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
nameof(C_Resize),
outputResolution,
includeResizeGroup: true,
includeModel: false,
includePredictorModel: false);
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
nameof(D2_FaceParts),
outputResolution,
includeResizeGroup: true,
includeModel: true,
includePredictorModel: true);
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
if (!Directory.Exists(cContentDirectory))
_ = Directory.CreateDirectory(cContentDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
if (!Directory.Exists(eDistanceContentTicksDirectory))
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
if (!Directory.Exists(d2FacePartsContentDirectory))
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
compare.ConstructProgressBar(onlyOne.Count, message);
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
{
if (distanceSettings.SaveIndividually)
break;
locationContainer = keyValuePair.Value;
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
continue;
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
continue;
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
continue;
directory = recordC.Directory;
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
results.Add(SaveContainer.Get(recordC.DebugDirectory));
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
{
if (!distanceSettings.SaveSortingWithoutPerson)
throw new NotSupportedException();
if (recordC.Ticks is null)
continue;
}
results.Add(SaveContainer.Get(recordC.PersonDirectory));
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
results.Add(saveContainer);
}
return results.AsReadOnly();
}
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
{
RecordC result;
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
throw new NotImplementedException();
long? ticks = null;
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
result = new(debugDirectory, directory, ticks, personDirectory);
return result;
}
internal record RecordA(long? Ticks, string? Directory);
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting);
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory);
} }

View File

@ -9,49 +9,69 @@ namespace View_by_Distance.Distance.Models.Stateless;
public interface IDistance public interface IDistance
{ {
static ReadOnlyCollection<ExifDirectory> TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); $"{by switch
static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) => {
MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections); IMapLogic.Mapping => nameof(IMapLogic.Mapping),
IMapLogic.Sorting => saveIndividually ?
nameof(IMapLogic.Individually) :
nameof(IMapLogic.Sorting),
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
_ => throw new NotImplementedException()
}}{(!isDefaultName ? "-A" : "-Z")}";
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) => public static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
Extract(compareSettings, exifDirectories);
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
MappedLogicA.Extract(compareSettings, exifDirectories);
static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
GetPostFilterLocationContainer(preFiltered, distanceLimits);
static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
GetOnlyOne(distanceSettings, matrix);
static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
FilterLogicC.GetOnlyOne(distanceSettings, matrix); FilterLogicC.GetOnlyOne(distanceSettings, matrix);
static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) => public static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne); FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) => public static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers); FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
MappedLogicA.Extract(compareSettings, exifDirectories);
public static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers); FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
public static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
public static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
public static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
internal static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
GetOnlyOne(distanceSettings, matrix);
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
GetPostFilterLocationContainer(preFiltered, distanceLimits);
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
Extract(compareSettings, exifDirectories);
internal static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
internal static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
} }

View File

@ -14,33 +14,53 @@ internal static class MappedLogicA
string? PersonDisplayDirectoryName, string? PersonDisplayDirectoryName,
FilePath FilePath); FilePath FilePath);
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections) internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
{ {
List<MappedFile> results = []; Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
FilePath filePath; int? wholePercentages;
MappedFile mappedFile; Dictionary<int, FilePath>? keyValues;
string personKeyFormatted; Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
List<string> distinct = []; foreach (ExifDirectory exifDirectory in exifDirectories)
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
{ {
if (personContainer.Key is null) if (exifDirectory.FilePath.Id is null)
continue; continue;
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--) if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
{ {
filePath = personContainer.DisplayDirectoryAllFilePaths[i]; keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []);
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension) if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
continue; throw new Exception();
if (distinct.Contains(filePath.Name))
continue;
distinct.Add(filePath.Name);
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
results.Add(mappedFile);
} }
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
if (wholePercentages is null)
continue;
keyValues.Add(wholePercentages.Value, exifDirectory.FilePath);
} }
return results; foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
return results.AsReadOnly();
}
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
{
List<ExifDirectory> results = [];
string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent));
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
if (mappedFiles.Count > 0)
{
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
compare.ConstructProgressBar(mappedFiles.Count, message);
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
{
compare.Tick();
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
});
}
return results.AsReadOnly();
} }
private static ReadOnlyCollection<MappedFile> GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection<MappedLogicB.Record> records) private static ReadOnlyCollection<MappedFile> GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection<MappedLogicB.Record> records)
@ -102,6 +122,35 @@ internal static class MappedLogicA
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections)
{
List<MappedFile> results = [];
FilePath filePath;
MappedFile mappedFile;
string personKeyFormatted;
List<string> distinct = [];
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
{
if (personContainer.Key is null)
continue;
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
{
filePath = personContainer.DisplayDirectoryAllFilePaths[i];
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension)
continue;
if (distinct.Contains(filePath.Name))
continue;
distinct.Add(filePath.Name);
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
results.Add(mappedFile);
}
}
return results;
}
private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List<ExifDirectory> exifDirectories, ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipCollection, MappedFile mappedFile) private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List<ExifDirectory> exifDirectories, ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipCollection, MappedFile mappedFile)
{ {
int? id; int? id;
@ -152,53 +201,4 @@ internal static class MappedLogicA
exifDirectories.Add(exifDirectory); exifDirectories.Add(exifDirectory);
} }
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
{
List<ExifDirectory> results = [];
string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent));
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
if (mappedFiles.Count > 0)
{
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
compare.ConstructProgressBar(mappedFiles.Count, message);
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
{
compare.Tick();
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
});
}
return results.AsReadOnly();
}
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
{
Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
int? wholePercentages;
Dictionary<int, FilePath>? keyValues;
Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
foreach (ExifDirectory exifDirectory in exifDirectories)
{
if (exifDirectory.FilePath.Id is null)
continue;
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
{
keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []);
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
throw new Exception();
}
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
if (wholePercentages is null)
continue;
keyValues.Add(wholePercentages.Value, exifDirectory.FilePath);
}
foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
return results.AsReadOnly();
}
} }

View File

@ -24,327 +24,6 @@ internal static class MappedLogicB
bool? IsLocationContainerDebugDirectory, bool? IsLocationContainerDebugDirectory,
float? TotalDays); float? TotalDays);
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
{
string checkFile;
string actionDirectoryName = Path.GetFileName(actionDirectory);
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
foreach (string file in files)
{
if (facesFileNames.Contains(file))
{
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
if (File.Exists(checkFile))
continue;
File.Move(file, checkFile);
continue;
}
File.Delete(file);
}
}
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
{
string[] files;
string checkFile;
string? checkDirectory;
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
if (!Directory.Exists(checkDirectory))
Directory.Move(directory, checkDirectory);
else
{
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (string file in files)
{
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
continue;
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
checkDirectory = Path.GetDirectoryName(checkFile);
if (checkDirectory is null)
continue;
if (File.Exists(checkFile))
continue;
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
File.Move(file, checkFile);
}
}
}
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
}
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory)
{
List<TicksDirectory> results = [];
float? totalDays;
long? next = null;
string? checkDirectory;
DateTime directoryDateTime;
DirectoryInfo directoryInfo;
TicksDirectory ticksDirectory;
long? lastDirectoryTicks = null;
DateTime dateTime = DateTime.Now;
DateTime alternateDirectoryDateTime;
string ticksDirectoryNameFirstSegment;
bool? isLocationContainerDebugDirectory;
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
for (int i = 1; i < 5; i++)
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
if (!Directory.Exists(eDistanceContentDirectory))
_ = Directory.CreateDirectory(eDistanceContentDirectory);
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string ticksFullPath in ticksFullPaths)
{
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
if (ticksDirectoryNameFirstSegment.Length < 3)
continue;
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
throw new NotSupportedException();
if (next is null)
next = new DateTime(directoryTicks).Ticks;
else
{
next += month;
checkDirectory = Path.GetDirectoryName(ticksFullPath);
if (string.IsNullOrEmpty(checkDirectory))
{
if (string.IsNullOrEmpty(checkDirectory))
continue;
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern))
continue;
Directory.Move(ticksFullPath, checkDirectory);
continue;
}
}
directoryInfo = new(ticksFullPath);
directoryDateTime = new DateTime(directoryTicks);
if (directoryInfo.CreationTime.Ticks != directoryTicks)
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory);
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
results.Add(ticksDirectory);
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
continue;
lastDirectoryTicks = directoryTicks;
}
string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray();
if (compare.Length > 0 && distanceSettings.ReMap)
throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>");
return results;
}
private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory)
{
bool isDefault;
string[] files;
FileInfo[] collection;
string[] facesFileNames;
string yearDirectoryName;
string[] yearDirectories;
string alphaDirectoryName;
string matchDirectoryName;
string personKeyFormatted;
string[] alphaDirectories;
string[] matchDirectories;
string[] actionDirectories;
string personDisplayDirectory;
string[] personKeyDirectories;
string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
foreach (string segmentCDirectory in segmentCDirectories)
{
personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyDirectory in personKeyDirectories)
{
personKeyFormatted = Path.GetFileName(personKeyDirectory);
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
yearDirectoryName = Path.GetFileName(yearDirectory);
if (yearDirectoryName.StartsWith('='))
Directory.Move(yearDirectory, yearDirectory.Replace('=', '~'));
}
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
yearDirectoryName = Path.GetFileName(yearDirectory);
matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray();
if (alphaDirectories.Length == 0)
continue;
alphaDirectoryName = Path.GetFileName(alphaDirectories[0]);
foreach (string matchDirectory in matchDirectories)
{
matchDirectoryName = Path.GetFileName(matchDirectory);
files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly);
if (files.Length != 4)
continue;
collection = files.Select(l => new FileInfo(l)).ToArray();
isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
if (isDefault)
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray();
else
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray();
if (facesFileNames.Length == 0)
continue;
personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName);
if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory))
continue;
_ = Process.Start("explorer", matchDirectory);
for (int i = 0; i < int.MaxValue; i++)
{
Thread.Sleep(500);
actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray();
if (actionDirectories.Length > 0)
{
MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames);
break;
}
}
}
}
}
}
}
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
{
string result;
string checkDirectory;
string directory = file;
List<string> collection = [];
for (int i = 0; i < file.Length; i++)
{
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
if (directory == ticksDirectory.Directory)
break;
collection.Add(Path.GetFileName(directory));
}
collection.Reverse();
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
foreach (string directoryName in collection)
checkDirectory = Path.Combine(checkDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
result = Path.Combine(checkDirectory, fileName);
if (File.Exists(result))
throw new Exception($"File <{fileName}> already exists!");
File.Move(file, result);
return result;
}
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
{
List<Record> results = [];
string @enum;
Record record;
string fileName;
string checkFile;
FilePath filePath;
FileHolder fileHolder;
int? wholePercentages;
foreach (string file in files)
{
if (file.EndsWith(".lnk"))
continue;
fileHolder = FileHolder.Get(file);
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
if (filePath.Id is null)
continue;
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
if (wholePercentages is null)
continue;
fileName = Path.GetFileName(file);
if (distinct.Contains(fileName))
{
checkFile = $"{file}.dup";
if (File.Exists(checkFile))
continue;
File.Move(file, checkFile);
continue;
}
if (file.StartsWith(ticksDirectory.Directory))
{
@enum = IPath.GetEnum(filePath).ToString();
if (!ticksDirectory.Directory.EndsWith(@enum))
{
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
fileHolder = FileHolder.Get(checkFile);
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
if (filePath.Id is null)
continue;
}
}
distinct.Add(fileName);
record = new(DirectoryNumber: directoryNumber,
IsDefault: isDefault,
LinksCount: linksCount,
MappedFaceFilePath: filePath,
PersonDisplayDirectoryName: personDisplayDirectoryName,
PersonKeyFormatted: personKeyFormatted);
results.Add(record);
}
return results;
}
private static string[] RenameBirth(string[] files)
{
List<string> results = [];
string checkFile;
foreach (string file in files)
{
if (file.EndsWith(".brt"))
{
results.Add(file);
continue;
}
checkFile = $"{file}.brt";
if (File.Exists(checkFile))
{
results.Add(file);
continue;
}
File.Move(file, checkFile);
results.Add(checkFile);
}
return results.ToArray();
}
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
{
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
if (Directory.Exists(newestPersonKeyDirectory))
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
else
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
}
private static int? GetLinksCount(string yearDirectory)
{
int? result;
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
if (yearDirectoryNameSegments.Length != 3)
result = null;
else
{
string lastSegment = yearDirectoryNameSegments[^1];
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
result = null;
else
result = lastSegment[0] - 65;
}
return result;
}
internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections) internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
{ {
List<Record> results = []; List<Record> results = [];
@ -526,4 +205,325 @@ internal static class MappedLogicB
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory)
{
List<TicksDirectory> results = [];
float? totalDays;
long? next = null;
string? checkDirectory;
DateTime directoryDateTime;
DirectoryInfo directoryInfo;
TicksDirectory ticksDirectory;
long? lastDirectoryTicks = null;
DateTime dateTime = DateTime.Now;
DateTime alternateDirectoryDateTime;
string ticksDirectoryNameFirstSegment;
bool? isLocationContainerDebugDirectory;
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
for (int i = 1; i < 5; i++)
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
if (!Directory.Exists(eDistanceContentDirectory))
_ = Directory.CreateDirectory(eDistanceContentDirectory);
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string ticksFullPath in ticksFullPaths)
{
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
if (ticksDirectoryNameFirstSegment.Length < 3)
continue;
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
throw new NotSupportedException();
if (next is null)
next = new DateTime(directoryTicks).Ticks;
else
{
next += month;
checkDirectory = Path.GetDirectoryName(ticksFullPath);
if (string.IsNullOrEmpty(checkDirectory))
{
if (string.IsNullOrEmpty(checkDirectory))
continue;
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern))
continue;
Directory.Move(ticksFullPath, checkDirectory);
continue;
}
}
directoryInfo = new(ticksFullPath);
directoryDateTime = new DateTime(directoryTicks);
if (directoryInfo.CreationTime.Ticks != directoryTicks)
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory);
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
results.Add(ticksDirectory);
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
continue;
lastDirectoryTicks = directoryTicks;
}
string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray();
if (compare.Length > 0 && distanceSettings.ReMap)
throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>");
return results;
}
private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory)
{
bool isDefault;
string[] files;
FileInfo[] collection;
string[] facesFileNames;
string yearDirectoryName;
string[] yearDirectories;
string alphaDirectoryName;
string matchDirectoryName;
string personKeyFormatted;
string[] alphaDirectories;
string[] matchDirectories;
string[] actionDirectories;
string personDisplayDirectory;
string[] personKeyDirectories;
string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
foreach (string segmentCDirectory in segmentCDirectories)
{
personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyDirectory in personKeyDirectories)
{
personKeyFormatted = Path.GetFileName(personKeyDirectory);
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
yearDirectoryName = Path.GetFileName(yearDirectory);
if (yearDirectoryName.StartsWith('='))
Directory.Move(yearDirectory, yearDirectory.Replace('=', '~'));
}
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
yearDirectoryName = Path.GetFileName(yearDirectory);
matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray();
if (alphaDirectories.Length == 0)
continue;
alphaDirectoryName = Path.GetFileName(alphaDirectories[0]);
foreach (string matchDirectory in matchDirectories)
{
matchDirectoryName = Path.GetFileName(matchDirectory);
files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly);
if (files.Length != 4)
continue;
collection = files.Select(l => new FileInfo(l)).ToArray();
isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
if (isDefault)
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray();
else
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray();
if (facesFileNames.Length == 0)
continue;
personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName);
if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory))
continue;
_ = Process.Start("explorer", matchDirectory);
for (int i = 0; i < int.MaxValue; i++)
{
Thread.Sleep(500);
actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray();
if (actionDirectories.Length > 0)
{
MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames);
break;
}
}
}
}
}
}
}
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
{
string checkFile;
string actionDirectoryName = Path.GetFileName(actionDirectory);
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
foreach (string file in files)
{
if (facesFileNames.Contains(file))
{
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
if (File.Exists(checkFile))
continue;
File.Move(file, checkFile);
continue;
}
File.Delete(file);
}
}
private static int? GetLinksCount(string yearDirectory)
{
int? result;
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
if (yearDirectoryNameSegments.Length != 3)
result = null;
else
{
string lastSegment = yearDirectoryNameSegments[^1];
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
result = null;
else
result = lastSegment[0] - 65;
}
return result;
}
private static string[] RenameBirth(string[] files)
{
List<string> results = [];
string checkFile;
foreach (string file in files)
{
if (file.EndsWith(".brt"))
{
results.Add(file);
continue;
}
checkFile = $"{file}.brt";
if (File.Exists(checkFile))
{
results.Add(file);
continue;
}
File.Move(file, checkFile);
results.Add(checkFile);
}
return results.ToArray();
}
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
{
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
if (Directory.Exists(newestPersonKeyDirectory))
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
else
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
}
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
{
string[] files;
string checkFile;
string? checkDirectory;
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
if (!Directory.Exists(checkDirectory))
Directory.Move(directory, checkDirectory);
else
{
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (string file in files)
{
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
continue;
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
checkDirectory = Path.GetDirectoryName(checkFile);
if (checkDirectory is null)
continue;
if (File.Exists(checkFile))
continue;
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
File.Move(file, checkFile);
}
}
}
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
}
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
{
List<Record> results = [];
string @enum;
Record record;
string fileName;
string checkFile;
FilePath filePath;
FileHolder fileHolder;
int? wholePercentages;
foreach (string file in files)
{
if (file.EndsWith(".lnk"))
continue;
fileHolder = FileHolder.Get(file);
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
if (filePath.Id is null)
continue;
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
if (wholePercentages is null)
continue;
fileName = Path.GetFileName(file);
if (distinct.Contains(fileName))
{
checkFile = $"{file}.dup";
if (File.Exists(checkFile))
continue;
File.Move(file, checkFile);
continue;
}
if (file.StartsWith(ticksDirectory.Directory))
{
@enum = IPath.GetEnum(filePath).ToString();
if (!ticksDirectory.Directory.EndsWith(@enum))
{
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
fileHolder = FileHolder.Get(checkFile);
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
if (filePath.Id is null)
continue;
}
}
distinct.Add(fileName);
record = new(DirectoryNumber: directoryNumber,
IsDefault: isDefault,
LinksCount: linksCount,
MappedFaceFilePath: filePath,
PersonDisplayDirectoryName: personDisplayDirectoryName,
PersonKeyFormatted: personKeyFormatted);
results.Add(record);
}
return results;
}
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
{
string result;
string checkDirectory;
string directory = file;
List<string> collection = [];
for (int i = 0; i < file.Length; i++)
{
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
if (directory == ticksDirectory.Directory)
break;
collection.Add(Path.GetFileName(directory));
}
collection.Reverse();
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
foreach (string directoryName in collection)
checkDirectory = Path.Combine(checkDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
result = Path.Combine(checkDirectory, fileName);
if (File.Exists(result))
throw new Exception($"File <{fileName}> already exists!");
File.Move(file, result);
return result;
}
} }

View File

@ -54,51 +54,7 @@ internal static class Get
return results.AsReadOnly(); return results.AsReadOnly();
} }
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
{
return file =>
{
rename.Tick();
ExifDirectory exifDirectory;
MetadataGroup metadataGroup;
DeterministicHashCode deterministicHashCode;
FileHolder fileHolder = FileHolder.Get(file);
bool fastForwardMovingPictureExpertsGroupUsed;
MinimumYearAndPathCombined minimumYearAndPathCombined;
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
if (distinct.Contains(key))
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
return;
if (filePath.Id is not null)
{
fastForwardMovingPictureExpertsGroupFiles = null;
deterministicHashCode = new(null, filePath.Id, null);
}
else
{
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(renameSettings, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
}
filePath = FilePath.Get(filePath, deterministicHashCode);
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
lock (metadataGroups)
metadataGroups.Add(metadataGroup);
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
{
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
File.Delete(fastForwardMovingPictureExpertsGroupFile);
}
};
}
internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
{ {
return file => return file =>
{ {
@ -125,7 +81,7 @@ internal static class Get
} }
else else
{ {
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(windowsSettings, httpClient, filePath); fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, httpClient, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null); fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath); deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
} }
@ -145,4 +101,48 @@ internal static class Get
}; };
} }
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
{
return file =>
{
rename.Tick();
ExifDirectory exifDirectory;
MetadataGroup metadataGroup;
DeterministicHashCode deterministicHashCode;
FileHolder fileHolder = FileHolder.Get(file);
bool fastForwardMovingPictureExpertsGroupUsed;
MinimumYearAndPathCombined minimumYearAndPathCombined;
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
if (distinct.Contains(key))
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
return;
if (filePath.Id is not null)
{
fastForwardMovingPictureExpertsGroupFiles = null;
deterministicHashCode = new(null, filePath.Id, null);
}
else
{
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
}
filePath = FilePath.Get(filePath, deterministicHashCode);
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
lock (metadataGroups)
metadataGroups.Add(metadataGroup);
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
{
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
File.Delete(fastForwardMovingPictureExpertsGroupFile);
}
};
}
} }

View File

@ -72,9 +72,9 @@ public interface IMetadata
static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<NginxFileSystem> collection) => static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<NginxFileSystem> collection) =>
Get.GetKeyValuePairs(collection); Get.GetKeyValuePairs(collection);
Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) => Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups); SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) => static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups); Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
} }

View File

@ -9,7 +9,6 @@ public record RenameSettings(string Company,
Dictionary<string, string?> DirectoryDictionary, Dictionary<string, string?> DirectoryDictionary,
string? FirstPassFile, string? FirstPassFile,
bool ForceNewId, bool ForceNewId,
string[] IgnoreExtensions,
bool InPlace, bool InPlace,
bool InPlaceMoveDirectory, bool InPlaceMoveDirectory,
bool InPlaceWithOriginalName, bool InPlaceWithOriginalName,
@ -20,9 +19,7 @@ public record RenameSettings(string Company,
string RelativePropertyCollectionFile, string RelativePropertyCollectionFile,
bool RequireRootDirectoryExists, bool RequireRootDirectoryExists,
string[] SidecarExtensions, string[] SidecarExtensions,
bool SkipIdFiles, bool SkipIdFiles) : Shared.Models.Properties.IRenameSettings
string[] ValidImageFormatExtensions,
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameSettings
{ {
public override string ToString() public override string ToString()

View File

@ -11,7 +11,6 @@ using View_by_Distance.Metadata.Models;
using View_by_Distance.Metadata.Models.Stateless; using View_by_Distance.Metadata.Models.Stateless;
using View_by_Distance.Rename.Models; using View_by_Distance.Rename.Models;
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; using View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Rename; namespace View_by_Distance.Rename;
@ -35,39 +34,58 @@ public partial class Rename : IRename, IDisposable
private ProgressBar? _ProgressBar; private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions; private readonly ProgressBarOptions _ProgressBarOptions;
public Rename(List<string> args, ILogger<Program>? 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;
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
RenameWork(logger, appSettings, rename, ticks);
}
void IRename.Tick() => void IRename.Tick() =>
_ProgressBar?.Tick(); _ProgressBar?.Tick();
void IRename.ConstructProgressBar(int maxTicks, string message)
{
_ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
}
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
_ProgressBar?.Dispose(); _ProgressBar?.Dispose();
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath) void IRename.ConstructProgressBar(int maxTicks, string message)
{
_ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
}
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
{
DeterministicHashCode result;
int? id;
int? width;
int? height;
try
{
#pragma warning disable CA1416
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);
#pragma warning restore CA1416
id = IId.GetDeterministicHashCode(bytes);
}
catch (Exception)
{
id = null;
width = null;
height = null;
}
result = new(height, id, width);
return result;
}
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath)
{ {
List<string> results = []; List<string> results = [];
bool isValidVideoFormatExtensions = renameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
if (isValidVideoFormatExtensions) if (isValidVideoFormatExtensions)
{ {
bool check; bool check;
@ -97,40 +115,241 @@ public partial class Rename : IRename, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
#pragma warning disable CA1416 public Rename(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
{ {
DeterministicHashCode result; if (isSilent)
int? id; { }
int? width; if (args is null)
int? height; throw new NullReferenceException(nameof(args));
try if (console is null)
{ throw new NullReferenceException(nameof(console));
using Image image = Image.FromFile(filePath.FullName); IRename rename = this;
width = image.Width; long ticks = DateTime.Now.Ticks;
height = image.Height; _ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using Bitmap bitmap = new(image); RenameWork(logger, appSettings, rename, ticks);
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 RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
{
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
if (!Directory.Exists(sourceDirectory))
_ = Directory.CreateDirectory(sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
if (files.Count > 0)
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
{
if (recordCollection.Count > 0)
recordCollection = new([]);
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
}
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
{
DirectoryInfo directoryInfo = new(sourceDirectory);
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
if (lines.Count != 0)
{
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
}
}
}
private static ReadOnlyCollection<int> GetIds(RenameSettings renameSettings)
{
ReadOnlyCollection<int> results;
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.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(renameSettings.RelativePropertyCollectionFile))
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
return results;
}
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
{
ReadOnlyCollection<Record> results;
List<FirstPass> collection;
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile))
collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile);
else
{
string json = File.ReadAllText(checkFile);
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
}
if (appSettings.RenameSettings.JustMediaDate)
results = new([]);
else
results = GetRecordCollection(appSettings, collection);
return results;
}
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile)
{
List<FirstPass> results;
FirstPass firstPass;
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
if (appSettingsMaxDegreeOfParallelism == 1)
{
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
}
else
{
results = [];
List<string> distinct = [];
List<MetadataGroup> metadataGroups = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
Thread.Sleep(500);
foreach (MetadataGroup metadataGroup in metadataGroups)
{
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
else
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
results.Add(firstPass);
}
}
if (!string.IsNullOrEmpty(checkFile))
{
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
}
return results;
}
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
{
List<FirstPass> results = [];
int index = -1;
TimeSpan timeSpan;
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
{
index += 1;
rename.Tick();
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
{
if (appSettings.RenameSettings.InPlaceMoveDirectory)
continue;
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
}
if (keyValuePair.Value.Count > 2)
throw new NotSupportedException("Too many sidecar files!");
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
timeSpan = new(DateTime.Now.Ticks - ticks);
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
break;
}
return results;
}
private void SetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, int index, KeyValuePair<string, List<FileHolder>> keyValuePair, List<FirstPass> results)
{
FilePath filePath;
FirstPass firstPass;
string directoryName;
ExifDirectory exifDirectory;
List<FileHolder> sidecarFiles;
DeterministicHashCode deterministicHashCode;
bool fastForwardMovingPictureExpertsGroupUsed;
MinimumYearAndPathCombined minimumYearAndPathCombined;
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
foreach (FileHolder fileHolder in keyValuePair.Value)
{
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
continue;
if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
continue;
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
continue;
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
{
fastForwardMovingPictureExpertsGroupFiles = null;
deterministicHashCode = new(null, filePath.Id, null);
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
continue;
}
else
{
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
}
sidecarFiles = [];
filePath = FilePath.Get(filePath, deterministicHashCode);
for (int i = 0; i < keyValuePair.Value.Count; i++)
{
if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value)
JustMediaDate(logger, appSettings, metadata, filePath);
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
continue;
sidecarFiles.Add(keyValuePair.Value[i]);
}
try
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
catch (Exception)
{
logger?.LogWarning("<{filePath}>", filePath.FullName);
continue;
}
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
{
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
File.Delete(fastForwardMovingPictureExpertsGroupFile);
}
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
fastForwardMovingPictureExpertsGroupUsed = true;
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
results.Add(firstPass);
}
}
private void JustMediaDate(ILogger<Program>? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath)
{
ExifDirectory? exifDirectory;
MinimumYearAndPathCombined? minimumYearAndPathCombined;
try
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
catch (Exception)
{
exifDirectory = null;
minimumYearAndPathCombined = null;
logger?.LogWarning("<{filePath}>", filePath.FullName);
}
if (exifDirectory is null || minimumYearAndPathCombined is null)
logger?.LogWarning("<{filePath}>", filePath.FullName);
else
{
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
if (dateTime is null)
logger?.LogWarning("<{filePath}>", filePath.FullName);
else
{
File.SetCreationTime(filePath.FullName, dateTime.Value);
Thread.Sleep(500);
File.SetLastWriteTime(filePath.FullName, dateTime.Value);
}
}
}
private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles) private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles)
{ {
@ -189,126 +408,6 @@ public partial class Rename : IRename, IDisposable
} }
} }
private void JustMediaDate(ILogger<Program>? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath)
{
ExifDirectory? exifDirectory;
MinimumYearAndPathCombined? minimumYearAndPathCombined;
try
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
catch (Exception)
{
exifDirectory = null;
minimumYearAndPathCombined = null;
logger?.LogWarning("<{filePath}>", filePath.FullName);
}
if (exifDirectory is null || minimumYearAndPathCombined is null)
logger?.LogWarning("<{filePath}>", filePath.FullName);
else
{
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
if (dateTime is null)
logger?.LogWarning("<{filePath}>", filePath.FullName);
else
{
File.SetCreationTime(filePath.FullName, dateTime.Value);
Thread.Sleep(500);
File.SetLastWriteTime(filePath.FullName, dateTime.Value);
}
}
}
private void SetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, int index, KeyValuePair<string, List<FileHolder>> keyValuePair, List<FirstPass> results)
{
FilePath filePath;
FirstPass firstPass;
string directoryName;
ExifDirectory exifDirectory;
List<FileHolder> sidecarFiles;
DeterministicHashCode deterministicHashCode;
bool fastForwardMovingPictureExpertsGroupUsed;
MinimumYearAndPathCombined minimumYearAndPathCombined;
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
foreach (FileHolder fileHolder in keyValuePair.Value)
{
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
continue;
if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
continue;
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
continue;
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
{
fastForwardMovingPictureExpertsGroupFiles = null;
deterministicHashCode = new(null, filePath.Id, null);
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
continue;
}
else
{
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
}
sidecarFiles = [];
filePath = FilePath.Get(filePath, deterministicHashCode);
for (int i = 0; i < keyValuePair.Value.Count; i++)
{
if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value)
JustMediaDate(logger, appSettings, metadata, filePath);
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
continue;
sidecarFiles.Add(keyValuePair.Value[i]);
}
try
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
catch (Exception)
{
logger?.LogWarning("<{filePath}>", filePath.FullName);
continue;
}
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
{
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
File.Delete(fastForwardMovingPictureExpertsGroupFile);
}
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
fastForwardMovingPictureExpertsGroupUsed = true;
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
results.Add(firstPass);
}
}
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
{
List<FirstPass> results = [];
int index = -1;
TimeSpan timeSpan;
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
{
index += 1;
rename.Tick();
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
{
if (appSettings.RenameSettings.InPlaceMoveDirectory)
continue;
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
}
if (keyValuePair.Value.Count > 2)
throw new NotSupportedException("Too many sidecar files!");
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
timeSpan = new(DateTime.Now.Ticks - ticks);
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
break;
}
return results;
}
private static ReadOnlyCollection<Record> GetRecordCollection(AppSettings appSettings, List<FirstPass> collection) private static ReadOnlyCollection<Record> GetRecordCollection(AppSettings appSettings, List<FirstPass> collection)
{ {
List<Record> results = []; List<Record> results = [];
@ -336,172 +435,22 @@ public partial class Rename : IRename, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile) private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
{
List<FirstPass> results;
FirstPass firstPass;
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
if (appSettingsMaxDegreeOfParallelism == 1)
{
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
}
else
{
results = [];
List<string> distinct = [];
List<MetadataGroup> metadataGroups = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
Thread.Sleep(500);
foreach (MetadataGroup metadataGroup in metadataGroups)
{
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
else
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
results.Add(firstPass);
}
}
if (!string.IsNullOrEmpty(checkFile))
{
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
}
return results;
}
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
{
ReadOnlyCollection<Record> results;
List<FirstPass> collection;
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile))
collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile);
else
{
string json = File.ReadAllText(checkFile);
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
}
if (appSettings.RenameSettings.JustMediaDate)
results = new([]);
else
results = GetRecordCollection(appSettings, collection);
return results;
}
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
{ {
string paddedId;
Identifier identifier;
List<Identifier> identifiers = [];
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
foreach (Record record in recordCollection) foreach (Record record in recordCollection)
{ {
if (record.ExifDirectory.FilePath.Id is null) if (record.ExifDirectory.FilePath.Id is null)
continue; continue;
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length) paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null);
throw new NotSupportedException(); identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.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 string GetTFW(Record 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(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
{
string? result;
string year = record.DateTime.Year.ToString();
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
result = null;
else
{
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
result = null;
else
{
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
isWrongYear = null;
string directoryName;
string tfw = GetTFW(record, isWrongYear);
string? maker = IMetadata.GetMaker(record.ExifDirectory);
string rootDirectory = appSettings.ResultSettings.RootDirectory;
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2)
directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
else
{
directoryName = record.DateTime.ToString("yyyy-MM-dd");
if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value))
directoryName = value;
}
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
}
}
return result;
}
private static List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
{
List<ToDo> results = [];
ToDo toDo;
string checkFile;
FilePath filePath;
string checkFileExtension;
foreach (FileHolder fileHolder in record.SidecarFiles)
{
checkFileExtension = fileHolder.ExtensionLowered;
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, 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);
toDo = new(Directory: checkDirectory,
FileInfo: new(filePath.FullName),
File: checkFile,
JsonFile: false);
results.Add(toDo);
}
return results;
}
private static bool? GetDirectoryCheck(ResultSettings resultSettings)
{
bool? result = null;
IEnumerable<string> files;
string[] directories = Directory.GetDirectories(resultSettings.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<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection) private static ReadOnlyCollection<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection)
@ -589,17 +538,114 @@ public partial class Rename : IRename, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection) private static bool? GetDirectoryCheck(ResultSettings resultSettings)
{ {
List<string> distinct = []; bool? result = null;
foreach (ToDo toDo in toDoCollection) IEnumerable<string> files;
string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{ {
if (toDo.Directory is null || distinct.Contains(toDo.Directory)) files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
continue; foreach (string _ in files)
if (!Directory.Exists(toDo.Directory)) {
_ = Directory.CreateDirectory(toDo.Directory); if (result is null)
distinct.Add(toDo.Directory); result = false;
else if (result.Value)
result = true;
break;
}
if (result is not null && result.Value)
break;
} }
return result;
}
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
{
foreach (Record record in recordCollection)
{
if (record.ExifDirectory.FilePath.Id is null)
continue;
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length)
throw new NotSupportedException();
}
}
private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
{
string? result;
string year = record.DateTime.Year.ToString();
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
result = null;
else
{
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
result = null;
else
{
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
isWrongYear = null;
string directoryName;
string tfw = GetTFW(record, isWrongYear);
string? maker = IMetadata.GetMaker(record.ExifDirectory);
string rootDirectory = appSettings.ResultSettings.RootDirectory;
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2)
directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
else
{
directoryName = record.DateTime.ToString("yyyy-MM-dd");
if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value))
directoryName = value;
}
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
}
}
return result;
}
private static string GetTFW(Record 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 List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
{
List<ToDo> results = [];
ToDo toDo;
string checkFile;
FilePath filePath;
string checkFileExtension;
foreach (FileHolder fileHolder in record.SidecarFiles)
{
checkFileExtension = fileHolder.ExtensionLowered;
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, 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);
toDo = new(Directory: checkDirectory,
FileInfo: new(filePath.FullName),
File: checkFile,
JsonFile: false);
results.Add(toDo);
}
return results;
} }
private ReadOnlyCollection<string> RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection<ToDo> toDoCollection) private ReadOnlyCollection<string> RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection<ToDo> toDoCollection)
@ -642,65 +688,16 @@ public partial class Rename : IRename, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection) private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection)
{ {
string paddedId; List<string> distinct = [];
Identifier identifier; foreach (ToDo toDo in toDoCollection)
List<Identifier> identifiers = [];
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
foreach (Record record in recordCollection)
{ {
if (record.ExifDirectory.FilePath.Id is null) if (toDo.Directory is null || distinct.Contains(toDo.Directory))
continue; continue;
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null); if (!Directory.Exists(toDo.Directory))
identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks); _ = Directory.CreateDirectory(toDo.Directory);
identifiers.Add(identifier); distinct.Add(toDo.Directory);
}
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<int> GetIds(RenameSettings renameSettings)
{
ReadOnlyCollection<int> results;
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.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(renameSettings.RelativePropertyCollectionFile))
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
return results;
}
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
{
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
if (!Directory.Exists(sourceDirectory))
_ = Directory.CreateDirectory(sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
if (files.Count > 0)
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
{
if (recordCollection.Count > 0)
recordCollection = new([]);
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
}
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
{
DirectoryInfo directoryInfo = new(sourceDirectory);
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
if (lines.Count != 0)
{
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
}
} }
} }

View File

@ -6,9 +6,6 @@ public interface ICompareSettings
public string FacesFileNameExtension { init; get; } public string FacesFileNameExtension { init; get; }
public string FacesHiddenFileNameExtension { init; get; } public string FacesHiddenFileNameExtension { init; get; }
public string FacesPartsFileNameExtension { init; get; } public string FacesPartsFileNameExtension { init; get; }
public string[] IgnoreExtensions { init; get; }
public int MaxDegreeOfParallelism { init; get; } public int MaxDegreeOfParallelism { init; get; }
public string[] ValidImageFormatExtensions { init; get; }
public string[] ValidVideoFormatExtensions { init; get; }
} }

View File

@ -3,9 +3,6 @@ namespace View_by_Distance.Shared.Models.Properties;
public interface IRenameSettings public interface IRenameSettings
{ {
public string[] IgnoreExtensions { init; get; }
public bool SkipIdFiles { init; get; } public bool SkipIdFiles { init; get; }
public string[] ValidImageFormatExtensions { init; get; }
public string[] ValidVideoFormatExtensions { init; get; }
} }

View File

@ -3,8 +3,4 @@ namespace View_by_Distance.Shared.Models.Properties;
public interface IWindowsSettings public interface IWindowsSettings
{ {
public string[] IgnoreExtensions { init; get; }
public string[] ValidImageFormatExtensions { init; get; }
public string[] ValidVideoFormatExtensions { init; get; }
} }

View File

@ -8,12 +8,15 @@ public record ResultSettings(string DateGroup,
string ModelName, string ModelName,
int NumberOfJitters, int NumberOfJitters,
int NumberOfTimesToUpsample, int NumberOfTimesToUpsample,
string[] IgnoreExtensions,
string PredictorModelName, string PredictorModelName,
int ResultAllInOneSubdirectoryLength, int ResultAllInOneSubdirectoryLength,
string ResultCollection, string ResultCollection,
string ResultContent, string ResultContent,
string ResultSingleton, string ResultSingleton,
string RootDirectory) string RootDirectory,
string[] ValidImageFormatExtensions,
string[] ValidVideoFormatExtensions)
{ {
public override string ToString() public override string ToString()

View File

@ -5,44 +5,69 @@ public interface IId
const int DeterministicHashCode = 9876543; const int DeterministicHashCode = 9876543;
static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) => public static int GetDeterministicHashCode(byte[] value) =>
metadataSettings.Offset == DeterministicHashCode;
string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
GetId(resultSettings, metadataSettings, intelligentId);
static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
Id.GetId(resultSettings, metadataSettings, intelligentId);
string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9'
&& fileNameFirstSegment.All(char.IsNumber);
bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
int TestStatic_GetDeterministicHashCode(byte[] value) =>
GetDeterministicHashCode(value);
static int GetDeterministicHashCode(byte[] value) =>
Id.GetDeterministicHashCode(value); Id.GetDeterministicHashCode(value);
public static byte GetHasIgnoreKeyword(FilePath filePath) =>
Id.GetHasIgnoreKeyword(filePath);
public static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) =>
metadataSettings.Offset == DeterministicHashCode;
public static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
Id.GetHasDateTimeOriginal(resultSettings, filePath);
public static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
Id.GetMissingDateTimeOriginal(resultSettings, filePath);
public static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
public static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
Id.GetId(resultSettings, metadataSettings, intelligentId);
public static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
&& fileNameFirstSegment.All(char.IsNumber);
public static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
internal int TestStatic_GetDeterministicHashCode(byte[] value) =>
GetDeterministicHashCode(value);
internal byte TestStatic_GetHasIgnoreKeyword(FilePath filePath) =>
GetHasIgnoreKeyword(filePath);
internal byte TestStatic_GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
GetHasDateTimeOriginal(resultSettings, filePath);
internal byte TestStatic_GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
GetMissingDateTimeOriginal(resultSettings, filePath);
internal bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
internal int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
GetId(resultSettings, metadataSettings, intelligentId);
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
} }

View File

@ -1,12 +1,11 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models.Properties;
namespace View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Shared.Models.Stateless;
public interface IRename public interface IRename
{ {
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath); ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(FilePath filePath); DeterministicHashCode GetDeterministicHashCode(FilePath filePath);
void ConstructProgressBar(int maxTicks, string message); void ConstructProgressBar(int maxTicks, string message);
void Tick(); void Tick();

View File

@ -1,12 +1,11 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models.Properties;
namespace View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Shared.Models.Stateless;
public interface IWindows public interface IWindows
{ {
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings windowsSettings, HttpClient? httpClient, FilePath filePath); ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath); DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri); DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri);
void ConstructProgressBar(int maxTicks, string message); void ConstructProgressBar(int maxTicks, string message);

View File

@ -5,19 +5,34 @@ namespace View_by_Distance.Shared.Models.Stateless;
internal abstract class Id internal abstract class Id
{ {
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) internal static int GetDeterministicHashCode(byte[] value)
{ {
bool result; int result;
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength) unchecked
result = false;
else
{ {
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber); int hash1 = (5381 << 16) + 5381;
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0])); int hash2 = hash1;
for (int i = 0; i < value.Length; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ value[i];
if (i == value.Length - 1)
break;
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
}
result = hash1 + (hash2 * 1566083941);
} }
return result; return result;
} }
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
(byte)(filePath.Id > -1 ? 8 : 2);
internal static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
internal static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : 5);
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
{ {
int result; int result;
@ -28,13 +43,26 @@ internal abstract class Id
_ = results.Append(intelligentId[i]); _ = results.Append(intelligentId[i]);
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]); _ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
result = int.Parse(results.ToString()); result = int.Parse(results.ToString());
if (intelligentId[^1] is '1' or '2' or '3') if (intelligentId[^1] is '1' or '2' or '3' or '4')
result *= -1; result *= -1;
else if (intelligentId[^1] is not '9' and not '8' and not '7') else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
throw new NotSupportedException(); throw new NotSupportedException();
return result; return result;
} }
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment)
{
bool result;
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength)
result = false;
else
{
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
}
return result;
}
#pragma warning disable IDE0060 #pragma warning disable IDE0060
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
#pragma warning restore IDE0060 #pragma warning restore IDE0060
@ -80,23 +108,4 @@ internal abstract class Id
return result; return result;
} }
internal static int GetDeterministicHashCode(byte[] value)
{
int result;
unchecked
{
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;
for (int i = 0; i < value.Length; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ value[i];
if (i == value.Length - 1)
break;
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
}
result = hash1 + (hash2 * 1566083941);
}
return result;
}
} }

View File

@ -5,35 +5,29 @@ namespace View_by_Distance.Shared.Models.Stateless;
internal abstract class XPath internal abstract class XPath
{ {
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower) private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
{ {
string result; Dictionary<byte, List<string>> results = [];
if (forceExtensionToLower) List<string>? c;
foreach (CombinedEnumAndIndex cei in collection)
{ {
string extension = Path.GetExtension(path); if (!results.TryGetValue(cei.Enum, out c))
string extensionLowered = Path.GetExtension(path).ToLower();
if (extension != extensionLowered)
{ {
string? directoryName = Path.GetDirectoryName(path); results.Add(cei.Enum, []);
if (string.IsNullOrEmpty(directoryName)) if (!results.TryGetValue(cei.Enum, out c))
throw new NullReferenceException(directoryName); throw new Exception();
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
if (string.IsNullOrEmpty(fileNameWithoutExtension))
throw new NullReferenceException(fileNameWithoutExtension);
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
} }
c.Add(cei.Combined);
} }
result = path[length..].Replace(@"\", "/"); return Convert(results);
return result;
} }
internal static bool DeleteEmptyDirectories(string rootDirectory) private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs)
{ {
bool result; Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
List<string> results = []; foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
DeleteEmptyDirectories(rootDirectory, results); results.Add(keyValuePair.Key, new(keyValuePair.Value));
result = results.Count > 0; return results.AsReadOnly();
return result;
} }
internal static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) internal static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories)
@ -71,45 +65,56 @@ internal abstract class XPath
} }
} }
internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches) internal static byte GetEnum(FilePath filePath) =>
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
private static byte GetEnum(bool? ik, bool? dto)
{ {
bool result; byte result;
string text; if (ik is not null && ik.Value && dto is not null && dto.Value)
if (!compareBeforeWrite) result = 11;
result = true; else if (ik is not null && ik.Value && dto is not null && !dto.Value)
result = 15;
else if (ik is not null && ik.Value && dto is null)
result = 19;
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
result = 51;
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
result = 55;
else if (ik is not null && !ik.Value && dto is null)
result = 59;
else if (ik is null && dto is not null && dto.Value)
result = 91;
else if (ik is null && dto is not null && !dto.Value)
result = 95;
else if (ik is null && dto is null)
result = 99;
else else
{ throw new Exception();
if (!File.Exists(path))
text = string.Empty;
else
text = File.ReadAllText(path);
result = text != contents;
if (!result && updateDateWhenMatches)
{
if (updateToWhenMatches is null)
File.SetLastWriteTime(path, DateTime.Now);
else
File.SetLastWriteTime(path, updateToWhenMatches.Value);
}
}
if (result)
{
if (path.Contains("()"))
File.WriteAllText(path, contents);
else if (path.Contains("{}") && !path.EndsWith(".json"))
File.WriteAllText(path, contents);
else if (path.Contains("[]") && !path.EndsWith(".json"))
File.WriteAllText(path, contents);
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
File.WriteAllText(path, contents);
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
File.WriteAllText(path, contents);
else
File.WriteAllText(path, contents);
}
return result; return result;
} }
internal static List<string> GetDirectories(string directory)
{
List<string> results = [];
string? checkDirectory = directory;
string? pathRoot = Path.GetPathRoot(directory);
if (string.IsNullOrEmpty(pathRoot))
throw new NullReferenceException(nameof(pathRoot));
if (Directory.Exists(directory))
results.Add(directory);
for (int i = 0; i < int.MaxValue; i++)
{
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
break;
results.Add(checkDirectory);
}
results.Add(pathRoot);
results.Reverse();
return results;
}
internal static List<string> GetDirectoryNames(string directory) internal static List<string> GetDirectoryNames(string directory)
{ {
List<string> results = []; List<string> results = [];
@ -146,83 +151,15 @@ internal abstract class XPath
return results; return results;
} }
internal static List<string> GetDirectories(string directory) internal static bool DeleteEmptyDirectories(string rootDirectory)
{ {
bool result;
List<string> results = []; List<string> results = [];
string? checkDirectory = directory; DeleteEmptyDirectories(rootDirectory, results);
string? pathRoot = Path.GetPathRoot(directory); result = results.Count > 0;
if (string.IsNullOrEmpty(pathRoot))
throw new NullReferenceException(nameof(pathRoot));
if (Directory.Exists(directory))
results.Add(directory);
for (int i = 0; i < int.MaxValue; i++)
{
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
break;
results.Add(checkDirectory);
}
results.Add(pathRoot);
results.Reverse();
return results;
}
internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
{
int result = 0;
string? directory;
string? checkDirectory;
List<string> results = [];
checkDirectory = sourceDirectory;
for (int i = 0; i < int.MaxValue; i++)
{
result += 1;
directory = Path.GetFileName(checkDirectory);
if (string.IsNullOrEmpty(directory))
break;
results.Add(directory);
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (checkDirectory == rootDirectory)
break;
}
results.Reverse();
return new(result, results);
}
internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
{
string result;
string? checkDirectory;
checkDirectory = Path.GetDirectoryName(sourceDirectory);
for (int i = 0; i < level; i++)
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory))
throw new Exception();
checkDirectory = Path.Combine(checkDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
result = checkDirectory;
return result; return result;
} }
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
{
DateTime dateTime = new(ticks);
IEnumerable<string> fileSystemEntries;
string[] directories;
if (!Directory.Exists(rootDirectory))
directories = [];
else
directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
foreach (string directory in directories)
{
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
if (fileSystemEntries.Any())
continue;
Directory.SetLastWriteTime(directory, dateTime);
}
}
internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory)
{ {
bool check; bool check;
@ -265,49 +202,117 @@ internal abstract class XPath
} }
} }
private static byte GetEnum(bool? ik, bool? dto) internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
{ {
byte result; DateTime dateTime = new(ticks);
if (ik is not null && ik.Value && dto is not null && dto.Value) IEnumerable<string> fileSystemEntries;
result = 11; string[] directories;
else if (ik is not null && ik.Value && dto is not null && !dto.Value) if (!Directory.Exists(rootDirectory))
result = 15; directories = [];
else if (ik is not null && ik.Value && dto is null)
result = 19;
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
result = 51;
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
result = 55;
else if (ik is not null && !ik.Value && dto is null)
result = 59;
else if (ik is null && dto is not null && dto.Value)
result = 91;
else if (ik is null && dto is not null && !dto.Value)
result = 95;
else if (ik is null && dto is null)
result = 99;
else else
throw new Exception(); directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
foreach (string directory in directories)
{
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
if (fileSystemEntries.Any())
continue;
Directory.SetLastWriteTime(directory, dateTime);
}
}
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower)
{
string result;
if (forceExtensionToLower)
{
string extension = Path.GetExtension(path);
string extensionLowered = Path.GetExtension(path).ToLower();
if (extension != extensionLowered)
{
string? directoryName = Path.GetDirectoryName(path);
if (string.IsNullOrEmpty(directoryName))
throw new NullReferenceException(directoryName);
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
if (string.IsNullOrEmpty(fileNameWithoutExtension))
throw new NullReferenceException(fileNameWithoutExtension);
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
}
}
result = path[length..].Replace(@"\", "/");
return result; return result;
} }
internal static byte GetEnum(FilePath filePath) => internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); {
string result;
string? checkDirectory;
checkDirectory = Path.GetDirectoryName(sourceDirectory);
for (int i = 0; i < level; i++)
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory))
throw new Exception();
checkDirectory = Path.Combine(checkDirectory, directoryName);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
result = checkDirectory;
return result;
}
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileNameWithoutExtension) internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
{
int result = 0;
string? directory;
string? checkDirectory;
List<string> results = [];
checkDirectory = sourceDirectory;
for (int i = 0; i < int.MaxValue; i++)
{
result += 1;
directory = Path.GetFileName(checkDirectory);
if (string.IsNullOrEmpty(directory))
break;
results.Add(directory);
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (checkDirectory == rootDirectory)
break;
}
results.Reverse();
return new(result, results);
}
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath)
{ {
CombinedEnumAndIndex result; CombinedEnumAndIndex result;
if (filePath.Id is not null)
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.Id.Value.ToString());
else
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.NameWithoutExtension);
return result;
}
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath, string fileNameWithoutExtension)
{
CombinedEnumAndIndex result;
byte @enum;
int converted; int converted;
string combined; string combined;
byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(resultSettings, filePath);
if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null)
throw new NotImplementedException();
if (filePath.HasIgnoreKeyword.Value)
@enum = IId.GetHasIgnoreKeyword(filePath);
else if (!filePath.HasDateTimeOriginal.Value)
@enum = missingDateTimeOriginal;
else
@enum = IId.GetHasDateTimeOriginal(resultSettings, filePath);
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0]; string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ?
string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ? new('-', resultSettings.ResultAllInOneSubdirectoryLength) :
new('-', resultAllInOneSubdirectoryLength) : fileNameBeforeFirst[^resultSettings.ResultAllInOneSubdirectoryLength..];
fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..];
if (check.Any(l => !char.IsNumber(l))) if (check.Any(l => !char.IsNumber(l)))
{ {
combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}"; combined = $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}";
converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}"); converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}");
} }
else else
{ {
@ -318,16 +323,66 @@ internal abstract class XPath
return result; return result;
} }
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches)
{ {
CombinedEnumAndIndex result; bool result;
if (filePath.Id is not null) string text;
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString()); if (!compareBeforeWrite)
result = true;
else else
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.NameWithoutExtension); {
if (!File.Exists(path))
text = string.Empty;
else
text = File.ReadAllText(path);
result = text != contents;
if (!result && updateDateWhenMatches)
{
if (updateToWhenMatches is null)
File.SetLastWriteTime(path, DateTime.Now);
else
File.SetLastWriteTime(path, updateToWhenMatches.Value);
}
}
if (result)
{
if (path.Contains("()"))
File.WriteAllText(path, contents);
else if (path.Contains("{}") && !path.EndsWith(".json"))
File.WriteAllText(path, contents);
else if (path.Contains("[]") && !path.EndsWith(".json"))
File.WriteAllText(path, contents);
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
File.WriteAllText(path, contents);
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
File.WriteAllText(path, contents);
else
File.WriteAllText(path, contents);
}
return result; return result;
} }
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
{
Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
if (jsonGroups is not null)
{
DateTime dateTime = DateTime.Now;
ReadOnlyCollection<int> years = GetYears(resultSettings);
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>? k;
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime);
foreach (int year in years)
{
results.Add(year, []);
if (!results.TryGetValue(year, out k))
throw new NullReferenceException(nameof(k));
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
k.Add(keyValuePair.Key, keyValuePair.Value);
}
}
return Convert(results);
}
private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings) private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings)
{ {
List<int> results = []; List<int> results = [];
@ -337,44 +392,6 @@ internal abstract class XPath
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static byte[] GetBytes() =>
[
11,
15,
19,
51,
55,
59,
91,
95,
99
];
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
{
Dictionary<byte, ReadOnlyCollection<string>> results = [];
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, new(keyValuePair.Value));
return results.AsReadOnly();
}
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
{
Dictionary<byte, List<string>> results = [];
List<string>? c;
foreach (CombinedEnumAndIndex cei in collection)
{
if (!results.TryGetValue(cei.Enum, out c))
{
results.Add(cei.Enum, []);
if (!results.TryGetValue(cei.Enum, out c))
throw new Exception();
}
c.Add(cei.Combined);
}
return Convert(results);
}
private static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime) private static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime)
{ {
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = []; Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
@ -428,33 +445,25 @@ internal abstract class XPath
return results.AsReadOnly(); return results.AsReadOnly();
} }
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs) private static byte[] GetBytes() =>
[
1,
2,
3,
4,
5,
6,
7,
8,
9
];
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
{ {
Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = []; Dictionary<byte, ReadOnlyCollection<string>> results = [];
foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs) foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, new(keyValuePair.Value)); results.Add(keyValuePair.Key, new(keyValuePair.Value));
return results.AsReadOnly(); return results.AsReadOnly();
} }
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
{
Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
if (jsonGroups is not null)
{
DateTime dateTime = DateTime.Now;
ReadOnlyCollection<int> years = GetYears(resultSettings);
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>? k;
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime);
foreach (int year in years)
{
results.Add(year, []);
if (!results.TryGetValue(year, out k))
throw new NullReferenceException(nameof(k));
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
k.Add(keyValuePair.Key, keyValuePair.Value);
}
}
return Convert(results);
}
} }

View File

@ -6,12 +6,9 @@ namespace View_by_Distance.Windows.Models;
public record WindowsSettings(string Company, public record WindowsSettings(string Company,
string? Host, string? Host,
string[] IgnoreExtensions,
int MaxDegreeOfParallelism, int MaxDegreeOfParallelism,
string? Page, string? Page,
string[] SidecarExtensions, string[] SidecarExtensions,
string[] ValidImageFormatExtensions,
string[] ValidVideoFormatExtensions,
bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings
{ {

View File

@ -9,7 +9,6 @@ using System.Text.Json;
using View_by_Distance.Metadata.Models; using View_by_Distance.Metadata.Models;
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; using View_by_Distance.Shared.Models.Stateless;
using View_by_Distance.Windows.Models; using View_by_Distance.Windows.Models;
@ -21,48 +20,93 @@ public partial class Windows : IWindows, IDisposable
private ProgressBar? _ProgressBar; private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions; private readonly ProgressBarOptions _ProgressBarOptions;
public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console) DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
GetDeterministicHashCode(httpClient, uri);
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
{ {
if (isSilent) DeterministicHashCode result;
{ } if (httpClient is not null)
if (args is null) result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
throw new NullReferenceException(nameof(args)); else
if (console is null) {
throw new NullReferenceException(nameof(console)); Stream stream = File.OpenRead(filePath.FullName);
IWindows windows = this; result = GetDeterministicHashCode(stream);
long ticks = DateTime.Now.Ticks; stream.Dispose();
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; }
WindowsWork(logger, appSettings, windows, ticks); return result;
}
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri)
{
DeterministicHashCode result;
Stream stream = GetStream(httpClient, uri);
result = GetDeterministicHashCode(stream);
stream.Dispose();
return result;
}
private static Stream GetStream(HttpClient httpClient, Uri uri)
{
Stream result;
Task<Stream> task = httpClient.GetStreamAsync(uri);
task.Wait();
result = task.Result;
return result;
}
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
{
DeterministicHashCode result;
int? id;
int? width;
int? height;
try
{
#pragma warning disable CA1416
using Image image = Image.FromStream(stream);
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);
#pragma warning restore CA1416
id = IId.GetDeterministicHashCode(bytes);
}
catch (Exception)
{
id = null;
width = null;
height = null;
}
result = new(height, id, width);
return result;
} }
void IWindows.Tick() => void IWindows.Tick() =>
_ProgressBar?.Tick(); _ProgressBar?.Tick();
void IWindows.ConstructProgressBar(int maxTicks, string message)
{
_ProgressBar?.Dispose();
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
}
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
_ProgressBar?.Dispose(); _ProgressBar?.Dispose();
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
private static void DownloadFile(HttpClient httpClient, FilePath filePath) void IWindows.ConstructProgressBar(int maxTicks, string message)
{ {
FileStream fileStream = new(filePath.FullName, FileMode.Truncate); _ProgressBar?.Dispose();
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName); _ProgressBar = new(maxTicks, message, _ProgressBarOptions);
httpResponseMessage.Wait();
Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
task.Wait();
} }
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath) ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath)
{ {
List<string> results = []; List<string> results = [];
bool isValidVideoFormatExtensions = WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered); bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
if (isValidVideoFormatExtensions) if (isValidVideoFormatExtensions)
{ {
bool check; bool check;
@ -94,75 +138,54 @@ public partial class Windows : IWindows, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
#pragma warning disable CA1416 private static void DownloadFile(HttpClient httpClient, FilePath filePath)
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
{ {
DeterministicHashCode result; FileStream fileStream = new(filePath.FullName, FileMode.Truncate);
int? id; Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
int? width; httpResponseMessage.Wait();
int? height; Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
try
{
using Image image = Image.FromStream(stream);
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;
}
private static Stream GetStream(HttpClient httpClient, Uri uri)
{
Stream result;
Task<Stream> task = httpClient.GetStreamAsync(uri);
task.Wait(); task.Wait();
result = task.Result;
return result;
} }
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri) public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
{ {
DeterministicHashCode result; if (isSilent)
Stream stream = GetStream(httpClient, uri); { }
result = GetDeterministicHashCode(stream); if (args is null)
stream.Dispose(); throw new NullReferenceException(nameof(args));
return result; if (console is null)
throw new NullReferenceException(nameof(console));
IWindows windows = this;
long ticks = DateTime.Now.Ticks;
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
WindowsWork(logger, appSettings, windows, ticks);
} }
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) => private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
GetDeterministicHashCode(httpClient, uri);
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
{ {
DeterministicHashCode result; if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
if (httpClient is not null) Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
else else
{ {
Stream stream = File.OpenRead(filePath.FullName); string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
result = GetDeterministicHashCode(stream); WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
stream.Dispose();
} }
return result;
} }
#pragma warning restore CA1416 private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page)
{
List<string> messages = [];
HttpClient httpClient = new();
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception();
windows.ConstructProgressBar(collection.Count, nameof(Verify));
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages));
httpClient.Dispose();
foreach (string message in messages)
logger?.LogWarning("{message}", message);
}
private static ReadOnlyCollection<NginxFileSystem>? GetRecursiveCollection(HttpClient httpClient, string host, string page) private static ReadOnlyCollection<NginxFileSystem>? GetRecursiveCollection(HttpClient httpClient, string host, string page)
{ {
@ -227,19 +250,46 @@ public partial class Windows : IWindows, IDisposable
messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})"); messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})");
} }
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page) private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
{ {
List<string> messages = []; ReadOnlyCollection<FirstPass> results;
HttpClient httpClient = new(); if (!Directory.Exists(sourceDirectory))
_ = Directory.CreateDirectory(sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
if (files.Count > 0)
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism; int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception(); windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
windows.ConstructProgressBar(collection.Count, nameof(Verify)); if (appSettingsMaxDegreeOfParallelism == 1)
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) => results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata);
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages)); else
httpClient.Dispose(); results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
foreach (string message in messages) string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
logger?.LogWarning("{message}", message); File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
}
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
{
List<FirstPass> results = [];
int index = -1;
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
keyValuePairs = IMetadata.GetKeyValuePairs(files);
else
{
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
}
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
{
if (keyValuePair.Value.Count > 2)
throw new NotSupportedException("Too many sidecar files!");
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
}
return results.AsReadOnly();
} }
private static ReadOnlyCollection<NginxFileSystem> GetRecursiveCollection(string host, string page) private static ReadOnlyCollection<NginxFileSystem> GetRecursiveCollection(string host, string page)
@ -270,7 +320,7 @@ public partial class Windows : IWindows, IDisposable
{ {
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered)) if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
continue; continue;
if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
continue; continue;
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result); filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result);
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null)) if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
@ -285,7 +335,7 @@ public partial class Windows : IWindows, IDisposable
} }
else else
{ {
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath); fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, httpClient, filePath);
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result); fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result);
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath); deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
} }
@ -310,7 +360,7 @@ public partial class Windows : IWindows, IDisposable
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles) foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
File.Delete(fastForwardMovingPictureExpertsGroupFile); File.Delete(fastForwardMovingPictureExpertsGroupFile);
} }
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered)) if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
fastForwardMovingPictureExpertsGroupUsed = true; fastForwardMovingPictureExpertsGroupUsed = true;
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray()); firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
results.Add(firstPass); results.Add(firstPass);
@ -318,27 +368,6 @@ public partial class Windows : IWindows, IDisposable
return result; return result;
} }
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
{
List<FirstPass> results = [];
int index = -1;
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
keyValuePairs = IMetadata.GetKeyValuePairs(files);
else
{
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
}
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
{
if (keyValuePair.Value.Count > 2)
throw new NotSupportedException("Too many sidecar files!");
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
}
return results.AsReadOnly();
}
private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism) private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
{ {
List<FirstPass> results = []; List<FirstPass> results = [];
@ -346,12 +375,12 @@ public partial class Windows : IWindows, IDisposable
List<string> distinct = []; List<string> distinct = [];
List<MetadataGroup> metadataGroups = []; List<MetadataGroup> metadataGroups = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups)); files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, metadata, distinct, metadataGroups));
if (_ProgressBar?.CurrentTick != results.Count) if (_ProgressBar?.CurrentTick != results.Count)
throw new NotSupportedException(); throw new NotSupportedException();
foreach (MetadataGroup metadataGroup in metadataGroups) foreach (MetadataGroup metadataGroup in metadataGroups)
{ {
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered)) if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
else else
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray()); firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
@ -360,36 +389,4 @@ public partial class Windows : IWindows, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
{
ReadOnlyCollection<FirstPass> results;
if (!Directory.Exists(sourceDirectory))
_ = Directory.CreateDirectory(sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
if (files.Count > 0)
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
if (appSettingsMaxDegreeOfParallelism == 1)
results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata);
else
results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
}
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
{
if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
else
{
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
}
}
} }