6 Commits

Author SHA1 Message Date
05fb8685d9 Removed Rectangle from LocationContainer
mapped-ids-then-whole-percentages-to-location-container

save-extracted-face

save-extracted-java-script-object-notation
2025-07-06 10:45:59 -07:00
2c9b1a68c0 House Cleaning 2025-07-05 13:37:47 -07:00
8f7fd02ba8 Interface over passing ticks 2025-07-04 09:11:05 -07:00
93598255c0 Changed GetDimensions to handle a stream at the end and one exit 2025-06-29 08:33:58 -07:00
9a51d995cc validation-image-file 2025-04-20 14:16:03 -07:00
23256c8152 Alignment with Console 2025-04-06 15:45:10 -07:00
31 changed files with 943 additions and 662 deletions

View File

@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using ShellProgressBar;
using System.Collections.ObjectModel;
using System.Drawing;
using View_by_Distance.Compare.Models;
using View_by_Distance.Distance.Models.Stateless;
using View_by_Distance.Face.Models.Stateless;
@ -14,6 +15,9 @@ namespace View_by_Distance.Compare;
public partial class Compare : ICompare, IDisposable
{
public long Ticks { get; init; }
public int? CurrentTick => _ProgressBar?.CurrentTick;
private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions;
@ -41,54 +45,56 @@ public partial class Compare : ICompare, IDisposable
if (console is null)
throw new NullReferenceException(nameof(console));
ICompare compare = this;
long ticks = DateTime.Now.Ticks;
Ticks = DateTime.Now.Ticks;
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
CompareWork(logger, appSettings, compare, ticks);
CompareWork(logger, appSettings, compare);
}
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare)
{
const int updated = 0;
DistanceLimits? distanceLimits;
logger?.LogInformation("{Ticks}", ticks);
ReadOnlyCollection<LocationContainer> matrix;
logger?.LogInformation("{Ticks}", compare.Ticks);
ReadOnlyCollection<SaveContainer> saveContainers;
ReadOnlyCollection<ExifDirectory> exifDirectories;
ReadOnlyCollection<LocationContainer> preFiltered;
ReadOnlyCollection<LocationContainer> postFiltered;
ReadOnlyDictionary<string, LocationContainer> onlyOne;
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, compare);
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer = GetMappedIdsThenWholePercentagesToLocationContainer(appSettings, compare, readOnlyCollections);
if (appSettings.CompareSettings.SaveExtractedFaces || appSettings.CompareSettings.SaveExtractedJavaScriptObjectNotation)
SaveExtracted(appSettings, mappedIdsThenWholePercentagesToLocationContainer);
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);
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, outputResolution);
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, readOnlyCollections, mappedIdsThenWholePercentagesToLocationContainer, exifDirectories);
if (preFiltered.Count == 0)
continue;
if (appSettings.CompareSettings.SaveExtractedFaces || appSettings.CompareSettings.SaveExtractedJavaScriptObjectNotation)
SaveExtracted(appSettings, preFiltered);
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);
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, compare, mappedIdsThenWholePercentagesToLocationContainer, 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);
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, outputResolution, onlyOne);
if (saveContainers.Count == 0)
continue;
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, updated, saveContainers);
}
}
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks)
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, ICompare compare)
{
bool result = appSettings.DistanceSettings.SaveSortingWithoutPerson;
if (!result)
@ -103,7 +109,7 @@ public partial class Compare : ICompare, IDisposable
{
string seasonDirectory;
DirectoryInfo directoryInfo;
DateTime dateTime = new(ticks);
DateTime dateTime = new(compare.Ticks);
string rootDirectory = appSettings.ResultSettings.RootDirectory;
(int season, string seasonName) = IDate.GetSeason(dateTime.DayOfYear);
string eDistanceContentDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(E_Distance), appSettings.ResultSettings.ResultContent);
@ -153,16 +159,127 @@ public partial class Compare : ICompare, IDisposable
return result;
}
private static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(AppSettings appSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedIdsThenWholePercentagesToLocationContainer(AppSettings appSettings, ICompare compare, ReadOnlyCollections readOnlyCollections)
{
ReadOnlyCollection<ExifDirectory> results;
ReadOnlyCollection<ExifDirectory> exifDirectories = IDistance.GetMapped(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.PeopleSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections);
if (exifDirectories.Count == 0 && !appSettings.DistanceSettings.SaveSortingWithoutPerson)
throw new NotSupportedException($"Switch {nameof(appSettings.DistanceSettings.SaveSortingWithoutPerson)}!");
results = IDistance.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> results;
results = IDistance.GetMappedIdsThenWholePercentagesToLocationContainer(appSettings.ResultSettings,
appSettings.MetadataSettings,
appSettings.PeopleSettings,
appSettings.DistanceSettings,
appSettings.CompareSettings,
compare,
readOnlyCollections);
if (results.Count == 0 && !appSettings.DistanceSettings.SaveSortingWithoutPerson)
throw new NotSupportedException($"Switch {nameof(appSettings.DistanceSettings.SaveSortingWithoutPerson)}!");
return results;
}
private void SaveExtracted(AppSettings appSettings, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer)
{
ReadOnlyCollection<string>? paths;
ReadOnlyDictionary<string, ReadOnlyCollection<string>> rootDirectoryFileNameToPaths = GetRootDirectoryFileNameToPaths(appSettings.ResultSettings, appSettings.CompareSettings);
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mappedIdsThenWholePercentagesToLocationContainer)
{
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
{
if (keyValue.Value.ExifDirectory is null || keyValue.Value.FaceFile?.Location is null)
continue;
if (rootDirectoryFileNameToPaths.TryGetValue(keyValue.Value.FilePath.FileNameFirstSegment, out paths))
{
if (appSettings.CompareSettings.SaveExtractedJavaScriptObjectNotation && keyValue.Value.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is not null)
SaveExtractedJavaScriptObjectNotation(keyValue.Key, keyValue.Value, paths);
if (appSettings.CompareSettings.SaveExtractedFaces)
SaveExtractedFace(keyValuePair.Key, keyValue.Key, keyValue.Value.ExifDirectory, keyValue.Value.FaceFile.Location, keyValue.Value.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, paths);
}
}
}
}
private static void SaveExtracted(AppSettings appSettings, ReadOnlyCollection<LocationContainer> preFiltered)
{
ReadOnlyCollection<string>? paths;
ReadOnlyDictionary<string, ReadOnlyCollection<string>> rootDirectoryFileNameToPaths = GetRootDirectoryFileNameToPaths(appSettings.ResultSettings, appSettings.CompareSettings);
foreach (LocationContainer locationContainer in preFiltered)
{
if (locationContainer?.FilePath?.Id is null || locationContainer?.WholePercentages is null || locationContainer?.ExifDirectory is null || locationContainer?.FaceFile?.Location is null)
continue;
if (rootDirectoryFileNameToPaths.TryGetValue(locationContainer.FilePath.FileNameFirstSegment, out paths))
{
if (appSettings.CompareSettings.SaveExtractedJavaScriptObjectNotation && locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is not null)
SaveExtractedJavaScriptObjectNotation(locationContainer.WholePercentages.Value, locationContainer, paths);
if (appSettings.CompareSettings.SaveExtractedFaces)
SaveExtractedFace(locationContainer.FilePath.Id.Value, locationContainer.WholePercentages.Value, locationContainer.ExifDirectory, locationContainer.FaceFile.Location, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, paths);
}
}
}
private static ReadOnlyDictionary<string, ReadOnlyCollection<string>> GetRootDirectoryFileNameToPaths(ResultSettings resultSettings, CompareSettings compareSettings)
{
Dictionary<string, ReadOnlyCollection<string>> results = [];
string key;
string extension;
List<string>? collection;
Dictionary<string, List<string>> keyValuePairs = [];
string[] files = !compareSettings.SaveExtractedFaces && !compareSettings.SaveExtractedJavaScriptObjectNotation ? [] : Directory.GetFiles(resultSettings.RootDirectory, "*", SearchOption.AllDirectories);
foreach (string file in files)
{
extension = Path.GetExtension(file);
if (resultSettings.IgnoreExtensions.Contains(extension))
continue;
key = Path.GetFileNameWithoutExtension(file);
if (!keyValuePairs.TryGetValue(key, out collection))
{
keyValuePairs.Add(key, []);
if (!keyValuePairs.TryGetValue(key, out collection))
throw new Exception();
}
collection.Add(file);
}
foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
return results.AsReadOnly();
}
private static void SaveExtractedJavaScriptObjectNotation(int wholePercentages, LocationContainer locationContainer, ReadOnlyCollection<string> paths)
{
string file;
string json;
foreach (string path in paths)
{
json = locationContainer.GetWithoutEncoding();
file = $"{path}-{wholePercentages}.json";
_ = IPath.WriteAllText(file, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
}
}
private static void SaveExtractedFace(int id, int wholePercentages, ExifDirectory _, Location location, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, ReadOnlyCollection<string> paths)
{
int width;
int height;
string person;
foreach (string path in paths)
{
width = location.Right - location.Left;
height = location.Bottom - location.Top;
person = personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? string.Empty : $"-{personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName}";
ExtractFace(file: path,
width: width,
height: height,
left: location.Left,
top: location.Top,
suffix: $"-{id}-{wholePercentages}{person}-face.jpg");
}
}
private static void ExtractFace(string file, float width, float height, double left, double top, string suffix)
{
RectangleF rectangle = new((float)left, (float)top, width, height);
using Bitmap source = new(file);
using Bitmap bitmap = new((int)width, (int)height);
using (Graphics graphics = Graphics.FromImage(bitmap))
graphics.DrawImage(source, new RectangleF(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
bitmap.Save($"{file}{suffix}");
}
}

View File

@ -9,7 +9,9 @@ public record CompareSettings(string Company,
string FacesHiddenFileNameExtension,
string FacesPartsFileNameExtension,
int MaxDegreeOfParallelism,
string[] OutputResolutions) : Shared.Models.Properties.ICompareSettings
string[] OutputResolutions,
bool SaveExtractedFaces,
bool SaveExtractedJavaScriptObjectNotation) : Shared.Models.Properties.ICompareSettings
{
public override string ToString()

View File

@ -1,6 +1,7 @@
using System.Collections.ObjectModel;
using System.Text.Json;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Distance.Models.Stateless;
@ -8,27 +9,135 @@ namespace View_by_Distance.Distance.Models.Stateless;
internal static class FaceEncodingLogic
{
internal static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories)
internal static void MoveUnableToMatch(FilePath filePath)
{
List<ExifDirectory> results = [];
string? json;
FaceEncoding? faceEncoding;
ExifDirectory exifDirectory;
FaceRecognitionDotNet.Models.FaceEncoding? encoding;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string checkFile = $"{filePath.FullName}.unk";
if (File.Exists(filePath.FullName) && !File.Exists(checkFile))
File.Move(filePath.FullName, checkFile);
}
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedIdsThenWholePercentagesToLocationContainer(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections)
{
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> results;
List<LocationContainer?> locationContainers = [];
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ReadOnlyCollection<ExifDirectory> exifDirectories = MappedLogicA.GetMapped(resultSettings,
metadataSettings,
peopleSettings,
distanceSettings,
compareSettings,
compare,
readOnlyCollections);
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds);
string message = $") Building Mapped with Encoding Face Files Collection - {totalSeconds} total second(s)";
compare.ConstructProgressBar(exifDirectories.Count, message);
foreach (ExifDirectory e in exifDirectories)
_ = Parallel.For(0, exifDirectories.Count, parallelOptions, (i, state) =>
LocationContainersParallelFor(distanceSettings, compareSettings, compare, exifDirectories, i, locationContainers));
results = GetMappedIdsThenWholePercentagesToLocationContainer(locationContainers);
return results;
}
private static void LocationContainersParallelFor(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollection<ExifDirectory> exifDirectories, int i, List<LocationContainer?> results)
{
compare.Tick();
ExifDirectory exifDirectory = exifDirectories[i];
LocationContainer? locationContainer = GetLocationContainer(distanceSettings, compareSettings, exifDirectory);
results.Add(locationContainer);
}
internal static LocationContainer? GetLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ExifDirectory exifDirectory)
{
LocationContainer? result;
string? json;
DateOnly dateOnly;
FaceFile? faceFile;
int? wholePercentages;
FaceEncoding? faceEncoding;
FaceRecognitionDotNet.Models.FaceEncoding? encoding;
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
if (wholePercentages is null)
{
compare.Tick();
json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(e);
faceEncoding = json is null ? null : JsonSerializer.Deserialize(json, FaceEncodingGenerationContext.Default.FaceEncoding);
if (faceEncoding is null)
continue;
encoding = FaceRecognitionDotNet.Models.FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
exifDirectory = ExifDirectory.Get(encoding, e);
results.Add(exifDirectory);
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
result = null;
}
else
{
faceFile = GetFaceFile(distanceSettings, exifDirectory);
if (faceFile is null)
result = null;
else
{
dateOnly = DateOnly.FromDateTime(new DateTime(exifDirectory.FilePath.CreationTicks));
json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(exifDirectory);
faceEncoding = json is null ? null : JsonSerializer.Deserialize(json, FaceEncodingGenerationContext.Default.FaceEncoding);
if (faceEncoding is null)
result = null;
else
{
encoding = FaceRecognitionDotNet.Models.FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
result = new(CreationDateOnly: dateOnly,
ExifDirectory: exifDirectory,
Encoding: encoding,
FaceFile: faceFile,
FilePath: exifDirectory.FilePath,
LengthPermyriad: null,
LengthSource: null,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName: exifDirectory.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
WholePercentages: wholePercentages);
}
}
}
return result;
}
private static FaceFile? GetFaceFile(DistanceSettings distanceSettings, ExifDirectory exifDirectory)
{
FaceFile? result;
string? json = Metadata.Models.Stateless.IMetadata.GetOutputResolution(exifDirectory);
if (json is null || !json.Contains(nameof(DateTime)))
{
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
result = null;
}
else
{
result = JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
if (result is null || result.Location is null)
{
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
result = null;
}
}
return result;
}
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedIdsThenWholePercentagesToLocationContainer(List<LocationContainer?> locationContainers)
{
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
int id;
int wholePercentages;
Dictionary<int, LocationContainer>? keyValue;
Dictionary<int, Dictionary<int, LocationContainer>> keyValuePairs = [];
foreach (LocationContainer? locationContainer in locationContainers)
{
if (locationContainer?.FilePath.Id is null || locationContainer.WholePercentages is null)
continue;
id = locationContainer.FilePath.Id.Value;
wholePercentages = locationContainer.WholePercentages.Value;
if (!keyValuePairs.TryGetValue(id, out keyValue))
{
keyValuePairs.Add(id, []);
if (!keyValuePairs.TryGetValue(id, out keyValue))
throw new Exception();
}
keyValue.Add(wholePercentages, locationContainer);
}
foreach (KeyValuePair<int, Dictionary<int, LocationContainer>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
return results.AsReadOnly();
}

View File

@ -32,7 +32,7 @@ internal static class FilterLogicA
return result;
}
internal static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories)
internal static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, ReadOnlyCollection<ExifDirectory> exifDirectories)
{
List<LocationContainer> results = [];
string? json;
@ -41,11 +41,11 @@ internal static class FilterLogicA
bool? isFocusPerson;
bool? inSkipCollection;
FaceEncoding? faceEncoding;
ReadOnlyDictionary<int, FilePath>? keyValues;
FaceRecognitionDotNet.Models.FaceEncoding? encoding;
ReadOnlyDictionary<int, LocationContainer>? keyValues;
List<FilePathAndWholePercentages>? wholePercentagesCollection;
ReadOnlyCollection<LocationContainer> locationContainers = FilterLogicB.GetLocationContainers(distanceSettings, compareSettings, compare, ticks, exifDirectories, nameof(FilterLogicA));
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
ReadOnlyCollection<LocationContainer> locationContainers = FilterLogicB.GetLocationContainers(distanceSettings, compareSettings, compare, exifDirectories, nameof(FilterLogicA));
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds);
string message = $") PreFiltering LocationContainers Face Files Collection - {totalSeconds} total second(s)";
compare.ConstructProgressBar(locationContainers.Count, message);
foreach (LocationContainer locationContainer in locationContainers)
@ -53,7 +53,7 @@ internal static class FilterLogicA
compare.Tick();
if (locationContainer.FilePath.Id is null || locationContainer.WholePercentages is null)
continue;
if (keyValuePairs.TryGetValue(locationContainer.FilePath.Id.Value, out keyValues))
if (mappedIdsThenWholePercentagesToLocationContainer.TryGetValue(locationContainer.FilePath.Id.Value, out keyValues))
{
if (keyValues.ContainsKey(locationContainer.WholePercentages.Value))
continue;
@ -85,7 +85,7 @@ internal static class FilterLogicA
if (faceEncoding is null)
continue;
encoding = FaceRecognitionDotNet.Models.FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
results.Add(LocationContainer.Get(locationContainer, encoding, keepExifDirectory: false));
results.Add(LocationContainer.Get(locationContainer, encoding));
}
return results.AsReadOnly();
}

