Removed Obsolete A_Property Methods

Changed GetDimensions to handle a stream at the end and one exit

Switched to using Action? over IDlibDotNet for Tick method
This commit is contained in:
2025-06-29 16:15:56 -07:00
parent c7ded16e50
commit 72ab5e737e
15 changed files with 330 additions and 462 deletions

12
.vscode/tasks.json vendored
View File

@ -148,6 +148,18 @@
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{
"label": "buildDuplicateSearch",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Duplicate-Search/Duplicate-Search.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{ {
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20", "label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
"type": "shell", "type": "shell",

View File

@ -1,4 +1,5 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Text.Json;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless.Methods; using View_by_Distance.Shared.Models.Stateless.Methods;
@ -57,7 +58,7 @@ internal abstract class Container
return results; return results;
} }
internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string _) internal static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers)
{ {
int count; int count;
Models.Container[] results; Models.Container[] results;
@ -101,11 +102,11 @@ internal abstract class Container
throw new Exception(); throw new Exception();
} }
} }
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories(); (_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, propertyConfiguration.ResultSingleton); string bMetadataSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
if (!Directory.Exists(aPropertySingletonDirectory)) if (!Directory.Exists(bMetadataSingletonDirectory))
_ = Directory.CreateDirectory(aPropertySingletonDirectory); _ = Directory.CreateDirectory(bMetadataSingletonDirectory);
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter); List<FilePair> filePairs = GetFilePairs(propertyConfiguration, bMetadataSingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter, dlibDotNet.Tick);
foreach (FilePair filePair in filePairs) foreach (FilePair filePair in filePairs)
{ {
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items)) if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
@ -126,24 +127,24 @@ internal abstract class Container
return (filePairs.Count, results.ToArray()); return (filePairs.Count, results.ToArray());
} }
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter) private static List<FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string bMetadataSingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter, Action? tick)
{ {
List<FilePair> results = []; List<FilePair> results = [];
const string extension = ".json"; const string extension = ".json";
ReadOnlyCollection<Shared.Models.FilePair> filePairs; ReadOnlyCollection<Shared.Models.FilePair> filePairs;
string jsonGroupDirectory = aPropertySingletonDirectory; string jsonGroupDirectory = bMetadataSingletonDirectory;
int maxDegreeOfParallelism = Environment.ProcessorCount; int maxDegreeOfParallelism = Environment.ProcessorCount;
int filesCollectionDirectoryLength = filesCollectionDirectory.Length; int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection); filePairs = IFilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => _ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) =>
ParallelFor(dlibDotNet, propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, exifDirectoriesById, filePairs[i], results)); ParallelFor(propertyConfiguration, jsonGroupDirectory, extension, keyValuePairs, splatNineIdentifiers, filesCollectionDirectoryLength, exifDirectoriesById, filePairs[i], results, tick));
return results; return results;
} }
private static void ParallelFor(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, int rootDirectoryLength, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, Shared.Models.FilePair filePair, List<FilePair> results) private static void ParallelFor(IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, int rootDirectoryLength, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, Shared.Models.FilePair filePair, List<FilePair> results, Action? tick)
{ {
dlibDotNet?.Tick(); tick?.Invoke();
bool abandoned = false; bool abandoned = false;
FileHolder sourceDirectoryFileHolder; FileHolder sourceDirectoryFileHolder;
if (exifDirectoriesById is null || filePair.FilePath.Id is null || !exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory)) if (exifDirectoriesById is null || filePair.FilePath.Id is null || !exifDirectoriesById.TryGetValue(filePair.FilePath.Id.Value, out ExifDirectory? exifDirectory))
@ -208,7 +209,14 @@ internal abstract class Container
string jsonFileName = $"{fileName}{extension}"; string jsonFileName = $"{fileName}{extension}";
string fullFileName = Path.Combine(directory, jsonFileName); string fullFileName = Path.Combine(directory, jsonFileName);
MoveIf(jsonFileName, cei, directory, fullFileName); MoveIf(jsonFileName, cei, directory, fullFileName);
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName); FileInfo fileInfo = new(fullFileName);
if (exifDirectory is not null && !fileInfo.Exists)
{
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
fileInfo.Refresh();
}
sourceDirectoryFileHolder = IFileHolder.Get(fileInfo);
} }
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks) if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
{ {

View File

@ -8,8 +8,8 @@ namespace View_by_Distance.Container.Models.Stateless.Methods;
public interface IContainer public interface IContainer
{ {
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) => public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers) =>
Container.GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory); Container.GetContainers(propertyConfiguration, splatNineIdentifiers);
public static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) => public static DateTime[] GetContainerDateTimes(ReadOnlyCollection<Item> items) =>
Container.GetContainerDateTimes(items); Container.GetContainerDateTimes(items);
@ -17,8 +17,8 @@ public interface IContainer
public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) => public static ReadOnlyCollection<Item> GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
Container.GetValidImageItems(propertyConfiguration, container); Container.GetValidImageItems(propertyConfiguration, container);
public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) => public static (int, Models.Container[]) GetContainers(IPropertyConfiguration propertyConfiguration) =>
GetContainers(propertyConfiguration, null, aPropertySingletonDirectory); GetContainers(propertyConfiguration, splatNineIdentifiers: null);
public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) => public static List<int> GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers); Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
@ -38,8 +38,8 @@ public interface IContainer
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) => internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, Models.Container container) =>
GetValidImageItems(propertyConfiguration, container); GetValidImageItems(propertyConfiguration, container);
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) => internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration) =>
GetContainers(propertyConfiguration, aPropertySingletonDirectory); GetContainers(propertyConfiguration);
internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) => internal List<int> TestStatic_GetFilteredDistinctIds(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers); GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
@ -50,8 +50,8 @@ public interface IContainer
internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) => internal ReadOnlyCollection<Item> TestStatic_GetValidImageItems(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems); GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, string aPropertySingletonDirectory) => internal (int, Models.Container[]) TestStatic_GetContainers(IPropertyConfiguration propertyConfiguration, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers) =>
GetContainers(propertyConfiguration, splatNineIdentifiers, aPropertySingletonDirectory); GetContainers(propertyConfiguration, splatNineIdentifiers);
internal ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) => internal ReadOnlyCollection<Models.Container> TestStatic_GetContainers(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string facesFileNameExtension, string facesHiddenFileNameExtension, string eDistanceContentDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById) =>
GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById); GetContainers(dlibDotNet, propertyConfiguration, facesFileNameExtension, facesHiddenFileNameExtension, eDistanceContentDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById);

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Phares.Shared; using Phares.Shared;
using System.Globalization; using System.Globalization;

