Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
23256c8152 | |||
1bbe583359 | |||
9fb6f0fa05 | |||
ae23e803fa | |||
c15c854481 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -475,4 +475,4 @@ Rename/.vscode/.UserSecrets/secrets.json
|
||||
Rename/.vscode/.UserSecretsOld/rename.json
|
||||
Rename/.vscode/.UserSecretsOld/secrets.json
|
||||
Windows/.vscode/.UserSecrets/secrets.json
|
||||
Windows/.vscode/.iCloudPhotos2025
|
||||
Windows/.vscode/.7-Question
|
14
.vscode/tasks.json
vendored
14
.vscode/tasks.json
vendored
@ -628,5 +628,19 @@
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
||||
"type": "shell",
|
||||
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
||||
"args": [
|
||||
"s",
|
||||
"X",
|
||||
"L:/Git/AA",
|
||||
"Day-Helper-2025-03-20",
|
||||
"false",
|
||||
"4"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
@ -7,9 +7,12 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>770b6ae3-266e-4d5f-970a-173709b064de</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Compare</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -36,10 +39,10 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\"/>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.12" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.14" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
|
@ -17,6 +17,21 @@ public partial class Compare : ICompare, IDisposable
|
||||
private ProgressBar? _ProgressBar;
|
||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||
|
||||
void ICompare.Tick() =>
|
||||
_ProgressBar?.Tick();
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
void ICompare.ConstructProgressBar(int maxTicks, string message)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
public Compare(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||
{
|
||||
if (isSilent)
|
||||
@ -31,19 +46,46 @@ public partial class Compare : ICompare, IDisposable
|
||||
CompareWork(logger, appSettings, compare, ticks);
|
||||
}
|
||||
|
||||
void ICompare.Tick() =>
|
||||
_ProgressBar?.Tick();
|
||||
|
||||
void ICompare.ConstructProgressBar(int maxTicks, string message)
|
||||
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
const int updated = 0;
|
||||
DistanceLimits? distanceLimits;
|
||||
logger?.LogInformation("{Ticks}", ticks);
|
||||
ReadOnlyCollection<LocationContainer> matrix;
|
||||
ReadOnlyCollection<SaveContainer> saveContainers;
|
||||
ReadOnlyCollection<ExifDirectory> exifDirectories;
|
||||
ReadOnlyCollection<LocationContainer> preFiltered;
|
||||
ReadOnlyCollection<LocationContainer> postFiltered;
|
||||
ReadOnlyDictionary<string, LocationContainer> onlyOne;
|
||||
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
|
||||
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
|
||||
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
|
||||
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
|
||||
{
|
||||
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
|
||||
continue;
|
||||
_ProgressBar?.Dispose();
|
||||
logger?.LogInformation("{outputResolution}", outputResolution);
|
||||
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
|
||||
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
if (preFiltered.Count == 0)
|
||||
continue;
|
||||
distanceLimits = new(appSettings.DistanceSettings);
|
||||
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||
if (postFiltered.Count == 0)
|
||||
continue;
|
||||
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
if (matrix.Count == 0)
|
||||
continue;
|
||||
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
|
||||
if (onlyOne.Count == 0)
|
||||
continue;
|
||||
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
if (saveContainers.Count == 0)
|
||||
continue;
|
||||
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks)
|
||||
@ -123,46 +165,4 @@ public partial class Compare : ICompare, IDisposable
|
||||
return results;
|
||||
}
|
||||
|
||||
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
|
||||
{
|
||||
const int updated = 0;
|
||||
DistanceLimits? distanceLimits;
|
||||
logger?.LogInformation("{Ticks}", ticks);
|
||||
ReadOnlyCollection<LocationContainer> matrix;
|
||||
ReadOnlyCollection<SaveContainer> saveContainers;
|
||||
ReadOnlyCollection<ExifDirectory> exifDirectories;
|
||||
ReadOnlyCollection<LocationContainer> preFiltered;
|
||||
ReadOnlyCollection<LocationContainer> postFiltered;
|
||||
ReadOnlyDictionary<string, LocationContainer> onlyOne;
|
||||
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
|
||||
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
|
||||
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
|
||||
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
|
||||
{
|
||||
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
|
||||
continue;
|
||||
_ProgressBar?.Dispose();
|
||||
logger?.LogInformation("{outputResolution}", outputResolution);
|
||||
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
|
||||
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
if (preFiltered.Count == 0)
|
||||
continue;
|
||||
distanceLimits = new(appSettings.DistanceSettings);
|
||||
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||
if (postFiltered.Count == 0)
|
||||
continue;
|
||||
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
if (matrix.Count == 0)
|
||||
continue;
|
||||
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
|
||||
if (onlyOne.Count == 0)
|
||||
continue;
|
||||
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
if (saveContainers.Count == 0)
|
||||
continue;
|
||||
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -20,16 +20,16 @@ public record AppSettings(ResultSettings ResultSettings,
|
||||
|
||||
private static void Verify(AppSettings appSettings)
|
||||
{
|
||||
if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDaysDeltaTolerance));
|
||||
if (appSettings.DistanceSettings.RangeDistanceTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeDistanceTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDistanceTolerance));
|
||||
if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceAreaTolerance));
|
||||
if (appSettings.DistanceSettings.RangeFaceConfidence.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeFaceConfidence.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceConfidence));
|
||||
_ = DateTime.Now.AddDays(-appSettings.DistanceSettings.RangeDaysDeltaTolerance[1]);
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Length > 0)
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any())
|
||||
throw new Exception("Settings has SaveSortingWithoutPerson and JLinks!");
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && !string.IsNullOrEmpty(appSettings.DistanceSettings.FocusModel))
|
||||
throw new Exception("Settings has SaveSortingWithoutPerson and FocusModel!");
|
||||
|
@ -8,11 +8,8 @@ public record CompareSettings(string Company,
|
||||
string FacesFileNameExtension,
|
||||
string FacesHiddenFileNameExtension,
|
||||
string FacesPartsFileNameExtension,
|
||||
string[] IgnoreExtensions,
|
||||
int MaxDegreeOfParallelism,
|
||||
string[] OutputResolutions,
|
||||
string[] ValidImageFormatExtensions,
|
||||
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.ICompareSettings
|
||||
string[] OutputResolutions) : Shared.Models.Properties.ICompareSettings
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
|
@ -6,9 +6,12 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.Distance</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
@ -11,11 +11,21 @@ namespace View_by_Distance.Distance.Models.Stateless;
|
||||
internal static class FilterLogicD
|
||||
{
|
||||
|
||||
internal record RecordA(long? Ticks, string? Directory);
|
||||
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(cContentDirectory, cei.Combined);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting);
|
||||
|
||||
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory);
|
||||
internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
||||
{
|
||||
@ -39,141 +49,12 @@ internal static class FilterLogicD
|
||||
else if (isBySorting && useFiltersCounter.HasValue)
|
||||
byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
||||
else
|
||||
{
|
||||
byValue = $"{by.Value switch
|
||||
{
|
||||
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
|
||||
IMapLogic.Sorting => saveIndividually ? nameof(IMapLogic.Individually) : nameof(IMapLogic.Sorting),
|
||||
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
|
||||
_ => throw new NotImplementedException()
|
||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||
}
|
||||
byValue = IDistance.Get(saveIndividually, forceSingleImageHumanized, by.Value, isDefaultName);
|
||||
}
|
||||
result = new(byValue, isByMapping, isBySorting);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
|
||||
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
|
||||
|
||||
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
|
||||
{
|
||||
RecordC result;
|
||||
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
|
||||
throw new NotImplementedException();
|
||||
long? ticks = null;
|
||||
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
|
||||
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
|
||||
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
|
||||
result = new(debugDirectory, directory, ticks, personDirectory);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(cContentDirectory, directoryName);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
|
||||
{
|
||||
List<SaveContainer> results = [];
|
||||
RecordB recordB;
|
||||
RecordC recordC;
|
||||
string segmentB;
|
||||
string checkFile;
|
||||
string? directory;
|
||||
string shortcutFile;
|
||||
string facesDirectory;
|
||||
bool isCounterPersonYear;
|
||||
string facePartsDirectory;
|
||||
FileHolder? faceFileHolder;
|
||||
SaveContainer? saveContainer;
|
||||
FileHolder? resizedFileHolder;
|
||||
int? useFiltersCounter = null;
|
||||
string resizeContentDirectory;
|
||||
FileHolder? facePartsFileHolder;
|
||||
FileHolder? hiddenFaceFileHolder;
|
||||
LocationContainer locationContainer;
|
||||
bool sortingContainersAny = onlyOne.Count > 0;
|
||||
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
|
||||
nameof(E_Distance),
|
||||
resultSettings.ResultContent);
|
||||
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||
nameof(C_Resize),
|
||||
outputResolution,
|
||||
includeResizeGroup: true,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||
nameof(D2_FaceParts),
|
||||
outputResolution,
|
||||
includeResizeGroup: true,
|
||||
includeModel: true,
|
||||
includePredictorModel: true);
|
||||
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||
if (!Directory.Exists(cContentDirectory))
|
||||
_ = Directory.CreateDirectory(cContentDirectory);
|
||||
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
|
||||
if (!Directory.Exists(eDistanceContentTicksDirectory))
|
||||
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
|
||||
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||
if (!Directory.Exists(d2FacePartsContentDirectory))
|
||||
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
|
||||
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||
compare.ConstructProgressBar(onlyOne.Count, message);
|
||||
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
|
||||
{
|
||||
if (distanceSettings.SaveIndividually)
|
||||
break;
|
||||
locationContainer = keyValuePair.Value;
|
||||
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
||||
continue;
|
||||
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||
continue;
|
||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
|
||||
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
|
||||
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
|
||||
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
|
||||
continue;
|
||||
directory = recordC.Directory;
|
||||
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
|
||||
results.Add(SaveContainer.Get(recordC.DebugDirectory));
|
||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||
{
|
||||
if (!distanceSettings.SaveSortingWithoutPerson)
|
||||
throw new NotSupportedException();
|
||||
if (recordC.Ticks is null)
|
||||
continue;
|
||||
}
|
||||
results.Add(SaveContainer.Get(recordC.PersonDirectory));
|
||||
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
|
||||
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
|
||||
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
||||
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
||||
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
|
||||
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
||||
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
|
||||
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
|
||||
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
||||
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
||||
results.Add(saveContainer);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers)
|
||||
{
|
||||
string fileName;
|
||||
@ -285,4 +166,115 @@ internal static class FilterLogicD
|
||||
}
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
|
||||
{
|
||||
List<SaveContainer> results = [];
|
||||
RecordB recordB;
|
||||
RecordC recordC;
|
||||
string segmentB;
|
||||
string checkFile;
|
||||
string? directory;
|
||||
string shortcutFile;
|
||||
string facesDirectory;
|
||||
bool isCounterPersonYear;
|
||||
string facePartsDirectory;
|
||||
FileHolder? faceFileHolder;
|
||||
SaveContainer? saveContainer;
|
||||
FileHolder? resizedFileHolder;
|
||||
int? useFiltersCounter = null;
|
||||
string resizeContentDirectory;
|
||||
FileHolder? facePartsFileHolder;
|
||||
FileHolder? hiddenFaceFileHolder;
|
||||
LocationContainer locationContainer;
|
||||
bool sortingContainersAny = onlyOne.Count > 0;
|
||||
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
|
||||
nameof(E_Distance),
|
||||
resultSettings.ResultContent);
|
||||
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||
nameof(C_Resize),
|
||||
outputResolution,
|
||||
includeResizeGroup: true,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||
nameof(D2_FaceParts),
|
||||
outputResolution,
|
||||
includeResizeGroup: true,
|
||||
includeModel: true,
|
||||
includePredictorModel: true);
|
||||
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||
if (!Directory.Exists(cContentDirectory))
|
||||
_ = Directory.CreateDirectory(cContentDirectory);
|
||||
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
|
||||
if (!Directory.Exists(eDistanceContentTicksDirectory))
|
||||
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
|
||||
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||
if (!Directory.Exists(d2FacePartsContentDirectory))
|
||||
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
|
||||
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||
compare.ConstructProgressBar(onlyOne.Count, message);
|
||||
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
|
||||
{
|
||||
if (distanceSettings.SaveIndividually)
|
||||
break;
|
||||
locationContainer = keyValuePair.Value;
|
||||
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
||||
continue;
|
||||
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||
continue;
|
||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
|
||||
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
|
||||
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
|
||||
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
|
||||
continue;
|
||||
directory = recordC.Directory;
|
||||
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
|
||||
results.Add(SaveContainer.Get(recordC.DebugDirectory));
|
||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||
{
|
||||
if (!distanceSettings.SaveSortingWithoutPerson)
|
||||
throw new NotSupportedException();
|
||||
if (recordC.Ticks is null)
|
||||
continue;
|
||||
}
|
||||
results.Add(SaveContainer.Get(recordC.PersonDirectory));
|
||||
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
|
||||
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
|
||||
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
||||
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
||||
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
|
||||
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
||||
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
|
||||
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
|
||||
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
||||
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
||||
results.Add(saveContainer);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
|
||||
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
|
||||
|
||||
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
|
||||
{
|
||||
RecordC result;
|
||||
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
|
||||
throw new NotImplementedException();
|
||||
long? ticks = null;
|
||||
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
|
||||
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
|
||||
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
|
||||
result = new(debugDirectory, directory, ticks, personDirectory);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal record RecordA(long? Ticks, string? Directory);
|
||||
|
||||
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting);
|
||||
|
||||
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory);
|
||||
|
||||
}
|
@ -9,49 +9,69 @@ namespace View_by_Distance.Distance.Models.Stateless;
|
||||
public interface IDistance
|
||||
{
|
||||
|
||||
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);
|
||||
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);
|
||||
static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
|
||||
$"{by switch
|
||||
{
|
||||
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
|
||||
IMapLogic.Sorting => saveIndividually ?
|
||||
nameof(IMapLogic.Individually) :
|
||||
nameof(IMapLogic.Sorting),
|
||||
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
|
||||
_ => throw new NotImplementedException()
|
||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
Extract(compareSettings, exifDirectories);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
MappedLogicA.Extract(compareSettings, exifDirectories);
|
||||
|
||||
static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||
static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||
|
||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
|
||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
||||
GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||
static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
||||
FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||
|
||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
|
||||
static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||
GetOnlyOne(distanceSettings, matrix);
|
||||
static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||
public static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||
FilterLogicC.GetOnlyOne(distanceSettings, matrix);
|
||||
|
||||
static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
public static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||
|
||||
static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
||||
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
||||
static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
||||
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, 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, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
|
||||
public static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
||||
MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
||||
|
||||
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
|
||||
public static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
|
||||
internal static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||
GetOnlyOne(distanceSettings, matrix);
|
||||
|
||||
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||
|
||||
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
||||
GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
Extract(compareSettings, exifDirectories);
|
||||
|
||||
internal static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
||||
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
||||
|
||||
internal static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||
|
||||
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
||||
GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
||||
|
||||
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||
|
||||
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||
|
||||
}
|
@ -14,33 +14,53 @@ internal static class MappedLogicA
|
||||
string? PersonDisplayDirectoryName,
|
||||
FilePath FilePath);
|
||||
|
||||
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections)
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
|
||||
{
|
||||
List<MappedFile> results = [];
|
||||
FilePath filePath;
|
||||
MappedFile mappedFile;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
|
||||
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
|
||||
Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
|
||||
int? wholePercentages;
|
||||
Dictionary<int, FilePath>? keyValues;
|
||||
Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
|
||||
foreach (ExifDirectory exifDirectory in exifDirectories)
|
||||
{
|
||||
if (personContainer.Key is null)
|
||||
if (exifDirectory.FilePath.Id is null)
|
||||
continue;
|
||||
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
||||
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
||||
{
|
||||
filePath = personContainer.DisplayDirectoryAllFilePaths[i];
|
||||
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension)
|
||||
continue;
|
||||
if (distinct.Contains(filePath.Name))
|
||||
continue;
|
||||
distinct.Add(filePath.Name);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
|
||||
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
|
||||
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
|
||||
results.Add(mappedFile);
|
||||
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);
|
||||
}
|
||||
return results;
|
||||
foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
|
||||
{
|
||||
List<ExifDirectory> results = [];
|
||||
string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent));
|
||||
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
|
||||
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
|
||||
if (mappedFiles.Count > 0)
|
||||
{
|
||||
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
|
||||
compare.ConstructProgressBar(mappedFiles.Count, message);
|
||||
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
compare.Tick();
|
||||
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
|
||||
});
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<MappedFile> GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection<MappedLogicB.Record> records)
|
||||
@ -102,6 +122,35 @@ internal static class MappedLogicA
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections)
|
||||
{
|
||||
List<MappedFile> results = [];
|
||||
FilePath filePath;
|
||||
MappedFile mappedFile;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
|
||||
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
|
||||
{
|
||||
if (personContainer.Key is null)
|
||||
continue;
|
||||
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
||||
{
|
||||
filePath = personContainer.DisplayDirectoryAllFilePaths[i];
|
||||
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension)
|
||||
continue;
|
||||
if (distinct.Contains(filePath.Name))
|
||||
continue;
|
||||
distinct.Add(filePath.Name);
|
||||
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
|
||||
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
|
||||
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
|
||||
results.Add(mappedFile);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List<ExifDirectory> exifDirectories, ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipCollection, MappedFile mappedFile)
|
||||
{
|
||||
int? id;
|
||||
@ -152,53 +201,4 @@ internal static class MappedLogicA
|
||||
exifDirectories.Add(exifDirectory);
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
|
||||
{
|
||||
List<ExifDirectory> results = [];
|
||||
string eDistanceContentDirectory = IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent);
|
||||
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
|
||||
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
|
||||
if (mappedFiles.Count > 0)
|
||||
{
|
||||
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
|
||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
|
||||
compare.ConstructProgressBar(mappedFiles.Count, message);
|
||||
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
compare.Tick();
|
||||
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
|
||||
});
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
|
||||
{
|
||||
Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
|
||||
int? wholePercentages;
|
||||
Dictionary<int, FilePath>? keyValues;
|
||||
Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
|
||||
foreach (ExifDirectory exifDirectory in exifDirectories)
|
||||
{
|
||||
if (exifDirectory.FilePath.Id is null)
|
||||
continue;
|
||||
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
||||
{
|
||||
keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []);
|
||||
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
||||
throw new Exception();
|
||||
}
|
||||
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
|
||||
if (wholePercentages is null)
|
||||
continue;
|
||||
keyValues.Add(wholePercentages.Value, exifDirectory.FilePath);
|
||||
}
|
||||
foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
@ -21,62 +21,188 @@ internal static class MappedLogicB
|
||||
internal record TicksDirectory(DateTime AlternateDirectoryDateTime,
|
||||
string Directory,
|
||||
DateTime DirectoryDateTime,
|
||||
string DirectoryName,
|
||||
bool? IsLocationContainerDebugDirectory,
|
||||
float? TotalDays);
|
||||
|
||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||
{
|
||||
string checkFile;
|
||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (facesFileNames.Contains(file))
|
||||
{
|
||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||
internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
|
||||
{
|
||||
List<Record> results = [];
|
||||
bool check;
|
||||
string message;
|
||||
string[] files;
|
||||
string checkFile;
|
||||
bool? isDefault;
|
||||
int? linksCount;
|
||||
int totalSeconds;
|
||||
DateTime dateTime;
|
||||
TimeSpan timeSpan;
|
||||
int directoryNumber;
|
||||
List<Record> records;
|
||||
string? checkDirectory;
|
||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
string[] yearDirectories;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
string? personFirstInitial;
|
||||
bool isReservedDirectoryName;
|
||||
string[] personNameDirectories;
|
||||
string? newestPersonKeyFormatted;
|
||||
string? personDisplayDirectoryName;
|
||||
string[] personNameLinkDirectories;
|
||||
string? personFirstInitialDirectory;
|
||||
List<TicksDirectory> ticksDirectories;
|
||||
string[] personKeyFormattedDirectories;
|
||||
string manualCopyHumanized = nameof(IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
||||
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
Directory.Move(directory, checkDirectory);
|
||||
else
|
||||
check = false;
|
||||
results.Clear();
|
||||
distinct.Clear();
|
||||
directoryNumber = 0;
|
||||
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(distanceSettings, eDistanceContentDirectory);
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - 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)
|
||||
{
|
||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
if (i == 1)
|
||||
compare.Tick();
|
||||
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
||||
{
|
||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||
continue;
|
||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
File.Move(file, checkFile);
|
||||
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
||||
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(IMapLogic.ManualCopy));
|
||||
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(IMapLogic.Individually)))
|
||||
{
|
||||
Individually(compareSettings, ticksDirectory, personKeyFormattedDirectory);
|
||||
throw new Exception($"B) Move personKey directories up one from {nameof(IMapLogic.Sorting)} and delete {nameof(IMapLogic.Sorting)} directory!");
|
||||
}
|
||||
_ = readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
||||
if (readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
{
|
||||
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
||||
if (timeSpan.TotalDays > 6)
|
||||
throw new Exception($"{distanceSettings.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
||||
}
|
||||
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string yearDirectory in yearDirectories)
|
||||
{
|
||||
if (check && !Directory.Exists(yearDirectory))
|
||||
continue;
|
||||
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
||||
linksCount = null;
|
||||
else
|
||||
linksCount = GetLinksCount(yearDirectory);
|
||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (personNameDirectories.Length > 1)
|
||||
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||
foreach (string personNameDirectory in personNameDirectories)
|
||||
{
|
||||
directoryNumber++;
|
||||
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
||||
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
||||
{
|
||||
if (personKeyFormatted.Length != peopleSettings.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, peopleSettings.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Delete(yearDirectory, recursive: true);
|
||||
continue;
|
||||
}
|
||||
Directory.Move(personNameDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
continue;
|
||||
}
|
||||
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (isReservedDirectoryName && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {nameof(IMapLogic.Sorting)} and delete {nameof(IMapLogic.Sorting)} directory!");
|
||||
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
||||
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
||||
if (!isDefault.Value)
|
||||
{
|
||||
if (readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
files = RenameBirth(files);
|
||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||
{
|
||||
if (!check)
|
||||
check = true;
|
||||
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (personKeyFormatted.Length != peopleSettings.PersonBirthdayFormat.Length)
|
||||
continue;
|
||||
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !readOnlyCollections.PersonKeyFormattedCollection.Contains(personKeyFormatted))
|
||||
personFirstInitialDirectory = personNameDirectory;
|
||||
else
|
||||
{
|
||||
personFirstInitial = personDisplayDirectoryName[..1];
|
||||
if (personFirstInitial.All(char.IsDigit))
|
||||
{
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
||||
continue;
|
||||
}
|
||||
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
||||
if (Directory.Exists(personFirstInitialDirectory))
|
||||
throw new Exception("Forgot to ...");
|
||||
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
||||
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
records = GetRecords(resultSettings, metadataSettings, compareSettings, ticksDirectory, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName);
|
||||
if (records.Count > 0)
|
||||
results.AddRange(records);
|
||||
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
||||
{
|
||||
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith(".lnk"))
|
||||
continue;
|
||||
File.Delete(file);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
}
|
||||
if (check)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory)
|
||||
@ -85,13 +211,13 @@ internal static class MappedLogicB
|
||||
float? totalDays;
|
||||
long? next = null;
|
||||
string? checkDirectory;
|
||||
string ticksDirectoryName;
|
||||
DateTime directoryDateTime;
|
||||
DirectoryInfo directoryInfo;
|
||||
TicksDirectory ticksDirectory;
|
||||
long? lastDirectoryTicks = null;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
DateTime alternateDirectoryDateTime;
|
||||
string ticksDirectoryNameFirstSegment;
|
||||
bool? isLocationContainerDebugDirectory;
|
||||
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
||||
for (int i = 1; i < 5; i++)
|
||||
@ -101,10 +227,10 @@ internal static class MappedLogicB
|
||||
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string ticksFullPath in ticksFullPaths)
|
||||
{
|
||||
ticksDirectoryName = Path.GetFileName(ticksFullPath);
|
||||
if (ticksDirectoryName.Length < 3)
|
||||
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
|
||||
if (ticksDirectoryNameFirstSegment.Length < 3)
|
||||
continue;
|
||||
if (!long.TryParse(ticksDirectoryName, out long directoryTicks))
|
||||
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
|
||||
throw new NotSupportedException();
|
||||
if (next is null)
|
||||
next = new DateTime(directoryTicks).Ticks;
|
||||
@ -130,9 +256,9 @@ internal static class MappedLogicB
|
||||
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
||||
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
|
||||
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
||||
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryName.EndsWith(distanceSettings.LocationContainerDebugDirectory);
|
||||
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory);
|
||||
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
||||
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), ticksDirectoryName, isLocationContainerDebugDirectory, totalDays);
|
||||
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
|
||||
results.Add(ticksDirectory);
|
||||
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
||||
continue;
|
||||
@ -217,40 +343,42 @@ internal static class MappedLogicB
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||
{
|
||||
List<Record> results = [];
|
||||
Record record;
|
||||
string fileName;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
FileHolder fileHolder;
|
||||
int? wholePercentages;
|
||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.EndsWith(".lnk"))
|
||||
continue;
|
||||
fileHolder = FileHolder.Get(file);
|
||||
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
|
||||
if (wholePercentages is null)
|
||||
continue;
|
||||
fileName = Path.GetFileName(file);
|
||||
if (distinct.Contains(fileName))
|
||||
if (facesFileNames.Contains(file))
|
||||
{
|
||||
checkFile = $"{file}.dup";
|
||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
distinct.Add(fileName);
|
||||
record = new(directoryNumber, isDefault, linksCount, filePath, personDisplayDirectoryName, personKeyFormatted);
|
||||
results.Add(record);
|
||||
File.Delete(file);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static int? GetLinksCount(string yearDirectory)
|
||||
{
|
||||
int? result;
|
||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||
if (yearDirectoryNameSegments.Length != 3)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
string lastSegment = yearDirectoryNameSegments[^1];
|
||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||
result = null;
|
||||
else
|
||||
result = lastSegment[0] - 65;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string[] RenameBirth(string[] files)
|
||||
@ -285,216 +413,117 @@ internal static class MappedLogicB
|
||||
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
||||
}
|
||||
|
||||
private static int? GetLinksCount(string yearDirectory)
|
||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||
{
|
||||
int? result;
|
||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||
if (yearDirectoryNameSegments.Length != 3)
|
||||
result = null;
|
||||
else
|
||||
string[] files;
|
||||
string checkFile;
|
||||
string? checkDirectory;
|
||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
string lastSegment = yearDirectoryNameSegments[^1];
|
||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||
result = null;
|
||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
Directory.Move(directory, checkDirectory);
|
||||
else
|
||||
result = lastSegment[0] - 65;
|
||||
{
|
||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||
continue;
|
||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
File.Move(file, checkFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||
}
|
||||
|
||||
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||
{
|
||||
List<Record> results = [];
|
||||
string @enum;
|
||||
Record record;
|
||||
string fileName;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
FileHolder fileHolder;
|
||||
int? wholePercentages;
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.EndsWith(".lnk"))
|
||||
continue;
|
||||
fileHolder = FileHolder.Get(file);
|
||||
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
|
||||
if (wholePercentages is null)
|
||||
continue;
|
||||
fileName = Path.GetFileName(file);
|
||||
if (distinct.Contains(fileName))
|
||||
{
|
||||
checkFile = $"{file}.dup";
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
continue;
|
||||
}
|
||||
if (file.StartsWith(ticksDirectory.Directory))
|
||||
{
|
||||
@enum = IPath.GetEnum(filePath).ToString();
|
||||
if (!ticksDirectory.Directory.EndsWith(@enum))
|
||||
{
|
||||
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
|
||||
fileHolder = FileHolder.Get(checkFile);
|
||||
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
distinct.Add(fileName);
|
||||
record = new(DirectoryNumber: directoryNumber,
|
||||
IsDefault: isDefault,
|
||||
LinksCount: linksCount,
|
||||
MappedFaceFilePath: filePath,
|
||||
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
||||
PersonKeyFormatted: personKeyFormatted);
|
||||
results.Add(record);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
|
||||
{
|
||||
string result;
|
||||
string checkDirectory;
|
||||
string directory = file;
|
||||
List<string> collection = [];
|
||||
for (int i = 0; i < file.Length; i++)
|
||||
{
|
||||
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
|
||||
if (directory == ticksDirectory.Directory)
|
||||
break;
|
||||
collection.Add(Path.GetFileName(directory));
|
||||
}
|
||||
collection.Reverse();
|
||||
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
|
||||
foreach (string directoryName in collection)
|
||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
result = Path.Combine(checkDirectory, fileName);
|
||||
if (File.Exists(result))
|
||||
throw new Exception($"File <{fileName}> already exists!");
|
||||
File.Move(file, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
|
||||
{
|
||||
List<Record> results = [];
|
||||
bool check;
|
||||
string message;
|
||||
string[] files;
|
||||
bool? isDefault;
|
||||
int? linksCount;
|
||||
int totalSeconds;
|
||||
DateTime dateTime;
|
||||
TimeSpan timeSpan;
|
||||
int directoryNumber;
|
||||
string? checkDirectory;
|
||||
string[] yearDirectories;
|
||||
string personKeyFormatted;
|
||||
List<string> distinct = [];
|
||||
string? personFirstInitial;
|
||||
bool isReservedDirectoryName;
|
||||
string[] personNameDirectories;
|
||||
string? newestPersonKeyFormatted;
|
||||
string? personDisplayDirectoryName;
|
||||
string[] personNameLinkDirectories;
|
||||
string? personFirstInitialDirectory;
|
||||
List<TicksDirectory> ticksDirectories;
|
||||
string[] personKeyFormattedDirectories;
|
||||
string manualCopyHumanized = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title);
|
||||
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
check = false;
|
||||
results.Clear();
|
||||
distinct.Clear();
|
||||
directoryNumber = 0;
|
||||
ticksDirectories = UpdateDateVerifyAndGetTicksDirectories(distanceSettings, eDistanceContentDirectory);
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - 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)
|
||||
{
|
||||
if (i == 1)
|
||||
compare.Tick();
|
||||
personKeyFormattedDirectories = Directory.GetDirectories(ticksDirectory.Directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personKeyFormattedDirectory in personKeyFormattedDirectories)
|
||||
{
|
||||
personKeyFormatted = Path.GetFileName(personKeyFormattedDirectory);
|
||||
isReservedDirectoryName = personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Sorting)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Mapping)) || personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.ManualCopy));
|
||||
if (!isReservedDirectoryName && personKeyFormatted.StartsWith(nameof(Shared.Models.Stateless.IMapLogic.Individually)))
|
||||
{
|
||||
Individually(compareSettings, ticksDirectory, personKeyFormattedDirectory);
|
||||
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
}
|
||||
_ = readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted);
|
||||
if (readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
{
|
||||
timeSpan = new TimeSpan(DateTime.Now.Ticks - ticksDirectory.DirectoryDateTime.Ticks);
|
||||
if (timeSpan.TotalDays > 6)
|
||||
throw new Exception($"{distanceSettings.MappingDefaultName} <{ticksDirectory.DirectoryDateTime}> are only allowed within x days!");
|
||||
}
|
||||
yearDirectories = Directory.GetDirectories(personKeyFormattedDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string yearDirectory in yearDirectories)
|
||||
{
|
||||
if (check && !Directory.Exists(yearDirectory))
|
||||
continue;
|
||||
if (ticksDirectory.IsLocationContainerDebugDirectory is null || !ticksDirectory.IsLocationContainerDebugDirectory.Value)
|
||||
linksCount = null;
|
||||
else
|
||||
linksCount = GetLinksCount(yearDirectory);
|
||||
if (ticksDirectory.DirectoryName != distanceSettings.LocationContainerDebugDirectory)
|
||||
{
|
||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
}
|
||||
if (ticksDirectory.DirectoryName == distanceSettings.LocationContainerDebugDirectory)
|
||||
{
|
||||
isDefault = null;
|
||||
personDisplayDirectoryName = null;
|
||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
results.AddRange(GetRecords(resultSettings, metadataSettings, compareSettings, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
||||
files = Directory.GetFiles(yearDirectory, "*.lnk", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
continue;
|
||||
}
|
||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (personNameDirectories.Length > 1)
|
||||
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||
foreach (string personNameDirectory in personNameDirectories)
|
||||
{
|
||||
directoryNumber++;
|
||||
personDisplayDirectoryName = Path.GetFileName(personNameDirectory);
|
||||
isDefault = IPerson.IsDefaultName(personDisplayDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||
if (isDefault.Value && personDisplayDirectoryName.Length == 1)
|
||||
{
|
||||
if (personKeyFormatted.Length != peopleSettings.PersonBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormatted, peopleSettings.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(yearDirectory, $"X+{dateTime.Ticks}");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Delete(yearDirectory, recursive: true);
|
||||
continue;
|
||||
}
|
||||
Directory.Move(personNameDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
continue;
|
||||
}
|
||||
if (isDefault.Value && (ticksDirectory.DirectoryDateTime.Hour != 0 || ticksDirectory.DirectoryDateTime.Minute != 0 || ticksDirectory.DirectoryDateTime.Second != 0))
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(ticksDirectory.Directory);
|
||||
if (checkDirectory is null)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, ticksDirectory.AlternateDirectoryDateTime.Ticks.ToString());
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkDirectory = Path.Combine(checkDirectory, personKeyFormatted);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
Directory.Move(personKeyFormattedDirectory, checkDirectory);
|
||||
if (!check)
|
||||
check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (isReservedDirectoryName && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
|
||||
if (personKeyFormatted == manualCopyHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {manualCopyHumanized} and delete {manualCopyHumanized} directory!");
|
||||
if (personKeyFormatted == forceSingleImageHumanized && files.Length > 0)
|
||||
throw new Exception($"Move personKey directories up one from {forceSingleImageHumanized} and delete {forceSingleImageHumanized} directory!");
|
||||
if (!isDefault.Value)
|
||||
{
|
||||
if (readOnlyCollections.PersonKeyFormattedToNewestPersonKeyFormatted.Count > 0 && newestPersonKeyFormatted is null)
|
||||
files = RenameBirth(files);
|
||||
else if (newestPersonKeyFormatted is not null && personKeyFormatted != newestPersonKeyFormatted)
|
||||
{
|
||||
if (!check)
|
||||
check = true;
|
||||
MovedToNewestPersonKeyFormatted(personKeyFormatted, newestPersonKeyFormatted, ticksDirectory, personKeyFormattedDirectory);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (personKeyFormatted.Length != peopleSettings.PersonBirthdayFormat.Length)
|
||||
continue;
|
||||
if (personDisplayDirectoryName.Length == 1 || isDefault.Value || !readOnlyCollections.PersonKeyFormattedCollection.Contains(personKeyFormatted))
|
||||
personFirstInitialDirectory = personNameDirectory;
|
||||
else
|
||||
{
|
||||
personFirstInitial = personDisplayDirectoryName[..1];
|
||||
if (personFirstInitial.All(char.IsDigit))
|
||||
{
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
File.Delete(file);
|
||||
_ = IPath.DeleteEmptyDirectories(personNameDirectory);
|
||||
continue;
|
||||
}
|
||||
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString());
|
||||
if (Directory.Exists(personFirstInitialDirectory))
|
||||
throw new Exception("Forgot to ...");
|
||||
Directory.Move(personNameDirectory, personFirstInitialDirectory);
|
||||
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
results.AddRange(GetRecords(resultSettings, metadataSettings, compareSettings, isDefault, files, directoryNumber, personKeyFormatted, linksCount, distinct, personDisplayDirectoryName));
|
||||
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personNameLinkDirectory in personNameLinkDirectories)
|
||||
{
|
||||
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith(".lnk"))
|
||||
continue;
|
||||
File.Delete(file);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(yearDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(personKeyFormattedDirectory);
|
||||
}
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
_ = IPath.DeleteEmptyDirectories(ticksDirectory.Directory);
|
||||
}
|
||||
if (check)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
@ -6,9 +6,12 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.Face</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
@ -6,10 +6,13 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.FaceRecognitionDotNet</PackageId>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Version>9.0.100.1</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<Company>Phares</Company>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
@ -4,11 +4,14 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>library</OutputType>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember142023>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1699920000)), 3600))))</HoursSinceNovember142023>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.Metadata</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>8.0.114.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1699920000)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -35,11 +38,11 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\"/>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -11,7 +11,7 @@ public class A_Metadata
|
||||
|
||||
private readonly ResultSettings _ResultSettings;
|
||||
private readonly MetadataSettings _MetadataSettings;
|
||||
private readonly ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<int, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> _ResultSingletonFileGroups;
|
||||
|
||||
public A_Metadata(ResultSettings resultSettings, MetadataSettings metadataSettings)
|
||||
{
|
||||
@ -23,46 +23,21 @@ public class A_Metadata
|
||||
includeResizeGroup: false,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
_FileGroups = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]);
|
||||
}
|
||||
|
||||
private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
MinimumYearAndPathCombined result;
|
||||
(_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(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(_FileGroups[minimumYear][_ResultSettings.ResultSingleton][directoryIndex], $"{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);
|
||||
(_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year;
|
||||
result = Path.Combine(_FileGroups[exifYear][_ResultSettings.ResultSingleton][directoryIndex], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json");
|
||||
return new(exifYear, result);
|
||||
}
|
||||
|
||||
private static (string, ExifDirectory?) Get(string jsonFile)
|
||||
{
|
||||
ExifDirectory? result;
|
||||
string json = File.ReadAllText(jsonFile);
|
||||
try
|
||||
Dictionary<int, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]);
|
||||
foreach (KeyValuePair<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||
if (result is null)
|
||||
throw new Exception();
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValue in keyValuePair.Value)
|
||||
{
|
||||
if (keyValue.Key == resultSettings.ResultSingleton)
|
||||
results.Add(keyValuePair.Key, keyValue.Value);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return new(json, result);
|
||||
_ResultSingletonFileGroups = new(results);
|
||||
ReadOnlyCollection<string> directories = new([Path.Combine(aResultsFullGroupDirectory, resultSettings.ResultSingleton)]);
|
||||
IPath.CreateDirectories(directories);
|
||||
}
|
||||
|
||||
public (MinimumYearAndPathCombined, ExifDirectory) GetMetadataCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, FilePath filePath)
|
||||
@ -136,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;
|
||||
@ -166,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;
|
||||
}
|
||||
|
||||
}
|
@ -54,51 +54,7 @@ internal static class Get
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||
{
|
||||
return file =>
|
||||
{
|
||||
rename.Tick();
|
||||
ExifDirectory exifDirectory;
|
||||
MetadataGroup metadataGroup;
|
||||
DeterministicHashCode deterministicHashCode;
|
||||
FileHolder fileHolder = FileHolder.Get(file);
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
|
||||
if (distinct.Contains(key))
|
||||
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
|
||||
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
|
||||
return;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(renameSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
|
||||
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
|
||||
lock (metadataGroups)
|
||||
metadataGroups.Add(metadataGroup);
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||
internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||
{
|
||||
return file =>
|
||||
{
|
||||
@ -125,7 +81,7 @@ internal static class Get
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(windowsSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
@ -145,4 +101,48 @@ internal static class Get
|
||||
};
|
||||
}
|
||||
|
||||
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||
{
|
||||
return file =>
|
||||
{
|
||||
rename.Tick();
|
||||
ExifDirectory exifDirectory;
|
||||
MetadataGroup metadataGroup;
|
||||
DeterministicHashCode deterministicHashCode;
|
||||
FileHolder fileHolder = FileHolder.Get(file);
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
|
||||
if (distinct.Contains(key))
|
||||
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
|
||||
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
|
||||
return;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
|
||||
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
|
||||
lock (metadataGroups)
|
||||
metadataGroups.Add(metadataGroup);
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -72,9 +72,9 @@ public interface IMetadata
|
||||
static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<NginxFileSystem> collection) =>
|
||||
Get.GetKeyValuePairs(collection);
|
||||
|
||||
Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||
SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups);
|
||||
static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||
Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups);
|
||||
Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||
SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
|
||||
static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||
Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
|
||||
|
||||
}
|
@ -6,9 +6,12 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.People</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@ -8,9 +8,12 @@
|
||||
<UserSecretsIdOld>fa0fa59b-afe4-4960-9afc-18fcbc7fb41b</UserSecretsIdOld>
|
||||
<UserSecretsId>843db3e1-e18f-4cba-8b00-967529a32635</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Rename</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -37,10 +40,10 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\"/>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.7.1" />
|
||||
<PackageReference Include="CliWrap" Version="3.8.2" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
|
||||
|
@ -6,21 +6,20 @@ namespace View_by_Distance.Rename.Models;
|
||||
|
||||
public record RenameSettings(string Company,
|
||||
string DefaultMaker,
|
||||
Dictionary<string, string?> DirectoryDictionary,
|
||||
string? FirstPassFile,
|
||||
bool ForceNewId,
|
||||
string[] IgnoreExtensions,
|
||||
bool InPlace,
|
||||
bool InPlaceMoveDirectory,
|
||||
bool InPlaceWithOriginalName,
|
||||
bool JustMediaDate,
|
||||
int MaxDegreeOfParallelism,
|
||||
int MaxMilliSecondsPerCall,
|
||||
bool OnlySaveIdentifiersToDisk,
|
||||
string RelativePropertyCollectionFile,
|
||||
bool RequireRootDirectoryExists,
|
||||
string[] SidecarExtensions,
|
||||
bool SkipIdFiles,
|
||||
string[] ValidImageFormatExtensions,
|
||||
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameSettings
|
||||
bool SkipIdFiles) : Shared.Models.Properties.IRenameSettings
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
|
786
Rename/Rename.cs
786
Rename/Rename.cs
@ -11,7 +11,6 @@ using View_by_Distance.Metadata.Models;
|
||||
using View_by_Distance.Metadata.Models.Stateless;
|
||||
using View_by_Distance.Rename.Models;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless;
|
||||
|
||||
namespace View_by_Distance.Rename;
|
||||
@ -35,39 +34,58 @@ public partial class Rename : IRename, IDisposable
|
||||
private ProgressBar? _ProgressBar;
|
||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||
|
||||
public Rename(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||
{
|
||||
if (isSilent)
|
||||
{ }
|
||||
if (args is null)
|
||||
throw new NullReferenceException(nameof(args));
|
||||
if (console is null)
|
||||
throw new NullReferenceException(nameof(console));
|
||||
IRename rename = this;
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
RenameWork(logger, appSettings, rename, ticks);
|
||||
}
|
||||
|
||||
void IRename.Tick() =>
|
||||
_ProgressBar?.Tick();
|
||||
|
||||
void IRename.ConstructProgressBar(int maxTicks, string message)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath)
|
||||
void IRename.ConstructProgressBar(int maxTicks, string message)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
int? id;
|
||||
int? width;
|
||||
int? height;
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
using Image image = Image.FromFile(filePath.FullName);
|
||||
width = image.Width;
|
||||
height = image.Height;
|
||||
using Bitmap bitmap = new(image);
|
||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
byte[] bytes = new byte[length];
|
||||
Marshal.Copy(intPtr, bytes, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
#pragma warning restore CA1416
|
||||
id = IId.GetDeterministicHashCode(bytes);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
id = null;
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
result = new(height, id, width);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
List<string> results = [];
|
||||
bool isValidVideoFormatExtensions = renameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||
bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||
if (isValidVideoFormatExtensions)
|
||||
{
|
||||
bool check;
|
||||
@ -97,40 +115,258 @@ public partial class Rename : IRename, IDisposable
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
|
||||
public Rename(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
int? id;
|
||||
int? width;
|
||||
int? height;
|
||||
try
|
||||
{
|
||||
using Image image = Image.FromFile(filePath.FullName);
|
||||
width = image.Width;
|
||||
height = image.Height;
|
||||
using Bitmap bitmap = new(image);
|
||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
byte[] bytes = new byte[length];
|
||||
Marshal.Copy(intPtr, bytes, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
id = IId.GetDeterministicHashCode(bytes);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
id = null;
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
result = new(height, id, width);
|
||||
return result;
|
||||
if (isSilent)
|
||||
{ }
|
||||
if (args is null)
|
||||
throw new NullReferenceException(nameof(args));
|
||||
if (console is null)
|
||||
throw new NullReferenceException(nameof(console));
|
||||
IRename rename = this;
|
||||
LogNetToHoursSince(logger);
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
RenameWork(logger, appSettings, rename, ticks);
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
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, long ticks)
|
||||
{
|
||||
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
|
||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||
if (!Directory.Exists(sourceDirectory))
|
||||
_ = Directory.CreateDirectory(sourceDirectory);
|
||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||
if (files.Count > 0)
|
||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
|
||||
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
|
||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||
{
|
||||
if (recordCollection.Count > 0)
|
||||
recordCollection = new([]);
|
||||
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
|
||||
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
|
||||
}
|
||||
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
|
||||
{
|
||||
DirectoryInfo directoryInfo = new(sourceDirectory);
|
||||
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
|
||||
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
|
||||
if (lines.Count != 0)
|
||||
{
|
||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetIds(RenameSettings renameSettings)
|
||||
{
|
||||
ReadOnlyCollection<int> results;
|
||||
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile;
|
||||
string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile);
|
||||
Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||
if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile))
|
||||
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
|
||||
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
||||
return results;
|
||||
}
|
||||
|
||||
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
|
||||
{
|
||||
ReadOnlyCollection<Record> results;
|
||||
List<FirstPass> collection;
|
||||
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
|
||||
if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile))
|
||||
collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile);
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(checkFile);
|
||||
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
|
||||
}
|
||||
if (appSettings.RenameSettings.JustMediaDate)
|
||||
results = new([]);
|
||||
else
|
||||
results = GetRecordCollection(appSettings, collection);
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile)
|
||||
{
|
||||
List<FirstPass> results;
|
||||
FirstPass firstPass;
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
{
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
|
||||
}
|
||||
else
|
||||
{
|
||||
results = [];
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
|
||||
Thread.Sleep(500);
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(checkFile))
|
||||
{
|
||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
TimeSpan timeSpan;
|
||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
index += 1;
|
||||
rename.Tick();
|
||||
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
|
||||
{
|
||||
if (appSettings.RenameSettings.InPlaceMoveDirectory)
|
||||
continue;
|
||||
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
|
||||
}
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
|
||||
timeSpan = new(DateTime.Now.Ticks - ticks);
|
||||
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
|
||||
break;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void SetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, int index, KeyValuePair<string, List<FileHolder>> keyValuePair, List<FirstPass> results)
|
||||
{
|
||||
FilePath filePath;
|
||||
FirstPass firstPass;
|
||||
string directoryName;
|
||||
ExifDirectory exifDirectory;
|
||||
List<FileHolder> sidecarFiles;
|
||||
DeterministicHashCode deterministicHashCode;
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value)
|
||||
JustMediaDate(logger, appSettings, metadata, filePath);
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
}
|
||||
|
||||
private void JustMediaDate(ILogger<Program>? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath)
|
||||
{
|
||||
ExifDirectory? exifDirectory;
|
||||
MinimumYearAndPathCombined? minimumYearAndPathCombined;
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
exifDirectory = null;
|
||||
minimumYearAndPathCombined = null;
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
}
|
||||
if (exifDirectory is null || minimumYearAndPathCombined is null)
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
else
|
||||
{
|
||||
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||
if (dateTime is null)
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
else
|
||||
{
|
||||
File.SetCreationTime(filePath.FullName, dateTime.Value);
|
||||
Thread.Sleep(500);
|
||||
File.SetLastWriteTime(filePath.FullName, dateTime.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles)
|
||||
{
|
||||
@ -146,7 +382,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)
|
||||
@ -176,7 +412,7 @@ public partial class Rename : IRename, IDisposable
|
||||
JsonFile: minimumYearAndPathCombined.PathCombined);
|
||||
toDoCollection.AddRange(GetSidecarFiles(appSettings, record, [], checkDirectory, paddedId));
|
||||
}
|
||||
_ = RenameFilesInDirectories(appSettings.RenameSettings, rename, new(toDoCollection));
|
||||
_ = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection.AsReadOnly());
|
||||
string jsonFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}.json");
|
||||
File.Move(minimumYearAndPathCombined.PathCombined, jsonFile, overwrite: true);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName && ids.Count > 0)
|
||||
@ -189,92 +425,6 @@ public partial class Rename : IRename, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, IEnumerable<string> files, A_Metadata metadata)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
FilePath filePath;
|
||||
TimeSpan timeSpan;
|
||||
FirstPass firstPass;
|
||||
string directoryName;
|
||||
ExifDirectory exifDirectory;
|
||||
List<FileHolder> sidecarFiles;
|
||||
DeterministicHashCode deterministicHashCode;
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
index += 1;
|
||||
rename.Tick();
|
||||
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
|
||||
{
|
||||
if (appSettings.RenameSettings.InPlaceMoveDirectory)
|
||||
continue;
|
||||
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
|
||||
}
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
timeSpan = new(DateTime.Now.Ticks - ticks);
|
||||
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
|
||||
break;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Record> GetRecordCollection(AppSettings appSettings, List<FirstPass> collection)
|
||||
{
|
||||
List<Record> results = [];
|
||||
@ -302,152 +452,22 @@ public partial class Rename : IRename, IDisposable
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
|
||||
{
|
||||
ReadOnlyCollection<Record> results;
|
||||
FirstPass firstPass;
|
||||
List<FirstPass> collection;
|
||||
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
|
||||
if (!string.IsNullOrEmpty(checkFile) && File.Exists(checkFile))
|
||||
{
|
||||
string json = File.ReadAllText(checkFile);
|
||||
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
|
||||
}
|
||||
else
|
||||
{
|
||||
collection = [];
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
collection.AddRange(GetFirstPassCollection(logger, appSettings, rename, ticks, ids, files, metadata));
|
||||
else
|
||||
{
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
|
||||
Thread.Sleep(500);
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
collection.Add(firstPass);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(checkFile))
|
||||
{
|
||||
string json = JsonSerializer.Serialize(collection, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
}
|
||||
}
|
||||
results = GetRecordCollection(appSettings, collection);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
|
||||
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
|
||||
{
|
||||
string paddedId;
|
||||
Identifier identifier;
|
||||
List<Identifier> identifiers = [];
|
||||
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
|
||||
foreach (Record record in recordCollection)
|
||||
{
|
||||
if (record.ExifDirectory.FilePath.Id is null)
|
||||
continue;
|
||||
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length)
|
||||
throw new NotSupportedException();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetTFW(Record record, bool? isWrongYear) =>
|
||||
string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I");
|
||||
|
||||
private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) =>
|
||||
splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}";
|
||||
|
||||
private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
|
||||
{
|
||||
string? result;
|
||||
string year = record.DateTime.Year.ToString();
|
||||
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
|
||||
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
|
||||
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
|
||||
isWrongYear = null;
|
||||
string tfw = GetTFW(record, isWrongYear);
|
||||
string? maker = IMetadata.GetMaker(record.ExifDirectory);
|
||||
string rootDirectory = appSettings.ResultSettings.RootDirectory;
|
||||
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
|
||||
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
|
||||
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
|
||||
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
|
||||
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
|
||||
string directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
|
||||
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
|
||||
{
|
||||
List<ToDo> results = [];
|
||||
ToDo toDo;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
string checkFileExtension;
|
||||
foreach (FileHolder fileHolder in record.SidecarFiles)
|
||||
{
|
||||
checkFileExtension = fileHolder.ExtensionLowered;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null);
|
||||
checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}");
|
||||
if (checkFile == filePath.FullName)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
checkFile = string.Concat(checkFile, ".del");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
}
|
||||
if (distinct.Contains(checkFile))
|
||||
continue;
|
||||
distinct.Add(checkFile);
|
||||
toDo = new(Directory: checkDirectory,
|
||||
FileInfo: new(filePath.FullName),
|
||||
File: checkFile,
|
||||
JsonFile: false);
|
||||
results.Add(toDo);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool? GetDirectoryCheck(ResultSettings resultSettings)
|
||||
{
|
||||
bool? result = null;
|
||||
IEnumerable<string> files;
|
||||
string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string _ in files)
|
||||
{
|
||||
if (result is null)
|
||||
result = false;
|
||||
else if (result.Value)
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
if (result is not null && result.Value)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||
_ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection)
|
||||
@ -459,15 +479,19 @@ public partial class Rename : IRename, IDisposable
|
||||
string paddedId;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
DateTime? dateTime;
|
||||
FileInfo[] matches;
|
||||
string directoryName;
|
||||
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;
|
||||
@ -478,7 +502,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;
|
||||
@ -493,8 +517,22 @@ public partial class Rename : IRename, IDisposable
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
}
|
||||
(directoryName, _) = IPath.GetDirectoryNameAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath);
|
||||
jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json");
|
||||
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)
|
||||
{
|
||||
fileHolder = FileHolder.Get(record.JsonFile);
|
||||
@ -535,17 +573,114 @@ public partial class Rename : IRename, IDisposable
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection)
|
||||
private static bool? GetDirectoryCheck(ResultSettings resultSettings)
|
||||
{
|
||||
List<string> distinct = [];
|
||||
foreach (ToDo toDo in toDoCollection)
|
||||
bool? result = null;
|
||||
IEnumerable<string> files;
|
||||
string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
if (toDo.Directory is null || distinct.Contains(toDo.Directory))
|
||||
continue;
|
||||
if (!Directory.Exists(toDo.Directory))
|
||||
_ = Directory.CreateDirectory(toDo.Directory);
|
||||
distinct.Add(toDo.Directory);
|
||||
files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
|
||||
foreach (string _ in files)
|
||||
{
|
||||
if (result is null)
|
||||
result = false;
|
||||
else if (result.Value)
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
if (result is not null && result.Value)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
|
||||
{
|
||||
foreach (Record record in recordCollection)
|
||||
{
|
||||
if (record.ExifDirectory.FilePath.Id is null)
|
||||
continue;
|
||||
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length)
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
|
||||
{
|
||||
string? result;
|
||||
string year = record.DateTime.Year.ToString();
|
||||
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
|
||||
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
|
||||
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
|
||||
isWrongYear = null;
|
||||
string directoryName;
|
||||
string tfw = GetTFW(record, isWrongYear);
|
||||
string? maker = IMetadata.GetMaker(record.ExifDirectory);
|
||||
string rootDirectory = appSettings.ResultSettings.RootDirectory;
|
||||
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
|
||||
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
|
||||
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
|
||||
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
|
||||
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
|
||||
if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2)
|
||||
directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
|
||||
else
|
||||
{
|
||||
directoryName = record.DateTime.ToString("yyyy-MM-dd");
|
||||
if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value))
|
||||
directoryName = value;
|
||||
}
|
||||
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetTFW(Record record, bool? isWrongYear) =>
|
||||
string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I");
|
||||
|
||||
private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) =>
|
||||
splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}";
|
||||
|
||||
private static List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
|
||||
{
|
||||
List<ToDo> results = [];
|
||||
ToDo toDo;
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
string checkFileExtension;
|
||||
foreach (FileHolder fileHolder in record.SidecarFiles)
|
||||
{
|
||||
checkFileExtension = fileHolder.ExtensionLowered;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null);
|
||||
checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}");
|
||||
if (checkFile == filePath.FullName)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
{
|
||||
checkFile = string.Concat(checkFile, ".del");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
}
|
||||
if (distinct.Contains(checkFile))
|
||||
continue;
|
||||
distinct.Add(checkFile);
|
||||
toDo = new(Directory: checkDirectory,
|
||||
FileInfo: new(filePath.FullName),
|
||||
File: checkFile,
|
||||
JsonFile: false);
|
||||
results.Add(toDo);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private ReadOnlyCollection<string> RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection<ToDo> toDoCollection)
|
||||
@ -588,65 +723,16 @@ public partial class Rename : IRename, IDisposable
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
|
||||
private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection)
|
||||
{
|
||||
string paddedId;
|
||||
Identifier identifier;
|
||||
List<Identifier> identifiers = [];
|
||||
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
|
||||
foreach (Record record in recordCollection)
|
||||
List<string> distinct = [];
|
||||
foreach (ToDo toDo in toDoCollection)
|
||||
{
|
||||
if (record.ExifDirectory.FilePath.Id is null)
|
||||
if (toDo.Directory is null || distinct.Contains(toDo.Directory))
|
||||
continue;
|
||||
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, 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);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetIds(RenameSettings renameSettings)
|
||||
{
|
||||
ReadOnlyCollection<int> results;
|
||||
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile;
|
||||
string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile);
|
||||
Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||
if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile))
|
||||
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
|
||||
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
||||
return results;
|
||||
}
|
||||
|
||||
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
|
||||
{
|
||||
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
|
||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||
if (!Directory.Exists(sourceDirectory))
|
||||
_ = Directory.CreateDirectory(sourceDirectory);
|
||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||
if (files.Count > 0)
|
||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
|
||||
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
|
||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||
{
|
||||
if (recordCollection.Count > 0)
|
||||
recordCollection = new([]);
|
||||
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
|
||||
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
|
||||
}
|
||||
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
|
||||
{
|
||||
DirectoryInfo directoryInfo = new(sourceDirectory);
|
||||
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
|
||||
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
|
||||
if (lines.Count != 0)
|
||||
{
|
||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
|
||||
}
|
||||
if (!Directory.Exists(toDo.Directory))
|
||||
_ = Directory.CreateDirectory(toDo.Directory);
|
||||
distinct.Add(toDo.Directory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,14 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember142023>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1699920000)), 3600))))</HoursSinceNovember142023>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.AA.Shared</PackageId>
|
||||
<Version>8.1.112.0</Version>
|
||||
<Version>8.0.114.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1699920000)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -34,9 +37,9 @@
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\"/>
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record CombinedEnumAndIndex(string Combined,
|
||||
byte Enum,
|
||||
int Index)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, CombinedEnumAndIndexSourceGenerationContext.Default.CombinedEnumAndIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(CombinedEnumAndIndex))]
|
||||
internal partial class CombinedEnumAndIndexSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -6,9 +6,6 @@ public interface ICompareSettings
|
||||
public string FacesFileNameExtension { init; get; }
|
||||
public string FacesHiddenFileNameExtension { init; get; }
|
||||
public string FacesPartsFileNameExtension { init; get; }
|
||||
public string[] IgnoreExtensions { init; get; }
|
||||
public int MaxDegreeOfParallelism { init; get; }
|
||||
public string[] ValidImageFormatExtensions { init; get; }
|
||||
public string[] ValidVideoFormatExtensions { init; get; }
|
||||
|
||||
}
|
@ -3,9 +3,6 @@ namespace View_by_Distance.Shared.Models.Properties;
|
||||
public interface IRenameSettings
|
||||
{
|
||||
|
||||
public string[] IgnoreExtensions { init; get; }
|
||||
public bool SkipIdFiles { init; get; }
|
||||
public string[] ValidImageFormatExtensions { init; get; }
|
||||
public string[] ValidVideoFormatExtensions { init; get; }
|
||||
|
||||
}
|
@ -3,8 +3,4 @@ namespace View_by_Distance.Shared.Models.Properties;
|
||||
public interface IWindowsSettings
|
||||
{
|
||||
|
||||
public string[] IgnoreExtensions { init; get; }
|
||||
public string[] ValidImageFormatExtensions { init; get; }
|
||||
public string[] ValidVideoFormatExtensions { init; get; }
|
||||
|
||||
}
|
@ -8,12 +8,15 @@ public record ResultSettings(string DateGroup,
|
||||
string ModelName,
|
||||
int NumberOfJitters,
|
||||
int NumberOfTimesToUpsample,
|
||||
string[] IgnoreExtensions,
|
||||
string PredictorModelName,
|
||||
int ResultAllInOneSubdirectoryLength,
|
||||
string ResultCollection,
|
||||
string ResultContent,
|
||||
string ResultSingleton,
|
||||
string RootDirectory)
|
||||
string RootDirectory,
|
||||
string[] ValidImageFormatExtensions,
|
||||
string[] ValidVideoFormatExtensions)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
|
@ -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);
|
||||
|
||||
}
|
@ -5,57 +5,69 @@ public interface IId
|
||||
|
||||
const int DeterministicHashCode = 9876543;
|
||||
|
||||
static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) =>
|
||||
metadataSettings.Offset == DeterministicHashCode;
|
||||
|
||||
string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
|
||||
int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||
GetId(resultSettings, metadataSettings, intelligentId);
|
||||
static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||
Id.GetId(resultSettings, metadataSettings, intelligentId);
|
||||
|
||||
string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
|
||||
string TestStatic_GetIgnoreFullPath(FilePath filePath, FileHolder fileHolder) =>
|
||||
GetIgnoreFullPath(filePath, fileHolder);
|
||||
static string GetIgnoreFullPath(FilePath filePath, FileHolder fileHolder) =>
|
||||
fileHolder.DirectoryFullPath is null ?
|
||||
throw new NotSupportedException() :
|
||||
filePath.Id > -1 ?
|
||||
fileHolder.NameWithoutExtension[^1] == '9' ?
|
||||
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}8{fileHolder.ExtensionLowered}") :
|
||||
throw new NotSupportedException("High") :
|
||||
fileHolder.NameWithoutExtension[^1] == '1' ?
|
||||
Path.Combine(fileHolder.DirectoryFullPath, $"{fileHolder.NameWithoutExtension[..^1]}2{fileHolder.ExtensionLowered}") :
|
||||
throw new NotSupportedException("Low");
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
|
||||
static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
||||
&& fileNameFirstSegment[^1] is '1' or '2' or '8' or '9'
|
||||
&& fileNameFirstSegment.All(char.IsNumber);
|
||||
|
||||
bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
|
||||
static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||
|
||||
int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
||||
GetDeterministicHashCode(value);
|
||||
static int GetDeterministicHashCode(byte[] value) =>
|
||||
public static int GetDeterministicHashCode(byte[] value) =>
|
||||
Id.GetDeterministicHashCode(value);
|
||||
|
||||
public static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
Id.GetHasIgnoreKeyword(filePath);
|
||||
|
||||
public static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) =>
|
||||
metadataSettings.Offset == DeterministicHashCode;
|
||||
|
||||
public static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
Id.GetHasDateTimeOriginal(resultSettings, filePath);
|
||||
|
||||
public static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
Id.GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||
|
||||
public static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||
|
||||
public static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||
Id.GetId(resultSettings, metadataSettings, intelligentId);
|
||||
|
||||
public static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '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 '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, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||
Id.GetIntelligentId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
|
||||
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);
|
||||
|
||||
internal byte TestStatic_GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
GetHasIgnoreKeyword(filePath);
|
||||
|
||||
internal byte TestStatic_GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
GetHasDateTimeOriginal(resultSettings, filePath);
|
||||
|
||||
internal byte TestStatic_GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
|
||||
|
||||
internal int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||
GetId(resultSettings, metadataSettings, intelligentId);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
|
||||
|
||||
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||
|
||||
internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, 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, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||
GetPaddedId(resultSettings, metadataSettings, id, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||
|
||||
}
|
@ -3,72 +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);
|
||||
public static byte GetEnum(FilePath filePath) =>
|
||||
XPath.GetEnum(filePath);
|
||||
|
||||
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) =>
|
||||
public 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) =>
|
||||
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);
|
||||
|
||||
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) =>
|
||||
public static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
XPath.GetDirectory(sourceDirectory, level, directoryName);
|
||||
|
||||
(string, int) TestStatic_GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
XPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
public static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
|
||||
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
|
||||
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
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);
|
||||
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless;
|
||||
|
||||
public interface IRename
|
||||
{
|
||||
|
||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath);
|
||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath);
|
||||
DeterministicHashCode GetDeterministicHashCode(FilePath filePath);
|
||||
void ConstructProgressBar(int maxTicks, string message);
|
||||
void Tick();
|
||||
|
@ -1,12 +1,11 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless;
|
||||
|
||||
public interface IWindows
|
||||
{
|
||||
|
||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings windowsSettings, HttpClient? httpClient, FilePath filePath);
|
||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath);
|
||||
DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath);
|
||||
DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri);
|
||||
void ConstructProgressBar(int maxTicks, string message);
|
||||
|
@ -5,81 +5,6 @@ namespace View_by_Distance.Shared.Models.Stateless;
|
||||
internal abstract class Id
|
||||
{
|
||||
|
||||
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment)
|
||||
{
|
||||
bool result;
|
||||
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
|
||||
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
|
||||
{
|
||||
int result;
|
||||
StringBuilder results = new();
|
||||
if (metadataSettings.IntMinValueLength < (resultSettings.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
for (int i = intelligentId.Length - (resultSettings.ResultAllInOneSubdirectoryLength + 2); i > -1; i--)
|
||||
_ = results.Append(intelligentId[i]);
|
||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||
result = int.Parse(results.ToString());
|
||||
if (intelligentId[^1] is '1' or '2')
|
||||
result *= -1;
|
||||
else if (intelligentId[^1] is not '9' and not '8')
|
||||
throw new NotSupportedException();
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0060
|
||||
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||
#pragma warning restore IDE0060
|
||||
{
|
||||
string result;
|
||||
StringBuilder stringBuilder = new();
|
||||
if (metadataSettings.IntMinValueLength < (resultSettings.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
int key;
|
||||
string value;
|
||||
List<char> resultAllInOneSubdirectoryChars = [];
|
||||
if (id > -1)
|
||||
{
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : 9;
|
||||
value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : 1;
|
||||
value = id.ToString()[1..].PadLeft(metadataSettings.IntMinValueLength, '0');
|
||||
}
|
||||
for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
||||
_ = stringBuilder.Append(value[i]);
|
||||
for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength; i < value.Length; i++)
|
||||
resultAllInOneSubdirectoryChars.Add(value[i]);
|
||||
result = $"{stringBuilder}{string.Join(string.Empty, resultAllInOneSubdirectoryChars)}{key}";
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, 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);
|
||||
int check = GetId(resultSettings, metadataSettings, intelligentId);
|
||||
if (check != id)
|
||||
throw new NotSupportedException();
|
||||
result = index is null || metadataSettings.Offset == IId.DeterministicHashCode ? intelligentId : $"{metadataSettings.Offset + index}{intelligentId}";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int GetDeterministicHashCode(byte[] value)
|
||||
{
|
||||
int result;
|
||||
@ -99,4 +24,99 @@ internal abstract class Id
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||
(byte)(filePath.Id > -1 ? 8 : 2);
|
||||
|
||||
internal static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
|
||||
|
||||
internal static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : filePath.Id > -1 ? 5 : 0);
|
||||
|
||||
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
|
||||
{
|
||||
int result;
|
||||
StringBuilder results = new();
|
||||
if (metadataSettings.IntMinValueLength < (resultSettings.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
for (int i = intelligentId.Length - (resultSettings.ResultAllInOneSubdirectoryLength + 2); i > -1; i--)
|
||||
_ = results.Append(intelligentId[i]);
|
||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||
result = int.Parse(results.ToString());
|
||||
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();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment)
|
||||
{
|
||||
bool result;
|
||||
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
|
||||
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0060
|
||||
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, string extensionLowered, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||
#pragma warning restore IDE0060
|
||||
{
|
||||
string result;
|
||||
StringBuilder stringBuilder = new();
|
||||
if (metadataSettings.IntMinValueLength < (resultSettings.ResultAllInOneSubdirectoryLength + 2))
|
||||
throw new NotSupportedException();
|
||||
int key;
|
||||
string value;
|
||||
List<char> resultAllInOneSubdirectoryChars = [];
|
||||
if (hasDateTimeOriginal is null)
|
||||
{
|
||||
key = 0;
|
||||
value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0');
|
||||
}
|
||||
else if (id > -1)
|
||||
{
|
||||
if (!resultSettings.ValidVideoFormatExtensions.Contains(extensionLowered))
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 8 : hasDateTimeOriginal.Value ? 9 : 7;
|
||||
else
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 6 : 5;
|
||||
value = id.ToString().PadLeft(metadataSettings.IntMinValueLength, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!resultSettings.ValidVideoFormatExtensions.Contains(extensionLowered))
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? 2 : hasDateTimeOriginal.Value ? 1 : 3;
|
||||
else
|
||||
key = hasIgnoreKeyword is not null && hasIgnoreKeyword.Value ? throw new NotImplementedException() : hasDateTimeOriginal.Value ? 4 : 0;
|
||||
value = id.ToString()[1..].PadLeft(metadataSettings.IntMinValueLength, '0');
|
||||
}
|
||||
for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
|
||||
_ = stringBuilder.Append(value[i]);
|
||||
for (int i = value.Length - resultSettings.ResultAllInOneSubdirectoryLength; i < value.Length; i++)
|
||||
resultAllInOneSubdirectoryChars.Add(value[i]);
|
||||
result = $"{stringBuilder}{string.Join(string.Empty, resultAllInOneSubdirectoryChars)}{key}";
|
||||
return result;
|
||||
}
|
||||
|
||||
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, extensionLowered, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||
int check = GetId(resultSettings, metadataSettings, intelligentId);
|
||||
if (check != id)
|
||||
throw new NotSupportedException();
|
||||
result = index is null || metadataSettings.Offset == IId.DeterministicHashCode ? intelligentId : $"{metadataSettings.Offset + index}{intelligentId}";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -7,179 +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) || check == directoryInfo.FullName)
|
||||
break;
|
||||
directoryName = Path.GetFileName(check);
|
||||
directorySegments = directoryName.Split(' ');
|
||||
(result, results) = IsWrongYear(directorySegments, year);
|
||||
if (result is not null)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -239,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);
|
||||
|
||||
}
|
@ -5,35 +5,29 @@ namespace View_by_Distance.Shared.Models.Stateless;
|
||||
internal abstract class XPath
|
||||
{
|
||||
|
||||
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower)
|
||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
|
||||
{
|
||||
string result;
|
||||
if (forceExtensionToLower)
|
||||
Dictionary<byte, List<string>> results = [];
|
||||
List<string>? c;
|
||||
foreach (CombinedEnumAndIndex cei in collection)
|
||||
{
|
||||
string extension = Path.GetExtension(path);
|
||||
string extensionLowered = Path.GetExtension(path).ToLower();
|
||||
if (extension != extensionLowered)
|
||||
if (!results.TryGetValue(cei.Enum, out c))
|
||||
{
|
||||
string? directoryName = Path.GetDirectoryName(path);
|
||||
if (string.IsNullOrEmpty(directoryName))
|
||||
throw new NullReferenceException(directoryName);
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
||||
if (string.IsNullOrEmpty(fileNameWithoutExtension))
|
||||
throw new NullReferenceException(fileNameWithoutExtension);
|
||||
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
|
||||
results.Add(cei.Enum, []);
|
||||
if (!results.TryGetValue(cei.Enum, out c))
|
||||
throw new Exception();
|
||||
}
|
||||
c.Add(cei.Combined);
|
||||
}
|
||||
result = path[length..].Replace(@"\", "/");
|
||||
return result;
|
||||
return Convert(results);
|
||||
}
|
||||
|
||||
internal static bool DeleteEmptyDirectories(string rootDirectory)
|
||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs)
|
||||
{
|
||||
bool result;
|
||||
List<string> results = [];
|
||||
DeleteEmptyDirectories(rootDirectory, results);
|
||||
result = results.Count > 0;
|
||||
return result;
|
||||
Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories)
|
||||
@ -71,45 +65,56 @@ internal abstract class XPath
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches)
|
||||
internal static byte GetEnum(FilePath filePath) =>
|
||||
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
||||
|
||||
private static byte GetEnum(bool? ik, bool? dto)
|
||||
{
|
||||
bool result;
|
||||
string text;
|
||||
if (!compareBeforeWrite)
|
||||
result = true;
|
||||
byte result;
|
||||
if (ik is not null && ik.Value && dto is not null && dto.Value)
|
||||
result = 11;
|
||||
else if (ik is not null && ik.Value && dto is not null && !dto.Value)
|
||||
result = 15;
|
||||
else if (ik is not null && ik.Value && dto is null)
|
||||
result = 19;
|
||||
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
|
||||
result = 51;
|
||||
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
|
||||
result = 55;
|
||||
else if (ik is not null && !ik.Value && dto is null)
|
||||
result = 59;
|
||||
else if (ik is null && dto is not null && dto.Value)
|
||||
result = 91;
|
||||
else if (ik is null && dto is not null && !dto.Value)
|
||||
result = 95;
|
||||
else if (ik is null && dto is null)
|
||||
result = 99;
|
||||
else
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
text = string.Empty;
|
||||
else
|
||||
text = File.ReadAllText(path);
|
||||
result = text != contents;
|
||||
if (!result && updateDateWhenMatches)
|
||||
{
|
||||
if (updateToWhenMatches is null)
|
||||
File.SetLastWriteTime(path, DateTime.Now);
|
||||
else
|
||||
File.SetLastWriteTime(path, updateToWhenMatches.Value);
|
||||
}
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
if (path.Contains("()"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
||||
File.WriteAllText(path, contents);
|
||||
else
|
||||
File.WriteAllText(path, contents);
|
||||
}
|
||||
throw new Exception();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectories(string directory)
|
||||
{
|
||||
List<string> results = [];
|
||||
string? checkDirectory = directory;
|
||||
string? pathRoot = Path.GetPathRoot(directory);
|
||||
if (string.IsNullOrEmpty(pathRoot))
|
||||
throw new NullReferenceException(nameof(pathRoot));
|
||||
if (Directory.Exists(directory))
|
||||
results.Add(directory);
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
|
||||
break;
|
||||
results.Add(checkDirectory);
|
||||
}
|
||||
results.Add(pathRoot);
|
||||
results.Reverse();
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectoryNames(string directory)
|
||||
{
|
||||
List<string> results = [];
|
||||
@ -146,83 +151,15 @@ internal abstract class XPath
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<string> GetDirectories(string directory)
|
||||
internal static bool DeleteEmptyDirectories(string rootDirectory)
|
||||
{
|
||||
bool result;
|
||||
List<string> results = [];
|
||||
string? checkDirectory = directory;
|
||||
string? pathRoot = Path.GetPathRoot(directory);
|
||||
if (string.IsNullOrEmpty(pathRoot))
|
||||
throw new NullReferenceException(nameof(pathRoot));
|
||||
if (Directory.Exists(directory))
|
||||
results.Add(directory);
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
|
||||
break;
|
||||
results.Add(checkDirectory);
|
||||
}
|
||||
results.Add(pathRoot);
|
||||
results.Reverse();
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
|
||||
{
|
||||
int result = 0;
|
||||
string? directory;
|
||||
string? checkDirectory;
|
||||
List<string> results = [];
|
||||
checkDirectory = sourceDirectory;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
result += 1;
|
||||
directory = Path.GetFileName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
break;
|
||||
results.Add(directory);
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (checkDirectory == rootDirectory)
|
||||
break;
|
||||
}
|
||||
results.Reverse();
|
||||
return new(result, results);
|
||||
}
|
||||
|
||||
internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
|
||||
{
|
||||
string result;
|
||||
string? checkDirectory;
|
||||
checkDirectory = Path.GetDirectoryName(sourceDirectory);
|
||||
for (int i = 0; i < level; i++)
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
throw new Exception();
|
||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
result = checkDirectory;
|
||||
DeleteEmptyDirectories(rootDirectory, results);
|
||||
result = results.Count > 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
|
||||
{
|
||||
DateTime dateTime = new(ticks);
|
||||
IEnumerable<string> fileSystemEntries;
|
||||
string[] directories;
|
||||
if (!Directory.Exists(rootDirectory))
|
||||
directories = [];
|
||||
else
|
||||
directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (fileSystemEntries.Any())
|
||||
continue;
|
||||
Directory.SetLastWriteTime(directory, dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory)
|
||||
{
|
||||
bool check;
|
||||
@ -265,40 +202,204 @@ internal abstract class XPath
|
||||
}
|
||||
}
|
||||
|
||||
private static (string, int) GetDirectoryNameAndIndex(int resultAllInOneSubdirectoryLength, string fileNameWithoutExtension)
|
||||
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);
|
||||
IEnumerable<string> fileSystemEntries;
|
||||
string[] directories;
|
||||
if (!Directory.Exists(rootDirectory))
|
||||
directories = [];
|
||||
else
|
||||
directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
|
||||
if (fileSystemEntries.Any())
|
||||
continue;
|
||||
Directory.SetLastWriteTime(directory, dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower)
|
||||
{
|
||||
int converted;
|
||||
string result;
|
||||
if (forceExtensionToLower)
|
||||
{
|
||||
string extension = Path.GetExtension(path);
|
||||
string extensionLowered = Path.GetExtension(path).ToLower();
|
||||
if (extension != extensionLowered)
|
||||
{
|
||||
string? directoryName = Path.GetDirectoryName(path);
|
||||
if (string.IsNullOrEmpty(directoryName))
|
||||
throw new NullReferenceException(directoryName);
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
||||
if (string.IsNullOrEmpty(fileNameWithoutExtension))
|
||||
throw new NullReferenceException(fileNameWithoutExtension);
|
||||
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
|
||||
}
|
||||
}
|
||||
result = path[length..].Replace(@"\", "/");
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
|
||||
{
|
||||
string result;
|
||||
string? checkDirectory;
|
||||
checkDirectory = Path.GetDirectoryName(sourceDirectory);
|
||||
for (int i = 0; i < level; i++)
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
throw new Exception();
|
||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
result = checkDirectory;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
|
||||
{
|
||||
int result = 0;
|
||||
string? directory;
|
||||
string? checkDirectory;
|
||||
List<string> results = [];
|
||||
checkDirectory = sourceDirectory;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
result += 1;
|
||||
directory = Path.GetFileName(checkDirectory);
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
break;
|
||||
results.Add(directory);
|
||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||
if (checkDirectory == rootDirectory)
|
||||
break;
|
||||
}
|
||||
results.Reverse();
|
||||
return new(result, results);
|
||||
}
|
||||
|
||||
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
CombinedEnumAndIndex result;
|
||||
if (filePath.Id is not null)
|
||||
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.Id.Value.ToString());
|
||||
else
|
||||
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.NameWithoutExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath, string fileNameWithoutExtension)
|
||||
{
|
||||
CombinedEnumAndIndex result;
|
||||
byte @enum;
|
||||
int converted;
|
||||
string combined;
|
||||
byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||
if (!filePath.IsIntelligentIdFormat)
|
||||
@enum = missingDateTimeOriginal;
|
||||
else
|
||||
{
|
||||
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 < resultAllInOneSubdirectoryLength ? new('-', resultAllInOneSubdirectoryLength) : fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..];
|
||||
string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ?
|
||||
new('-', resultSettings.ResultAllInOneSubdirectoryLength) :
|
||||
fileNameBeforeFirst[^resultSettings.ResultAllInOneSubdirectoryLength..];
|
||||
if (check.Any(l => !char.IsNumber(l)))
|
||||
{
|
||||
result = new('-', resultAllInOneSubdirectoryLength);
|
||||
converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}");
|
||||
combined = $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}";
|
||||
converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = check;
|
||||
combined = $"{@enum}{check}";
|
||||
converted = int.Parse(check);
|
||||
}
|
||||
return new(result, converted);
|
||||
result = new(combined, @enum, converted);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, int id)
|
||||
internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches)
|
||||
{
|
||||
(string result, int converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, id.ToString());
|
||||
return new(result, converted);
|
||||
}
|
||||
|
||||
internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
int converted;
|
||||
if (filePath.Id is not null)
|
||||
(result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.Id.Value.ToString());
|
||||
bool result;
|
||||
string text;
|
||||
if (!compareBeforeWrite)
|
||||
result = true;
|
||||
else
|
||||
(result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.NameWithoutExtension);
|
||||
return new(result, converted);
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
text = string.Empty;
|
||||
else
|
||||
text = File.ReadAllText(path);
|
||||
result = text != contents;
|
||||
if (!result && updateDateWhenMatches)
|
||||
{
|
||||
if (updateToWhenMatches is null)
|
||||
File.SetLastWriteTime(path, DateTime.Now);
|
||||
else
|
||||
File.SetLastWriteTime(path, updateToWhenMatches.Value);
|
||||
}
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
if (path.Contains("()"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
||||
File.WriteAllText(path, contents);
|
||||
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
||||
File.WriteAllText(path, contents);
|
||||
else
|
||||
File.WriteAllText(path, contents);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
|
||||
{
|
||||
Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
||||
if (jsonGroups is not null)
|
||||
{
|
||||
DateTime dateTime = DateTime.Now;
|
||||
ReadOnlyCollection<int> years = GetYears(resultSettings);
|
||||
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>? k;
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime);
|
||||
foreach (int year in years)
|
||||
{
|
||||
results.Add(year, []);
|
||||
if (!results.TryGetValue(year, out k))
|
||||
throw new NullReferenceException(nameof(k));
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||
k.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
}
|
||||
return Convert(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings)
|
||||
@ -310,65 +411,79 @@ internal abstract class XPath
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> Convert(Dictionary<int, Dictionary<string, string[]>> collection)
|
||||
private static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime)
|
||||
{
|
||||
Dictionary<int, ReadOnlyDictionary<string, string[]>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<string, string[]>> keyValuePair in collection)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
|
||||
{
|
||||
Dictionary<int, Dictionary<string, string[]>> results = [];
|
||||
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
||||
int plusOne;
|
||||
string directory;
|
||||
string checkDirectory;
|
||||
Dictionary<string, string[]>? keyValuePairs;
|
||||
ReadOnlyCollection<int> years = GetYears(resultSettings);
|
||||
CombinedEnumAndIndex cei;
|
||||
byte[] bytes = GetBytes();
|
||||
List<CombinedEnumAndIndex> collection = [];
|
||||
ReadOnlyDictionary<byte, ReadOnlyCollection<string>> keyValuePairs;
|
||||
int converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}");
|
||||
int plusOne = converted + 1;
|
||||
List<string> collection = [];
|
||||
foreach (int year in years)
|
||||
if (jsonGroups is not null)
|
||||
{
|
||||
results.Add(year, []);
|
||||
if (!results.TryGetValue(year, out keyValuePairs))
|
||||
throw new NullReferenceException(nameof(keyValuePairs));
|
||||
if (jsonGroups is not null)
|
||||
plusOne = converted + 1;
|
||||
foreach (string jsonGroup in jsonGroups)
|
||||
{
|
||||
foreach (string jsonGroup in jsonGroups)
|
||||
if (resultsFullGroupDirectory is null)
|
||||
continue;
|
||||
foreach (byte @enum in bytes)
|
||||
{
|
||||
if (resultsFullGroupDirectory is null)
|
||||
continue;
|
||||
collection.Clear();
|
||||
for (int i = 0; i < plusOne; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonGroup))
|
||||
{
|
||||
if (i == converted)
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, new('-', resultSettings.ResultAllInOneSubdirectoryLength)));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}"));
|
||||
else
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
directory = Path.Combine(resultsFullGroupDirectory, jsonGroup);
|
||||
if (i == converted)
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, new('-', resultSettings.ResultAllInOneSubdirectoryLength)));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}"));
|
||||
else
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}"));
|
||||
}
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
collection.Add(checkDirectory);
|
||||
cei = new(Combined: checkDirectory, Enum: @enum, Index: -1);
|
||||
collection.Add(cei);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(jsonGroup))
|
||||
keyValuePairs.Add(jsonGroup, collection.ToArray());
|
||||
else
|
||||
keyValuePairs.Add(year.ToString(), collection.ToArray());
|
||||
}
|
||||
keyValuePairs = Convert(collection);
|
||||
if (!string.IsNullOrEmpty(jsonGroup))
|
||||
results.Add(jsonGroup, keyValuePairs);
|
||||
else
|
||||
results.Add(dateTime.Ticks.ToString(), keyValuePairs);
|
||||
}
|
||||
}
|
||||
return Convert(results);
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static byte[] GetBytes() =>
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9
|
||||
];
|
||||
|
||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
|
||||
{
|
||||
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
||||
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
5
Windows/.vscode/11.http
vendored
Normal file
5
Windows/.vscode/11.http
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
@host = http://192.168.0.11:8080
|
||||
|
||||
GET {{host}}/iCloud%20Photos%202025
|
||||
|
||||
###
|
5
Windows/.vscode/mklink.md
vendored
Normal file
5
Windows/.vscode/mklink.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# mklink
|
||||
|
||||
```bash 1741014465915 = 638766112659150000 = 2025-0.Winter = Mon Mar 03 2025 08:07:45 GMT-0700 (Mountain Standard Time)
|
||||
mklink /J "L:\Git\AA\Windows\.vscode\.7-Question" "V:\7-Question"
|
||||
````
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@ -7,9 +7,12 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<UserSecretsId>076c87e8-c7f0-40a3-aba3-73eb7f9ea892</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<HoursSinceNovember122024>$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</HoursSinceNovember122024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageId>Phares.View.by.Distance.Windows</PackageId>
|
||||
<Version>8.0.112.0</Version>
|
||||
<Version>9.0.104.$([System.Math]::Floor($([MSBuild]::Divide($([MSBuild]::Subtract($([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()), 1731369600)), 3600))))</Version>
|
||||
<Company>Phares</Company>
|
||||
<Authors>Mike Phares</Authors>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@ -39,13 +42,13 @@
|
||||
<None Include=".vscode\read-me.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.7.1" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.12" />
|
||||
<PackageReference Include="CliWrap" Version="3.8.2" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.14" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
<PackageReference Include="ShellProgressBar" Version="5.2.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.12" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.14" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<RuntimeHostConfigurationOption Include="System.Drawing.EnableUnixSupport" Value="true" />
|
||||
|
@ -6,12 +6,9 @@ namespace View_by_Distance.Windows.Models;
|
||||
|
||||
public record WindowsSettings(string Company,
|
||||
string? Host,
|
||||
string[] IgnoreExtensions,
|
||||
int MaxDegreeOfParallelism,
|
||||
string? Page,
|
||||
string[] SidecarExtensions,
|
||||
string[] ValidImageFormatExtensions,
|
||||
string[] ValidVideoFormatExtensions,
|
||||
bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings
|
||||
{
|
||||
|
||||
|
@ -9,7 +9,6 @@ using System.Text.Json;
|
||||
using View_by_Distance.Metadata.Models;
|
||||
using View_by_Distance.Metadata.Models.Stateless;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless;
|
||||
using View_by_Distance.Windows.Models;
|
||||
|
||||
@ -21,42 +20,98 @@ public partial class Windows : IWindows, IDisposable
|
||||
private ProgressBar? _ProgressBar;
|
||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||
|
||||
public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
|
||||
GetDeterministicHashCode(httpClient, uri);
|
||||
|
||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
|
||||
{
|
||||
if (isSilent)
|
||||
{ }
|
||||
if (args is null)
|
||||
throw new NullReferenceException(nameof(args));
|
||||
if (console is null)
|
||||
throw new NullReferenceException(nameof(console));
|
||||
IWindows windows = this;
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
WindowsWork(logger, appSettings, windows, ticks);
|
||||
DeterministicHashCode result;
|
||||
if (httpClient is not null)
|
||||
result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
|
||||
else
|
||||
{
|
||||
Stream stream = File.OpenRead(filePath.FullName);
|
||||
result = GetDeterministicHashCode(stream);
|
||||
stream.Dispose();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
Stream stream = GetStream(httpClient, uri);
|
||||
result = GetDeterministicHashCode(stream);
|
||||
stream.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Stream GetStream(HttpClient httpClient, Uri uri)
|
||||
{
|
||||
Stream result;
|
||||
Task<Stream> task = httpClient.GetStreamAsync(uri);
|
||||
task.Wait();
|
||||
result = task.Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
int? id;
|
||||
int? width;
|
||||
int? height;
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
using Image image = Image.FromStream(stream);
|
||||
width = image.Width;
|
||||
height = image.Height;
|
||||
using Bitmap bitmap = new(image);
|
||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
byte[] bytes = new byte[length];
|
||||
Marshal.Copy(intPtr, bytes, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
#pragma warning restore CA1416
|
||||
id = IId.GetDeterministicHashCode(bytes);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
id = null;
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
result = new(height, id, width);
|
||||
return result;
|
||||
}
|
||||
|
||||
void IWindows.Tick() =>
|
||||
_ProgressBar?.Tick();
|
||||
|
||||
void IWindows.ConstructProgressBar(int maxTicks, string message)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath)
|
||||
void IWindows.ConstructProgressBar(int maxTicks, string message)
|
||||
{
|
||||
_ProgressBar?.Dispose();
|
||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||
}
|
||||
|
||||
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath)
|
||||
{
|
||||
List<string> results = [];
|
||||
bool isValidVideoFormatExtensions = WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||
bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||
if (isValidVideoFormatExtensions)
|
||||
{
|
||||
bool check;
|
||||
if (httpClient is not null)
|
||||
DownloadFile(httpClient, filePath);
|
||||
try
|
||||
{
|
||||
CommandTask<CommandResult> commandTask = Cli.Wrap("L:/Git/ffmpeg-2024-10-02-git-358fdf3083-full_build/bin/ffmpeg.exe")
|
||||
@ -83,75 +138,74 @@ public partial class Windows : IWindows, IDisposable
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
|
||||
private static void DownloadFile(HttpClient httpClient, FilePath filePath)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
int? id;
|
||||
int? width;
|
||||
int? height;
|
||||
try
|
||||
{
|
||||
using Image image = Image.FromStream(stream);
|
||||
width = image.Width;
|
||||
height = image.Height;
|
||||
using Bitmap bitmap = new(image);
|
||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
IntPtr intPtr = bitmapData.Scan0;
|
||||
int length = bitmapData.Stride * bitmap.Height;
|
||||
byte[] bytes = new byte[length];
|
||||
Marshal.Copy(intPtr, bytes, 0, length);
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
id = IId.GetDeterministicHashCode(bytes);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
id = null;
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
result = new(height, id, width);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Stream GetStream(HttpClient httpClient, Uri uri)
|
||||
{
|
||||
Stream result;
|
||||
Task<Stream> task = httpClient.GetStreamAsync(uri);
|
||||
FileStream fileStream = new(filePath.FullName, FileMode.Truncate);
|
||||
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
|
||||
httpResponseMessage.Wait();
|
||||
Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
|
||||
task.Wait();
|
||||
result = task.Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri)
|
||||
public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
Stream stream = GetStream(httpClient, uri);
|
||||
result = GetDeterministicHashCode(stream);
|
||||
stream.Dispose();
|
||||
return result;
|
||||
if (isSilent)
|
||||
{ }
|
||||
if (args is null)
|
||||
throw new NullReferenceException(nameof(args));
|
||||
if (console is null)
|
||||
throw new NullReferenceException(nameof(console));
|
||||
IWindows windows = this;
|
||||
LogNetToHoursSince(logger);
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
WindowsWork(logger, appSettings, windows, ticks);
|
||||
}
|
||||
|
||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
|
||||
GetDeterministicHashCode(httpClient, uri);
|
||||
|
||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
|
||||
private static void LogNetToHoursSince(ILogger<Program>? logger)
|
||||
{
|
||||
DeterministicHashCode result;
|
||||
if (httpClient is not null)
|
||||
result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
|
||||
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, long ticks)
|
||||
{
|
||||
if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||
else
|
||||
{
|
||||
Stream stream = File.OpenRead(filePath.FullName);
|
||||
result = GetDeterministicHashCode(stream);
|
||||
stream.Dispose();
|
||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||
if (!Directory.Exists(sourceDirectory))
|
||||
_ = Directory.CreateDirectory(sourceDirectory);
|
||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||
WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page)
|
||||
{
|
||||
List<string> messages = [];
|
||||
HttpClient httpClient = new();
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception();
|
||||
windows.ConstructProgressBar(collection.Count, nameof(Verify));
|
||||
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
||||
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages));
|
||||
httpClient.Dispose();
|
||||
foreach (string message in messages)
|
||||
logger?.LogWarning("{message}", message);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<NginxFileSystem>? GetRecursiveCollection(HttpClient httpClient, string host, string page)
|
||||
{
|
||||
@ -209,6 +263,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);
|
||||
@ -216,19 +271,43 @@ public partial class Windows : IWindows, IDisposable
|
||||
messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})");
|
||||
}
|
||||
|
||||
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page)
|
||||
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
|
||||
{
|
||||
List<string> messages = [];
|
||||
HttpClient httpClient = new();
|
||||
ReadOnlyCollection<FirstPass> results;
|
||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).AsReadOnly();
|
||||
if (files.Count > 0)
|
||||
_ = IPath.DeleteEmptyDirectories(sourceDirectory);
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception();
|
||||
windows.ConstructProgressBar(collection.Count, nameof(Verify));
|
||||
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
||||
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages));
|
||||
httpClient.Dispose();
|
||||
foreach (string message in messages)
|
||||
logger?.LogWarning("{message}", message);
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata);
|
||||
else
|
||||
results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
|
||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
|
||||
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||
keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||
else
|
||||
{
|
||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<NginxFileSystem> GetRecursiveCollection(string host, string page)
|
||||
@ -240,10 +319,10 @@ public partial class Windows : IWindows, IDisposable
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<FirstPass> GetCollection(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
|
||||
private static int WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, A_Metadata metadata, List<FirstPass> results, int index, KeyValuePair<string, List<FileHolder>> keyValuePair)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
int result = index + 1;
|
||||
windows.Tick();
|
||||
FilePath filePath;
|
||||
FirstPass firstPass;
|
||||
string directoryName;
|
||||
@ -253,116 +332,79 @@ public partial class Windows : IWindows, IDisposable
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
HttpClient? httpClient = string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page) ? null : new();
|
||||
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||
keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||
else
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
index += 1;
|
||||
windows.Tick();
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result);
|
||||
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (directoryName.EndsWith(filePath.Id.Value.ToString()))
|
||||
continue;
|
||||
if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (directoryName.EndsWith(filePath.Id.Value.ToString()))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
|
||||
{
|
||||
if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||
else
|
||||
{
|
||||
FirstPass firstPass;
|
||||
List<FirstPass> results = [];
|
||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||
if (!Directory.Exists(sourceDirectory))
|
||||
_ = Directory.CreateDirectory(sourceDirectory);
|
||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||
if (files.Count > 0)
|
||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
results.AddRange(GetCollection(logger, appSettings, windows, files, metadata));
|
||||
else
|
||||
{
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups));
|
||||
if (_ProgressBar?.CurrentTick != results.Count)
|
||||
throw new NotSupportedException();
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
FirstPass firstPass;
|
||||
List<string> distinct = [];
|
||||
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)
|
||||
throw new NotSupportedException();
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"rollForward": "latestMinor",
|
||||
"version": "9.0.103"
|
||||
"version": "9.0.0"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user