View File

@ -1,6 +1,4 @@
using System.Collections.ObjectModel;
using System.Drawing;
using System.Text.Json;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless;
@ -10,71 +8,30 @@ namespace View_by_Distance.Distance.Models.Stateless;
internal static class FilterLogicB
{
private static void MoveUnableToMatch(FilePath filePath)
{
string checkFile = $"{filePath.FullName}.unk";
if (File.Exists(filePath.FullName) && !File.Exists(checkFile))
File.Move(filePath.FullName, checkFile);
}
private static void LocationContainersParallelFor(DistanceSettings distanceSettings, ICompareSettings compareSettings, List<LocationContainer> locationContainers, ExifDirectory exifDirectory)
{
string? json;
if (exifDirectory.FilePath.Id is null)
return;
DateOnly dateOnly = DateOnly.FromDateTime(new DateTime(exifDirectory.FilePath.CreationTicks));
int? wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
if (wholePercentages is null)
{
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
return;
}
json = Metadata.Models.Stateless.IMetadata.GetOutputResolution(exifDirectory);
if (json is null || !json.Contains(nameof(DateTime)))
{
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
return;
}
FaceFile? faceFile = JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
if (faceFile is null || faceFile.Location is null)
{
if (distanceSettings.DistanceMoveUnableToMatch)
MoveUnableToMatch(exifDirectory.FilePath);
return;
}
RectangleF? rectangle = Shared.Models.Stateless.ILocation.GetPercentagesRectangle(distanceSettings, wholePercentages.Value);
if (rectangle is null)
return;
LocationContainer locationContainer = new(dateOnly,
exifDirectory,
exifDirectory.Encoding,
faceFile,
exifDirectory.FilePath,
null,
null,
exifDirectory.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
rectangle,
wholePercentages);
lock (locationContainers)
locationContainers.Add(locationContainer);
}
internal static ReadOnlyCollection<LocationContainer> GetLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories, string sourceClass)
internal static ReadOnlyCollection<LocationContainer> GetLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollection<ExifDirectory> exifDirectories, string sourceClass)
{
List<LocationContainer> results = [];
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds);
string message = $") Building LocationContainers Face Files Collection {sourceClass} - {totalSeconds} total second(s)";
compare.ConstructProgressBar(exifDirectories.Count, message);
_ = Parallel.For(0, exifDirectories.Count, parallelOptions, (i, state) =>
{
compare.Tick();
LocationContainersParallelFor(distanceSettings, compareSettings, results, exifDirectories[i]);
});
LocationContainersParallelFor(distanceSettings, compareSettings, compare, exifDirectories, i, results));
return results.AsReadOnly();
}
private static void LocationContainersParallelFor(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollection<ExifDirectory> exifDirectories, int i, List<LocationContainer> results)
{
compare.Tick();
ExifDirectory exifDirectory = exifDirectories[i];
if (exifDirectory.FilePath.Id is null)
return;
LocationContainer? locationContainer = FaceEncodingLogic.GetLocationContainer(distanceSettings, compareSettings, exifDirectory);
if (locationContainer is null)
return;
lock (results)
results.Add(locationContainer);
}
}