View File

@ -571,14 +571,14 @@ public partial class E_Distance : IDistance
return results.AsReadOnly(); return results.AsReadOnly();
} }
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(IDlibDotNet dlibDotNet, Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> preFiltered, DistanceLimits distanceLimits, List<LocationContainer> postFiltered) public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> preFiltered, DistanceLimits distanceLimits, List<LocationContainer> postFiltered, Action? tick)
{ {
List<LocationContainer> results = []; List<LocationContainer> results = [];
ReadOnlyCollection<LocationContainer> locationContainers; ReadOnlyCollection<LocationContainer> locationContainers;
ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered); ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered);
foreach (LocationContainer locationContainer in postFiltered) foreach (LocationContainer locationContainer in postFiltered)
{ {
dlibDotNet.Tick(); tick?.Invoke();
locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer); locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer);
foreach (LocationContainer item in locationContainers) foreach (LocationContainer item in locationContainers)
{ {

View File

@ -3,7 +3,6 @@ using Phares.Shared;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using View_by_Distance.Drag_Drop.Models; using View_by_Distance.Drag_Drop.Models;
using View_by_Distance.Property.Models;
using View_by_Distance.Resize.Models; using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods; using View_by_Distance.Shared.Models.Stateless.Methods;
@ -20,7 +19,7 @@ public partial class DragDropSearch : Form
private readonly IsEnvironment _IsEnvironment; private readonly IsEnvironment _IsEnvironment;
private readonly Dictionary<int, Item> _IdToItem; private readonly Dictionary<int, Item> _IdToItem;
private readonly string _ResizeFileNameExtension; private readonly string _ResizeFileNameExtension;
private readonly Models.Configuration _Configuration; private readonly Configuration _Configuration;
private readonly IConfigurationRoot _ConfigurationRoot; private readonly IConfigurationRoot _ConfigurationRoot;
private readonly Property.Models.Configuration _PropertyConfiguration; private readonly Property.Models.Configuration _PropertyConfiguration;
@ -30,8 +29,8 @@ public partial class DragDropSearch : Form
_IdToItem = []; _IdToItem = [];
AppSettings appSettings; AppSettings appSettings;
string workingDirectory; string workingDirectory;
Configuration configuration;
IsEnvironment isEnvironment; IsEnvironment isEnvironment;
Models.Configuration configuration;
IConfigurationRoot configurationRoot; IConfigurationRoot configurationRoot;
Property.Models.Configuration propertyConfiguration; Property.Models.Configuration propertyConfiguration;
Assembly assembly = Assembly.GetExecutingAssembly(); Assembly assembly = Assembly.GetExecutingAssembly();
@ -93,8 +92,7 @@ public partial class DragDropSearch : Form
private void LoadData() private void LoadData()
{ {
Container.Models.Container[] containers; Container.Models.Container[] containers;
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}"); (_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration);
(_, containers) = View_by_Distance.Container.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory);
List<Item> collection = Program.GetItemCollection(_Configuration, containers); List<Item> collection = Program.GetItemCollection(_Configuration, containers);
foreach (Item item in collection) foreach (Item item in collection)
{ {

View File

@ -9,6 +9,7 @@ using View_by_Distance.Duplicate.Search.Models;
using View_by_Distance.Property.Models; using View_by_Distance.Property.Models;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Methods;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Duplicate.Search; namespace View_by_Distance.Duplicate.Search;
@ -71,8 +72,7 @@ public class DuplicateSearch
using (ProgressBar progressBar = new(1, message, options)) using (ProgressBar progressBar = new(1, message, options))
{ {
progressBar.Tick(); progressBar.Tick();
string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); (f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration);
(f, containers) = Container.Models.Stateless.Methods.IContainer.GetContainers(configuration, aPropertySingletonDirectory);
} }
return containers; return containers;
} }
@ -101,12 +101,15 @@ public class DuplicateSearch
private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds) private static Dictionary<int, List<MappingFromItem?>> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container.Models.Container[] containers, string destinationRoot, List<int> preloadIds)
{ {
Dictionary<int, List<MappingFromItem?>> results = []; Dictionary<int, List<MappingFromItem?>> results = [];
string? model;
string directory; string directory;
const int zero = 0; const int zero = 0;
DateTime? dateTime;
FileHolder resizedFileHolder; FileHolder resizedFileHolder;
DateTime[] containerDateTimes; DateTime[] containerDateTimes;
MappingFromItem? mappingFromItem; MappingFromItem? mappingFromItem;
List<MappingFromItem?>? collection; List<MappingFromItem?>? collection;
ReadOnlyCollection<string> keywords;
ReadOnlyCollection<Item> validImageItems; ReadOnlyCollection<Item> validImageItems;
const string duplicates = "-Duplicate(s)"; const string duplicates = "-Duplicate(s)";
if (containers.Length != 0) if (containers.Length != 0)
@ -145,12 +148,15 @@ public class DuplicateSearch
mappingFromItem = collection[zero]; mappingFromItem = collection[zero];
if (mappingFromItem is not null) if (mappingFromItem is not null)
{ {
dateTime = IDate.GetDateTimeOriginal(item.ExifDirectory);
keywords = IMetaBase.GetKeywords(item.ExifDirectory?.ExifBaseDirectories);
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(item.ExifDirectory);
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}")); resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}"));
collection[0] = new(mappingFromItem.ContainerDateTimes, item.Property.DateTimeDigitized, item.Property.DateTimeOriginal, mappingFromItem.Id, mappingFromItem.IsArchive, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, item.Property.Keywords ?? [], mappingFromItem.MinimumDateTime, item.Property.Model, mappingFromItem.RelativePath, resizedFileHolder); collection[0] = new(mappingFromItem.ContainerDateTimes, dateTime, mappingFromItem.Id, mappingFromItem.IsArchive, mappingFromItem.FilePath, mappingFromItem.IsWrongYear, keywords, mappingFromItem.MinimumDateTime, model, mappingFromItem.RelativePath, resizedFileHolder);
} }
} }
resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath)); resizedFileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath));
mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
collection.Add(mappingFromItem); collection.Add(mappingFromItem);
} }
} }

View File

@ -67,6 +67,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
_Exceptions = []; _Exceptions = [];
_Console = console; _Console = console;
_AppSettings = appSettings; _AppSettings = appSettings;
IDlibDotNet dlibDotNet = this;
_IsEnvironment = isEnvironment; _IsEnvironment = isEnvironment;
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
_JLinkResolvedDirectories = []; _JLinkResolvedDirectories = [];
@ -128,8 +129,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
{ {
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $") Building People Collection - {totalSeconds} total second(s)"; message = $") Building People Collection - {totalSeconds} total second(s)";
using ProgressBar progressBar = new(1, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(1, message);
progressBar.Tick(); dlibDotNet.Tick();
string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People)); string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People));
string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception(); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception();
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, propertyConfiguration.ResultSingleton)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, propertyConfiguration.ResultSingleton));
@ -196,7 +197,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string[] changesFrom = [nameof(A_Property)]; string[] changesFrom = [nameof(A_Property)];
List<Tuple<string, DateTime>> subFileTuples = []; List<Tuple<string, DateTime>> subFileTuples = [];
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber); FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any()) if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null)
throw new Exception();
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
throw new Exception(); throw new Exception();
if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime && item.SourceDirectoryFileHolder.LastWriteTime.Value != item.SourceDirectoryFileHolder.CreationTime.Value) if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime && item.SourceDirectoryFileHolder.LastWriteTime.Value != item.SourceDirectoryFileHolder.CreationTime.Value)
{ {
@ -327,12 +330,13 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
{ {
int result = 0; int result = 0;
int exceptionsCount = 0; int exceptionsCount = 0;
IDlibDotNet dlibDotNet = this;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
DateTime[] containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); DateTime[] containerDateTimes = Container.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems);
string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory)); string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory));
bool? isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath); bool? isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath);
bool anyPropertiesChangedForX = _Configuration.PropertyConfiguration.PropertiesChangedForProperty || _Configuration.PropertiesChangedForDistance || _Configuration.PropertiesChangedForFaces || _Configuration.PropertiesChangedForIndex || _Configuration.PropertiesChangedForMetadata || _Configuration.PropertiesChangedForResize; bool anyPropertiesChangedForX = _Configuration.PropertyConfiguration.PropertiesChangedForProperty || _Configuration.PropertiesChangedForDistance || _Configuration.PropertiesChangedForFaces || _Configuration.PropertiesChangedForIndex || _Configuration.PropertiesChangedForMetadata || _Configuration.PropertiesChangedForResize;
using ProgressBar progressBar = new(filteredItems.Count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(filteredItems.Count, message);
_ = Parallel.For(0, filteredItems.Count, parallelOptions, (i, state) => _ = Parallel.For(0, filteredItems.Count, parallelOptions, (i, state) =>
{ {
try try
@ -351,7 +355,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
containerDateTimes, containerDateTimes,
isFocusRelativePath); isFocusRelativePath);
if (!anyPropertiesChangedForX && (i == 0 || sourceDirectoryChanges.Count > 0)) if (!anyPropertiesChangedForX && (i == 0 || sourceDirectoryChanges.Count > 0))
progressBar.Tick(); dlibDotNet.Tick();
} }
catch (Exception) catch (Exception)
{ {
@ -450,8 +454,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
} }
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $"{totalSeconds} total second(s) - {outputResolution} - ### [###] / {readOnlyContainers.Count:000} - {total} / {count} total - <> - total not mapped {totalNotMapped:000000}"; message = $"{totalSeconds} total second(s) - {outputResolution} - ### [###] / {readOnlyContainers.Count:000} - {total} / {count} total - <> - total not mapped {totalNotMapped:000000}";
using ProgressBar progressBar = new(1, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(1, message);
progressBar.Tick(); dlibDotNet.Tick();
} }
} }
@ -607,7 +611,11 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
{ {
ExifDirectory? result; ExifDirectory? result;
if (filePair.Match is null) if (filePair.Match is null)
result = null; {
try
{ result = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath); }
catch (Exception) { result = null; }
}
else else
{ {
string json = File.ReadAllText(filePair.Match.FullName); string json = File.ReadAllText(filePair.Match.FullName);
@ -1003,9 +1011,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
return results.AsReadOnly(); return results.AsReadOnly();
} }
private void ParallelFor(IDlibDotNet dlibDotNet, FilePair filePair, Dictionary<int, ExifDirectory> results) private void ParallelFor(FilePair filePair, Dictionary<int, ExifDirectory> results, Action? tick)
{ {
dlibDotNet?.Tick(); tick?.Invoke();
if (filePair.FilePath.Id is null || results.ContainsKey(filePair.FilePath.Id.Value)) if (filePair.FilePath.Id is null || results.ContainsKey(filePair.FilePath.Id.Value))
return; return;
ExifDirectory? exifDirectory = GetExifDirectory(filePair); ExifDirectory? exifDirectory = GetExifDirectory(filePair);
@ -1087,7 +1095,6 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
const string directorySearchFilter = "*"; const string directorySearchFilter = "*";
bool configurationOutputResolutionsHas = false; bool configurationOutputResolutionsHas = false;
ReadOnlyDictionary<long, List<int>> personKeyToIds; ReadOnlyDictionary<long, List<int>> personKeyToIds;
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
string[] checkDirectories = string[] checkDirectories =
[ [
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Ancestry"), Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Ancestry"),
@ -1096,6 +1103,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
]; ];
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks, checkDirectories); bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks, checkDirectories);
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(); (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks); Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks);
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])"); a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
@ -1145,30 +1153,25 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
{ {
if (outputResolution.Any(char.IsNumber)) if (outputResolution.Any(char.IsNumber))
continue; continue;
Dictionary<int, ExifDirectory> exifDirectoriesById = []; bool filesCollectionCountIsOne = record?.FilesCollectionCountIsOne ?? false;
(cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
string? filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent); ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = record?.ExifDirectoriesById ?? new(new Dictionary<int, ExifDirectory>());
string? filesCollectionRootDirectory = record?.FilesCollectionRootDirectory ?? Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: true); ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: true);
record = new(FilesCollectionRootDirectory: filesCollectionRootDirectory, record = new(FilesCollectionRootDirectory: filesCollectionRootDirectory,
FilesCollectionCountIsOne: false, FilesCollectionCountIsOne: filesCollectionCountIsOne,
FilePathsCollection: filePathsCollection, FilePathsCollection: filePathsCollection,
ExifDirectoriesById: new(exifDirectoriesById), ExifDirectoriesById: exifDirectoriesById,
IdToFilePaths: null, IdToFilePaths: record?.IdToFilePaths,
SplatNineIdentifiers: null); SplatNineIdentifiers: record?.SplatNineIdentifiers);
break; break;
} }
} }
if (string.IsNullOrEmpty(record?.FilesCollectionRootDirectory) || record.FilePathsCollection.Count == 0) if (string.IsNullOrEmpty(record?.FilesCollectionRootDirectory) || record.FilePathsCollection.Count == 0)
throw new NullReferenceException(nameof(record.FilePathsCollection)); throw new NullReferenceException(nameof(record.FilePathsCollection));
foreach (string checkDirectory in checkDirectories)
{
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
if (!Directory.Exists(seasonDirectory))
_ = Directory.CreateDirectory(seasonDirectory);
}
int count = record.FilePathsCollection.Select(l => l.Count).Sum(); int count = record.FilePathsCollection.Select(l => l.Count).Sum();
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
_ProgressBar = new(count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(count, message);
ReadOnlyCollection<Container.Models.Container> readOnlyContainers = ReadOnlyCollection<Container.Models.Container> readOnlyContainers =
Container.Models.Stateless.Methods.IContainer.GetContainers(dlibDotNet, Container.Models.Stateless.Methods.IContainer.GetContainers(dlibDotNet,
_Configuration.PropertyConfiguration, _Configuration.PropertyConfiguration,
@ -1180,20 +1183,18 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
record.SplatNineIdentifiers, record.SplatNineIdentifiers,
record.FilePathsCollection, record.FilePathsCollection,
record.ExifDirectoriesById); record.ExifDirectoriesById);
_ProgressBar.Dispose(); Verify(argZero, readOnlyContainers);
foreach (string checkDirectory in checkDirectories)
{
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
if (!Directory.Exists(seasonDirectory))
_ = Directory.CreateDirectory(seasonDirectory);
}
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
DeleteContinueFiles(personContainers); DeleteContinueFiles(personContainers);
if (!runToDoCollectionFirst) if (!runToDoCollectionFirst)
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory); MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory);
FullDoWork(argZero, FullDoWork(argZero, propertyRoot, ticks, fPhotoPrismSingletonDirectory, count, metadata, record, readOnlyContainers, mapLogic);
propertyRoot,
ticks,
fPhotoPrismSingletonDirectory,
count,
metadata,
record,
readOnlyContainers,
mapLogic);
ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true); ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
if (_Configuration.LookForAbandoned) if (_Configuration.LookForAbandoned)
{ {
@ -1201,10 +1202,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
string d2ResultsFullGroupDirectory; string d2ResultsFullGroupDirectory;
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), _ProgressBarOptions); dlibDotNet.ConstructProgressBar(5, nameof(mapLogic.LookForAbandoned));
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution); (cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
mapLogic.LookForAbandoned(dlibDotNet, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); mapLogic.LookForAbandoned(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, dlibDotNet.Tick);
_ProgressBar.Dispose();
} }
} }
_Distance.Clear(); _Distance.Clear();
@ -1253,12 +1253,49 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
} }
} }
private void Verify(string argZero, ReadOnlyCollection<Container.Models.Container> readOnlyContainers)
{
int count = 0;
List<Item> items = [];
Container.Models.Container container;
ReadOnlyCollection<Item> filteredItems;
foreach (string outputResolution in _Configuration.OutputResolutions)
{
for (int i = 0; i < readOnlyContainers.Count; i++)
{
container = readOnlyContainers[i];
if (container.Items.Count == 0)
continue;
if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue;
filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, container);
if (filteredItems.Count == 0)
continue;
foreach (Item item in filteredItems)
{
count++;
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null)
{
items.Add(item);
continue;
}
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
{
items.Add(item);
continue;
}
}
}
}
if (items.Count > 0)
throw new Exception($"{items.Count} item(s) of {count} item(s) are not setup!");
}
private Record GetFilesCollectionThenCopyOrMove(IDlibDotNet dlibDotNet, long ticks, string fileSearchFilter, string directorySearchFilter, string bResultsFullGroupDirectory, string outputResolution) private Record GetFilesCollectionThenCopyOrMove(IDlibDotNet dlibDotNet, long ticks, string fileSearchFilter, string directorySearchFilter, string bResultsFullGroupDirectory, string outputResolution)
{ {
Record result; Record result;
int count; int count;
string message; string message;
ProgressBar progressBar;
const string extension = ".json"; const string extension = ".json";
ReadOnlyCollection<FilePair> filePairs; ReadOnlyCollection<FilePair> filePairs;
int maxDegreeOfParallelism = Environment.ProcessorCount; int maxDegreeOfParallelism = Environment.ProcessorCount;
@ -1276,24 +1313,23 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
count = filePathsCollection.Select(l => l.Count).Sum(); count = filePathsCollection.Select(l => l.Count).Sum();
filePairs = IFilePair.GetFilePairs(_Configuration.PropertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection); filePairs = IFilePair.GetFilePairs(_Configuration.PropertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; message = $") Preloading ExifDirectory Dictionary - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
progressBar = new(count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(count, message);
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], exifDirectoriesById)); _ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(filePairs[i], exifDirectoriesById, dlibDotNet.Tick));
progressBar.Dispose(); if (exifDirectoriesById.Count == 0)
throw new Exception("No exif directories were found!");
count = filePathsCollection.Select(l => l.Count).Sum(); count = filePathsCollection.Select(l => l.Count).Sum();
bool filesCollectionCountIsOne = GetFilesCollectionCountIsOne(filePathsCollection); bool filesCollectionCountIsOne = GetFilesCollectionCountIsOne(filePathsCollection);
message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
progressBar = new(count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(count, message);
(string[] distinctDirectories, List<(FilePath, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, () => progressBar.Tick()); (string[] distinctDirectories, List<(FilePath, string)> toDoCollection) = IDirectory.GetToDoCollection(_Configuration.PropertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, dlibDotNet.Tick);
progressBar.Dispose();
foreach (string distinctDirectory in distinctDirectories) foreach (string distinctDirectory in distinctDirectories)
{ {
if (!Directory.Exists(distinctDirectory)) if (!Directory.Exists(distinctDirectory))
_ = Directory.CreateDirectory(distinctDirectory); _ = Directory.CreateDirectory(distinctDirectory);
} }
message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; message = $") Copying to ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
progressBar = new(count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(count, message);
_ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, () => progressBar.Tick()); _ = IDirectory.CopyOrMove(toDoCollection, move: false, moveBack: false, dlibDotNet.Tick);
progressBar.Dispose();
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection); ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
ReadOnlyDictionary<int, Identifier> splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, idToFilePaths); ReadOnlyDictionary<int, Identifier> splatNineIdentifiers = GetSplatNineIdentifiersAndHideSplatNine(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, idToFilePaths);
result = new(ExifDirectoriesById: new(exifDirectoriesById), result = new(ExifDirectoriesById: new(exifDirectoriesById),
@ -1362,9 +1398,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
else else
{ {
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)"; string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
_ProgressBar = new(postFiltered.Count, message, _ProgressBarOptions); dlibDotNet.ConstructProgressBar(postFiltered.Count, message);
ReadOnlyCollection<LocationContainer> matrix = E_Distance.GetMatrixLocationContainers(dlibDotNet, _MapConfiguration, ticks, mapLogic, mappedWithEncoding, preFiltered, distanceLimits, postFiltered); ReadOnlyCollection<LocationContainer> matrix = E_Distance.GetMatrixLocationContainers(_MapConfiguration, ticks, mapLogic, mappedWithEncoding, preFiltered, distanceLimits, postFiltered, dlibDotNet.Tick);
_ProgressBar.Dispose();
ReadOnlyDictionary<string, LocationContainer> onlyOne = GetOnlyOne(distanceLimits, matrix); ReadOnlyDictionary<string, LocationContainer> onlyOne = GetOnlyOne(distanceLimits, matrix);
if (onlyOne.Count == 0) if (onlyOne.Count == 0)
results = []; results = [];

View File

@ -921,16 +921,16 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result; return result;
} }
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container.Models.Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, Action? tick)
{ {
string[] directories; string[] directories;
string? directoryName; string? directoryName;
List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers); List<int> distinctFilteredIds = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
LookForAbandoned(propertyConfiguration, distinctFilteredIds); LookForAbandoned(propertyConfiguration, distinctFilteredIds);
dlibDotNet.Tick(); tick?.Invoke();
List<string> distinctFilteredFileNameFirstSegments = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers); List<string> distinctFilteredFileNameFirstSegments = Container.Models.Stateless.Methods.IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
dlibDotNet.Tick(); tick?.Invoke();
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
@ -939,7 +939,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick(); tick?.Invoke();
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
@ -948,7 +948,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick(); tick?.Invoke();
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly); directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories) foreach (string directory in directories)
{ {
@ -957,7 +957,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
continue; continue;
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName); Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
} }
dlibDotNet.Tick(); tick?.Invoke();
} }
private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds) private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds)