View File

@ -24,23 +24,25 @@ internal static class FilterLogicC
return results.AsReadOnly();
}
private static ReadOnlyCollection<LocationContainer> GetCombined(DistanceSettings distanceSettings, Shared.Models.Properties.ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories, ReadOnlyCollection<LocationContainer> postFiltered)
private static ReadOnlyCollection<LocationContainer> GetCombined(ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, ReadOnlyCollection<LocationContainer> postFiltered)
{
List<LocationContainer> results = [];
foreach (LocationContainer locationContainer in postFiltered)
results.Add(locationContainer);
ReadOnlyCollection<LocationContainer> locationContainers = FilterLogicB.GetLocationContainers(distanceSettings, compareSettings, compare, ticks, exifDirectories, nameof(FilterLogicC));
foreach (LocationContainer locationContainer in locationContainers)
results.Add(locationContainer);
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mappedIdsThenWholePercentagesToLocationContainer)
{
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
results.Add(keyValue.Value);
}
return results.AsReadOnly();
}
internal static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, Shared.Models.Properties.ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered)
internal static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompare compare, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered)
{
List<LocationContainer> results = [];
ReadOnlyCollection<LocationContainer> collection;
ReadOnlyCollection<LocationContainer> locationContainers = GetCombined(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, postFiltered);
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
ReadOnlyCollection<LocationContainer> locationContainers = GetCombined(mappedIdsThenWholePercentagesToLocationContainer, postFiltered);
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds)} total second(s)";
compare.ConstructProgressBar(postFiltered.Count, message);
foreach (LocationContainer locationContainer in postFiltered)
{

View File

@ -55,7 +55,7 @@ internal static class FilterLogicD
return result;
}
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, int? updated, ReadOnlyCollection<SaveContainer> saveContainers)
{
string fileName;
string checkFile;
@ -70,7 +70,7 @@ internal static class FilterLogicD
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds);
string message;
if (updated is null)
message = $") {saveContainers.Count:000} save(s) - {totalSeconds} total second(s)";
@ -166,7 +166,7 @@ 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)
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
{
List<SaveContainer> results = [];
RecordB recordB;
@ -205,14 +205,14 @@ internal static class FilterLogicD
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
if (!Directory.Exists(cContentDirectory))
_ = Directory.CreateDirectory(cContentDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, compare.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)";
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds)} total second(s)";
compare.ConstructProgressBar(onlyOne.Count, message);
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
{

View File

@ -9,7 +9,7 @@ namespace View_by_Distance.Distance.Models.Stateless;
public interface IDistance
{
static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
public static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
$"{by switch
{
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
@ -23,55 +23,43 @@ public interface IDistance
public static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
FilterLogicC.GetOnlyOne(distanceSettings, matrix);
public static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
public static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
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, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, updated, saveContainers);
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);
public static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, outputResolution, onlyOne);
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<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompare compare, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compare, mappedIdsThenWholePercentagesToLocationContainer, distanceLimits, postFiltered);
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 ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedIdsThenWholePercentagesToLocationContainer(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections) =>
FaceEncodingLogic.GetMappedIdsThenWholePercentagesToLocationContainer(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, 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);
public static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, readOnlyCollections, mappedIdsThenWholePercentagesToLocationContainer, 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, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
SaveContainers(distanceSettings, compareSettings, compare, updated, saveContainers);
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, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, outputResolution, onlyOne);
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<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompare compare, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
GetMatrixLocationContainers(distanceSettings, compare, mappedIdsThenWholePercentagesToLocationContainer, distanceLimits, postFiltered);
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 ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> TestStatic_GetMappedIdsThenWholePercentagesToLocationContainer(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections) =>
GetMappedIdsThenWholePercentagesToLocationContainer(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, 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);
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedIdsThenWholePercentagesToLocationContainer, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, readOnlyCollections, mappedIdsThenWholePercentagesToLocationContainer, exifDirectories);
}

View File

@ -14,42 +14,16 @@ internal static class MappedLogicA
string? PersonDisplayDirectoryName,
FilePath FilePath);
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();
}
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, 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<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, 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);
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.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;

View File

@ -24,7 +24,7 @@ internal static class MappedLogicB
bool? IsLocationContainerDebugDirectory,
float? TotalDays);
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, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
{
List<Record> results = [];
bool check;
@ -59,7 +59,7 @@ internal static class MappedLogicB
distinct.Clear();
directoryNumber = 0;
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(distanceSettings, eDistanceContentDirectory);
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - compare.Ticks).TotalSeconds);
message = $"{i}) {ticksDirectories.Count:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
compare.ConstructProgressBar(ticksDirectories.Count, message);
foreach (TicksDirectory ticksDirectory in ticksDirectories)

View File

@ -21,13 +21,13 @@ internal static class Face
results.Add(exifDirectory);
}
internal static ReadOnlyCollection<ExifDirectory> GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution)
internal static ReadOnlyCollection<ExifDirectory> GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, string outputResolution)
{
List<ExifDirectory> results = [];
FileInfo fileInfo;
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
long? skipOlderThan = distanceSettings.SkipOlderThanDays < 1 ? null : new DateTime(ticks).AddDays(-distanceSettings.SkipOlderThanDays).Ticks;
long? skipOlderThan = distanceSettings.SkipOlderThanDays < 1 ? null : new DateTime(compare.Ticks).AddDays(-distanceSettings.SkipOlderThanDays).Ticks;
string resultsFullGroupDirectory = Path.GetFullPath(IResult.GetResultsFullGroupDirectory(resultSettings,
nameof(D_Face),
outputResolution,

View File

@ -8,9 +8,9 @@ namespace View_by_Distance.Face.Models.Stateless;
public interface IFace
{
ReadOnlyCollection<ExifDirectory> TestStatic_GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution) =>
GetExifDirectories(resultSettings, metadataSettings, distanceSettings, compareSettings, compare, ticks, outputResolution);
static ReadOnlyCollection<ExifDirectory> GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution) =>
Face.GetExifDirectories(resultSettings, metadataSettings, distanceSettings, compareSettings, compare, ticks, outputResolution);
ReadOnlyCollection<ExifDirectory> TestStatic_GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, string outputResolution) =>
GetExifDirectories(resultSettings, metadataSettings, distanceSettings, compareSettings, compare, outputResolution);
static ReadOnlyCollection<ExifDirectory> GetExifDirectories(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, string outputResolution) =>
Face.GetExifDirectories(resultSettings, metadataSettings, distanceSettings, compareSettings, compare, outputResolution);
}

View File