View File

@ -8,18 +8,18 @@ internal static class Dimensions
#pragma warning disable IDE0230 #pragma warning disable IDE0230
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new() private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
{ {
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
{ new byte[] { 0x42, 0x4D }, DecodeBitmap }, { 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, 0x37, 0x61 }, DecodeGif },
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif }, { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng }, { 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 #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]) if (thisBytes[i] == thatBytes[i])
continue; continue;
@ -103,24 +103,41 @@ internal static class Dimensions
internal static Size? GetDimensions(BinaryReader binaryReader) internal static Size? GetDimensions(BinaryReader binaryReader)
{ {
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length; Size? result;
byte[] magicBytes = new byte[maxMagicBytesLength]; List<byte> magicBytes = [];
for (int i = 0; i < maxMagicBytesLength; i += 1) 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(); result = null;
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders) 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)) magicBytes.Add(binaryReader.ReadByte());
return kvPair.Value(binaryReader); 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) internal static Size? GetDimensions(string path)
{ {
using BinaryReader binaryReader = new(File.OpenRead(path)); Size? result;
return GetDimensions(binaryReader); using FileStream fileStream = File.OpenRead(path);
using BinaryReader binaryReader = new(fileStream);
result = GetDimensions(binaryReader);
return result;
} }
} }