@ -36,45 +36,8 @@ public class A_Metadata
}
}
_ResultSingletonFileGroups = new(results);
}
private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath)
{
MinimumYearAndPathCombined result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
DateTime minimumDateTime = new(filePath.CreationTicks < filePath.LastWriteTicks ? filePath.CreationTicks : filePath.LastWriteTicks);
int minimumYear = minimumDateTime.Year < resultSettings.EpicYear ? resultSettings.EpicYear : minimumDateTime.Year;
result = new(minimumYear, Path.Combine(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"));
return result;
}
private (int, string) GetJsonFile(ResultSettings resultSettings, FilePath filePath, ExifDirectory exifDirectory)
{
string? result;
DateTime? dateTime;
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
dateTime ??= IDate.GetMinimum(exifDirectory);
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year;
result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json");
return new(exifYear, result);
}
private static (string, ExifDirectory?) Get(string jsonFile)
{
ExifDirectory? result;
string json = File.ReadAllText(jsonFile);
try
{
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
if (result is null)
throw new Exception();
}
catch (Exception)
{
result = null;
}
return new(json, result);
ReadOnlyCollection<string> directories = new([Path.Combine(aResultsFullGroupDirectory, resultSettings.ResultSingleton)]);
IPath.CreateDirectories(directories);
}
public (MinimumYearAndPathCombined, ExifDirectory) GetMetadataCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, FilePath filePath)
@ -148,19 +111,45 @@ public class A_Metadata
return new(minimumYearAndPathCombined, result);
}
private static Stream GetStream(HttpClient httpClient, FilePath filePath)
private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath)
{
Stream result;
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
httpResponseMessage.Wait();
Task task = httpResponseMessage.Result.Content.LoadIntoBufferAsync();
task.Wait();
Task<Stream> stream = httpResponseMessage.Result.Content.ReadAsStreamAsync();
stream.Wait();
result = stream.Result;
MinimumYearAndPathCombined result;
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
DateTime minimumDateTime = new(filePath.CreationTicks < filePath.LastWriteTicks ? filePath.CreationTicks : filePath.LastWriteTicks);
int minimumYear = minimumDateTime.Year < resultSettings.EpicYear ? resultSettings.EpicYear : minimumDateTime.Year;
result = new(minimumYear, Path.Combine(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"));
return result;
}
private (int, string) GetJsonFile(ResultSettings resultSettings, FilePath filePath, ExifDirectory exifDirectory)
{
string? result;
DateTime? dateTime;
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
dateTime ??= IDate.GetMinimum(exifDirectory);
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year;
result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json");
return new(exifYear, result);
}
private static (string, ExifDirectory?) Get(string jsonFile)
{
ExifDirectory? result;
string json = File.ReadAllText(jsonFile);
try
{
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
if (result is null)
throw new Exception();
}
catch (Exception)
{
result = null;
}
return new(json, result);
}
public (MinimumYearAndPathCombined, ExifDirectory) GetMetadataCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, HttpClient? httpClient, FilePath filePath)
{
ExifDirectory result;
@ -178,4 +167,17 @@ public class A_Metadata
return new(minimumYearAndPathCombined, result);
}
private static Stream GetStream(HttpClient httpClient, FilePath filePath)
{
Stream result;
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
httpResponseMessage.Wait();
Task task = httpResponseMessage.Result.Content.LoadIntoBufferAsync();
task.Wait();
Task<Stream> stream = httpResponseMessage.Result.Content.ReadAsStreamAsync();
stream.Wait();
result = stream.Result;
return result;
}
}

View File

@ -8,18 +8,18 @@ internal static class Dimensions
#pragma warning disable IDE0230
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
{
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
};
#pragma warning restore IDE0230
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
{
for (int i = 0; i < thatBytes.Length; i += 1)
for (int i = 0; i < thisBytes.Count && i < thatBytes.Length; i += 1)
{
if (thisBytes[i] == thatBytes[i])
continue;
@ -103,30 +103,49 @@ internal static class Dimensions
internal static Size? GetDimensions(BinaryReader binaryReader)
{
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
byte[] magicBytes = new byte[maxMagicBytesLength];
for (int i = 0; i < maxMagicBytesLength; i += 1)
Size? result;
List<byte> magicBytes = [];
int[] magicBytesLengths = (from l in _ImageFormatDecoders.Keys where l.Length <= binaryReader.BaseStream.Length orderby l.Length descending select l.Length).ToArray();
if (magicBytesLengths.Length == 0)
result = null;
else
{
magicBytes[i] = binaryReader.ReadByte();
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
result = null;
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
for (int i = 0; i < magicBytesLengths[0]; i++)
{
if (StartsWith(magicBytes, kvPair.Key))
return kvPair.Value(binaryReader);
magicBytes.Add(binaryReader.ReadByte());
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
{
if (StartsWith(magicBytes, kvPair.Key))
{
result = kvPair.Value(binaryReader);
break;
}
}
if (result is not null)
break;
}
}
return null;
return result;
}
internal static Size? GetDimensions(string path)
{
using BinaryReader binaryReader = new(File.OpenRead(path));
return GetDimensions(binaryReader);
Size? result;
using FileStream fileStream = File.OpenRead(path);
using BinaryReader binaryReader = new(fileStream);
result = GetDimensions(binaryReader);
return result;
}
internal static Size? GetDimensions(Stream stream)
{
Size? result;
using BinaryReader binaryReader = new(stream);
return GetDimensions(binaryReader);
result = GetDimensions(binaryReader);
return result;
}
}

View File

@ -529,7 +529,6 @@ internal abstract class Exif
Shared.Models.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
Shared.Models.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
result = new(aviDirectories,
null,
exifBaseDirectories,
fileMetadataDirectories,
filePath,

View File

@ -19,7 +19,9 @@ public record RenameSettings(string Company,
string RelativePropertyCollectionFile,
bool RequireRootDirectoryExists,
string[] SidecarExtensions,
bool SkipIdFiles) : Shared.Models.Properties.IRenameSettings
bool SkipIdFiles,
int ValidationImageDeterministicHashCodeId,
string ValidationImageFile) : Shared.Models.Properties.IRenameSettings
{
public override string ToString()

View File

@ -18,6 +18,9 @@ namespace View_by_Distance.Rename;
public partial class Rename : IRename, IDisposable
{
public long Ticks { get; init; }
public int? CurrentTick => _ProgressBar?.CurrentTick;
private sealed record ToDo(string? Directory,
FileInfo FileInfo,
string File,
@ -124,23 +127,53 @@ public partial class Rename : IRename, IDisposable
if (console is null)
throw new NullReferenceException(nameof(console));
IRename rename = this;
long ticks = DateTime.Now.Ticks;
LogNetToHoursSince(logger);
Ticks = DateTime.Now.Ticks;
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
RenameWork(logger, appSettings, rename, ticks);
Verify(logger, appSettings, rename);
RenameWork(logger, appSettings, rename);
}
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IRename rename)
{
FileHolder fileHolder = FileHolder.Get(appSettings.RenameSettings.ValidationImageFile);
FilePath filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null);
DeterministicHashCode deterministicHashCode = rename.GetDeterministicHashCode(filePath);
if (deterministicHashCode.Id is null)
throw new NullReferenceException(nameof(deterministicHashCode));
if (deterministicHashCode.Id.Value != appSettings.RenameSettings.ValidationImageDeterministicHashCodeId)
throw new Exception("Deterministic hash code id is incorrect!");
logger?.LogDebug("Validated deterministic hash code id");
}
private static void LogNetToHoursSince(ILogger<Program>? logger)
{
double secondsInAHour = 3600f;
long epoch = new DateTime(1970, 1, 1).Ticks;
long net8ReleaseDate = new DateTime(2023, 11, 14).Ticks;
long net9ReleaseDate = new DateTime(2024, 11, 12).Ticks;
double net8TotalSeconds = new TimeSpan(net8ReleaseDate - epoch).TotalSeconds;
double net9TotalSeconds = new TimeSpan(net9ReleaseDate - epoch).TotalSeconds;
logger?.LogInformation("It has been {net8TotalSeconds} seconds since net8 was released", net8TotalSeconds);
logger?.LogInformation("It has been {net9TotalSeconds} seconds since net9 was released", net9TotalSeconds);
double net8TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net8TotalSeconds) / secondsInAHour);
double net9TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net9TotalSeconds) / secondsInAHour);
logger?.LogInformation("It has been {net8TotalHours} hours since net8 was released", net8TotalHours);
logger?.LogInformation("It has been {net9TotalHours} hours since net9 was released", net9TotalHours);
}
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename)
{
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);
logger?.LogInformation("{Ticks} {RootDirectory}", rename.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);
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ids, sourceDirectory, files);
SaveIdentifiersToDisk(appSettings, rename, recordCollection);
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
{
if (recordCollection.Count > 0)
@ -173,13 +206,13 @@ public partial class Rename : IRename, IDisposable
return results;
}
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, 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);
collection = GetRecordCollection(logger, appSettings, rename, ids, sourceDirectory, files, checkFile);
else
{
string json = File.ReadAllText(checkFile);
@ -192,7 +225,7 @@ public partial class Rename : IRename, IDisposable
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)
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile)
{
List<FirstPass> results;
FirstPass firstPass;
@ -203,7 +236,7 @@ public partial class Rename : IRename, IDisposable
if (appSettingsMaxDegreeOfParallelism == 1)
{
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
results = GetFirstPassCollection(logger, appSettings, rename, ids, metadata, keyValuePairs);
}
else
{
@ -225,13 +258,13 @@ public partial class Rename : IRename, IDisposable
if (!string.IsNullOrEmpty(checkFile))
{
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
File.WriteAllText(Path.Combine(sourceDirectory, $"{rename.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)
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
{
List<FirstPass> results = [];
int index = -1;
@ -249,7 +282,7 @@ public partial class Rename : IRename, IDisposable
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);
timeSpan = new(DateTime.Now.Ticks - rename.Ticks);
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
break;
}
@ -365,7 +398,7 @@ public partial class Rename : IRename, IDisposable
bool hasIgnoreKeyword = appSettings.MetadataSettings.IgnoreRulesKeyWords.Any(keywords.Contains);
string checkFileExtension = exifDirectory.FilePath.ExtensionLowered == jpeg ? jpg : exifDirectory.FilePath.ExtensionLowered;
bool hasDateTimeOriginal = dateTime is not null;
string paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, exifDirectory.FilePath.Id.Value, hasIgnoreKeyword, hasDateTimeOriginal, i);
string paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, exifDirectory.FilePath.Id.Value, exifDirectory.FilePath.ExtensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, i);
string checkDirectory = appSettings.RenameSettings.InPlaceWithOriginalName ? Path.Combine(exifDirectory.FilePath.DirectoryFullPath, exifDirectory.FilePath.FileNameFirstSegment) : exifDirectory.FilePath.DirectoryFullPath;
string checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}");
if (checkFile != exifDirectory.FilePath.FullName)
@ -435,7 +468,7 @@ public partial class Rename : IRename, IDisposable
return results.AsReadOnly();
}
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
private static void SaveIdentifiersToDisk(AppSettings appSettings, IRename rename, ReadOnlyCollection<Record> recordCollection)
{
string paddedId;
Identifier identifier;
@ -445,12 +478,12 @@ public partial class Rename : IRename, IDisposable
{
if (record.ExifDirectory.FilePath.Id is null)
continue;
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null);
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.ExtensionLowered, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null);
identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks);
identifiers.Add(identifier);
}
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);
_ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{rename.Ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
}
private static ReadOnlyCollection<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection)
@ -462,15 +495,19 @@ public partial class Rename : IRename, IDisposable
string paddedId;
string checkFile;
FilePath filePath;
DateTime? dateTime;
FileInfo[] matches;
FileHolder fileHolder;
bool? hasIgnoreKeyword;
string? checkDirectory;
CombinedEnumAndIndex cei;
bool? hasDateTimeOriginal;
const string jpg = ".jpg";
string checkFileExtension;
List<string> distinct = [];
const string jpeg = ".jpeg";
string jsonFileSubDirectory;
ReadOnlyCollection<string> keywords;
bool? directoryCheck = GetDirectoryCheck(appSettings.ResultSettings);
VerifyIntMinValueLength(appSettings.MetadataSettings, recordCollection);
bool multipleDirectoriesWithFiles = directoryCheck is not null && directoryCheck.Value;
@ -481,7 +518,7 @@ public partial class Rename : IRename, IDisposable
record = sorted[i];
if (record.ExifDirectory.FilePath.Id is null)
continue;
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, i);
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.ExtensionLowered, record.HasIgnoreKeyword, record.HasDateTimeOriginal, i);
checkDirectory = GetCheckDirectory(appSettings, directoryInfo, record, ids, multipleDirectoriesWithFiles, paddedId);
if (string.IsNullOrEmpty(checkDirectory))
continue;
@ -496,6 +533,20 @@ public partial class Rename : IRename, IDisposable
if (File.Exists(checkFile))
continue;
}
if (record.ExifDirectory.FilePath.HasDateTimeOriginal is not null && record.ExifDirectory.FilePath.HasIgnoreKeyword is not null)
{
hasIgnoreKeyword = record.ExifDirectory.FilePath.HasIgnoreKeyword;
hasDateTimeOriginal = record.ExifDirectory.FilePath.HasDateTimeOriginal;
}
else
{
dateTime = IDate.GetDateTimeOriginal(record.ExifDirectory);
hasDateTimeOriginal = dateTime is not null;
if (dateTime is null && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(record.ExifDirectory.FilePath.ExtensionLowered))
continue;
keywords = IMetadata.GetKeywords(record.ExifDirectory);
hasIgnoreKeyword = appSettings.MetadataSettings.IgnoreRulesKeyWords.Any(keywords.Contains);
}
cei = IPath.GetCombinedEnumAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath);
jsonFile = Path.Combine(jsonFileSubDirectory, cei.Combined, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json");
if (record.JsonFile != jsonFile)
@ -658,7 +709,7 @@ public partial class Rename : IRename, IDisposable
foreach (ToDo toDo in toDoCollection)
{
if (useProgressBar)
_ProgressBar?.Tick();
rename?.Tick();
if (!toDo.FileInfo.Exists)
continue;
if (toDo.JsonFile)
@ -683,8 +734,6 @@ public partial class Rename : IRename, IDisposable
results.Add($"{toDo.FileInfo.FullName}\t{toDo.File}");
}
}
if (useProgressBar)
_ProgressBar?.Dispose();
return results.AsReadOnly();
}

View File

@ -4,7 +4,6 @@ using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public record ExifDirectory(AviDirectory[] AviDirectories,
object? Encoding,
ExifDirectoryBase[] ExifBaseDirectories,
FileMetadataDirectory[] FileMetadataDirectories,
FilePath FilePath,
@ -28,25 +27,6 @@ public record ExifDirectory(AviDirectory[] AviDirectories,
return result;
}
public static ExifDirectory Get(object encoding, ExifDirectory e) =>
new(e.AviDirectories,
encoding,
e.ExifBaseDirectories,
e.FileMetadataDirectories,
e.FilePath,
e.GifHeaderDirectories,
e.GpsDirectories,
e.Height,
e.JpegDirectories,
e.MakernoteDirectories,
e.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
e.PhotoshopDirectories,
e.PngDirectories,
e.QuickTimeMovieHeaderDirectories,
e.QuickTimeTrackHeaderDirectories,
e.WebPDirectories,
e.Width);
}
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -1,4 +1,5 @@
using System.Drawing;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
@ -10,40 +11,67 @@ public record LocationContainer(DateOnly? CreationDateOnly,
int? LengthPermyriad,
FilePath? LengthSource,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
RectangleF? Rectangle,
int? WholePercentages)
{
public static LocationContainer Get(LocationContainer locationContainer, object? encoding, bool keepExifDirectory)
public string GetWithoutEncoding()
{
string result;
WithoutEncoding withoutEncoding = new(CreationDateOnly: CreationDateOnly,
ExifDirectory: ExifDirectory,
FaceFile: FaceFile,
FilePath: FilePath,
LengthPermyriad: LengthPermyriad,
LengthSource: LengthSource,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName: PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
WholePercentages: WholePercentages);
result = JsonSerializer.Serialize(withoutEncoding, WithoutEncodingSourceGenerationContext.Default.WithoutEncoding);
return result;
}
public static LocationContainer Get(LocationContainer locationContainer, object? encoding)
{
LocationContainer result;
result = new(locationContainer.CreationDateOnly,
keepExifDirectory ? locationContainer.ExifDirectory : null,
encoding,
locationContainer.FaceFile,
locationContainer.FilePath,
locationContainer.LengthPermyriad,
locationContainer.LengthSource,
locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
locationContainer.Rectangle,
locationContainer.WholePercentages);
result = new(CreationDateOnly: locationContainer.CreationDateOnly,
ExifDirectory: locationContainer.ExifDirectory,
Encoding: encoding,
FaceFile: locationContainer.FaceFile,
FilePath: locationContainer.FilePath,
LengthPermyriad: locationContainer.LengthPermyriad,
LengthSource: locationContainer.LengthSource,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName: locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
WholePercentages: locationContainer.WholePercentages);
return result;
}
public static LocationContainer Get(LocationContainer source, LocationContainer locationContainer, int lengthPermyriad, bool keepExifDirectory, bool keepEncoding)
{
LocationContainer result;
result = new(locationContainer.CreationDateOnly,
keepExifDirectory ? locationContainer.ExifDirectory : null,
keepEncoding ? locationContainer.Encoding : null,
locationContainer.FaceFile,
locationContainer.FilePath,
lengthPermyriad,
source.FilePath,
locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
locationContainer.Rectangle,
locationContainer.WholePercentages);
result = new(CreationDateOnly: locationContainer.CreationDateOnly,
ExifDirectory: keepExifDirectory ? locationContainer.ExifDirectory : null,
Encoding: keepEncoding ? locationContainer.Encoding : null,
FaceFile: locationContainer.FaceFile,
FilePath: locationContainer.FilePath,
LengthPermyriad: lengthPermyriad,
LengthSource: source.FilePath,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName: locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
WholePercentages: locationContainer.WholePercentages);
return result;
}
}
internal record WithoutEncoding(DateOnly? CreationDateOnly,
ExifDirectory? ExifDirectory,
FaceFile? FaceFile,
FilePath FilePath,
int? LengthPermyriad,
FilePath? LengthSource,
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName,
int? WholePercentages);
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(WithoutEncoding))]
internal partial class WithoutEncodingSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -4,6 +4,8 @@ public interface ICompare
{
void Tick();
long Ticks { get; }
int? CurrentTick { get; }
void ConstructProgressBar(int maxTicks, string message);
}

View File