View File

@ -1,4 +1,3 @@
using ShellProgressBar;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
@ -66,40 +65,6 @@ public class A_Property
converted: false)); converted: false));
} }
[Obsolete("Use ExifDirectory")]
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container.Models.Container[] containers)
{
int total = 0;
string message;
int totalSeconds;
bool anyNullOrNoIsUniqueFileName;
List<Exception> exceptions = [];
Container.Models.Container container;
int containersLength = containers.Length;
const string outputResolution = "Original";
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
string propertyRoot = IResult.GetResultsGroupDirectory(_PropertyConfiguration, nameof(A_Property));
for (int i = 0; i < containers.Length; i++)
{
container = containers[i];
if (container.Items.Count == 0)
continue;
sourceDirectoryChanges.Clear();
if (container.Items.Count == 0)
continue;
anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName);
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message);
if (exceptions.Count == container.Items.Count)
throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!"));
if (exceptions.Count != 0)
_ExceptionsDirectories.Add(container.SourceDirectory);
total += container.Items.Count;
}
}
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName) private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
{ {
_AngleBracketCollection.Clear(); _AngleBracketCollection.Clear();
@ -112,180 +77,6 @@ public class A_Property
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
} }
[Obsolete("Use ExifDirectory")]
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container.Models.Container container, ReadOnlyCollection<Item> items, string message)
{
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(items.Count, message, options);
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
{
try
{
long ticks = DateTime.Now.Ticks;
DateTime dateTime = DateTime.Now;
List<Tuple<string, DateTime>> collection;
SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
if (i == 0 || sourceDirectoryChanges.Count != 0)
progressBar.Tick();
lock (sourceDirectoryFileTuples)
collection = (from l in sourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList();
lock (sourceDirectoryChanges)
sourceDirectoryChanges.AddRange(collection);
}
catch (Exception ex)
{
lock (exceptions)
exceptions.Add(ex);
}
});
}
[Obsolete("Use ExifDirectory")]
private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
{
Shared.Models.Property property;
List<string> parseExceptions = [];
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}");
if (item.IsValidImageFormatExtension && item.FilePath.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.FilePath.FullName != filteredSourceDirectoryFileExtensionLowered)
File.Move(item.FilePath.FullName, filteredSourceDirectoryFileExtensionLowered);
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.ExifDirectory is null)
{
property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
lock (sourceDirectoryChanges)
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
lock (item)
item.Update(null);
}
}
[Obsolete("Use ExifDirectory")]
private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension)
{
Shared.Models.Property? result;
int? id = null;
FileInfo fileInfo;
string? json = null;
bool hasWrongYearProperty = false;
string[] changesFrom = [];
string angleBracket = _AngleBracketCollection[0];
bool populateId = _Configuration.PopulatePropertyId;
if (!item.IsUniqueFileName)
fileInfo = new(Path.Combine(angleBracket.Replace("<>", _PropertyConfiguration.ResultSingleton), $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"));
else
{
string fileName = $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json";
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, item.FilePath);
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
fileInfo = new(Path.Combine(directory, fileName));
MoveIf(fileName, cei, directory, fileInfo);
}
List<DateTime> dateTimes = (from l in sourceDirectoryFileTuples where l is not null && changesFrom.Contains(l.Item1) select l.Item2).ToList();
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
{
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
fileInfo.Refresh();
}
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
}
if (_Configuration.PropertiesChangedForProperty)
result = null;
else if (!fileInfo.Exists)
result = null;
else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old"))
throw new ArgumentException("must be a *.json file");
else if (dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
result = null;
else
{
json = File.ReadAllText(fileInfo.FullName);
try
{
if (item.ExifDirectory is not null)
result = null;
else
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
if (result is not null && json.Contains("WrongYear"))
{
id = result.Id;
hasWrongYearProperty = true;
result = null;
}
if (!isIgnoreExtension && item.IsValidImageFormatExtension && ((populateId && result?.Id is null) || result?.Width is null || result.Height is null))
{
id = result?.Id;
result = null;
}
if (!isIgnoreExtension && item.IsValidImageFormatExtension && populateId && result is not null && result.LastWriteTime.Ticks != item.FilePath.LastWriteTicks)
{
id = null;
result = null;
}
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result?.Width is not null && result.Height is not null && result.Width.Value == result.Height.Value)
{
id = result.Id;
result = null;
if (result?.Width is not null && result.Height is not null && result.Width.Value != result.Height.Value)
throw new Exception("Was square!");
}
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result is not null && result.FileSize != item.FilePath.Length)
{
id = result.Id;
result = null;
}
if (result is not null)
{
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.LastWriteTime));
if (fileInfo.CreationTime != result.LastWriteTime)
{
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
}
}
}
catch (Exception)
{
result = null;
parseExceptions.Add(nameof(A_Property));
}
}
if (result is null)
{
id ??= item.FilePath.Id;
(_, _, result) = Stateless.Property.GetProperty(populateId, metadata, item.FilePath, result, isIgnoreExtension, item.IsValidImageFormatExtension, id, _ASCIIEncoding);
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
{
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime)
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
else
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
}
}
}
else if (hasWrongYearProperty)
{
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
{
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
}
}
return result;
}
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo) private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
{ {
string[] segments = directory.Split(cei.Combined); string[] segments = directory.Split(cei.Combined);
@ -305,22 +96,4 @@ public class A_Property
} }
} }
[Obsolete("Use ExifDirectory")]
public Shared.Models.Property GetProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions)
{
Shared.Models.Property result;
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
if (!angleBracketCollectionAny)
{
if (item.FilePath.DirectoryFullPath is null)
throw new NullReferenceException(nameof(item.FilePath.DirectoryFullPath));
SetAngleBracketCollection(item.FilePath.DirectoryFullPath, !item.IsUniqueFileName);
}
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
result = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
if (!angleBracketCollectionAny)
_AngleBracketCollection.Clear();
return result;
}
} }

View File

@ -76,7 +76,7 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem
} }
else else
{ {
System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom); System.Drawing.Size size = Stateless.Methods.Dimensions.GetDimensions(fileInfo.FullName, faceRight, faceBottom);
imageWidth = size.Width; imageWidth = size.Width;
imageHeight = size.Height; imageHeight = size.Height;
} }

View File

@ -0,0 +1,149 @@
using System.Drawing;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
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 },
};
#pragma warning restore IDE0230
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
{
for (int i = 0; i < thisBytes.Count && i < thatBytes.Length; i += 1)
{
if (thisBytes[i] == thatBytes[i])
continue;
return false;
}
return true;
}
private static short ReadLittleEndianInt16(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(short)];
for (int i = 0; i < sizeof(short); i += 1)
bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt16(bytes, 0);
}
private static int ReadLittleEndianInt32(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(int)];
for (int i = 0; i < sizeof(int); i += 1)
bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt32(bytes, 0);
}
private static Size? DecodeBitmap(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(16);
int width = binaryReader.ReadInt32();
int height = binaryReader.ReadInt32();
return new Size(width, height);
}
private static Size? DecodeGif(BinaryReader binaryReader)
{
int width = binaryReader.ReadInt16();
int height = binaryReader.ReadInt16();
return new Size(width, height);
}
private static Size? DecodePng(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(8);
int width = ReadLittleEndianInt32(binaryReader);
int height = ReadLittleEndianInt32(binaryReader);
return new Size(width, height);
}
private static Size? DecodeJfif(BinaryReader binaryReader)
{
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
short chunkLength = ReadLittleEndianInt16(binaryReader);
if (marker == 0xc0)
{
_ = binaryReader.ReadByte();
int height = ReadLittleEndianInt16(binaryReader);
int width = ReadLittleEndianInt16(binaryReader);
return new Size(width, height);
}
if (chunkLength >= 0)
_ = binaryReader.ReadBytes(chunkLength - 2);
else
{
ushort uChunkLength = (ushort)chunkLength;
_ = binaryReader.ReadBytes(uChunkLength - 2);
}
}
return null;
}
private static Size? DecodeWebP(BinaryReader binaryReader)
{
_ = binaryReader.ReadUInt32(); // Size
_ = binaryReader.ReadBytes(15); // WEBP, VP8 + more
_ = binaryReader.ReadBytes(3); // SYNC
int width = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits width
int height = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits height
return new Size(width, height);
}
internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom)
{
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
{
result = null;
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
for (int i = 0; i < magicBytesLengths[0]; i++)
{
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;
}
}
if (result is null)
{
if (faceRight is null || faceBottom is null)
throw new Exception("face is null!");
result = new(faceRight.Value, faceBottom.Value);
}
return result.Value;
}
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
{
Size result;
using FileStream fileStream = File.OpenRead(path);
using BinaryReader binaryReader = new(fileStream);
result = GetDimensions(binaryReader, faceRight, faceBottom);
return result;
}
}