@ -3,24 +3,28 @@ namespace View_by_Distance.Shared.Models.Stateless;
public interface IDate
{
(bool?, string[]) TestStatic_IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
IsWrongYear(directoryInfo, filePath, exifDirectory);
static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
XDate.IsWrongYear(directoryInfo, filePath, exifDirectory);
(int Season, string seasonName) TestStatic_GetSeason(int dayOfYear) =>
GetSeason(dayOfYear);
static (int Season, string seasonName) GetSeason(int dayOfYear) =>
XDate.GetSeason(dayOfYear);
DateTime? TestStatic_GetDateTimeOriginal(ExifDirectory exifDirectory) =>
GetDateTimeOriginal(exifDirectory);
static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) =>
XDate.GetDateTimeOriginal(exifDirectory);
DateTime TestStatic_GetMinimum(ExifDirectory exifDirectory) =>
GetMinimum(exifDirectory);
static DateTime GetMinimum(ExifDirectory exifDirectory) =>
public static DateTime GetMinimum(ExifDirectory exifDirectory) =>
XDate.GetMinimum(exifDirectory);
public static (int Season, string seasonName) GetSeason(int dayOfYear) =>
XDate.GetSeason(dayOfYear);
public static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory) =>
XDate.GetDateTimeOriginal(exifDirectory);
public static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
XDate.IsWrongYear(directoryInfo, filePath, exifDirectory);
internal DateTime TestStatic_GetMinimum(ExifDirectory exifDirectory) =>
GetMinimum(exifDirectory);
internal (int Season, string seasonName) TestStatic_GetSeason(int dayOfYear) =>
GetSeason(dayOfYear);
internal DateTime? TestStatic_GetDateTimeOriginal(ExifDirectory exifDirectory) =>
GetDateTimeOriginal(exifDirectory);
internal (bool?, string[]) TestStatic_IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory) =>
IsWrongYear(directoryInfo, filePath, exifDirectory);
}

View File

@ -27,18 +27,18 @@ public interface IId
Id.GetId(resultSettings, metadataSettings, intelligentId);
public static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '0' or '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
&& fileNameFirstSegment[^1] is '0' or '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
&& fileNameFirstSegment.All(char.IsNumber);
public static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
public static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
Id.GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
Id.GetPaddedId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index);
internal int TestStatic_GetDeterministicHashCode(byte[] value) =>
GetDeterministicHashCode(value);
@ -64,10 +64,10 @@ public interface IId
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, string extensionLowered, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
GetPaddedId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index);
}

View File

@ -5,21 +5,16 @@ namespace View_by_Distance.Shared.Models.Stateless;
public interface ILocation
{
RectangleF? TestStatic_GetPercentagesRectangle(DistanceSettings distanceSettings, int wholePercentages) =>
GetPercentagesRectangle(distanceSettings, wholePercentages);
static RectangleF? GetPercentagesRectangle(DistanceSettings distanceSettings, int wholePercentages) =>
Location.GetPercentagesRectangle(distanceSettings, wholePercentages);
Models.Location TestStatic_GetTrimBound(double detectionConfidence, Rectangle rectangle, int width, int height, int facesCount) =>
TrimBound(detectionConfidence, rectangle, width, height, facesCount);
static Models.Location TrimBound(double detectionConfidence, Rectangle rectangle, int width, int height, int facesCount) =>
Models.Location.Get(Math.Min(rectangle.Bottom, height),
detectionConfidence,
height,
Math.Max(rectangle.Left, 0),
Math.Min(rectangle.Right, width),
Math.Max(rectangle.Top, 0),
width,
facesCount);
detectionConfidence,
height,
Math.Max(rectangle.Left, 0),
Math.Min(rectangle.Right, width),
Math.Max(rectangle.Top, 0),
width,
facesCount);
}

View File

@ -3,77 +3,96 @@ using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Stateless;
public interface IPath
{ // ...
{
string TestStatic_GetRelativePath(string path, int length) =>
GetRelativePath(path, length);
static string GetRelativePath(string path, int length) =>
XPath.GetRelativePath(path, length, forceExtensionToLower: false);
bool TestStatic_DeleteEmptyDirectories(string rootDirectory) =>
DeleteEmptyDirectories(rootDirectory);
static bool DeleteEmptyDirectories(string rootDirectory) =>
XPath.DeleteEmptyDirectories(rootDirectory);
void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
ChangeDateForEmptyDirectories(rootDirectory, ticks);
static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
MakeHiddenIfAllItemsAreHidden(rootDirectory);
static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
void TestStatic_DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
DeleteEmptyDirectories(rootDirectory, deletedDirectories);
static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
// $dirs = gci "" -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName $dirs | Foreach-Object { Remove-Item $_ }
string[] TestStatic_GetDirectoryNames(string directory) =>
GetDirectoryNames(directory);
static string[] GetDirectoryNames(string directory) =>
XPath.GetDirectoryNames(directory).ToArray();
string[] TestStatic_GetDirectories(string directory) =>
GetDirectories(directory);
static string[] GetDirectories(string directory) =>
XPath.GetDirectories(directory).ToArray();
string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) =>
GetRelativePath(path, length, forceExtensionToLower);
static string GetRelativePath(string path, int length, bool forceExtensionToLower) =>
XPath.GetRelativePath(path, length, forceExtensionToLower);
bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
(int level, List<string> directories) TestStatic_Get(string rootDirectory, string sourceDirectory) =>
Get(rootDirectory, sourceDirectory);
static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory) =>
XPath.Get(rootDirectory, sourceDirectory);
string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) =>
GetDirectory(sourceDirectory, level, directoryName);
static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
XPath.GetDirectory(sourceDirectory, level, directoryName);
CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
GetCombinedEnumAndIndex(resultSettings, filePath);
static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
XPath.GetCombinedEnumAndIndex(resultSettings, filePath);
ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
byte TestStatic_GetEnum(FilePath filePath) =>
GetEnum(filePath);
static byte GetEnum(FilePath filePath) =>
public static byte GetEnum(FilePath filePath) =>
XPath.GetEnum(filePath);
public static string[] GetDirectories(string directory) =>
XPath.GetDirectories(directory).ToArray();
public static string[] GetDirectoryNames(string directory) =>
XPath.GetDirectoryNames(directory).ToArray();
public static string GetRelativePath(string path, int length) =>
XPath.GetRelativePath(path, length, forceExtensionToLower: false);
public static bool DeleteEmptyDirectories(string rootDirectory) =>
XPath.DeleteEmptyDirectories(rootDirectory);
public static void MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
XPath.MakeHiddenIfAllItemsAreHidden(rootDirectory);
public static void CreateDirectories(ReadOnlyCollection<string> directories) =>
XPath.CreateDirectories(directories);
public static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
XPath.ChangeDateForEmptyDirectories(rootDirectory, ticks);
public static string GetRelativePath(string path, int length, bool forceExtensionToLower) =>
XPath.GetRelativePath(path, length, forceExtensionToLower);
public static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
XPath.GetDirectory(sourceDirectory, level, directoryName);
public static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
public static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory) =>
XPath.Get(rootDirectory, sourceDirectory);
public static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
XPath.GetCombinedEnumAndIndex(resultSettings, filePath);
public static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
public static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
internal byte TestStatic_GetEnum(FilePath filePath) =>
GetEnum(filePath);
internal string[] TestStatic_GetDirectories(string directory) =>
GetDirectories(directory);
internal string[] TestStatic_GetDirectoryNames(string directory) =>
GetDirectoryNames(directory);
internal string TestStatic_GetRelativePath(string path, int length) =>
GetRelativePath(path, length);
internal bool TestStatic_DeleteEmptyDirectories(string rootDirectory) =>
DeleteEmptyDirectories(rootDirectory);
internal void TestStatic_MakeHiddenIfAllItemsAreHidden(string rootDirectory) =>
MakeHiddenIfAllItemsAreHidden(rootDirectory);
internal void TestStatic_CreateDirectories(ReadOnlyCollection<string> directories) =>
CreateDirectories(directories);
internal void TestStatic_ChangeDateForEmptyDirectories(string rootDirectory, long ticks) =>
ChangeDateForEmptyDirectories(rootDirectory, ticks);
internal string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower) =>
GetRelativePath(path, length, forceExtensionToLower);
internal string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName) =>
GetDirectory(sourceDirectory, level, directoryName);
internal void TestStatic_DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
DeleteEmptyDirectories(rootDirectory, deletedDirectories);
internal (int level, List<string> directories) TestStatic_Get(string rootDirectory, string sourceDirectory) =>
Get(rootDirectory, sourceDirectory);
internal CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
GetCombinedEnumAndIndex(resultSettings, filePath);
internal bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) =>
WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches);
internal ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
}

View File

@ -5,9 +5,11 @@ namespace View_by_Distance.Shared.Models.Stateless;
public interface IRename
{
void Tick();
long Ticks { get; }
int? CurrentTick { get; }
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(FilePath filePath);
void ConstructProgressBar(int maxTicks, string message);
void Tick();
}

View File

@ -5,10 +5,12 @@ namespace View_by_Distance.Shared.Models.Stateless;
public interface IWindows
{
void Tick();
long Ticks { get; }
int? CurrentTick { get; }
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath);
DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri);
void ConstructProgressBar(int maxTicks, string message);
void Tick();
}

View File