View File

@ -1,132 +0,0 @@
using System.Drawing;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class ImageHelper
{
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
{
for (int i = 0; i < thatBytes.Length; i += 1)
{
if (thisBytes[i] != thatBytes[i])
return false;
}
return true;
}
private static short ReadLittleEndianInt16(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(short)];
for (int i = 0; i < sizeof(short); i += 1)
bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt16(bytes, 0);
}
private static int ReadLittleEndianInt32(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(int)];
for (int i = 0; i < sizeof(int); i += 1)
bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt32(bytes, 0);
}
private static Size DecodeBitmap(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(16);
int width = binaryReader.ReadInt32();
int height = binaryReader.ReadInt32();
return new Size(width, height);
}
private static Size DecodeGif(BinaryReader binaryReader)
{
int width = binaryReader.ReadInt16();
int height = binaryReader.ReadInt16();
return new Size(width, height);
}
private static Size DecodePng(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(8);
int width = ReadLittleEndianInt32(binaryReader);
int height = ReadLittleEndianInt32(binaryReader);
return new Size(width, height);
}
private static Size DecodeJfif(BinaryReader binaryReader)
{
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
short chunkLength = ReadLittleEndianInt16(binaryReader);
if (marker == 0xc0)
{
_ = binaryReader.ReadByte();
int height = ReadLittleEndianInt16(binaryReader);
int width = ReadLittleEndianInt16(binaryReader);
return new Size(width, height);
}
_ = binaryReader.ReadBytes(chunkLength - 2);
}
throw new ArgumentException("Could not recognize image format.");
}
/// <summary>
/// Gets the dimensions of an image.
/// </summary>
/// <param name="path">The path of the image to get the dimensions of.</param>
/// <returns>The dimensions of the specified image.</returns>
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom)
{
Size? result = null;
#pragma warning disable IDE0230
Dictionary<byte[], Func<BinaryReader, Size>> _ImageFormatDecoders = new()
{
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
{ 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 },
};
#pragma warning restore IDE0230
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
byte[] magicBytes = new byte[maxMagicBytesLength];
for (int i = 0; i < maxMagicBytesLength; i += 1)
{
magicBytes[i] = binaryReader.ReadByte();
foreach (KeyValuePair<byte[], Func<BinaryReader, Size>> kvPair in _ImageFormatDecoders)
{
if (!StartsWith(magicBytes, kvPair.Key))
continue;
result = kvPair.Value(binaryReader);
break;
}
if (result is not null)
break;
}
if (result is null)
{
if (faceRight is null || faceBottom is null)
throw new Exception("face is null!");
result = new(faceRight.Value, faceBottom.Value);
}
return result.Value;
}
/// <summary>
/// Gets the dimensions of an image.
/// </summary>
/// <param name="path">The path of the image to get the dimensions of.</param>
/// <returns>The dimensions of the specified image.</returns>
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
{
Size result;
using BinaryReader binaryReader = new(File.OpenRead(path));
result = GetDimensions(binaryReader, faceRight, faceBottom);
return result;
}
}

View File

@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Search", "Drag-Dr
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Set-Property-Item", "Drag-Drop-Set-Property-Item\Drag-Drop-Set-Property-Item.csproj", "{BFF75D8C-48E6-4B84-B480-3E5A4F9B2DD8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Set-Property-Item", "Drag-Drop-Set-Property-Item\Drag-Drop-Set-Property-Item.csproj", "{BFF75D8C-48E6-4B84-B480-3E5A4F9B2DD8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicate-Search", "Duplicate-Search\Duplicate-Search.csproj", "{48E87D9B-B802-467A-BDC7-E86F7FD01D5C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Face", "Face\Face.csproj", "{A12E19E5-59C0-40D4-B807-DF1334D4906D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Face", "Face\Face.csproj", "{A12E19E5-59C0-40D4-B807-DF1334D4906D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceParts", "FaceParts\FaceParts.csproj", "{919525B1-60BA-40C6-BA66-6F7F4C526E01}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceParts", "FaceParts\FaceParts.csproj", "{919525B1-60BA-40C6-BA66-6F7F4C526E01}"