@ -28,10 +28,17 @@ internal abstract class Id
(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);
(byte)(IsIgnoreOrValidVideoFormatExtension(resultSettings, filePath) ? filePath.Id > -1 ? 6 : 4 : filePath.Id > -1 ? 9 : 1);
private static bool IsIgnoreOrValidVideoFormatExtension(ResultSettings resultSettings, FilePath filePath) =>
IsIgnoreOrValidVideoFormatExtension(resultSettings, filePath.ExtensionLowered);
private static bool IsIgnoreOrValidVideoFormatExtension(ResultSettings resultSettings, string extensionLowered) =>
resultSettings.IgnoreExtensions.Contains(extensionLowered)
|| resultSettings.ValidVideoFormatExtensions.Contains(extensionLowered);
internal static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : 5);
(byte)(IsIgnoreOrValidVideoFormatExtension(resultSettings, filePath) ? filePath.Id > -1 ? 5 : 0 : filePath.Id > -1 ? 7 : 3);
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
{
@ -43,7 +50,7 @@ internal abstract class Id
_ = results.Append(intelligentId[i]);
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
result = int.Parse(results.ToString());
if (intelligentId[^1] is '1' or '2' or '3' or '4')
if (intelligentId[^1] is '0' or '1' or '2' or '3' or '4')
result *= -1;
else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
throw new NotSupportedException();
@ -64,7 +71,7 @@ internal abstract class Id
}
#pragma warning disable IDE0060
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
#pragma warning restore IDE0060
{
string result;
@ -74,14 +81,25 @@ internal abstract class Id
int key;
string value;
List<char> resultAllInOneSubdirectoryChars = [];
if (id > -1)
if (hasDateTimeOriginal is null)
{
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 9 : 7;
key = 0;
value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0');
}
else if (id > -1)
{
if (IsIgnoreOrValidVideoFormatExtension(resultSettings, extensionLowered))
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 6 : 5;
else
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal.Value ? 9 : 7;
value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0');
}
else
{
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal is not null && hasDateTimeOriginal.Value ? 1 : 3;
if (IsIgnoreOrValidVideoFormatExtension(resultSettings, extensionLowered))
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 4 : 0;
else
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal.Value ? 1 : 3;
value = id.ToString()[1..].PadLeft(metadataSettings.IntMinValueLength, '0');
}
for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
@ -92,14 +110,14 @@ internal abstract class Id
return result;
}
internal static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
internal static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index)
{
string result;
if (metadataSettings.Offset < 0)
result = Guid.NewGuid().ToString();
else
{
string intelligentId = GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
string intelligentId = GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
int check = GetId(resultSettings, metadataSettings, intelligentId);
if (check != id)
throw new NotSupportedException();

View File

@ -1,6 +1,4 @@
using System.Drawing;
namespace View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Shared.Models.Stateless;
internal abstract class Location
{
@ -47,32 +45,4 @@ internal abstract class Location
return result;
}
internal static RectangleF? GetPercentagesRectangle(DistanceSettings distanceSettings, int wholePercentages)
{
RectangleF? result;
string wp = wholePercentages.ToString();
int length = (distanceSettings.LocationDigits - 1) / 4;
string[] segments =
[
wp[..1],
wp.Substring(1, length),
wp.Substring(3, length),
wp.Substring(5, length),
wp.Substring(7, length)
];
if (string.Join(string.Empty, segments) != wp)
result = null;
else
{
if (!int.TryParse(segments[1], out int xWholePercent) || !int.TryParse(segments[2], out int yWholePercent) || !int.TryParse(segments[3], out int wWholePercent) || !int.TryParse(segments[4], out int hWholePercent))
result = null;
else
{
float factor = 100;
result = new(xWholePercent / factor, yWholePercent / factor, wWholePercent / factor, hWholePercent / factor);
}
}
return result;
}
}

View File

@ -7,181 +7,11 @@ namespace View_by_Distance.Shared.Models.Stateless;
internal abstract class XDate
{
private record Record(bool? IsWrongYear, string[] Years);
internal static (int Season, string seasonName) GetSeason(int dayOfYear)
internal static DateTime GetMinimum(ExifDirectory exifDirectory)
{
(int Season, string seasonName) result = dayOfYear switch
{
< 78 => new(0, "Winter"),
< 124 => new(1, "Spring"),
< 171 => new(2, "Spring"),
< 217 => new(3, "Summer"),
< 264 => new(4, "Summer"),
< 309 => new(5, "Fall"),
< 354 => new(6, "Fall"),
_ => new(7, "Winter")
};
return result;
}
private static Record IsWrongYear(string[] segments, string year)
{
Record result;
bool? check;
string[] results = (
from l
in segments
where l?.Length > 2
&& (
l[..2] is "18" or "19" or "20"
|| (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
)
select l
).ToArray();
string[] matches = (
from l
in results
where l == year
|| (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..4] == year && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.')
select l
).ToArray();
if (results.Length == 0)
check = null;
else
check = matches.Length == 0;
result = new(check, results);
return result;
}
internal static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory)
{
string[] results = [];
bool? result = null;
string year;
string directoryName;
string[] directorySegments;
List<DateTime> collection = [];
string? check = Path.GetFullPath(filePath.FullName);
DateTime? dateTimeOriginal = GetDateTimeOriginal(exifDirectory);
if (dateTimeOriginal is not null)
collection.Add(dateTimeOriginal.Value);
else
{
ReadOnlyCollection<DateTime> dateTimes = GetDateTimes(exifDirectory);
foreach (DateTime dateTime in dateTimes)
collection.Add(dateTime);
}
foreach (DateTime dateTime in collection)
{
year = dateTime.ToString("yyyy");
for (int i = 0; i < int.MaxValue; i++)
{
check = Path.GetDirectoryName(check);
if (string.IsNullOrEmpty(check))
break;
directoryName = Path.GetFileName(check);
directorySegments = directoryName.Split(' ');
(result, results) = IsWrongYear(directorySegments, year);
if (result is not null)
break;
if (check == directoryInfo.FullName)
break;
}
if (result is not null && !result.Value)
break;
}
return new(result, results);
}
internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory)
{
DateTime? result;
List<DateTime> results = [];
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
{
if (exifDirectoryBase.DateTimeOriginal is not null)
results.Add(exifDirectoryBase.DateTimeOriginal.Value);
}
foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories)
{
if (aviDirectory.DateTimeOriginal is not null)
results.Add(aviDirectory.DateTimeOriginal.Value);
}
foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories)
{
if (quickTimeMovieHeaderDirectory.Created is not null)
{
if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1)
continue;
results.Add(quickTimeMovieHeaderDirectory.Created.Value);
}
}
foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories)
{
if (quickTimeTrackHeaderDirectory.Created is not null)
{
if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1)
continue;
results.Add(quickTimeTrackHeaderDirectory.Created.Value);
}
}
result = results.Count == 0 ? null : results.Min();
return result;
}
private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension)
{
DateTime? result = null;
int length;
string format;
string fullFormat;
StringBuilder value = new();
const string ticksExample = "##################";
string[][] dateFormats =
[
[string.Empty, "yyyyMMdd_HHmmss", string.Empty],
[string.Empty, "yyyyMMddHHmmssfff", string.Empty],
[string.Empty, "yyyyMMdd_", ticksExample],
[string.Empty, "yyyy-MM-dd_", ticksExample],
[string.Empty, "yyyy-MM-dd.", ticksExample],
// [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"],
[string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty],
[string.Empty, "yyyyMMdd_HHmmss", "_LLS"],
[string.Empty, "yyyyMMdd_HHmmss", "_HDR"],
["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"],
["IMG_", "yyyyMMdd_HHmmss", string.Empty],
["IMG#####-", "yyyyMMdd-HHmm", string.Empty],
["CameraZOOM-", "yyyyMMddHHmmss", string.Empty],
["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty]
];
foreach (string[] dateFormat in dateFormats)
{
_ = value.Clear();
if (dateFormat.Length != 3)
throw new Exception();
fullFormat = string.Join(string.Empty, dateFormat);
if (fileNameWithoutExtension.Length != fullFormat.Length)
continue;
format = dateFormat[1];
length = dateFormat[0].Length + dateFormat[1].Length;
for (int i = dateFormat[0].Length; i < length; i++)
_ = value.Append(fileNameWithoutExtension[i]);
if (value.Length != format.Length)
continue;
if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
{
if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks))
result = checkDateTime;
else
result = new DateTime(ticks);
break;
}
}
DateTime result;
ReadOnlyCollection<DateTime> results = GetDateTimes(exifDirectory);
result = results.Count == 0 ? DateTime.MinValue : results.Min();
return result;
}
@ -241,12 +71,182 @@ internal abstract class XDate
return results.AsReadOnly();
}
internal static DateTime GetMinimum(ExifDirectory exifDirectory)
private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension)
{
DateTime result;
ReadOnlyCollection<DateTime> results = GetDateTimes(exifDirectory);
result = results.Count == 0 ? DateTime.MinValue : results.Min();
DateTime? result = null;
int length;
string format;
string fullFormat;
StringBuilder value = new();
const string ticksExample = "##################";
string[][] dateFormats =
[
[string.Empty, "yyyyMMdd_HHmmss", string.Empty],
[string.Empty, "yyyyMMddHHmmssfff", string.Empty],
[string.Empty, "yyyyMMdd_", ticksExample],
[string.Empty, "yyyy-MM-dd_", ticksExample],
[string.Empty, "yyyy-MM-dd.", ticksExample],
// [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"],
[string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty],
[string.Empty, "yyyyMMdd_HHmmss", "_LLS"],
[string.Empty, "yyyyMMdd_HHmmss", "_HDR"],
["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"],
["IMG_", "yyyyMMdd_HHmmss", string.Empty],
["IMG#####-", "yyyyMMdd-HHmm", string.Empty],
["CameraZOOM-", "yyyyMMddHHmmss", string.Empty],
["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty]
];
foreach (string[] dateFormat in dateFormats)
{
_ = value.Clear();
if (dateFormat.Length != 3)
throw new Exception();
fullFormat = string.Join(string.Empty, dateFormat);
if (fileNameWithoutExtension.Length != fullFormat.Length)
continue;
format = dateFormat[1];
length = dateFormat[0].Length + dateFormat[1].Length;
for (int i = dateFormat[0].Length; i < length; i++)
_ = value.Append(fileNameWithoutExtension[i]);
if (value.Length != format.Length)
continue;
if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
{
if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks))
result = checkDateTime;
else
result = new DateTime(ticks);
break;
}
}
return result;
}
internal static (int Season, string seasonName) GetSeason(int dayOfYear)
{
(int Season, string seasonName) result = dayOfYear switch
{
< 78 => new(0, "Winter"),
< 124 => new(1, "Spring"),
< 171 => new(2, "Spring"),
< 217 => new(3, "Summer"),
< 264 => new(4, "Summer"),
< 309 => new(5, "Fall"),
< 354 => new(6, "Fall"),
_ => new(7, "Winter")
};
return result;
}
internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory)
{
DateTime? result;
List<DateTime> results = [];
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
{
if (exifDirectoryBase.DateTimeOriginal is not null)
results.Add(exifDirectoryBase.DateTimeOriginal.Value);
}
foreach (AviDirectory aviDirectory in exifDirectory.AviDirectories)
{
if (aviDirectory.DateTimeOriginal is not null)
results.Add(aviDirectory.DateTimeOriginal.Value);
}
foreach (QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in exifDirectory.QuickTimeMovieHeaderDirectories)
{
if (quickTimeMovieHeaderDirectory.Created is not null)
{
if (quickTimeMovieHeaderDirectory.Created.Value.Year == 1904 && quickTimeMovieHeaderDirectory.Created.Value.Month == 1 && quickTimeMovieHeaderDirectory.Created.Value.Day == 1)
continue;
results.Add(quickTimeMovieHeaderDirectory.Created.Value);
}
}
foreach (QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in exifDirectory.QuickTimeTrackHeaderDirectories)
{
if (quickTimeTrackHeaderDirectory.Created is not null)
{
if ((quickTimeTrackHeaderDirectory.Created.Value.Year is 1904 or 1970) && quickTimeTrackHeaderDirectory.Created.Value.Month == 1 && quickTimeTrackHeaderDirectory.Created.Value.Day == 1)
continue;
results.Add(quickTimeTrackHeaderDirectory.Created.Value);
}
}
result = results.Count == 0 ? null : results.Min();
return result;
}
internal static (bool?, string[]) IsWrongYear(DirectoryInfo directoryInfo, FilePath filePath, ExifDirectory exifDirectory)
{
string[] results = [];
bool? result = null;
string year;
string directoryName;
string[] directorySegments;
List<DateTime> collection = [];
string? check = Path.GetFullPath(filePath.FullName);
DateTime? dateTimeOriginal = GetDateTimeOriginal(exifDirectory);
if (dateTimeOriginal is not null)
collection.Add(dateTimeOriginal.Value);
else
{
ReadOnlyCollection<DateTime> dateTimes = GetDateTimes(exifDirectory);
foreach (DateTime dateTime in dateTimes)
collection.Add(dateTime);
}
foreach (DateTime dateTime in collection)
{
year = dateTime.ToString("yyyy");
for (int i = 0; i < int.MaxValue; i++)
{
check = Path.GetDirectoryName(check);
if (string.IsNullOrEmpty(check))
break;
directoryName = Path.GetFileName(check);
directorySegments = directoryName.Split(' ');
(result, results) = IsWrongYear(directorySegments, year);
if (result is not null)
break;
if (check == directoryInfo.FullName)
break;
}
if (result is not null && !result.Value)
break;
}
return new(result, results);
}
private static Record IsWrongYear(string[] segments, string year)
{
Record result;
bool? check;
string[] results = (
from l
in segments
where l?.Length > 2
&& (
l[..2] is "18" or "19" or "20"
|| (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
)
select l
).ToArray();
string[] matches = (
from l
in results
where l == year
|| (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..4] == year && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.')
select l
).ToArray();
if (results.Length == 0)
check = null;
else
check = matches.Length == 0;
result = new(check, results);
return result;
}
private record Record(bool? IsWrongYear, string[] Years);
}

View File

@ -202,6 +202,20 @@ internal abstract class XPath
}
}
internal static void CreateDirectories(ReadOnlyCollection<string> directories)
{
string checkDirectory;
foreach (string directory in directories)
{
for (int i = 0; i < 101; i++)
{
checkDirectory = Path.Combine(directory, i.ToString("000"));
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
}
}
}
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
{
DateTime dateTime = new(ticks);
@ -297,14 +311,19 @@ internal abstract class XPath
int converted;
string combined;
byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(resultSettings, filePath);
if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null)
throw new NotImplementedException();
if (filePath.HasIgnoreKeyword.Value)
@enum = IId.GetHasIgnoreKeyword(filePath);
else if (!filePath.HasDateTimeOriginal.Value)
if (!filePath.IsIntelligentIdFormat)
@enum = missingDateTimeOriginal;
else
@enum = IId.GetHasDateTimeOriginal(resultSettings, filePath);
{
if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null)
throw new NotImplementedException("Chicken and Egg!");
if (filePath.HasIgnoreKeyword.Value)
@enum = IId.GetHasIgnoreKeyword(filePath);
else if (!filePath.HasDateTimeOriginal.Value)
@enum = missingDateTimeOriginal;
else
@enum = IId.GetHasDateTimeOriginal(resultSettings, filePath);
}
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ?
new('-', resultSettings.ResultAllInOneSubdirectoryLength) :
@ -447,6 +466,7 @@ internal abstract class XPath
private static byte[] GetBytes() =>
[
0,
1,
2,
3,

View File

@ -17,6 +17,9 @@ namespace View_by_Distance.Windows;
public partial class Windows : IWindows, IDisposable
{
public long Ticks { get; init; }
public int? CurrentTick => _ProgressBar?.CurrentTick;
private ProgressBar? _ProgressBar;
private readonly ProgressBarOptions _ProgressBarOptions;
@ -156,19 +159,39 @@ public partial class Windows : IWindows, IDisposable
if (console is null)
throw new NullReferenceException(nameof(console));
IWindows windows = this;
long ticks = DateTime.Now.Ticks;
LogNetToHoursSince(logger);
Ticks = DateTime.Now.Ticks;
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
WindowsWork(logger, appSettings, windows, ticks);
WindowsWork(logger, appSettings, windows);
}
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
private static void LogNetToHoursSince(ILogger<Program>? logger)
{
double secondsInAHour = 3600f;
long epoch = new DateTime(1970, 1, 1).Ticks;
long net8ReleaseDate = new DateTime(2023, 11, 14).Ticks;
long net9ReleaseDate = new DateTime(2024, 11, 12).Ticks;
double net8TotalSeconds = new TimeSpan(net8ReleaseDate - epoch).TotalSeconds;
double net9TotalSeconds = new TimeSpan(net9ReleaseDate - epoch).TotalSeconds;
logger?.LogInformation("It has been {net8TotalSeconds} seconds since net8 was released", net8TotalSeconds);
logger?.LogInformation("It has been {net9TotalSeconds} seconds since net9 was released", net9TotalSeconds);
double net8TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net8TotalSeconds) / secondsInAHour);
double net9TotalHours = Math.Floor((DateTimeOffset.UtcNow.ToUnixTimeSeconds() - net9TotalSeconds) / secondsInAHour);
logger?.LogInformation("It has been {net8TotalHours} hours since net8 was released", net8TotalHours);
logger?.LogInformation("It has been {net9TotalHours} hours since net9 was released", net9TotalHours);
}
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows)
{
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);
if (!Directory.Exists(sourceDirectory))
_ = Directory.CreateDirectory(sourceDirectory);
logger?.LogInformation("{Ticks} {RootDirectory}", windows.Ticks, sourceDirectory);
WindowsWork(logger, appSettings, windows, sourceDirectory);
}
}
@ -243,6 +266,7 @@ public partial class Windows : IWindows, IDisposable
string paddedId = IId.GetPaddedId(resultSettings: appSettings.ResultSettings,
metadataSettings: appSettings.MetadataSettings,
id: deterministicHashCode.Id.Value,
extensionLowered: appSettings.ResultSettings.ValidImageFormatExtensions[0],
hasIgnoreKeyword: null,
hasDateTimeOriginal: null,
index: null);
@ -250,15 +274,12 @@ public partial class Windows : IWindows, IDisposable
messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})");
}
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, 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();
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).AsReadOnly();
if (files.Count > 0)
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
_ = IPath.DeleteEmptyDirectories(sourceDirectory);
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
@ -268,7 +289,7 @@ public partial class Windows : IWindows, IDisposable
else
results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
File.WriteAllText(Path.Combine(sourceDirectory, $"{windows.Ticks}.json"), json);
}
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
@ -376,7 +397,7 @@ public partial class Windows : IWindows, IDisposable
List<MetadataGroup> metadataGroups = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, metadata, distinct, metadataGroups));
if (_ProgressBar?.CurrentTick != results.Count)
if (windows?.CurrentTick != results.Count)
throw new NotSupportedException();
foreach (MetadataGroup metadataGroup in metadataGroups)
{