Mostly Sorting
Video Merge as 4, 5, and 6 Enum change to last character
This commit is contained in:
parent
ae23e803fa
commit
9fb6f0fa05
14
.vscode/tasks.json
vendored
14
.vscode/tasks.json
vendored
@ -628,5 +628,19 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
||||||
|
"args": [
|
||||||
|
"s",
|
||||||
|
"X",
|
||||||
|
"L:/Git/AA",
|
||||||
|
"Day-Helper-2025-03-20",
|
||||||
|
"false",
|
||||||
|
"4"
|
||||||
|
],
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -17,6 +17,21 @@ public partial class Compare : ICompare, IDisposable
|
|||||||
private ProgressBar? _ProgressBar;
|
private ProgressBar? _ProgressBar;
|
||||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||||
|
|
||||||
|
void ICompare.Tick() =>
|
||||||
|
_ProgressBar?.Tick();
|
||||||
|
|
||||||
|
void IDisposable.Dispose()
|
||||||
|
{
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICompare.ConstructProgressBar(int maxTicks, string message)
|
||||||
|
{
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||||
|
}
|
||||||
|
|
||||||
public Compare(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
public Compare(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||||
{
|
{
|
||||||
if (isSilent)
|
if (isSilent)
|
||||||
@ -31,19 +46,46 @@ public partial class Compare : ICompare, IDisposable
|
|||||||
CompareWork(logger, appSettings, compare, ticks);
|
CompareWork(logger, appSettings, compare, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICompare.Tick() =>
|
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
|
||||||
_ProgressBar?.Tick();
|
|
||||||
|
|
||||||
void ICompare.ConstructProgressBar(int maxTicks, string message)
|
|
||||||
{
|
{
|
||||||
_ProgressBar?.Dispose();
|
const int updated = 0;
|
||||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
DistanceLimits? distanceLimits;
|
||||||
}
|
logger?.LogInformation("{Ticks}", ticks);
|
||||||
|
ReadOnlyCollection<LocationContainer> matrix;
|
||||||
void IDisposable.Dispose()
|
ReadOnlyCollection<SaveContainer> saveContainers;
|
||||||
{
|
ReadOnlyCollection<ExifDirectory> exifDirectories;
|
||||||
_ProgressBar?.Dispose();
|
ReadOnlyCollection<LocationContainer> preFiltered;
|
||||||
GC.SuppressFinalize(this);
|
ReadOnlyCollection<LocationContainer> postFiltered;
|
||||||
|
ReadOnlyDictionary<string, LocationContainer> onlyOne;
|
||||||
|
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
|
||||||
|
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
|
||||||
|
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
|
||||||
|
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
|
||||||
|
{
|
||||||
|
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
|
||||||
|
continue;
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
logger?.LogInformation("{outputResolution}", outputResolution);
|
||||||
|
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
|
||||||
|
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||||
|
if (preFiltered.Count == 0)
|
||||||
|
continue;
|
||||||
|
distanceLimits = new(appSettings.DistanceSettings);
|
||||||
|
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||||
|
if (postFiltered.Count == 0)
|
||||||
|
continue;
|
||||||
|
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||||
|
if (matrix.Count == 0)
|
||||||
|
continue;
|
||||||
|
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
|
||||||
|
if (onlyOne.Count == 0)
|
||||||
|
continue;
|
||||||
|
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
|
||||||
|
if (saveContainers.Count == 0)
|
||||||
|
continue;
|
||||||
|
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks)
|
private static bool GetRunToDoCollectionFirst(AppSettings appSettings, long ticks)
|
||||||
@ -123,46 +165,4 @@ public partial class Compare : ICompare, IDisposable
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompareWork(ILogger<Program>? logger, AppSettings appSettings, ICompare compare, long ticks)
|
|
||||||
{
|
|
||||||
const int updated = 0;
|
|
||||||
DistanceLimits? distanceLimits;
|
|
||||||
logger?.LogInformation("{Ticks}", ticks);
|
|
||||||
ReadOnlyCollection<LocationContainer> matrix;
|
|
||||||
ReadOnlyCollection<SaveContainer> saveContainers;
|
|
||||||
ReadOnlyCollection<ExifDirectory> exifDirectories;
|
|
||||||
ReadOnlyCollection<LocationContainer> preFiltered;
|
|
||||||
ReadOnlyCollection<LocationContainer> postFiltered;
|
|
||||||
ReadOnlyDictionary<string, LocationContainer> onlyOne;
|
|
||||||
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(appSettings, ticks);
|
|
||||||
ReadOnlyCollections readOnlyCollections = GetReadOnlyCollections(appSettings);
|
|
||||||
ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding = GetMappedExifDirectoryWithEncoding(appSettings, compare, ticks, readOnlyCollections);
|
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs = IDistance.Extract(appSettings.CompareSettings, mappedExifDirectoryWithEncoding);
|
|
||||||
foreach (string outputResolution in appSettings.CompareSettings.OutputResolutions)
|
|
||||||
{
|
|
||||||
if (runToDoCollectionFirst || outputResolution.Any(char.IsNumber))
|
|
||||||
continue;
|
|
||||||
_ProgressBar?.Dispose();
|
|
||||||
logger?.LogInformation("{outputResolution}", outputResolution);
|
|
||||||
exifDirectories = IFace.GetExifDirectories(appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution);
|
|
||||||
preFiltered = IDistance.GetPreFilterLocationContainer(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
|
||||||
if (preFiltered.Count == 0)
|
|
||||||
continue;
|
|
||||||
distanceLimits = new(appSettings.DistanceSettings);
|
|
||||||
postFiltered = IDistance.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
|
||||||
if (postFiltered.Count == 0)
|
|
||||||
continue;
|
|
||||||
matrix = IDistance.GetMatrixLocationContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
|
||||||
if (matrix.Count == 0)
|
|
||||||
continue;
|
|
||||||
onlyOne = IDistance.GetOnlyOne(appSettings.DistanceSettings, matrix);
|
|
||||||
if (onlyOne.Count == 0)
|
|
||||||
continue;
|
|
||||||
saveContainers = IDistance.GetSaveContainers(appSettings.ResultSettings, appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, outputResolution, onlyOne);
|
|
||||||
if (saveContainers.Count == 0)
|
|
||||||
continue;
|
|
||||||
IDistance.SaveContainers(appSettings.DistanceSettings, appSettings.CompareSettings, compare, ticks, updated, saveContainers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -8,11 +8,8 @@ public record CompareSettings(string Company,
|
|||||||
string FacesFileNameExtension,
|
string FacesFileNameExtension,
|
||||||
string FacesHiddenFileNameExtension,
|
string FacesHiddenFileNameExtension,
|
||||||
string FacesPartsFileNameExtension,
|
string FacesPartsFileNameExtension,
|
||||||
string[] IgnoreExtensions,
|
|
||||||
int MaxDegreeOfParallelism,
|
int MaxDegreeOfParallelism,
|
||||||
string[] OutputResolutions,
|
string[] OutputResolutions) : Shared.Models.Properties.ICompareSettings
|
||||||
string[] ValidImageFormatExtensions,
|
|
||||||
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.ICompareSettings
|
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -11,11 +11,21 @@ namespace View_by_Distance.Distance.Models.Stateless;
|
|||||||
internal static class FilterLogicD
|
internal static class FilterLogicD
|
||||||
{
|
{
|
||||||
|
|
||||||
internal record RecordA(long? Ticks, string? Directory);
|
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||||
|
result = Path.Combine(cContentDirectory, cei.Combined);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting);
|
internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
|
||||||
|
{
|
||||||
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory);
|
string result;
|
||||||
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||||
|
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
internal static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
||||||
{
|
{
|
||||||
@ -39,141 +49,12 @@ internal static class FilterLogicD
|
|||||||
else if (isBySorting && useFiltersCounter.HasValue)
|
else if (isBySorting && useFiltersCounter.HasValue)
|
||||||
byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
byValue = $"{nameof(IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
||||||
else
|
else
|
||||||
{
|
byValue = IDistance.Get(saveIndividually, forceSingleImageHumanized, by.Value, isDefaultName);
|
||||||
byValue = $"{by.Value switch
|
|
||||||
{
|
|
||||||
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
|
|
||||||
IMapLogic.Sorting => saveIndividually ? nameof(IMapLogic.Individually) : nameof(IMapLogic.Sorting),
|
|
||||||
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
|
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result = new(byValue, isByMapping, isBySorting);
|
result = new(byValue, isByMapping, isBySorting);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
|
|
||||||
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
|
|
||||||
|
|
||||||
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
|
|
||||||
{
|
|
||||||
RecordC result;
|
|
||||||
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
|
|
||||||
throw new NotImplementedException();
|
|
||||||
long? ticks = null;
|
|
||||||
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
|
|
||||||
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
|
|
||||||
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
|
|
||||||
result = new(debugDirectory, directory, ticks, personDirectory);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
|
|
||||||
{
|
|
||||||
string result;
|
|
||||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
|
||||||
result = Path.Combine(cContentDirectory, cei.Combined);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetFacePartsDirectoryX(ResultSettings resultSettings, string d2FacePartsContentDirectory, FilePath filePath)
|
|
||||||
{
|
|
||||||
string result;
|
|
||||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
|
||||||
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
|
|
||||||
{
|
|
||||||
List<SaveContainer> results = [];
|
|
||||||
RecordB recordB;
|
|
||||||
RecordC recordC;
|
|
||||||
string segmentB;
|
|
||||||
string checkFile;
|
|
||||||
string? directory;
|
|
||||||
string shortcutFile;
|
|
||||||
string facesDirectory;
|
|
||||||
bool isCounterPersonYear;
|
|
||||||
string facePartsDirectory;
|
|
||||||
FileHolder? faceFileHolder;
|
|
||||||
SaveContainer? saveContainer;
|
|
||||||
FileHolder? resizedFileHolder;
|
|
||||||
int? useFiltersCounter = null;
|
|
||||||
string resizeContentDirectory;
|
|
||||||
FileHolder? facePartsFileHolder;
|
|
||||||
FileHolder? hiddenFaceFileHolder;
|
|
||||||
LocationContainer locationContainer;
|
|
||||||
bool sortingContainersAny = onlyOne.Count > 0;
|
|
||||||
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
|
|
||||||
nameof(E_Distance),
|
|
||||||
resultSettings.ResultContent);
|
|
||||||
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
|
||||||
nameof(C_Resize),
|
|
||||||
outputResolution,
|
|
||||||
includeResizeGroup: true,
|
|
||||||
includeModel: false,
|
|
||||||
includePredictorModel: false);
|
|
||||||
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
|
||||||
nameof(D2_FaceParts),
|
|
||||||
outputResolution,
|
|
||||||
includeResizeGroup: true,
|
|
||||||
includeModel: true,
|
|
||||||
includePredictorModel: true);
|
|
||||||
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
|
|
||||||
if (!Directory.Exists(cContentDirectory))
|
|
||||||
_ = Directory.CreateDirectory(cContentDirectory);
|
|
||||||
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
|
|
||||||
if (!Directory.Exists(eDistanceContentTicksDirectory))
|
|
||||||
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
|
|
||||||
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
|
|
||||||
if (!Directory.Exists(d2FacePartsContentDirectory))
|
|
||||||
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
|
|
||||||
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
|
||||||
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
|
||||||
compare.ConstructProgressBar(onlyOne.Count, message);
|
|
||||||
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
|
|
||||||
{
|
|
||||||
if (distanceSettings.SaveIndividually)
|
|
||||||
break;
|
|
||||||
locationContainer = keyValuePair.Value;
|
|
||||||
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
|
||||||
continue;
|
|
||||||
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
|
||||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
|
||||||
continue;
|
|
||||||
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
|
|
||||||
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
|
|
||||||
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
|
|
||||||
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
|
|
||||||
continue;
|
|
||||||
directory = recordC.Directory;
|
|
||||||
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
|
|
||||||
results.Add(SaveContainer.Get(recordC.DebugDirectory));
|
|
||||||
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
|
||||||
{
|
|
||||||
if (!distanceSettings.SaveSortingWithoutPerson)
|
|
||||||
throw new NotSupportedException();
|
|
||||||
if (recordC.Ticks is null)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
results.Add(SaveContainer.Get(recordC.PersonDirectory));
|
|
||||||
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
|
|
||||||
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
|
|
||||||
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
|
||||||
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
|
||||||
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
|
|
||||||
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
|
||||||
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
|
|
||||||
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
|
|
||||||
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
|
||||||
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
|
||||||
results.Add(saveContainer);
|
|
||||||
}
|
|
||||||
return results.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers)
|
internal static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers)
|
||||||
{
|
{
|
||||||
string fileName;
|
string fileName;
|
||||||
@ -285,4 +166,115 @@ internal static class FilterLogicD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne)
|
||||||
|
{
|
||||||
|
List<SaveContainer> results = [];
|
||||||
|
RecordB recordB;
|
||||||
|
RecordC recordC;
|
||||||
|
string segmentB;
|
||||||
|
string checkFile;
|
||||||
|
string? directory;
|
||||||
|
string shortcutFile;
|
||||||
|
string facesDirectory;
|
||||||
|
bool isCounterPersonYear;
|
||||||
|
string facePartsDirectory;
|
||||||
|
FileHolder? faceFileHolder;
|
||||||
|
SaveContainer? saveContainer;
|
||||||
|
FileHolder? resizedFileHolder;
|
||||||
|
int? useFiltersCounter = null;
|
||||||
|
string resizeContentDirectory;
|
||||||
|
FileHolder? facePartsFileHolder;
|
||||||
|
FileHolder? hiddenFaceFileHolder;
|
||||||
|
LocationContainer locationContainer;
|
||||||
|
bool sortingContainersAny = onlyOne.Count > 0;
|
||||||
|
string eResultsFullGroupDirectory = IResult.GetResultsDateGroupDirectory(resultSettings,
|
||||||
|
nameof(E_Distance),
|
||||||
|
resultSettings.ResultContent);
|
||||||
|
string cResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||||
|
nameof(C_Resize),
|
||||||
|
outputResolution,
|
||||||
|
includeResizeGroup: true,
|
||||||
|
includeModel: false,
|
||||||
|
includePredictorModel: false);
|
||||||
|
string d2ResultsFullGroupDirectory = IResult.GetResultsFullGroupDirectory(resultSettings,
|
||||||
|
nameof(D2_FaceParts),
|
||||||
|
outputResolution,
|
||||||
|
includeResizeGroup: true,
|
||||||
|
includeModel: true,
|
||||||
|
includePredictorModel: true);
|
||||||
|
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||||
|
if (!Directory.Exists(cContentDirectory))
|
||||||
|
_ = Directory.CreateDirectory(cContentDirectory);
|
||||||
|
string eDistanceContentTicksDirectory = Path.Combine(eResultsFullGroupDirectory, ticks.ToString());
|
||||||
|
if (!Directory.Exists(eDistanceContentTicksDirectory))
|
||||||
|
_ = Directory.CreateDirectory(eDistanceContentTicksDirectory);
|
||||||
|
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, resultSettings.ResultContent);
|
||||||
|
if (!Directory.Exists(d2FacePartsContentDirectory))
|
||||||
|
_ = Directory.CreateDirectory(d2FacePartsContentDirectory);
|
||||||
|
string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||||
|
string message = $") Building Save Container Collection - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||||
|
compare.ConstructProgressBar(onlyOne.Count, message);
|
||||||
|
foreach (KeyValuePair<string, LocationContainer> keyValuePair in onlyOne)
|
||||||
|
{
|
||||||
|
if (distanceSettings.SaveIndividually)
|
||||||
|
break;
|
||||||
|
locationContainer = keyValuePair.Value;
|
||||||
|
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
||||||
|
continue;
|
||||||
|
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
||||||
|
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||||
|
continue;
|
||||||
|
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyTicks);
|
||||||
|
recordB = Get(useFiltersCounter, distanceSettings.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName);
|
||||||
|
recordC = Get(eDistanceContentTicksDirectory, recordB, locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName, segmentB);
|
||||||
|
if (string.IsNullOrEmpty(recordC.Directory) || string.IsNullOrEmpty(recordC.PersonDirectory))
|
||||||
|
continue;
|
||||||
|
directory = recordC.Directory;
|
||||||
|
if (!string.IsNullOrEmpty(recordC.DebugDirectory))
|
||||||
|
results.Add(SaveContainer.Get(recordC.DebugDirectory));
|
||||||
|
if (locationContainer.PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName is null)
|
||||||
|
{
|
||||||
|
if (!distanceSettings.SaveSortingWithoutPerson)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
if (recordC.Ticks is null)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
results.Add(SaveContainer.Get(recordC.PersonDirectory));
|
||||||
|
facesDirectory = locationContainer.LengthSource.DirectoryFullPath;
|
||||||
|
faceFileHolder = FileHolder.Get(locationContainer.LengthSource.FullName);
|
||||||
|
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
||||||
|
shortcutFile = Path.Combine(recordC.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
||||||
|
resizeContentDirectory = GetResizeContentDirectory(resultSettings, cContentDirectory, locationContainer.LengthSource);
|
||||||
|
facePartsDirectory = GetFacePartsDirectoryX(resultSettings, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
||||||
|
hiddenFaceFileHolder = FileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesHiddenFileNameExtension}"));
|
||||||
|
facePartsFileHolder = FileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{compareSettings.FacesPartsFileNameExtension}"));
|
||||||
|
resizedFileHolder = FileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
||||||
|
saveContainer = SaveContainer.Get(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
||||||
|
results.Add(saveContainer);
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RecordB Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName) =>
|
||||||
|
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKeyFormattedAndKeyTicksAndDisplayDirectoryName is null ? null : IMapLogic.Mapping, personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName);
|
||||||
|
|
||||||
|
private static RecordC Get(string eDistanceContentTicksDirectory, RecordB recordB, PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName? personKeyFormattedAndKeyTicksAndDisplayDirectoryName, string segmentB)
|
||||||
|
{
|
||||||
|
RecordC result;
|
||||||
|
if (string.IsNullOrEmpty(personKeyFormattedAndKeyTicksAndDisplayDirectoryName?.DisplayDirectoryName))
|
||||||
|
throw new NotImplementedException();
|
||||||
|
long? ticks = null;
|
||||||
|
string? debugDirectory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName);
|
||||||
|
string? directory = Path.Combine(eDistanceContentTicksDirectory, recordB.ByValue, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.KeyFormatted, segmentB);
|
||||||
|
string? personDirectory = Path.Combine(directory, personKeyFormattedAndKeyTicksAndDisplayDirectoryName.DisplayDirectoryName, "lnk");
|
||||||
|
result = new(debugDirectory, directory, ticks, personDirectory);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal record RecordA(long? Ticks, string? Directory);
|
||||||
|
|
||||||
|
internal record RecordB(string ByValue, bool IsByMapping, bool IsBySorting);
|
||||||
|
|
||||||
|
internal record RecordC(string? DebugDirectory, string? Directory, long? Ticks, string? PersonDirectory);
|
||||||
|
|
||||||
}
|
}
|
@ -9,49 +9,69 @@ namespace View_by_Distance.Distance.Models.Stateless;
|
|||||||
public interface IDistance
|
public interface IDistance
|
||||||
{
|
{
|
||||||
|
|
||||||
static ReadOnlyCollection<ExifDirectory> TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
static string Get(bool saveIndividually, string forceSingleImageHumanized, int by, bool isDefaultName) =>
|
||||||
GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
$"{by switch
|
||||||
static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
{
|
||||||
MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
IMapLogic.Mapping => nameof(IMapLogic.Mapping),
|
||||||
|
IMapLogic.Sorting => saveIndividually ?
|
||||||
|
nameof(IMapLogic.Individually) :
|
||||||
|
nameof(IMapLogic.Sorting),
|
||||||
|
IMapLogic.ForceSingleImage => forceSingleImageHumanized,
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||||
|
|
||||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
public static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||||
Extract(compareSettings, exifDirectories);
|
|
||||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
|
||||||
MappedLogicA.Extract(compareSettings, exifDirectories);
|
|
||||||
|
|
||||||
static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
|
||||||
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
|
||||||
static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
|
||||||
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
|
||||||
|
|
||||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
|
||||||
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
|
||||||
static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
|
||||||
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
|
||||||
|
|
||||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
|
||||||
GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
|
||||||
static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
|
||||||
FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
|
||||||
|
|
||||||
static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
|
||||||
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
|
||||||
static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
|
||||||
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
|
||||||
|
|
||||||
static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
|
||||||
GetOnlyOne(distanceSettings, matrix);
|
|
||||||
static ReadOnlyDictionary<string, LocationContainer> GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
|
||||||
FilterLogicC.GetOnlyOne(distanceSettings, matrix);
|
FilterLogicC.GetOnlyOne(distanceSettings, matrix);
|
||||||
|
|
||||||
static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
public static ReadOnlyCollection<ExifDirectory> GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
FaceEncodingLogic.GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||||
static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
|
||||||
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
|
||||||
|
|
||||||
static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
public static ReadOnlyCollection<LocationContainer> GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
||||||
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
FilterLogicC.GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||||
static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
|
||||||
|
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
|
MappedLogicA.Extract(compareSettings, exifDirectories);
|
||||||
|
|
||||||
|
public static void SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
||||||
FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
FilterLogicD.SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<SaveContainer> GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||||
|
FilterLogicD.GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
||||||
|
MappedLogicA.GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||||
|
FilterLogicC.GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<LocationContainer> GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
|
FilterLogicA.GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||||
|
|
||||||
|
internal static ReadOnlyDictionary<string, LocationContainer> TestStatic_GetOnlyOne(DistanceSettings distanceSettings, ReadOnlyCollection<LocationContainer> matrix) =>
|
||||||
|
GetOnlyOne(distanceSettings, matrix);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMappedExifDirectoryWithEncoding(ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
|
GetMappedExifDirectoryWithEncoding(compare, ticks, exifDirectories);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPostFilterLocationContainer(ReadOnlyCollection<LocationContainer> preFiltered, DistanceLimits distanceLimits) =>
|
||||||
|
GetPostFilterLocationContainer(preFiltered, distanceLimits);
|
||||||
|
|
||||||
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> TestStatic_Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
|
Extract(compareSettings, exifDirectories);
|
||||||
|
|
||||||
|
internal static void TestStatic_SaveContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, int? updated, ReadOnlyCollection<SaveContainer> saveContainers) =>
|
||||||
|
SaveContainers(distanceSettings, compareSettings, compare, ticks, updated, saveContainers);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<SaveContainer> TestStatic_GetSaveContainers(ResultSettings resultSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string outputResolution, ReadOnlyDictionary<string, LocationContainer> onlyOne) =>
|
||||||
|
GetSaveContainers(resultSettings, distanceSettings, compareSettings, compare, ticks, outputResolution, onlyOne);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<ExifDirectory> TestStatic_GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections) =>
|
||||||
|
GetMapped(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, readOnlyCollections);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetMatrixLocationContainers(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollection<ExifDirectory> mappedExifDirectoryWithEncoding, DistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> postFiltered) =>
|
||||||
|
GetMatrixLocationContainers(distanceSettings, compareSettings, compare, ticks, mappedExifDirectoryWithEncoding, distanceLimits, postFiltered);
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<LocationContainer> TestStatic_GetPreFilterLocationContainer(DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections, ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> keyValuePairs, ReadOnlyCollection<ExifDirectory> exifDirectories) =>
|
||||||
|
GetPreFilterLocationContainer(distanceSettings, compareSettings, compare, ticks, readOnlyCollections, keyValuePairs, exifDirectories);
|
||||||
|
|
||||||
}
|
}
|
@ -14,33 +14,53 @@ internal static class MappedLogicA
|
|||||||
string? PersonDisplayDirectoryName,
|
string? PersonDisplayDirectoryName,
|
||||||
FilePath FilePath);
|
FilePath FilePath);
|
||||||
|
|
||||||
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections)
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
|
||||||
{
|
{
|
||||||
List<MappedFile> results = [];
|
Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
|
||||||
FilePath filePath;
|
int? wholePercentages;
|
||||||
MappedFile mappedFile;
|
Dictionary<int, FilePath>? keyValues;
|
||||||
string personKeyFormatted;
|
Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
|
||||||
List<string> distinct = [];
|
foreach (ExifDirectory exifDirectory in exifDirectories)
|
||||||
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
|
|
||||||
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
|
|
||||||
{
|
{
|
||||||
if (personContainer.Key is null)
|
if (exifDirectory.FilePath.Id is null)
|
||||||
continue;
|
continue;
|
||||||
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
||||||
{
|
{
|
||||||
filePath = personContainer.DisplayDirectoryAllFilePaths[i];
|
keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []);
|
||||||
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension)
|
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
||||||
continue;
|
throw new Exception();
|
||||||
if (distinct.Contains(filePath.Name))
|
|
||||||
continue;
|
|
||||||
distinct.Add(filePath.Name);
|
|
||||||
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
|
|
||||||
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
|
|
||||||
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
|
|
||||||
results.Add(mappedFile);
|
|
||||||
}
|
}
|
||||||
|
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
|
||||||
|
if (wholePercentages is null)
|
||||||
|
continue;
|
||||||
|
keyValues.Add(wholePercentages.Value, exifDirectory.FilePath);
|
||||||
}
|
}
|
||||||
return results;
|
foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
|
||||||
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||||
|
return results.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
|
||||||
|
{
|
||||||
|
List<ExifDirectory> results = [];
|
||||||
|
string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent));
|
||||||
|
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
|
||||||
|
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
|
||||||
|
if (mappedFiles.Count > 0)
|
||||||
|
{
|
||||||
|
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
|
||||||
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
|
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
|
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
|
||||||
|
compare.ConstructProgressBar(mappedFiles.Count, message);
|
||||||
|
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
||||||
|
{
|
||||||
|
compare.Tick();
|
||||||
|
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<MappedFile> GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection<MappedLogicB.Record> records)
|
private static ReadOnlyCollection<MappedFile> GetMappedFiles(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections, ReadOnlyCollection<MappedLogicB.Record> records)
|
||||||
@ -102,6 +122,35 @@ internal static class MappedLogicA
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<MappedFile> GetDisplayDirectoryAllFiles(PeopleSettings peopleSettings, ICompareSettings compareSettings, ReadOnlyCollections readOnlyCollections)
|
||||||
|
{
|
||||||
|
List<MappedFile> results = [];
|
||||||
|
FilePath filePath;
|
||||||
|
MappedFile mappedFile;
|
||||||
|
string personKeyFormatted;
|
||||||
|
List<string> distinct = [];
|
||||||
|
PersonKeyFormattedAndKeyTicksAndDisplayDirectoryName personKeyFormattedAndKeyTicksAndDisplayDirectoryName;
|
||||||
|
foreach (PersonContainer personContainer in readOnlyCollections.PersonContainers)
|
||||||
|
{
|
||||||
|
if (personContainer.Key is null)
|
||||||
|
continue;
|
||||||
|
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
||||||
|
{
|
||||||
|
filePath = personContainer.DisplayDirectoryAllFilePaths[i];
|
||||||
|
if (filePath.ExtensionLowered != compareSettings.FacesFileNameExtension)
|
||||||
|
continue;
|
||||||
|
if (distinct.Contains(filePath.Name))
|
||||||
|
continue;
|
||||||
|
distinct.Add(filePath.Name);
|
||||||
|
personKeyFormatted = IPersonBirthday.GetFormatted(peopleSettings.PersonBirthdayFormat, personContainer.Key.Value);
|
||||||
|
personKeyFormattedAndKeyTicksAndDisplayDirectoryName = new(personKeyFormatted, personContainer.Key.Value, filePath.Name);
|
||||||
|
mappedFile = new(personKeyFormattedAndKeyTicksAndDisplayDirectoryName, personContainer.DisplayDirectoryName, filePath);
|
||||||
|
results.Add(mappedFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List<ExifDirectory> exifDirectories, ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipCollection, MappedFile mappedFile)
|
private static void MappedParallelFor(ResultSettings resultSettings, MetadataSettings metadataSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, List<ExifDirectory> exifDirectories, ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipCollection, MappedFile mappedFile)
|
||||||
{
|
{
|
||||||
int? id;
|
int? id;
|
||||||
@ -152,53 +201,4 @@ internal static class MappedLogicA
|
|||||||
exifDirectories.Add(exifDirectory);
|
exifDirectories.Add(exifDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ReadOnlyCollection<ExifDirectory> GetMapped(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, ReadOnlyCollections readOnlyCollections)
|
|
||||||
{
|
|
||||||
List<ExifDirectory> results = [];
|
|
||||||
string eDistanceContentDirectory = Path.GetFullPath(IResult.GetResultsDateGroupDirectory(resultSettings, nameof(E_Distance), resultSettings.ResultContent));
|
|
||||||
ReadOnlyCollection<MappedLogicB.Record> records = MappedLogicB.DeleteEmptyDirectoriesAndGetCollection(resultSettings, metadataSettings, peopleSettings, distanceSettings, compareSettings, compare, ticks, eDistanceContentDirectory, readOnlyCollections);
|
|
||||||
ReadOnlyCollection<MappedFile> mappedFiles = GetMappedFiles(resultSettings, metadataSettings, peopleSettings, compareSettings, readOnlyCollections, records);
|
|
||||||
if (mappedFiles.Count > 0)
|
|
||||||
{
|
|
||||||
int maxDegreeOfParallelism = compareSettings.MaxDegreeOfParallelism;
|
|
||||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
||||||
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
|
||||||
ReadOnlyDictionary<int, List<FilePathAndWholePercentages>> skipNotSkipCollection = readOnlyCollections.SkipNotSkipCollection;
|
|
||||||
compare.ConstructProgressBar(mappedFiles.Count, message);
|
|
||||||
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
|
||||||
{
|
|
||||||
compare.Tick();
|
|
||||||
MappedParallelFor(resultSettings, metadataSettings, distanceSettings, compareSettings, results, skipNotSkipCollection, mappedFiles[i]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return results.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, FilePath>> Extract(ICompareSettings compareSettings, ReadOnlyCollection<ExifDirectory> exifDirectories)
|
|
||||||
{
|
|
||||||
Dictionary<int, ReadOnlyDictionary<int, FilePath>> results = [];
|
|
||||||
int? wholePercentages;
|
|
||||||
Dictionary<int, FilePath>? keyValues;
|
|
||||||
Dictionary<int, Dictionary<int, FilePath>> keyValuePairs = [];
|
|
||||||
foreach (ExifDirectory exifDirectory in exifDirectories)
|
|
||||||
{
|
|
||||||
if (exifDirectory.FilePath.Id is null)
|
|
||||||
continue;
|
|
||||||
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
|
||||||
{
|
|
||||||
keyValuePairs.Add(exifDirectory.FilePath.Id.Value, []);
|
|
||||||
if (!keyValuePairs.TryGetValue(exifDirectory.FilePath.Id.Value, out keyValues))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
wholePercentages = IMapping.GetWholePercentages(compareSettings, exifDirectory.FilePath);
|
|
||||||
if (wholePercentages is null)
|
|
||||||
continue;
|
|
||||||
keyValues.Add(wholePercentages.Value, exifDirectory.FilePath);
|
|
||||||
}
|
|
||||||
foreach (KeyValuePair<int, Dictionary<int, FilePath>> keyValuePair in keyValuePairs)
|
|
||||||
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
|
||||||
return results.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -24,327 +24,6 @@ internal static class MappedLogicB
|
|||||||
bool? IsLocationContainerDebugDirectory,
|
bool? IsLocationContainerDebugDirectory,
|
||||||
float? TotalDays);
|
float? TotalDays);
|
||||||
|
|
||||||
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
|
||||||
{
|
|
||||||
string checkFile;
|
|
||||||
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
|
||||||
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (facesFileNames.Contains(file))
|
|
||||||
{
|
|
||||||
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
|
||||||
{
|
|
||||||
string[] files;
|
|
||||||
string checkFile;
|
|
||||||
string? checkDirectory;
|
|
||||||
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string directory in directories)
|
|
||||||
{
|
|
||||||
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
Directory.Move(directory, checkDirectory);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
|
||||||
continue;
|
|
||||||
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
|
||||||
checkDirectory = Path.GetDirectoryName(checkFile);
|
|
||||||
if (checkDirectory is null)
|
|
||||||
continue;
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory)
|
|
||||||
{
|
|
||||||
List<TicksDirectory> results = [];
|
|
||||||
float? totalDays;
|
|
||||||
long? next = null;
|
|
||||||
string? checkDirectory;
|
|
||||||
DateTime directoryDateTime;
|
|
||||||
DirectoryInfo directoryInfo;
|
|
||||||
TicksDirectory ticksDirectory;
|
|
||||||
long? lastDirectoryTicks = null;
|
|
||||||
DateTime dateTime = DateTime.Now;
|
|
||||||
DateTime alternateDirectoryDateTime;
|
|
||||||
string ticksDirectoryNameFirstSegment;
|
|
||||||
bool? isLocationContainerDebugDirectory;
|
|
||||||
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
|
||||||
for (int i = 1; i < 5; i++)
|
|
||||||
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
|
||||||
if (!Directory.Exists(eDistanceContentDirectory))
|
|
||||||
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
|
||||||
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string ticksFullPath in ticksFullPaths)
|
|
||||||
{
|
|
||||||
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
|
|
||||||
if (ticksDirectoryNameFirstSegment.Length < 3)
|
|
||||||
continue;
|
|
||||||
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
|
|
||||||
throw new NotSupportedException();
|
|
||||||
if (next is null)
|
|
||||||
next = new DateTime(directoryTicks).Ticks;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
next += month;
|
|
||||||
checkDirectory = Path.GetDirectoryName(ticksFullPath);
|
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
|
||||||
continue;
|
|
||||||
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
|
|
||||||
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern))
|
|
||||||
continue;
|
|
||||||
Directory.Move(ticksFullPath, checkDirectory);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
directoryInfo = new(ticksFullPath);
|
|
||||||
directoryDateTime = new DateTime(directoryTicks);
|
|
||||||
if (directoryInfo.CreationTime.Ticks != directoryTicks)
|
|
||||||
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
|
|
||||||
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
|
||||||
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
|
|
||||||
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
|
||||||
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory);
|
|
||||||
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
|
||||||
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
|
|
||||||
results.Add(ticksDirectory);
|
|
||||||
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
|
||||||
continue;
|
|
||||||
lastDirectoryTicks = directoryTicks;
|
|
||||||
}
|
|
||||||
string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray();
|
|
||||||
if (compare.Length > 0 && distanceSettings.ReMap)
|
|
||||||
throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>");
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory)
|
|
||||||
{
|
|
||||||
bool isDefault;
|
|
||||||
string[] files;
|
|
||||||
FileInfo[] collection;
|
|
||||||
string[] facesFileNames;
|
|
||||||
string yearDirectoryName;
|
|
||||||
string[] yearDirectories;
|
|
||||||
string alphaDirectoryName;
|
|
||||||
string matchDirectoryName;
|
|
||||||
string personKeyFormatted;
|
|
||||||
string[] alphaDirectories;
|
|
||||||
string[] matchDirectories;
|
|
||||||
string[] actionDirectories;
|
|
||||||
string personDisplayDirectory;
|
|
||||||
string[] personKeyDirectories;
|
|
||||||
string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string segmentCDirectory in segmentCDirectories)
|
|
||||||
{
|
|
||||||
personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string personKeyDirectory in personKeyDirectories)
|
|
||||||
{
|
|
||||||
personKeyFormatted = Path.GetFileName(personKeyDirectory);
|
|
||||||
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string yearDirectory in yearDirectories)
|
|
||||||
{
|
|
||||||
yearDirectoryName = Path.GetFileName(yearDirectory);
|
|
||||||
if (yearDirectoryName.StartsWith('='))
|
|
||||||
Directory.Move(yearDirectory, yearDirectory.Replace('=', '~'));
|
|
||||||
}
|
|
||||||
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string yearDirectory in yearDirectories)
|
|
||||||
{
|
|
||||||
yearDirectoryName = Path.GetFileName(yearDirectory);
|
|
||||||
matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray();
|
|
||||||
if (alphaDirectories.Length == 0)
|
|
||||||
continue;
|
|
||||||
alphaDirectoryName = Path.GetFileName(alphaDirectories[0]);
|
|
||||||
foreach (string matchDirectory in matchDirectories)
|
|
||||||
{
|
|
||||||
matchDirectoryName = Path.GetFileName(matchDirectory);
|
|
||||||
files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
if (files.Length != 4)
|
|
||||||
continue;
|
|
||||||
collection = files.Select(l => new FileInfo(l)).ToArray();
|
|
||||||
isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
|
||||||
if (isDefault)
|
|
||||||
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray();
|
|
||||||
else
|
|
||||||
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray();
|
|
||||||
if (facesFileNames.Length == 0)
|
|
||||||
continue;
|
|
||||||
personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName);
|
|
||||||
if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory))
|
|
||||||
continue;
|
|
||||||
_ = Process.Start("explorer", matchDirectory);
|
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
|
||||||
{
|
|
||||||
Thread.Sleep(500);
|
|
||||||
actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray();
|
|
||||||
if (actionDirectories.Length > 0)
|
|
||||||
{
|
|
||||||
MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
|
|
||||||
{
|
|
||||||
string result;
|
|
||||||
string checkDirectory;
|
|
||||||
string directory = file;
|
|
||||||
List<string> collection = [];
|
|
||||||
for (int i = 0; i < file.Length; i++)
|
|
||||||
{
|
|
||||||
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
|
|
||||||
if (directory == ticksDirectory.Directory)
|
|
||||||
break;
|
|
||||||
collection.Add(Path.GetFileName(directory));
|
|
||||||
}
|
|
||||||
collection.Reverse();
|
|
||||||
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
|
|
||||||
foreach (string directoryName in collection)
|
|
||||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
result = Path.Combine(checkDirectory, fileName);
|
|
||||||
if (File.Exists(result))
|
|
||||||
throw new Exception($"File <{fileName}> already exists!");
|
|
||||||
File.Move(file, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
|
||||||
{
|
|
||||||
List<Record> results = [];
|
|
||||||
string @enum;
|
|
||||||
Record record;
|
|
||||||
string fileName;
|
|
||||||
string checkFile;
|
|
||||||
FilePath filePath;
|
|
||||||
FileHolder fileHolder;
|
|
||||||
int? wholePercentages;
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (file.EndsWith(".lnk"))
|
|
||||||
continue;
|
|
||||||
fileHolder = FileHolder.Get(file);
|
|
||||||
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
|
||||||
if (filePath.Id is null)
|
|
||||||
continue;
|
|
||||||
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
|
|
||||||
if (wholePercentages is null)
|
|
||||||
continue;
|
|
||||||
fileName = Path.GetFileName(file);
|
|
||||||
if (distinct.Contains(fileName))
|
|
||||||
{
|
|
||||||
checkFile = $"{file}.dup";
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (file.StartsWith(ticksDirectory.Directory))
|
|
||||||
{
|
|
||||||
@enum = IPath.GetEnum(filePath).ToString();
|
|
||||||
if (!ticksDirectory.Directory.EndsWith(@enum))
|
|
||||||
{
|
|
||||||
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
|
|
||||||
fileHolder = FileHolder.Get(checkFile);
|
|
||||||
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
|
||||||
if (filePath.Id is null)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
distinct.Add(fileName);
|
|
||||||
record = new(DirectoryNumber: directoryNumber,
|
|
||||||
IsDefault: isDefault,
|
|
||||||
LinksCount: linksCount,
|
|
||||||
MappedFaceFilePath: filePath,
|
|
||||||
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
|
||||||
PersonKeyFormatted: personKeyFormatted);
|
|
||||||
results.Add(record);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string[] RenameBirth(string[] files)
|
|
||||||
{
|
|
||||||
List<string> results = [];
|
|
||||||
string checkFile;
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (file.EndsWith(".brt"))
|
|
||||||
{
|
|
||||||
results.Add(file);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
checkFile = $"{file}.brt";
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
{
|
|
||||||
results.Add(file);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
File.Move(file, checkFile);
|
|
||||||
results.Add(checkFile);
|
|
||||||
}
|
|
||||||
return results.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
|
|
||||||
{
|
|
||||||
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
|
|
||||||
if (Directory.Exists(newestPersonKeyDirectory))
|
|
||||||
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
|
|
||||||
else
|
|
||||||
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int? GetLinksCount(string yearDirectory)
|
|
||||||
{
|
|
||||||
int? result;
|
|
||||||
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
|
||||||
if (yearDirectoryNameSegments.Length != 3)
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string lastSegment = yearDirectoryNameSegments[^1];
|
|
||||||
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
result = lastSegment[0] - 65;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
|
internal static ReadOnlyCollection<Record> DeleteEmptyDirectoriesAndGetCollection(ResultSettings resultSettings, MetadataSettings metadataSettings, PeopleSettings peopleSettings, DistanceSettings distanceSettings, ICompareSettings compareSettings, ICompare compare, long ticks, string eDistanceContentDirectory, ReadOnlyCollections readOnlyCollections)
|
||||||
{
|
{
|
||||||
List<Record> results = [];
|
List<Record> results = [];
|
||||||
@ -526,4 +205,325 @@ internal static class MappedLogicB
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<TicksDirectory> UpdateDateVerifyAndGetTicksDirectories(DistanceSettings distanceSettings, string eDistanceContentDirectory)
|
||||||
|
{
|
||||||
|
List<TicksDirectory> results = [];
|
||||||
|
float? totalDays;
|
||||||
|
long? next = null;
|
||||||
|
string? checkDirectory;
|
||||||
|
DateTime directoryDateTime;
|
||||||
|
DirectoryInfo directoryInfo;
|
||||||
|
TicksDirectory ticksDirectory;
|
||||||
|
long? lastDirectoryTicks = null;
|
||||||
|
DateTime dateTime = DateTime.Now;
|
||||||
|
DateTime alternateDirectoryDateTime;
|
||||||
|
string ticksDirectoryNameFirstSegment;
|
||||||
|
bool? isLocationContainerDebugDirectory;
|
||||||
|
long month = dateTime.AddMonths(1).Ticks - dateTime.Ticks;
|
||||||
|
for (int i = 1; i < 5; i++)
|
||||||
|
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
||||||
|
if (!Directory.Exists(eDistanceContentDirectory))
|
||||||
|
_ = Directory.CreateDirectory(eDistanceContentDirectory);
|
||||||
|
string[] ticksFullPaths = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string ticksFullPath in ticksFullPaths)
|
||||||
|
{
|
||||||
|
ticksDirectoryNameFirstSegment = Path.GetFileName(ticksFullPath).Split('.')[0];
|
||||||
|
if (ticksDirectoryNameFirstSegment.Length < 3)
|
||||||
|
continue;
|
||||||
|
if (!long.TryParse(ticksDirectoryNameFirstSegment, out long directoryTicks))
|
||||||
|
throw new NotSupportedException();
|
||||||
|
if (next is null)
|
||||||
|
next = new DateTime(directoryTicks).Ticks;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
next += month;
|
||||||
|
checkDirectory = Path.GetDirectoryName(ticksFullPath);
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
|
continue;
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, next.Value.ToString());
|
||||||
|
if (ticksFullPath == checkDirectory || !checkDirectory.EndsWith(distanceSettings.LocationContainerDirectoryPattern))
|
||||||
|
continue;
|
||||||
|
Directory.Move(ticksFullPath, checkDirectory);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
directoryInfo = new(ticksFullPath);
|
||||||
|
directoryDateTime = new DateTime(directoryTicks);
|
||||||
|
if (directoryInfo.CreationTime.Ticks != directoryTicks)
|
||||||
|
Directory.SetCreationTime(ticksFullPath, new DateTime(directoryTicks));
|
||||||
|
if (directoryInfo.LastWriteTime.Ticks != directoryTicks)
|
||||||
|
Directory.SetLastWriteTime(ticksFullPath, new DateTime(directoryTicks));
|
||||||
|
alternateDirectoryDateTime = new DateTime(directoryDateTime.Year, directoryDateTime.Month, directoryDateTime.Day).AddMonths(1);
|
||||||
|
isLocationContainerDebugDirectory = distanceSettings.LocationContainerDebugDirectory is null ? null : ticksDirectoryNameFirstSegment.EndsWith(distanceSettings.LocationContainerDebugDirectory);
|
||||||
|
totalDays = lastDirectoryTicks is null || new TimeSpan(dateTime.Ticks - directoryTicks).TotalDays < 1 ? null : (float)new TimeSpan(directoryTicks - lastDirectoryTicks.Value).TotalDays;
|
||||||
|
ticksDirectory = new(alternateDirectoryDateTime, ticksFullPath, new(directoryTicks), isLocationContainerDebugDirectory, totalDays);
|
||||||
|
results.Add(ticksDirectory);
|
||||||
|
if (directoryDateTime.Hour == 0 && directoryDateTime.Minute == 0 && directoryDateTime.Second == 0)
|
||||||
|
continue;
|
||||||
|
lastDirectoryTicks = directoryTicks;
|
||||||
|
}
|
||||||
|
string[] compare = (from l in results where l.TotalDays is not null and < 9.95f select l.Directory).ToArray();
|
||||||
|
if (compare.Length > 0 && distanceSettings.ReMap)
|
||||||
|
throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>");
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Individually(ICompareSettings compareSettings, TicksDirectory ticksDirectory, string directory)
|
||||||
|
{
|
||||||
|
bool isDefault;
|
||||||
|
string[] files;
|
||||||
|
FileInfo[] collection;
|
||||||
|
string[] facesFileNames;
|
||||||
|
string yearDirectoryName;
|
||||||
|
string[] yearDirectories;
|
||||||
|
string alphaDirectoryName;
|
||||||
|
string matchDirectoryName;
|
||||||
|
string personKeyFormatted;
|
||||||
|
string[] alphaDirectories;
|
||||||
|
string[] matchDirectories;
|
||||||
|
string[] actionDirectories;
|
||||||
|
string personDisplayDirectory;
|
||||||
|
string[] personKeyDirectories;
|
||||||
|
string[] segmentCDirectories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string segmentCDirectory in segmentCDirectories)
|
||||||
|
{
|
||||||
|
personKeyDirectories = Directory.GetDirectories(segmentCDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string personKeyDirectory in personKeyDirectories)
|
||||||
|
{
|
||||||
|
personKeyFormatted = Path.GetFileName(personKeyDirectory);
|
||||||
|
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string yearDirectory in yearDirectories)
|
||||||
|
{
|
||||||
|
yearDirectoryName = Path.GetFileName(yearDirectory);
|
||||||
|
if (yearDirectoryName.StartsWith('='))
|
||||||
|
Directory.Move(yearDirectory, yearDirectory.Replace('=', '~'));
|
||||||
|
}
|
||||||
|
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string yearDirectory in yearDirectories)
|
||||||
|
{
|
||||||
|
yearDirectoryName = Path.GetFileName(yearDirectory);
|
||||||
|
matchDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
alphaDirectories = matchDirectories.Where(l => !long.TryParse(Path.GetFileName(l), out long a)).ToArray();
|
||||||
|
if (alphaDirectories.Length == 0)
|
||||||
|
continue;
|
||||||
|
alphaDirectoryName = Path.GetFileName(alphaDirectories[0]);
|
||||||
|
foreach (string matchDirectory in matchDirectories)
|
||||||
|
{
|
||||||
|
matchDirectoryName = Path.GetFileName(matchDirectory);
|
||||||
|
files = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
if (files.Length != 4)
|
||||||
|
continue;
|
||||||
|
collection = files.Select(l => new FileInfo(l)).ToArray();
|
||||||
|
isDefault = IPerson.IsDefaultName(alphaDirectoryName) && IPersonBirthday.IsCounterPersonYear(personKeyFormatted[..4]);
|
||||||
|
if (isDefault)
|
||||||
|
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension select l.FullName).ToArray();
|
||||||
|
else
|
||||||
|
facesFileNames = (from l in collection where l.Extension == compareSettings.FacesFileNameExtension && l.Name.Contains(matchDirectoryName) select l.FullName).ToArray();
|
||||||
|
if (facesFileNames.Length == 0)
|
||||||
|
continue;
|
||||||
|
personDisplayDirectory = Path.Combine(matchDirectory, alphaDirectoryName);
|
||||||
|
if (!Directory.Exists(personDisplayDirectory) || !Directory.Exists(matchDirectory))
|
||||||
|
continue;
|
||||||
|
_ = Process.Start("explorer", matchDirectory);
|
||||||
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
actionDirectories = Directory.GetDirectories(matchDirectory, "*", SearchOption.TopDirectoryOnly).Where(l => l != personDisplayDirectory && !l.EndsWith("Maybe")).ToArray();
|
||||||
|
if (actionDirectories.Length > 0)
|
||||||
|
{
|
||||||
|
MoveTo(actionDirectories[0], ticksDirectory, directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName, files, facesFileNames);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveTo(string actionDirectory, TicksDirectory ticksDirectory, string directory, string personKeyFormatted, string yearDirectoryName, string alphaDirectoryName, string[] files, string[] facesFileNames)
|
||||||
|
{
|
||||||
|
string checkFile;
|
||||||
|
string actionDirectoryName = Path.GetFileName(actionDirectory);
|
||||||
|
string checkDirectory = actionDirectoryName.StartsWith("y", StringComparison.CurrentCultureIgnoreCase) ? Path.Combine(ticksDirectory.Directory, personKeyFormatted, yearDirectoryName, alphaDirectoryName) : Path.Combine(directory, actionDirectoryName);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (facesFileNames.Contains(file))
|
||||||
|
{
|
||||||
|
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int? GetLinksCount(string yearDirectory)
|
||||||
|
{
|
||||||
|
int? result;
|
||||||
|
string[] yearDirectoryNameSegments = Path.GetFileName(yearDirectory).Split('-');
|
||||||
|
if (yearDirectoryNameSegments.Length != 3)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string lastSegment = yearDirectoryNameSegments[^1];
|
||||||
|
if (lastSegment.Length != 3 || !lastSegment.All(l => l == lastSegment[0]))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = lastSegment[0] - 65;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] RenameBirth(string[] files)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
string checkFile;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (file.EndsWith(".brt"))
|
||||||
|
{
|
||||||
|
results.Add(file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
checkFile = $"{file}.brt";
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
{
|
||||||
|
results.Add(file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
results.Add(checkFile);
|
||||||
|
}
|
||||||
|
return results.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MovedToNewestPersonKeyFormatted(string personKeyFormatted, string newestPersonKeyFormatted, TicksDirectory ticksDirectory, string personKeyDirectory)
|
||||||
|
{
|
||||||
|
string newestPersonKeyDirectory = Path.Combine(ticksDirectory.Directory, newestPersonKeyFormatted);
|
||||||
|
if (Directory.Exists(newestPersonKeyDirectory))
|
||||||
|
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
|
||||||
|
else
|
||||||
|
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
|
||||||
|
{
|
||||||
|
string[] files;
|
||||||
|
string checkFile;
|
||||||
|
string? checkDirectory;
|
||||||
|
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
Directory.Move(directory, checkDirectory);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
|
||||||
|
continue;
|
||||||
|
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
|
||||||
|
checkDirectory = Path.GetDirectoryName(checkFile);
|
||||||
|
if (checkDirectory is null)
|
||||||
|
continue;
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = IPath.DeleteEmptyDirectories(personKeyDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Record> GetRecords(ResultSettings resultSettings, MetadataSettings metadataSettings, ICompareSettings compareSettings, TicksDirectory ticksDirectory, bool? isDefault, string[] files, int directoryNumber, string personKeyFormatted, int? linksCount, List<string> distinct, string? personDisplayDirectoryName)
|
||||||
|
{
|
||||||
|
List<Record> results = [];
|
||||||
|
string @enum;
|
||||||
|
Record record;
|
||||||
|
string fileName;
|
||||||
|
string checkFile;
|
||||||
|
FilePath filePath;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
int? wholePercentages;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
if (file.EndsWith(".lnk"))
|
||||||
|
continue;
|
||||||
|
fileHolder = FileHolder.Get(file);
|
||||||
|
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
wholePercentages = IMapping.GetWholePercentages(compareSettings, filePath);
|
||||||
|
if (wholePercentages is null)
|
||||||
|
continue;
|
||||||
|
fileName = Path.GetFileName(file);
|
||||||
|
if (distinct.Contains(fileName))
|
||||||
|
{
|
||||||
|
checkFile = $"{file}.dup";
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(file, checkFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (file.StartsWith(ticksDirectory.Directory))
|
||||||
|
{
|
||||||
|
@enum = IPath.GetEnum(filePath).ToString();
|
||||||
|
if (!ticksDirectory.Directory.EndsWith(@enum))
|
||||||
|
{
|
||||||
|
checkFile = GetCheckFile(ticksDirectory, @enum, fileName, file);
|
||||||
|
fileHolder = FileHolder.Get(checkFile);
|
||||||
|
filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distinct.Add(fileName);
|
||||||
|
record = new(DirectoryNumber: directoryNumber,
|
||||||
|
IsDefault: isDefault,
|
||||||
|
LinksCount: linksCount,
|
||||||
|
MappedFaceFilePath: filePath,
|
||||||
|
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
||||||
|
PersonKeyFormatted: personKeyFormatted);
|
||||||
|
results.Add(record);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetCheckFile(TicksDirectory ticksDirectory, string @enum, string fileName, string file)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
string checkDirectory;
|
||||||
|
string directory = file;
|
||||||
|
List<string> collection = [];
|
||||||
|
for (int i = 0; i < file.Length; i++)
|
||||||
|
{
|
||||||
|
directory = Path.GetDirectoryName(directory) ?? throw new Exception();
|
||||||
|
if (directory == ticksDirectory.Directory)
|
||||||
|
break;
|
||||||
|
collection.Add(Path.GetFileName(directory));
|
||||||
|
}
|
||||||
|
collection.Reverse();
|
||||||
|
checkDirectory = $"{ticksDirectory.Directory}.{@enum}";
|
||||||
|
foreach (string directoryName in collection)
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
result = Path.Combine(checkDirectory, fileName);
|
||||||
|
if (File.Exists(result))
|
||||||
|
throw new Exception($"File <{fileName}> already exists!");
|
||||||
|
File.Move(file, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -54,51 +54,7 @@ internal static class Get
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||||
{
|
|
||||||
return file =>
|
|
||||||
{
|
|
||||||
rename.Tick();
|
|
||||||
ExifDirectory exifDirectory;
|
|
||||||
MetadataGroup metadataGroup;
|
|
||||||
DeterministicHashCode deterministicHashCode;
|
|
||||||
FileHolder fileHolder = FileHolder.Get(file);
|
|
||||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
|
||||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
|
||||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
|
||||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
|
||||||
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
|
||||||
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
|
|
||||||
if (distinct.Contains(key))
|
|
||||||
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
|
|
||||||
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
|
|
||||||
return;
|
|
||||||
if (filePath.Id is not null)
|
|
||||||
{
|
|
||||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
|
||||||
deterministicHashCode = new(null, filePath.Id, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(renameSettings, filePath);
|
|
||||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
|
||||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
|
||||||
}
|
|
||||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
|
||||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
|
||||||
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
|
|
||||||
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
|
|
||||||
lock (metadataGroups)
|
|
||||||
metadataGroups.Add(metadataGroup);
|
|
||||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
|
||||||
{
|
|
||||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
|
||||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
|
||||||
{
|
{
|
||||||
return file =>
|
return file =>
|
||||||
{
|
{
|
||||||
@ -125,7 +81,7 @@ internal static class Get
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(windowsSettings, httpClient, filePath);
|
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, httpClient, filePath);
|
||||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
||||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||||
}
|
}
|
||||||
@ -145,4 +101,48 @@ internal static class Get
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static Action<string> SetExifDirectoryCollection(IRename rename, ResultSettings resultSettings, MetadataSettings metadataSettings, IRenameSettings renameSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups)
|
||||||
|
{
|
||||||
|
return file =>
|
||||||
|
{
|
||||||
|
rename.Tick();
|
||||||
|
ExifDirectory exifDirectory;
|
||||||
|
MetadataGroup metadataGroup;
|
||||||
|
DeterministicHashCode deterministicHashCode;
|
||||||
|
FileHolder fileHolder = FileHolder.Get(file);
|
||||||
|
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||||
|
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||||
|
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||||
|
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||||
|
FilePath filePath = FilePath.Get(resultSettings, metadataSettings, fileHolder, index: null);
|
||||||
|
string key = $"{Path.Combine(fileHolder.DirectoryFullPath ?? throw new NotSupportedException(), fileHolder.NameWithoutExtension)}";
|
||||||
|
if (distinct.Contains(key))
|
||||||
|
throw new NotSupportedException("Turn off parallelism when sidecar files are present!");
|
||||||
|
if (renameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is null))
|
||||||
|
return;
|
||||||
|
if (filePath.Id is not null)
|
||||||
|
{
|
||||||
|
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||||
|
deterministicHashCode = new(null, filePath.Id, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(resultSettings, filePath);
|
||||||
|
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(resultSettings, metadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index: null);
|
||||||
|
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||||
|
}
|
||||||
|
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||||
|
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||||
|
(minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(resultSettings, metadataSettings, filePath);
|
||||||
|
metadataGroup = new(fastForwardMovingPictureExpertsGroupUsed, filePath, minimumYearAndPathCombined, exifDirectory, new([]));
|
||||||
|
lock (metadataGroups)
|
||||||
|
metadataGroups.Add(metadataGroup);
|
||||||
|
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||||
|
{
|
||||||
|
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||||
|
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -72,9 +72,9 @@ public interface IMetadata
|
|||||||
static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<NginxFileSystem> collection) =>
|
static ReadOnlyDictionary<string, List<FileHolder>> GetKeyValuePairs(IEnumerable<NginxFileSystem> collection) =>
|
||||||
Get.GetKeyValuePairs(collection);
|
Get.GetKeyValuePairs(collection);
|
||||||
|
|
||||||
Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
Action<string> TestStatic_SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||||
SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups);
|
SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
|
||||||
static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, IWindowsSettings windowsSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
static Action<string> SetExifDirectoryCollection(IWindows windows, ResultSettings resultSettings, MetadataSettings metadataSettings, A_Metadata metadata, List<string> distinct, List<MetadataGroup> metadataGroups) =>
|
||||||
Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, windowsSettings, metadata, distinct, metadataGroups);
|
Get.SetExifDirectoryCollection(windows, resultSettings, metadataSettings, metadata, distinct, metadataGroups);
|
||||||
|
|
||||||
}
|
}
|
@ -9,7 +9,6 @@ public record RenameSettings(string Company,
|
|||||||
Dictionary<string, string?> DirectoryDictionary,
|
Dictionary<string, string?> DirectoryDictionary,
|
||||||
string? FirstPassFile,
|
string? FirstPassFile,
|
||||||
bool ForceNewId,
|
bool ForceNewId,
|
||||||
string[] IgnoreExtensions,
|
|
||||||
bool InPlace,
|
bool InPlace,
|
||||||
bool InPlaceMoveDirectory,
|
bool InPlaceMoveDirectory,
|
||||||
bool InPlaceWithOriginalName,
|
bool InPlaceWithOriginalName,
|
||||||
@ -20,9 +19,7 @@ public record RenameSettings(string Company,
|
|||||||
string RelativePropertyCollectionFile,
|
string RelativePropertyCollectionFile,
|
||||||
bool RequireRootDirectoryExists,
|
bool RequireRootDirectoryExists,
|
||||||
string[] SidecarExtensions,
|
string[] SidecarExtensions,
|
||||||
bool SkipIdFiles,
|
bool SkipIdFiles) : Shared.Models.Properties.IRenameSettings
|
||||||
string[] ValidImageFormatExtensions,
|
|
||||||
string[] ValidVideoFormatExtensions) : Shared.Models.Properties.IRenameSettings
|
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
793
Rename/Rename.cs
793
Rename/Rename.cs
@ -11,7 +11,6 @@ using View_by_Distance.Metadata.Models;
|
|||||||
using View_by_Distance.Metadata.Models.Stateless;
|
using View_by_Distance.Metadata.Models.Stateless;
|
||||||
using View_by_Distance.Rename.Models;
|
using View_by_Distance.Rename.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
using View_by_Distance.Shared.Models.Stateless;
|
using View_by_Distance.Shared.Models.Stateless;
|
||||||
|
|
||||||
namespace View_by_Distance.Rename;
|
namespace View_by_Distance.Rename;
|
||||||
@ -35,39 +34,58 @@ public partial class Rename : IRename, IDisposable
|
|||||||
private ProgressBar? _ProgressBar;
|
private ProgressBar? _ProgressBar;
|
||||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||||
|
|
||||||
public Rename(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
|
||||||
{
|
|
||||||
if (isSilent)
|
|
||||||
{ }
|
|
||||||
if (args is null)
|
|
||||||
throw new NullReferenceException(nameof(args));
|
|
||||||
if (console is null)
|
|
||||||
throw new NullReferenceException(nameof(console));
|
|
||||||
IRename rename = this;
|
|
||||||
long ticks = DateTime.Now.Ticks;
|
|
||||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
||||||
RenameWork(logger, appSettings, rename, ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRename.Tick() =>
|
void IRename.Tick() =>
|
||||||
_ProgressBar?.Tick();
|
_ProgressBar?.Tick();
|
||||||
|
|
||||||
void IRename.ConstructProgressBar(int maxTicks, string message)
|
|
||||||
{
|
|
||||||
_ProgressBar?.Dispose();
|
|
||||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDisposable.Dispose()
|
void IDisposable.Dispose()
|
||||||
{
|
{
|
||||||
_ProgressBar?.Dispose();
|
_ProgressBar?.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath)
|
void IRename.ConstructProgressBar(int maxTicks, string message)
|
||||||
|
{
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
|
||||||
|
{
|
||||||
|
DeterministicHashCode result;
|
||||||
|
int? id;
|
||||||
|
int? width;
|
||||||
|
int? height;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
using Image image = Image.FromFile(filePath.FullName);
|
||||||
|
width = image.Width;
|
||||||
|
height = image.Height;
|
||||||
|
using Bitmap bitmap = new(image);
|
||||||
|
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||||
|
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||||
|
IntPtr intPtr = bitmapData.Scan0;
|
||||||
|
int length = bitmapData.Stride * bitmap.Height;
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
Marshal.Copy(intPtr, bytes, 0, length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
id = IId.GetDeterministicHashCode(bytes);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
id = null;
|
||||||
|
width = null;
|
||||||
|
height = null;
|
||||||
|
}
|
||||||
|
result = new(height, id, width);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyCollection<string> IRename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath)
|
||||||
{
|
{
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
bool isValidVideoFormatExtensions = renameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||||
if (isValidVideoFormatExtensions)
|
if (isValidVideoFormatExtensions)
|
||||||
{
|
{
|
||||||
bool check;
|
bool check;
|
||||||
@ -97,40 +115,241 @@ public partial class Rename : IRename, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
public Rename(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||||
|
|
||||||
DeterministicHashCode IRename.GetDeterministicHashCode(FilePath filePath)
|
|
||||||
{
|
{
|
||||||
DeterministicHashCode result;
|
if (isSilent)
|
||||||
int? id;
|
{ }
|
||||||
int? width;
|
if (args is null)
|
||||||
int? height;
|
throw new NullReferenceException(nameof(args));
|
||||||
try
|
if (console is null)
|
||||||
{
|
throw new NullReferenceException(nameof(console));
|
||||||
using Image image = Image.FromFile(filePath.FullName);
|
IRename rename = this;
|
||||||
width = image.Width;
|
long ticks = DateTime.Now.Ticks;
|
||||||
height = image.Height;
|
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
using Bitmap bitmap = new(image);
|
RenameWork(logger, appSettings, rename, ticks);
|
||||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
|
||||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
|
||||||
IntPtr intPtr = bitmapData.Scan0;
|
|
||||||
int length = bitmapData.Stride * bitmap.Height;
|
|
||||||
byte[] bytes = new byte[length];
|
|
||||||
Marshal.Copy(intPtr, bytes, 0, length);
|
|
||||||
bitmap.UnlockBits(bitmapData);
|
|
||||||
id = IId.GetDeterministicHashCode(bytes);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
id = null;
|
|
||||||
width = null;
|
|
||||||
height = null;
|
|
||||||
}
|
|
||||||
result = new(height, id, width);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
|
||||||
|
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||||
|
if (!Directory.Exists(sourceDirectory))
|
||||||
|
_ = Directory.CreateDirectory(sourceDirectory);
|
||||||
|
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||||
|
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||||
|
if (files.Count > 0)
|
||||||
|
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||||
|
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
|
||||||
|
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
|
||||||
|
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||||
|
{
|
||||||
|
if (recordCollection.Count > 0)
|
||||||
|
recordCollection = new([]);
|
||||||
|
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
|
||||||
|
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
|
||||||
|
}
|
||||||
|
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
|
||||||
|
{
|
||||||
|
DirectoryInfo directoryInfo = new(sourceDirectory);
|
||||||
|
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
|
||||||
|
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
|
||||||
|
if (lines.Count != 0)
|
||||||
|
{
|
||||||
|
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
||||||
|
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyCollection<int> GetIds(RenameSettings renameSettings)
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<int> results;
|
||||||
|
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile;
|
||||||
|
string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile);
|
||||||
|
Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||||
|
if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile))
|
||||||
|
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
|
||||||
|
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<Record> results;
|
||||||
|
List<FirstPass> collection;
|
||||||
|
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
|
||||||
|
if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile))
|
||||||
|
collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(checkFile);
|
||||||
|
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
|
||||||
|
}
|
||||||
|
if (appSettings.RenameSettings.JustMediaDate)
|
||||||
|
results = new([]);
|
||||||
|
else
|
||||||
|
results = GetRecordCollection(appSettings, collection);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile)
|
||||||
|
{
|
||||||
|
List<FirstPass> results;
|
||||||
|
FirstPass firstPass;
|
||||||
|
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||||
|
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
|
||||||
|
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||||
|
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||||
|
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||||
|
{
|
||||||
|
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||||
|
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
results = [];
|
||||||
|
List<string> distinct = [];
|
||||||
|
List<MetadataGroup> metadataGroups = [];
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||||
|
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
|
||||||
|
Thread.Sleep(500);
|
||||||
|
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||||
|
{
|
||||||
|
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||||
|
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||||
|
else
|
||||||
|
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||||
|
results.Add(firstPass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(checkFile))
|
||||||
|
{
|
||||||
|
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||||
|
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
|
||||||
|
{
|
||||||
|
List<FirstPass> results = [];
|
||||||
|
int index = -1;
|
||||||
|
TimeSpan timeSpan;
|
||||||
|
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||||
|
{
|
||||||
|
index += 1;
|
||||||
|
rename.Tick();
|
||||||
|
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
|
||||||
|
{
|
||||||
|
if (appSettings.RenameSettings.InPlaceMoveDirectory)
|
||||||
|
continue;
|
||||||
|
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
|
||||||
|
}
|
||||||
|
if (keyValuePair.Value.Count > 2)
|
||||||
|
throw new NotSupportedException("Too many sidecar files!");
|
||||||
|
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
|
||||||
|
timeSpan = new(DateTime.Now.Ticks - ticks);
|
||||||
|
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, int index, KeyValuePair<string, List<FileHolder>> keyValuePair, List<FirstPass> results)
|
||||||
|
{
|
||||||
|
FilePath filePath;
|
||||||
|
FirstPass firstPass;
|
||||||
|
string directoryName;
|
||||||
|
ExifDirectory exifDirectory;
|
||||||
|
List<FileHolder> sidecarFiles;
|
||||||
|
DeterministicHashCode deterministicHashCode;
|
||||||
|
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||||
|
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||||
|
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||||
|
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||||
|
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||||
|
{
|
||||||
|
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
|
continue;
|
||||||
|
if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
|
continue;
|
||||||
|
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||||
|
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||||
|
continue;
|
||||||
|
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
||||||
|
{
|
||||||
|
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||||
|
deterministicHashCode = new(null, filePath.Id, null);
|
||||||
|
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||||
|
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, filePath);
|
||||||
|
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||||
|
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||||
|
}
|
||||||
|
sidecarFiles = [];
|
||||||
|
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||||
|
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||||
|
{
|
||||||
|
if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value)
|
||||||
|
JustMediaDate(logger, appSettings, metadata, filePath);
|
||||||
|
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||||
|
continue;
|
||||||
|
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||||
|
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||||
|
{
|
||||||
|
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||||
|
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||||
|
}
|
||||||
|
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||||
|
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
|
||||||
|
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||||
|
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||||
|
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||||
|
results.Add(firstPass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void JustMediaDate(ILogger<Program>? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath)
|
||||||
|
{
|
||||||
|
ExifDirectory? exifDirectory;
|
||||||
|
MinimumYearAndPathCombined? minimumYearAndPathCombined;
|
||||||
|
try
|
||||||
|
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
exifDirectory = null;
|
||||||
|
minimumYearAndPathCombined = null;
|
||||||
|
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||||
|
}
|
||||||
|
if (exifDirectory is null || minimumYearAndPathCombined is null)
|
||||||
|
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||||
|
if (dateTime is null)
|
||||||
|
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
File.SetCreationTime(filePath.FullName, dateTime.Value);
|
||||||
|
Thread.Sleep(500);
|
||||||
|
File.SetLastWriteTime(filePath.FullName, dateTime.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles)
|
private void NonParallelismAndInPlace(AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, ExifDirectory exifDirectory, MinimumYearAndPathCombined minimumYearAndPathCombined, bool fastForwardMovingPictureExpertsGroupUsed, FileHolder[] sidecarFiles)
|
||||||
{
|
{
|
||||||
@ -189,126 +408,6 @@ public partial class Rename : IRename, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void JustMediaDate(ILogger<Program>? logger, AppSettings appSettings, A_Metadata metadata, FilePath filePath)
|
|
||||||
{
|
|
||||||
ExifDirectory? exifDirectory;
|
|
||||||
MinimumYearAndPathCombined? minimumYearAndPathCombined;
|
|
||||||
try
|
|
||||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
exifDirectory = null;
|
|
||||||
minimumYearAndPathCombined = null;
|
|
||||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
|
||||||
}
|
|
||||||
if (exifDirectory is null || minimumYearAndPathCombined is null)
|
|
||||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DateTime? dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
|
||||||
if (dateTime is null)
|
|
||||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
File.SetCreationTime(filePath.FullName, dateTime.Value);
|
|
||||||
Thread.Sleep(500);
|
|
||||||
File.SetLastWriteTime(filePath.FullName, dateTime.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, ReadOnlyCollection<int> ids, A_Metadata metadata, int index, KeyValuePair<string, List<FileHolder>> keyValuePair, List<FirstPass> results)
|
|
||||||
{
|
|
||||||
FilePath filePath;
|
|
||||||
FirstPass firstPass;
|
|
||||||
string directoryName;
|
|
||||||
ExifDirectory exifDirectory;
|
|
||||||
List<FileHolder> sidecarFiles;
|
|
||||||
DeterministicHashCode deterministicHashCode;
|
|
||||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
|
||||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
|
||||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
|
||||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
|
||||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
|
||||||
{
|
|
||||||
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
|
||||||
continue;
|
|
||||||
if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
|
||||||
continue;
|
|
||||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
|
||||||
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
|
||||||
continue;
|
|
||||||
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
|
||||||
{
|
|
||||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
|
||||||
deterministicHashCode = new(null, filePath.Id, null);
|
|
||||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
|
||||||
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath);
|
|
||||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
|
||||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
|
||||||
}
|
|
||||||
sidecarFiles = [];
|
|
||||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
|
||||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
|
||||||
{
|
|
||||||
if (appSettings.RenameSettings.JustMediaDate && filePath.HasDateTimeOriginal is not null && filePath.HasDateTimeOriginal.Value)
|
|
||||||
JustMediaDate(logger, appSettings, metadata, filePath);
|
|
||||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
|
||||||
continue;
|
|
||||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
|
||||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
|
||||||
{
|
|
||||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
|
||||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
|
||||||
}
|
|
||||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
|
||||||
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
|
|
||||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
|
||||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
|
||||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
|
||||||
results.Add(firstPass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, A_Metadata metadata, ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs)
|
|
||||||
{
|
|
||||||
List<FirstPass> results = [];
|
|
||||||
int index = -1;
|
|
||||||
TimeSpan timeSpan;
|
|
||||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
|
||||||
{
|
|
||||||
index += 1;
|
|
||||||
rename.Tick();
|
|
||||||
if (keyValuePair.Value.Count > 1 && !appSettings.RenameSettings.ForceNewId)
|
|
||||||
{
|
|
||||||
if (appSettings.RenameSettings.InPlaceMoveDirectory)
|
|
||||||
continue;
|
|
||||||
throw new NotSupportedException($"When sidecar files are present {nameof(appSettings.RenameSettings.ForceNewId)} must be true!");
|
|
||||||
}
|
|
||||||
if (keyValuePair.Value.Count > 2)
|
|
||||||
throw new NotSupportedException("Too many sidecar files!");
|
|
||||||
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
|
|
||||||
timeSpan = new(DateTime.Now.Ticks - ticks);
|
|
||||||
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlyCollection<Record> GetRecordCollection(AppSettings appSettings, List<FirstPass> collection)
|
private static ReadOnlyCollection<Record> GetRecordCollection(AppSettings appSettings, List<FirstPass> collection)
|
||||||
{
|
{
|
||||||
List<Record> results = [];
|
List<Record> results = [];
|
||||||
@ -336,172 +435,22 @@ public partial class Rename : IRename, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<FirstPass> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files, string? checkFile)
|
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
|
||||||
{
|
|
||||||
List<FirstPass> results;
|
|
||||||
FirstPass firstPass;
|
|
||||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
|
||||||
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
|
|
||||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
|
||||||
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
|
||||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
|
||||||
{
|
|
||||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
|
||||||
results = GetFirstPassCollection(logger, appSettings, rename, ticks, ids, metadata, keyValuePairs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
results = [];
|
|
||||||
List<string> distinct = [];
|
|
||||||
List<MetadataGroup> metadataGroups = [];
|
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
|
||||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
|
|
||||||
Thread.Sleep(500);
|
|
||||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
|
||||||
{
|
|
||||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
|
||||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
|
||||||
else
|
|
||||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
|
||||||
results.Add(firstPass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(checkFile))
|
|
||||||
{
|
|
||||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
|
||||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReadOnlyCollection<Record> GetRecordCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, string sourceDirectory, ReadOnlyCollection<string> files)
|
|
||||||
{
|
|
||||||
ReadOnlyCollection<Record> results;
|
|
||||||
List<FirstPass> collection;
|
|
||||||
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
|
|
||||||
if (string.IsNullOrEmpty(checkFile) || !File.Exists(checkFile))
|
|
||||||
collection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files, checkFile);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string json = File.ReadAllText(checkFile);
|
|
||||||
collection = JsonSerializer.Deserialize(json, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass) ?? throw new Exception();
|
|
||||||
}
|
|
||||||
if (appSettings.RenameSettings.JustMediaDate)
|
|
||||||
results = new([]);
|
|
||||||
else
|
|
||||||
results = GetRecordCollection(appSettings, collection);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
|
|
||||||
{
|
{
|
||||||
|
string paddedId;
|
||||||
|
Identifier identifier;
|
||||||
|
List<Identifier> identifiers = [];
|
||||||
|
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
|
||||||
foreach (Record record in recordCollection)
|
foreach (Record record in recordCollection)
|
||||||
{
|
{
|
||||||
if (record.ExifDirectory.FilePath.Id is null)
|
if (record.ExifDirectory.FilePath.Id is null)
|
||||||
continue;
|
continue;
|
||||||
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length)
|
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null);
|
||||||
throw new NotSupportedException();
|
identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks);
|
||||||
|
identifiers.Add(identifier);
|
||||||
}
|
}
|
||||||
}
|
string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||||
|
_ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||||
private static string GetTFW(Record record, bool? isWrongYear) =>
|
|
||||||
string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I");
|
|
||||||
|
|
||||||
private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) =>
|
|
||||||
splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}";
|
|
||||||
|
|
||||||
private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
|
|
||||||
{
|
|
||||||
string? result;
|
|
||||||
string year = record.DateTime.Year.ToString();
|
|
||||||
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
|
|
||||||
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
|
|
||||||
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
|
|
||||||
result = null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
|
|
||||||
isWrongYear = null;
|
|
||||||
string directoryName;
|
|
||||||
string tfw = GetTFW(record, isWrongYear);
|
|
||||||
string? maker = IMetadata.GetMaker(record.ExifDirectory);
|
|
||||||
string rootDirectory = appSettings.ResultSettings.RootDirectory;
|
|
||||||
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
|
|
||||||
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
|
|
||||||
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
|
|
||||||
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
|
|
||||||
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
|
|
||||||
if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2)
|
|
||||||
directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
directoryName = record.DateTime.ToString("yyyy-MM-dd");
|
|
||||||
if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value))
|
|
||||||
directoryName = value;
|
|
||||||
}
|
|
||||||
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
|
|
||||||
{
|
|
||||||
List<ToDo> results = [];
|
|
||||||
ToDo toDo;
|
|
||||||
string checkFile;
|
|
||||||
FilePath filePath;
|
|
||||||
string checkFileExtension;
|
|
||||||
foreach (FileHolder fileHolder in record.SidecarFiles)
|
|
||||||
{
|
|
||||||
checkFileExtension = fileHolder.ExtensionLowered;
|
|
||||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null);
|
|
||||||
checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}");
|
|
||||||
if (checkFile == filePath.FullName)
|
|
||||||
continue;
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
{
|
|
||||||
checkFile = string.Concat(checkFile, ".del");
|
|
||||||
if (File.Exists(checkFile))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (distinct.Contains(checkFile))
|
|
||||||
continue;
|
|
||||||
distinct.Add(checkFile);
|
|
||||||
toDo = new(Directory: checkDirectory,
|
|
||||||
FileInfo: new(filePath.FullName),
|
|
||||||
File: checkFile,
|
|
||||||
JsonFile: false);
|
|
||||||
results.Add(toDo);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool? GetDirectoryCheck(ResultSettings resultSettings)
|
|
||||||
{
|
|
||||||
bool? result = null;
|
|
||||||
IEnumerable<string> files;
|
|
||||||
string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string directory in directories)
|
|
||||||
{
|
|
||||||
files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
|
|
||||||
foreach (string _ in files)
|
|
||||||
{
|
|
||||||
if (result is null)
|
|
||||||
result = false;
|
|
||||||
else if (result.Value)
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (result is not null && result.Value)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection)
|
private static ReadOnlyCollection<ToDo> GetToDoCollection(AppSettings appSettings, DirectoryInfo directoryInfo, ReadOnlyCollection<int> ids, ReadOnlyCollection<string> files, ReadOnlyCollection<Record> recordCollection)
|
||||||
@ -589,17 +538,114 @@ public partial class Rename : IRename, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection)
|
private static bool? GetDirectoryCheck(ResultSettings resultSettings)
|
||||||
{
|
{
|
||||||
List<string> distinct = [];
|
bool? result = null;
|
||||||
foreach (ToDo toDo in toDoCollection)
|
IEnumerable<string> files;
|
||||||
|
string[] directories = Directory.GetDirectories(resultSettings.RootDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
if (toDo.Directory is null || distinct.Contains(toDo.Directory))
|
files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
|
||||||
continue;
|
foreach (string _ in files)
|
||||||
if (!Directory.Exists(toDo.Directory))
|
{
|
||||||
_ = Directory.CreateDirectory(toDo.Directory);
|
if (result is null)
|
||||||
distinct.Add(toDo.Directory);
|
result = false;
|
||||||
|
else if (result.Value)
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result is not null && result.Value)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void VerifyIntMinValueLength(MetadataSettings metadataSettings, ReadOnlyCollection<Record> recordCollection)
|
||||||
|
{
|
||||||
|
foreach (Record record in recordCollection)
|
||||||
|
{
|
||||||
|
if (record.ExifDirectory.FilePath.Id is null)
|
||||||
|
continue;
|
||||||
|
if (metadataSettings.IntMinValueLength < record.ExifDirectory.FilePath.Id.Value.ToString().Length)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetCheckDirectory(AppSettings appSettings, DirectoryInfo directoryInfo, Record record, ReadOnlyCollection<int> ids, bool multipleDirectoriesWithFiles, string paddedId)
|
||||||
|
{
|
||||||
|
string? result;
|
||||||
|
string year = record.DateTime.Year.ToString();
|
||||||
|
string checkDirectoryName = Path.GetFileName(record.ExifDirectory.FilePath.DirectoryFullPath);
|
||||||
|
if (multipleDirectoriesWithFiles && !checkDirectoryName.Contains(year))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(bool? isWrongYear, string[] years) = IDate.IsWrongYear(directoryInfo, record.ExifDirectory.FilePath, record.ExifDirectory);
|
||||||
|
if (appSettings.RenameSettings.InPlaceMoveDirectory && !record.ExifDirectory.FilePath.FileNameFirstSegment.Contains(paddedId))
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (record.ExifDirectory.FilePath.FullName[..2] != directoryInfo.FullName[..2])
|
||||||
|
isWrongYear = null;
|
||||||
|
string directoryName;
|
||||||
|
string tfw = GetTFW(record, isWrongYear);
|
||||||
|
string? maker = IMetadata.GetMaker(record.ExifDirectory);
|
||||||
|
string rootDirectory = appSettings.ResultSettings.RootDirectory;
|
||||||
|
string[] segments = checkDirectoryName.Split(years, StringSplitOptions.None);
|
||||||
|
(int seasonValue, string seasonName) = IDate.GetSeason(record.DateTime.DayOfYear);
|
||||||
|
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
|
||||||
|
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
|
||||||
|
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
|
||||||
|
if (!string.IsNullOrEmpty(splat) || isWrongYear is null || isWrongYear.Value || appSettings.RenameSettings.DirectoryDictionary.Count < 2)
|
||||||
|
directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directoryName = record.DateTime.ToString("yyyy-MM-dd");
|
||||||
|
if (appSettings.RenameSettings.DirectoryDictionary.TryGetValue(directoryName, out string? value) && !string.IsNullOrEmpty(value))
|
||||||
|
directoryName = value;
|
||||||
|
}
|
||||||
|
result = Path.GetFullPath(Path.Combine(rootDirectory, contains, directoryName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTFW(Record record, bool? isWrongYear) =>
|
||||||
|
string.Concat(record.HasDateTimeOriginal ? "T" : "F", isWrongYear is not null && isWrongYear.Value ? "W" : record.FastForwardMovingPictureExpertsGroupUsed ? "V" : "I");
|
||||||
|
|
||||||
|
private static string GetDirectoryName(string year, string tfw, string prefix, string? splat, int seasonValue, string seasonName, string makerSplit) =>
|
||||||
|
splat is null ? $"{prefix}{year} {tfw}{year}.{seasonValue} {seasonName}{makerSplit}" : $"{prefix}{year} {tfw}{year}{splat}";
|
||||||
|
|
||||||
|
private static List<ToDo> GetSidecarFiles(AppSettings appSettings, Record record, List<string> distinct, string checkDirectory, string paddedId)
|
||||||
|
{
|
||||||
|
List<ToDo> results = [];
|
||||||
|
ToDo toDo;
|
||||||
|
string checkFile;
|
||||||
|
FilePath filePath;
|
||||||
|
string checkFileExtension;
|
||||||
|
foreach (FileHolder fileHolder in record.SidecarFiles)
|
||||||
|
{
|
||||||
|
checkFileExtension = fileHolder.ExtensionLowered;
|
||||||
|
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index: null);
|
||||||
|
checkFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}");
|
||||||
|
if (checkFile == filePath.FullName)
|
||||||
|
continue;
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
{
|
||||||
|
checkFile = string.Concat(checkFile, ".del");
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (distinct.Contains(checkFile))
|
||||||
|
continue;
|
||||||
|
distinct.Add(checkFile);
|
||||||
|
toDo = new(Directory: checkDirectory,
|
||||||
|
FileInfo: new(filePath.FullName),
|
||||||
|
File: checkFile,
|
||||||
|
JsonFile: false);
|
||||||
|
results.Add(toDo);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReadOnlyCollection<string> RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection<ToDo> toDoCollection)
|
private ReadOnlyCollection<string> RenameFilesInDirectories(RenameSettings renameSettings, IRename rename, ReadOnlyCollection<ToDo> toDoCollection)
|
||||||
@ -642,65 +688,16 @@ public partial class Rename : IRename, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SaveIdentifiersToDisk(long ticks, AppSettings appSettings, ReadOnlyCollection<Record> recordCollection)
|
private static void VerifyDirectories(ReadOnlyCollection<ToDo> toDoCollection)
|
||||||
{
|
{
|
||||||
string paddedId;
|
List<string> distinct = [];
|
||||||
Identifier identifier;
|
foreach (ToDo toDo in toDoCollection)
|
||||||
List<Identifier> identifiers = [];
|
|
||||||
string aMetadataCollectionDirectory = IResult.GetResultsDateGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata), appSettings.ResultSettings.ResultCollection);
|
|
||||||
foreach (Record record in recordCollection)
|
|
||||||
{
|
{
|
||||||
if (record.ExifDirectory.FilePath.Id is null)
|
if (toDo.Directory is null || distinct.Contains(toDo.Directory))
|
||||||
continue;
|
continue;
|
||||||
paddedId = IId.GetPaddedId(appSettings.ResultSettings, appSettings.MetadataSettings, record.ExifDirectory.FilePath.Id.Value, record.HasIgnoreKeyword, record.HasDateTimeOriginal, index: null);
|
if (!Directory.Exists(toDo.Directory))
|
||||||
identifier = new([], record.HasDateTimeOriginal, record.ExifDirectory.FilePath.Id.Value, record.ExifDirectory.FilePath.Length, paddedId, record.DateTime.Ticks);
|
_ = Directory.CreateDirectory(toDo.Directory);
|
||||||
identifiers.Add(identifier);
|
distinct.Add(toDo.Directory);
|
||||||
}
|
|
||||||
string json = JsonSerializer.Serialize(identifiers.OrderBy(l => l.PaddedId).ToArray(), IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
|
||||||
_ = IPath.WriteAllText(Path.Combine(aMetadataCollectionDirectory, $"{ticks}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlyCollection<int> GetIds(RenameSettings renameSettings)
|
|
||||||
{
|
|
||||||
ReadOnlyCollection<int> results;
|
|
||||||
string? propertyCollectionFile = string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile) ? null : renameSettings.RelativePropertyCollectionFile;
|
|
||||||
string? json = !File.Exists(propertyCollectionFile) ? null : File.ReadAllText(propertyCollectionFile);
|
|
||||||
Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
|
||||||
if (identifiers is null && !string.IsNullOrEmpty(renameSettings.RelativePropertyCollectionFile))
|
|
||||||
throw new Exception($"Invalid {nameof(renameSettings.RelativePropertyCollectionFile)}");
|
|
||||||
results = identifiers is null ? new([]) : new((from l in identifiers select l.Id).ToArray());
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenameWork(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks)
|
|
||||||
{
|
|
||||||
ReadOnlyCollection<int> ids = GetIds(appSettings.RenameSettings);
|
|
||||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
|
||||||
if (!Directory.Exists(sourceDirectory))
|
|
||||||
_ = Directory.CreateDirectory(sourceDirectory);
|
|
||||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
|
||||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
|
||||||
if (files.Count > 0)
|
|
||||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
|
||||||
ReadOnlyCollection<Record> recordCollection = GetRecordCollection(logger, appSettings, rename, ticks, ids, sourceDirectory, files);
|
|
||||||
SaveIdentifiersToDisk(ticks, appSettings, recordCollection);
|
|
||||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
|
||||||
{
|
|
||||||
if (recordCollection.Count > 0)
|
|
||||||
recordCollection = new([]);
|
|
||||||
string aMetadataSingletonDirectory = IResult.GetResultsGroupDirectory(appSettings.ResultSettings, nameof(A_Metadata));
|
|
||||||
_ = IPath.DeleteEmptyDirectories(aMetadataSingletonDirectory);
|
|
||||||
}
|
|
||||||
if (!appSettings.RenameSettings.OnlySaveIdentifiersToDisk)
|
|
||||||
{
|
|
||||||
DirectoryInfo directoryInfo = new(sourceDirectory);
|
|
||||||
ReadOnlyCollection<ToDo> toDoCollection = GetToDoCollection(appSettings, directoryInfo, ids, files, recordCollection);
|
|
||||||
ReadOnlyCollection<string> lines = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection);
|
|
||||||
if (lines.Count != 0)
|
|
||||||
{
|
|
||||||
File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
|
|
||||||
_ = IPath.DeleteEmptyDirectories(directoryInfo.FullName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,6 @@ public interface ICompareSettings
|
|||||||
public string FacesFileNameExtension { init; get; }
|
public string FacesFileNameExtension { init; get; }
|
||||||
public string FacesHiddenFileNameExtension { init; get; }
|
public string FacesHiddenFileNameExtension { init; get; }
|
||||||
public string FacesPartsFileNameExtension { init; get; }
|
public string FacesPartsFileNameExtension { init; get; }
|
||||||
public string[] IgnoreExtensions { init; get; }
|
|
||||||
public int MaxDegreeOfParallelism { init; get; }
|
public int MaxDegreeOfParallelism { init; get; }
|
||||||
public string[] ValidImageFormatExtensions { init; get; }
|
|
||||||
public string[] ValidVideoFormatExtensions { init; get; }
|
|
||||||
|
|
||||||
}
|
}
|
@ -3,9 +3,6 @@ namespace View_by_Distance.Shared.Models.Properties;
|
|||||||
public interface IRenameSettings
|
public interface IRenameSettings
|
||||||
{
|
{
|
||||||
|
|
||||||
public string[] IgnoreExtensions { init; get; }
|
|
||||||
public bool SkipIdFiles { init; get; }
|
public bool SkipIdFiles { init; get; }
|
||||||
public string[] ValidImageFormatExtensions { init; get; }
|
|
||||||
public string[] ValidVideoFormatExtensions { init; get; }
|
|
||||||
|
|
||||||
}
|
}
|
@ -3,8 +3,4 @@ namespace View_by_Distance.Shared.Models.Properties;
|
|||||||
public interface IWindowsSettings
|
public interface IWindowsSettings
|
||||||
{
|
{
|
||||||
|
|
||||||
public string[] IgnoreExtensions { init; get; }
|
|
||||||
public string[] ValidImageFormatExtensions { init; get; }
|
|
||||||
public string[] ValidVideoFormatExtensions { init; get; }
|
|
||||||
|
|
||||||
}
|
}
|
@ -8,12 +8,15 @@ public record ResultSettings(string DateGroup,
|
|||||||
string ModelName,
|
string ModelName,
|
||||||
int NumberOfJitters,
|
int NumberOfJitters,
|
||||||
int NumberOfTimesToUpsample,
|
int NumberOfTimesToUpsample,
|
||||||
|
string[] IgnoreExtensions,
|
||||||
string PredictorModelName,
|
string PredictorModelName,
|
||||||
int ResultAllInOneSubdirectoryLength,
|
int ResultAllInOneSubdirectoryLength,
|
||||||
string ResultCollection,
|
string ResultCollection,
|
||||||
string ResultContent,
|
string ResultContent,
|
||||||
string ResultSingleton,
|
string ResultSingleton,
|
||||||
string RootDirectory)
|
string RootDirectory,
|
||||||
|
string[] ValidImageFormatExtensions,
|
||||||
|
string[] ValidVideoFormatExtensions)
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -5,44 +5,69 @@ public interface IId
|
|||||||
|
|
||||||
const int DeterministicHashCode = 9876543;
|
const int DeterministicHashCode = 9876543;
|
||||||
|
|
||||||
static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) =>
|
public static int GetDeterministicHashCode(byte[] value) =>
|
||||||
metadataSettings.Offset == DeterministicHashCode;
|
|
||||||
|
|
||||||
string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
|
||||||
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
|
||||||
static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
|
||||||
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
|
||||||
|
|
||||||
int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
|
||||||
GetId(resultSettings, metadataSettings, intelligentId);
|
|
||||||
static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
|
||||||
Id.GetId(resultSettings, metadataSettings, intelligentId);
|
|
||||||
|
|
||||||
string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
|
||||||
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
|
||||||
static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
|
||||||
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
|
||||||
|
|
||||||
bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
|
||||||
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
|
|
||||||
static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
|
||||||
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
|
||||||
|
|
||||||
bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
|
||||||
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
|
||||||
static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
|
||||||
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
|
||||||
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '7' or '8' or '9'
|
|
||||||
&& fileNameFirstSegment.All(char.IsNumber);
|
|
||||||
|
|
||||||
bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
|
||||||
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
|
|
||||||
static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
|
||||||
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
|
|
||||||
|
|
||||||
int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
|
||||||
GetDeterministicHashCode(value);
|
|
||||||
static int GetDeterministicHashCode(byte[] value) =>
|
|
||||||
Id.GetDeterministicHashCode(value);
|
Id.GetDeterministicHashCode(value);
|
||||||
|
|
||||||
|
public static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||||
|
Id.GetHasIgnoreKeyword(filePath);
|
||||||
|
|
||||||
|
public static bool IsOffsetDeterministicHashCode(MetadataSettings metadataSettings) =>
|
||||||
|
metadataSettings.Offset == DeterministicHashCode;
|
||||||
|
|
||||||
|
public static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
Id.GetHasDateTimeOriginal(resultSettings, filePath);
|
||||||
|
|
||||||
|
public static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
Id.GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||||
|
|
||||||
|
public static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||||
|
Id.NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder.NameWithoutExtension.Split('.')[0]);
|
||||||
|
|
||||||
|
public static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||||
|
Id.GetId(resultSettings, metadataSettings, intelligentId);
|
||||||
|
|
||||||
|
public static bool NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||||
|
fileNameFirstSegment.Length - 1 == metadataSettings.IntMinValueLength && fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9' && fileNameFirstSegment.All(char.IsNumber);
|
||||||
|
|
||||||
|
public static bool NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||||
|
fileNameFirstSegment.Length == metadataSettings.IntMinValueLength + sortOrderOnlyLengthIndex + 1
|
||||||
|
&& fileNameFirstSegment[^1] is '1' or '2' or '3' or '4' or '5' or '6' or '7' or '8' or '9'
|
||||||
|
&& fileNameFirstSegment.All(char.IsNumber);
|
||||||
|
|
||||||
|
public static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||||
|
Id.GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||||
|
|
||||||
|
public static string GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||||
|
Id.GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||||
|
|
||||||
|
internal int TestStatic_GetDeterministicHashCode(byte[] value) =>
|
||||||
|
GetDeterministicHashCode(value);
|
||||||
|
|
||||||
|
internal byte TestStatic_GetHasIgnoreKeyword(FilePath filePath) =>
|
||||||
|
GetHasIgnoreKeyword(filePath);
|
||||||
|
|
||||||
|
internal byte TestStatic_GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
GetHasDateTimeOriginal(resultSettings, filePath);
|
||||||
|
|
||||||
|
internal byte TestStatic_GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||||
|
|
||||||
|
internal bool TestStatic_NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, FileHolder fileHolder) =>
|
||||||
|
NameWithoutExtensionIsIdFormat(metadataSettings, fileHolder);
|
||||||
|
|
||||||
|
internal int TestStatic_GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId) =>
|
||||||
|
GetId(resultSettings, metadataSettings, intelligentId);
|
||||||
|
|
||||||
|
internal bool TestStatic_NameWithoutExtensionIsIntelligentIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment) =>
|
||||||
|
NameWithoutExtensionIsIntelligentIdFormat(metadataSettings, fileNameFirstSegment);
|
||||||
|
|
||||||
|
internal bool TestStatic_NameWithoutExtensionIsPaddedIntelligentIdFormat(MetadataSettings metadataSettings, int sortOrderOnlyLengthIndex, string fileNameFirstSegment) =>
|
||||||
|
NameWithoutExtensionIsPaddedIntelligentIdFormat(metadataSettings, sortOrderOnlyLengthIndex, fileNameFirstSegment);
|
||||||
|
|
||||||
|
internal string TestStatic_GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal) =>
|
||||||
|
GetIntelligentId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal);
|
||||||
|
|
||||||
|
internal string TestStatic_GetPaddedId(ResultSettings resultSettings, MetadataSettings metadataSettings, int id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal, int? index) =>
|
||||||
|
GetPaddedId(resultSettings, metadataSettings, id, hasIgnoreKeyword, hasDateTimeOriginal, index);
|
||||||
|
|
||||||
}
|
}
|
@ -1,12 +1,11 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless;
|
namespace View_by_Distance.Shared.Models.Stateless;
|
||||||
|
|
||||||
public interface IRename
|
public interface IRename
|
||||||
{
|
{
|
||||||
|
|
||||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IRenameSettings renameSettings, FilePath filePath);
|
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, FilePath filePath);
|
||||||
DeterministicHashCode GetDeterministicHashCode(FilePath filePath);
|
DeterministicHashCode GetDeterministicHashCode(FilePath filePath);
|
||||||
void ConstructProgressBar(int maxTicks, string message);
|
void ConstructProgressBar(int maxTicks, string message);
|
||||||
void Tick();
|
void Tick();
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless;
|
namespace View_by_Distance.Shared.Models.Stateless;
|
||||||
|
|
||||||
public interface IWindows
|
public interface IWindows
|
||||||
{
|
{
|
||||||
|
|
||||||
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings windowsSettings, HttpClient? httpClient, FilePath filePath);
|
ReadOnlyCollection<string> ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath);
|
||||||
DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath);
|
DeterministicHashCode GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath);
|
||||||
DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri);
|
DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri);
|
||||||
void ConstructProgressBar(int maxTicks, string message);
|
void ConstructProgressBar(int maxTicks, string message);
|
||||||
|
@ -5,19 +5,34 @@ namespace View_by_Distance.Shared.Models.Stateless;
|
|||||||
internal abstract class Id
|
internal abstract class Id
|
||||||
{
|
{
|
||||||
|
|
||||||
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment)
|
internal static int GetDeterministicHashCode(byte[] value)
|
||||||
{
|
{
|
||||||
bool result;
|
int result;
|
||||||
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength)
|
unchecked
|
||||||
result = false;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
|
int hash1 = (5381 << 16) + 5381;
|
||||||
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
|
int hash2 = hash1;
|
||||||
|
for (int i = 0; i < value.Length; i += 2)
|
||||||
|
{
|
||||||
|
hash1 = ((hash1 << 5) + hash1) ^ value[i];
|
||||||
|
if (i == value.Length - 1)
|
||||||
|
break;
|
||||||
|
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
|
||||||
|
}
|
||||||
|
result = hash1 + (hash2 * 1566083941);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static byte GetHasIgnoreKeyword(FilePath filePath) =>
|
||||||
|
(byte)(filePath.Id > -1 ? 8 : 2);
|
||||||
|
|
||||||
|
internal static byte GetHasDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
|
||||||
|
|
||||||
|
internal static byte GetMissingDateTimeOriginal(ResultSettings resultSettings, FilePath filePath) =>
|
||||||
|
(byte)(!resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : 5);
|
||||||
|
|
||||||
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
|
internal static int GetId(ResultSettings resultSettings, MetadataSettings metadataSettings, string intelligentId)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
@ -28,13 +43,26 @@ internal abstract class Id
|
|||||||
_ = results.Append(intelligentId[i]);
|
_ = results.Append(intelligentId[i]);
|
||||||
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
_ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
|
||||||
result = int.Parse(results.ToString());
|
result = int.Parse(results.ToString());
|
||||||
if (intelligentId[^1] is '1' or '2' or '3')
|
if (intelligentId[^1] is '1' or '2' or '3' or '4')
|
||||||
result *= -1;
|
result *= -1;
|
||||||
else if (intelligentId[^1] is not '9' and not '8' and not '7')
|
else if (intelligentId[^1] is not '9' and not '8' and not '7' and not '6' and not '5')
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool NameWithoutExtensionIsIdFormat(MetadataSettings metadataSettings, string fileNameFirstSegment)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataSettings.IntMinValueLength)
|
||||||
|
result = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
|
||||||
|
result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning disable IDE0060
|
#pragma warning disable IDE0060
|
||||||
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
internal static string GetIntelligentId(ResultSettings resultSettings, MetadataSettings metadataSettings, long id, bool? hasIgnoreKeyword, bool? hasDateTimeOriginal)
|
||||||
#pragma warning restore IDE0060
|
#pragma warning restore IDE0060
|
||||||
@ -80,23 +108,4 @@ internal abstract class Id
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int GetDeterministicHashCode(byte[] value)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
int hash1 = (5381 << 16) + 5381;
|
|
||||||
int hash2 = hash1;
|
|
||||||
for (int i = 0; i < value.Length; i += 2)
|
|
||||||
{
|
|
||||||
hash1 = ((hash1 << 5) + hash1) ^ value[i];
|
|
||||||
if (i == value.Length - 1)
|
|
||||||
break;
|
|
||||||
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
|
|
||||||
}
|
|
||||||
result = hash1 + (hash2 * 1566083941);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,35 +5,29 @@ namespace View_by_Distance.Shared.Models.Stateless;
|
|||||||
internal abstract class XPath
|
internal abstract class XPath
|
||||||
{
|
{
|
||||||
|
|
||||||
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower)
|
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
|
||||||
{
|
{
|
||||||
string result;
|
Dictionary<byte, List<string>> results = [];
|
||||||
if (forceExtensionToLower)
|
List<string>? c;
|
||||||
|
foreach (CombinedEnumAndIndex cei in collection)
|
||||||
{
|
{
|
||||||
string extension = Path.GetExtension(path);
|
if (!results.TryGetValue(cei.Enum, out c))
|
||||||
string extensionLowered = Path.GetExtension(path).ToLower();
|
|
||||||
if (extension != extensionLowered)
|
|
||||||
{
|
{
|
||||||
string? directoryName = Path.GetDirectoryName(path);
|
results.Add(cei.Enum, []);
|
||||||
if (string.IsNullOrEmpty(directoryName))
|
if (!results.TryGetValue(cei.Enum, out c))
|
||||||
throw new NullReferenceException(directoryName);
|
throw new Exception();
|
||||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
|
||||||
if (string.IsNullOrEmpty(fileNameWithoutExtension))
|
|
||||||
throw new NullReferenceException(fileNameWithoutExtension);
|
|
||||||
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
|
|
||||||
}
|
}
|
||||||
|
c.Add(cei.Combined);
|
||||||
}
|
}
|
||||||
result = path[length..].Replace(@"\", "/");
|
return Convert(results);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool DeleteEmptyDirectories(string rootDirectory)
|
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs)
|
||||||
{
|
{
|
||||||
bool result;
|
Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
||||||
List<string> results = [];
|
foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
||||||
DeleteEmptyDirectories(rootDirectory, results);
|
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||||
result = results.Count > 0;
|
return results.AsReadOnly();
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories)
|
internal static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories)
|
||||||
@ -71,45 +65,56 @@ internal abstract class XPath
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches)
|
internal static byte GetEnum(FilePath filePath) =>
|
||||||
|
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
||||||
|
|
||||||
|
private static byte GetEnum(bool? ik, bool? dto)
|
||||||
{
|
{
|
||||||
bool result;
|
byte result;
|
||||||
string text;
|
if (ik is not null && ik.Value && dto is not null && dto.Value)
|
||||||
if (!compareBeforeWrite)
|
result = 11;
|
||||||
result = true;
|
else if (ik is not null && ik.Value && dto is not null && !dto.Value)
|
||||||
|
result = 15;
|
||||||
|
else if (ik is not null && ik.Value && dto is null)
|
||||||
|
result = 19;
|
||||||
|
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
|
||||||
|
result = 51;
|
||||||
|
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
|
||||||
|
result = 55;
|
||||||
|
else if (ik is not null && !ik.Value && dto is null)
|
||||||
|
result = 59;
|
||||||
|
else if (ik is null && dto is not null && dto.Value)
|
||||||
|
result = 91;
|
||||||
|
else if (ik is null && dto is not null && !dto.Value)
|
||||||
|
result = 95;
|
||||||
|
else if (ik is null && dto is null)
|
||||||
|
result = 99;
|
||||||
else
|
else
|
||||||
{
|
throw new Exception();
|
||||||
if (!File.Exists(path))
|
|
||||||
text = string.Empty;
|
|
||||||
else
|
|
||||||
text = File.ReadAllText(path);
|
|
||||||
result = text != contents;
|
|
||||||
if (!result && updateDateWhenMatches)
|
|
||||||
{
|
|
||||||
if (updateToWhenMatches is null)
|
|
||||||
File.SetLastWriteTime(path, DateTime.Now);
|
|
||||||
else
|
|
||||||
File.SetLastWriteTime(path, updateToWhenMatches.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
if (path.Contains("()"))
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
else
|
|
||||||
File.WriteAllText(path, contents);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static List<string> GetDirectories(string directory)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
string? checkDirectory = directory;
|
||||||
|
string? pathRoot = Path.GetPathRoot(directory);
|
||||||
|
if (string.IsNullOrEmpty(pathRoot))
|
||||||
|
throw new NullReferenceException(nameof(pathRoot));
|
||||||
|
if (Directory.Exists(directory))
|
||||||
|
results.Add(directory);
|
||||||
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
|
{
|
||||||
|
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
|
||||||
|
break;
|
||||||
|
results.Add(checkDirectory);
|
||||||
|
}
|
||||||
|
results.Add(pathRoot);
|
||||||
|
results.Reverse();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
internal static List<string> GetDirectoryNames(string directory)
|
internal static List<string> GetDirectoryNames(string directory)
|
||||||
{
|
{
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
@ -146,83 +151,15 @@ internal abstract class XPath
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<string> GetDirectories(string directory)
|
internal static bool DeleteEmptyDirectories(string rootDirectory)
|
||||||
{
|
{
|
||||||
|
bool result;
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
string? checkDirectory = directory;
|
DeleteEmptyDirectories(rootDirectory, results);
|
||||||
string? pathRoot = Path.GetPathRoot(directory);
|
result = results.Count > 0;
|
||||||
if (string.IsNullOrEmpty(pathRoot))
|
|
||||||
throw new NullReferenceException(nameof(pathRoot));
|
|
||||||
if (Directory.Exists(directory))
|
|
||||||
results.Add(directory);
|
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
|
||||||
{
|
|
||||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
|
||||||
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
|
|
||||||
break;
|
|
||||||
results.Add(checkDirectory);
|
|
||||||
}
|
|
||||||
results.Add(pathRoot);
|
|
||||||
results.Reverse();
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
string? directory;
|
|
||||||
string? checkDirectory;
|
|
||||||
List<string> results = [];
|
|
||||||
checkDirectory = sourceDirectory;
|
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
|
||||||
{
|
|
||||||
result += 1;
|
|
||||||
directory = Path.GetFileName(checkDirectory);
|
|
||||||
if (string.IsNullOrEmpty(directory))
|
|
||||||
break;
|
|
||||||
results.Add(directory);
|
|
||||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
|
||||||
if (checkDirectory == rootDirectory)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
results.Reverse();
|
|
||||||
return new(result, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
|
|
||||||
{
|
|
||||||
string result;
|
|
||||||
string? checkDirectory;
|
|
||||||
checkDirectory = Path.GetDirectoryName(sourceDirectory);
|
|
||||||
for (int i = 0; i < level; i++)
|
|
||||||
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
|
||||||
if (string.IsNullOrEmpty(checkDirectory))
|
|
||||||
throw new Exception();
|
|
||||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
|
||||||
if (!Directory.Exists(checkDirectory))
|
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
|
||||||
result = checkDirectory;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
|
|
||||||
{
|
|
||||||
DateTime dateTime = new(ticks);
|
|
||||||
IEnumerable<string> fileSystemEntries;
|
|
||||||
string[] directories;
|
|
||||||
if (!Directory.Exists(rootDirectory))
|
|
||||||
directories = [];
|
|
||||||
else
|
|
||||||
directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
|
|
||||||
foreach (string directory in directories)
|
|
||||||
{
|
|
||||||
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
if (fileSystemEntries.Any())
|
|
||||||
continue;
|
|
||||||
Directory.SetLastWriteTime(directory, dateTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory)
|
internal static void MakeHiddenIfAllItemsAreHidden(string rootDirectory)
|
||||||
{
|
{
|
||||||
bool check;
|
bool check;
|
||||||
@ -265,49 +202,117 @@ internal abstract class XPath
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte GetEnum(bool? ik, bool? dto)
|
internal static void ChangeDateForEmptyDirectories(string rootDirectory, long ticks)
|
||||||
{
|
{
|
||||||
byte result;
|
DateTime dateTime = new(ticks);
|
||||||
if (ik is not null && ik.Value && dto is not null && dto.Value)
|
IEnumerable<string> fileSystemEntries;
|
||||||
result = 11;
|
string[] directories;
|
||||||
else if (ik is not null && ik.Value && dto is not null && !dto.Value)
|
if (!Directory.Exists(rootDirectory))
|
||||||
result = 15;
|
directories = [];
|
||||||
else if (ik is not null && ik.Value && dto is null)
|
|
||||||
result = 19;
|
|
||||||
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
|
|
||||||
result = 51;
|
|
||||||
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
|
|
||||||
result = 55;
|
|
||||||
else if (ik is not null && !ik.Value && dto is null)
|
|
||||||
result = 59;
|
|
||||||
else if (ik is null && dto is not null && dto.Value)
|
|
||||||
result = 91;
|
|
||||||
else if (ik is null && dto is not null && !dto.Value)
|
|
||||||
result = 95;
|
|
||||||
else if (ik is null && dto is null)
|
|
||||||
result = 99;
|
|
||||||
else
|
else
|
||||||
throw new Exception();
|
directories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories);
|
||||||
|
foreach (string directory in directories)
|
||||||
|
{
|
||||||
|
fileSystemEntries = Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
if (fileSystemEntries.Any())
|
||||||
|
continue;
|
||||||
|
Directory.SetLastWriteTime(directory, dateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetRelativePath(string path, int length, bool forceExtensionToLower)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
if (forceExtensionToLower)
|
||||||
|
{
|
||||||
|
string extension = Path.GetExtension(path);
|
||||||
|
string extensionLowered = Path.GetExtension(path).ToLower();
|
||||||
|
if (extension != extensionLowered)
|
||||||
|
{
|
||||||
|
string? directoryName = Path.GetDirectoryName(path);
|
||||||
|
if (string.IsNullOrEmpty(directoryName))
|
||||||
|
throw new NullReferenceException(directoryName);
|
||||||
|
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
||||||
|
if (string.IsNullOrEmpty(fileNameWithoutExtension))
|
||||||
|
throw new NullReferenceException(fileNameWithoutExtension);
|
||||||
|
path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = path[length..].Replace(@"\", "/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte GetEnum(FilePath filePath) =>
|
internal static string GetDirectory(string sourceDirectory, int level, string directoryName)
|
||||||
GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
{
|
||||||
|
string result;
|
||||||
|
string? checkDirectory;
|
||||||
|
checkDirectory = Path.GetDirectoryName(sourceDirectory);
|
||||||
|
for (int i = 0; i < level; i++)
|
||||||
|
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||||
|
if (string.IsNullOrEmpty(checkDirectory))
|
||||||
|
throw new Exception();
|
||||||
|
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||||
|
if (!Directory.Exists(checkDirectory))
|
||||||
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
|
result = checkDirectory;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileNameWithoutExtension)
|
internal static (int level, List<string> directories) Get(string rootDirectory, string sourceDirectory)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
string? directory;
|
||||||
|
string? checkDirectory;
|
||||||
|
List<string> results = [];
|
||||||
|
checkDirectory = sourceDirectory;
|
||||||
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
|
{
|
||||||
|
result += 1;
|
||||||
|
directory = Path.GetFileName(checkDirectory);
|
||||||
|
if (string.IsNullOrEmpty(directory))
|
||||||
|
break;
|
||||||
|
results.Add(directory);
|
||||||
|
checkDirectory = Path.GetDirectoryName(checkDirectory);
|
||||||
|
if (checkDirectory == rootDirectory)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
results.Reverse();
|
||||||
|
return new(result, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath)
|
||||||
{
|
{
|
||||||
CombinedEnumAndIndex result;
|
CombinedEnumAndIndex result;
|
||||||
|
if (filePath.Id is not null)
|
||||||
|
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.Id.Value.ToString());
|
||||||
|
else
|
||||||
|
result = GetCombinedEnumAndIndex(resultSettings, filePath, filePath.NameWithoutExtension);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath, string fileNameWithoutExtension)
|
||||||
|
{
|
||||||
|
CombinedEnumAndIndex result;
|
||||||
|
byte @enum;
|
||||||
int converted;
|
int converted;
|
||||||
string combined;
|
string combined;
|
||||||
|
byte missingDateTimeOriginal = IId.GetMissingDateTimeOriginal(resultSettings, filePath);
|
||||||
|
if (filePath.HasIgnoreKeyword is null || filePath.HasDateTimeOriginal is null)
|
||||||
|
throw new NotImplementedException();
|
||||||
|
if (filePath.HasIgnoreKeyword.Value)
|
||||||
|
@enum = IId.GetHasIgnoreKeyword(filePath);
|
||||||
|
else if (!filePath.HasDateTimeOriginal.Value)
|
||||||
|
@enum = missingDateTimeOriginal;
|
||||||
|
else
|
||||||
|
@enum = IId.GetHasDateTimeOriginal(resultSettings, filePath);
|
||||||
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
|
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
|
||||||
byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
string check = fileNameBeforeFirst.Length < resultSettings.ResultAllInOneSubdirectoryLength ?
|
||||||
string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ?
|
new('-', resultSettings.ResultAllInOneSubdirectoryLength) :
|
||||||
new('-', resultAllInOneSubdirectoryLength) :
|
fileNameBeforeFirst[^resultSettings.ResultAllInOneSubdirectoryLength..];
|
||||||
fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..];
|
|
||||||
if (check.Any(l => !char.IsNumber(l)))
|
if (check.Any(l => !char.IsNumber(l)))
|
||||||
{
|
{
|
||||||
combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}";
|
combined = $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}";
|
||||||
converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}");
|
converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -318,16 +323,66 @@ internal abstract class XPath
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath)
|
internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches)
|
||||||
{
|
{
|
||||||
CombinedEnumAndIndex result;
|
bool result;
|
||||||
if (filePath.Id is not null)
|
string text;
|
||||||
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString());
|
if (!compareBeforeWrite)
|
||||||
|
result = true;
|
||||||
else
|
else
|
||||||
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.NameWithoutExtension);
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
text = string.Empty;
|
||||||
|
else
|
||||||
|
text = File.ReadAllText(path);
|
||||||
|
result = text != contents;
|
||||||
|
if (!result && updateDateWhenMatches)
|
||||||
|
{
|
||||||
|
if (updateToWhenMatches is null)
|
||||||
|
File.SetLastWriteTime(path, DateTime.Now);
|
||||||
|
else
|
||||||
|
File.SetLastWriteTime(path, updateToWhenMatches.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if (path.Contains("()"))
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
else if (path.Contains("{}") && !path.EndsWith(".json"))
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
else if (path.Contains("[]") && !path.EndsWith(".json"))
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{')
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[')
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
else
|
||||||
|
File.WriteAllText(path, contents);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
|
||||||
|
{
|
||||||
|
Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
||||||
|
if (jsonGroups is not null)
|
||||||
|
{
|
||||||
|
DateTime dateTime = DateTime.Now;
|
||||||
|
ReadOnlyCollection<int> years = GetYears(resultSettings);
|
||||||
|
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>? k;
|
||||||
|
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime);
|
||||||
|
foreach (int year in years)
|
||||||
|
{
|
||||||
|
results.Add(year, []);
|
||||||
|
if (!results.TryGetValue(year, out k))
|
||||||
|
throw new NullReferenceException(nameof(k));
|
||||||
|
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
||||||
|
k.Add(keyValuePair.Key, keyValuePair.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Convert(results);
|
||||||
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings)
|
private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings)
|
||||||
{
|
{
|
||||||
List<int> results = [];
|
List<int> results = [];
|
||||||
@ -337,44 +392,6 @@ internal abstract class XPath
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] GetBytes() =>
|
|
||||||
[
|
|
||||||
11,
|
|
||||||
15,
|
|
||||||
19,
|
|
||||||
51,
|
|
||||||
55,
|
|
||||||
59,
|
|
||||||
91,
|
|
||||||
95,
|
|
||||||
99
|
|
||||||
];
|
|
||||||
|
|
||||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
|
|
||||||
{
|
|
||||||
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
|
||||||
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
|
||||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
|
||||||
return results.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
|
|
||||||
{
|
|
||||||
Dictionary<byte, List<string>> results = [];
|
|
||||||
List<string>? c;
|
|
||||||
foreach (CombinedEnumAndIndex cei in collection)
|
|
||||||
{
|
|
||||||
if (!results.TryGetValue(cei.Enum, out c))
|
|
||||||
{
|
|
||||||
results.Add(cei.Enum, []);
|
|
||||||
if (!results.TryGetValue(cei.Enum, out c))
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
c.Add(cei.Combined);
|
|
||||||
}
|
|
||||||
return Convert(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime)
|
private static ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups, DateTime dateTime)
|
||||||
{
|
{
|
||||||
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
||||||
@ -428,33 +445,25 @@ internal abstract class XPath
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs)
|
private static byte[] GetBytes() =>
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9
|
||||||
|
];
|
||||||
|
|
||||||
|
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(Dictionary<byte, List<string>> keyValuePairs)
|
||||||
{
|
{
|
||||||
Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
||||||
foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
||||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
|
|
||||||
{
|
|
||||||
Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
|
||||||
if (jsonGroups is not null)
|
|
||||||
{
|
|
||||||
DateTime dateTime = DateTime.Now;
|
|
||||||
ReadOnlyCollection<int> years = GetYears(resultSettings);
|
|
||||||
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>? k;
|
|
||||||
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups, dateTime);
|
|
||||||
foreach (int year in years)
|
|
||||||
{
|
|
||||||
results.Add(year, []);
|
|
||||||
if (!results.TryGetValue(year, out k))
|
|
||||||
throw new NullReferenceException(nameof(k));
|
|
||||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
|
|
||||||
k.Add(keyValuePair.Key, keyValuePair.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Convert(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -6,12 +6,9 @@ namespace View_by_Distance.Windows.Models;
|
|||||||
|
|
||||||
public record WindowsSettings(string Company,
|
public record WindowsSettings(string Company,
|
||||||
string? Host,
|
string? Host,
|
||||||
string[] IgnoreExtensions,
|
|
||||||
int MaxDegreeOfParallelism,
|
int MaxDegreeOfParallelism,
|
||||||
string? Page,
|
string? Page,
|
||||||
string[] SidecarExtensions,
|
string[] SidecarExtensions,
|
||||||
string[] ValidImageFormatExtensions,
|
|
||||||
string[] ValidVideoFormatExtensions,
|
|
||||||
bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings
|
bool VerifyOnly) : Shared.Models.Properties.IWindowsSettings
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using System.Text.Json;
|
|||||||
using View_by_Distance.Metadata.Models;
|
using View_by_Distance.Metadata.Models;
|
||||||
using View_by_Distance.Metadata.Models.Stateless;
|
using View_by_Distance.Metadata.Models.Stateless;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
using View_by_Distance.Shared.Models.Stateless;
|
using View_by_Distance.Shared.Models.Stateless;
|
||||||
using View_by_Distance.Windows.Models;
|
using View_by_Distance.Windows.Models;
|
||||||
|
|
||||||
@ -21,48 +20,93 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
private ProgressBar? _ProgressBar;
|
private ProgressBar? _ProgressBar;
|
||||||
private readonly ProgressBarOptions _ProgressBarOptions;
|
private readonly ProgressBarOptions _ProgressBarOptions;
|
||||||
|
|
||||||
public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
|
||||||
|
GetDeterministicHashCode(httpClient, uri);
|
||||||
|
|
||||||
|
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
|
||||||
{
|
{
|
||||||
if (isSilent)
|
DeterministicHashCode result;
|
||||||
{ }
|
if (httpClient is not null)
|
||||||
if (args is null)
|
result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
|
||||||
throw new NullReferenceException(nameof(args));
|
else
|
||||||
if (console is null)
|
{
|
||||||
throw new NullReferenceException(nameof(console));
|
Stream stream = File.OpenRead(filePath.FullName);
|
||||||
IWindows windows = this;
|
result = GetDeterministicHashCode(stream);
|
||||||
long ticks = DateTime.Now.Ticks;
|
stream.Dispose();
|
||||||
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
}
|
||||||
WindowsWork(logger, appSettings, windows, ticks);
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri)
|
||||||
|
{
|
||||||
|
DeterministicHashCode result;
|
||||||
|
Stream stream = GetStream(httpClient, uri);
|
||||||
|
result = GetDeterministicHashCode(stream);
|
||||||
|
stream.Dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream GetStream(HttpClient httpClient, Uri uri)
|
||||||
|
{
|
||||||
|
Stream result;
|
||||||
|
Task<Stream> task = httpClient.GetStreamAsync(uri);
|
||||||
|
task.Wait();
|
||||||
|
result = task.Result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
|
||||||
|
{
|
||||||
|
DeterministicHashCode result;
|
||||||
|
int? id;
|
||||||
|
int? width;
|
||||||
|
int? height;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
using Image image = Image.FromStream(stream);
|
||||||
|
width = image.Width;
|
||||||
|
height = image.Height;
|
||||||
|
using Bitmap bitmap = new(image);
|
||||||
|
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
||||||
|
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||||
|
IntPtr intPtr = bitmapData.Scan0;
|
||||||
|
int length = bitmapData.Stride * bitmap.Height;
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
Marshal.Copy(intPtr, bytes, 0, length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
id = IId.GetDeterministicHashCode(bytes);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
id = null;
|
||||||
|
width = null;
|
||||||
|
height = null;
|
||||||
|
}
|
||||||
|
result = new(height, id, width);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IWindows.Tick() =>
|
void IWindows.Tick() =>
|
||||||
_ProgressBar?.Tick();
|
_ProgressBar?.Tick();
|
||||||
|
|
||||||
void IWindows.ConstructProgressBar(int maxTicks, string message)
|
|
||||||
{
|
|
||||||
_ProgressBar?.Dispose();
|
|
||||||
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDisposable.Dispose()
|
void IDisposable.Dispose()
|
||||||
{
|
{
|
||||||
_ProgressBar?.Dispose();
|
_ProgressBar?.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DownloadFile(HttpClient httpClient, FilePath filePath)
|
void IWindows.ConstructProgressBar(int maxTicks, string message)
|
||||||
{
|
{
|
||||||
FileStream fileStream = new(filePath.FullName, FileMode.Truncate);
|
_ProgressBar?.Dispose();
|
||||||
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
|
_ProgressBar = new(maxTicks, message, _ProgressBarOptions);
|
||||||
httpResponseMessage.Wait();
|
|
||||||
Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
|
|
||||||
task.Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath)
|
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(ResultSettings resultSettings, HttpClient? httpClient, FilePath filePath)
|
||||||
{
|
{
|
||||||
List<string> results = [];
|
List<string> results = [];
|
||||||
bool isValidVideoFormatExtensions = WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
bool isValidVideoFormatExtensions = resultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered);
|
||||||
if (isValidVideoFormatExtensions)
|
if (isValidVideoFormatExtensions)
|
||||||
{
|
{
|
||||||
bool check;
|
bool check;
|
||||||
@ -94,75 +138,54 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
private static void DownloadFile(HttpClient httpClient, FilePath filePath)
|
||||||
|
|
||||||
private static DeterministicHashCode GetDeterministicHashCode(Stream stream)
|
|
||||||
{
|
{
|
||||||
DeterministicHashCode result;
|
FileStream fileStream = new(filePath.FullName, FileMode.Truncate);
|
||||||
int? id;
|
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
|
||||||
int? width;
|
httpResponseMessage.Wait();
|
||||||
int? height;
|
Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
|
||||||
try
|
|
||||||
{
|
|
||||||
using Image image = Image.FromStream(stream);
|
|
||||||
width = image.Width;
|
|
||||||
height = image.Height;
|
|
||||||
using Bitmap bitmap = new(image);
|
|
||||||
Rectangle rectangle = new(0, 0, image.Width, image.Height);
|
|
||||||
BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
|
||||||
IntPtr intPtr = bitmapData.Scan0;
|
|
||||||
int length = bitmapData.Stride * bitmap.Height;
|
|
||||||
byte[] bytes = new byte[length];
|
|
||||||
Marshal.Copy(intPtr, bytes, 0, length);
|
|
||||||
bitmap.UnlockBits(bitmapData);
|
|
||||||
id = IId.GetDeterministicHashCode(bytes);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
id = null;
|
|
||||||
width = null;
|
|
||||||
height = null;
|
|
||||||
}
|
|
||||||
result = new(height, id, width);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Stream GetStream(HttpClient httpClient, Uri uri)
|
|
||||||
{
|
|
||||||
Stream result;
|
|
||||||
Task<Stream> task = httpClient.GetStreamAsync(uri);
|
|
||||||
task.Wait();
|
task.Wait();
|
||||||
result = task.Result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DeterministicHashCode GetDeterministicHashCode(HttpClient httpClient, Uri uri)
|
public Windows(List<string> args, ILogger<Program>? logger, AppSettings appSettings, bool isSilent, IConsole console)
|
||||||
{
|
{
|
||||||
DeterministicHashCode result;
|
if (isSilent)
|
||||||
Stream stream = GetStream(httpClient, uri);
|
{ }
|
||||||
result = GetDeterministicHashCode(stream);
|
if (args is null)
|
||||||
stream.Dispose();
|
throw new NullReferenceException(nameof(args));
|
||||||
return result;
|
if (console is null)
|
||||||
|
throw new NullReferenceException(nameof(console));
|
||||||
|
IWindows windows = this;
|
||||||
|
long ticks = DateTime.Now.Ticks;
|
||||||
|
_ProgressBarOptions = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
WindowsWork(logger, appSettings, windows, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient httpClient, Uri uri) =>
|
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
|
||||||
GetDeterministicHashCode(httpClient, uri);
|
|
||||||
|
|
||||||
DeterministicHashCode IWindows.GetDeterministicHashCode(HttpClient? httpClient, FilePath filePath)
|
|
||||||
{
|
{
|
||||||
DeterministicHashCode result;
|
if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||||
if (httpClient is not null)
|
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||||
result = GetDeterministicHashCode(httpClient, new Uri(filePath.FullName));
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stream stream = File.OpenRead(filePath.FullName);
|
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||||
result = GetDeterministicHashCode(stream);
|
WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
|
||||||
stream.Dispose();
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CA1416
|
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page)
|
||||||
|
{
|
||||||
|
List<string> messages = [];
|
||||||
|
HttpClient httpClient = new();
|
||||||
|
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||||
|
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception();
|
||||||
|
windows.ConstructProgressBar(collection.Count, nameof(Verify));
|
||||||
|
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
||||||
|
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages));
|
||||||
|
httpClient.Dispose();
|
||||||
|
foreach (string message in messages)
|
||||||
|
logger?.LogWarning("{message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<NginxFileSystem>? GetRecursiveCollection(HttpClient httpClient, string host, string page)
|
private static ReadOnlyCollection<NginxFileSystem>? GetRecursiveCollection(HttpClient httpClient, string host, string page)
|
||||||
{
|
{
|
||||||
@ -227,19 +250,46 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})");
|
messages.Add($"!{nginxFileSystem.Name}.StartsWith({paddedId})");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Verify(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, string host, string page)
|
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
|
||||||
{
|
{
|
||||||
List<string> messages = [];
|
ReadOnlyCollection<FirstPass> results;
|
||||||
HttpClient httpClient = new();
|
if (!Directory.Exists(sourceDirectory))
|
||||||
|
_ = Directory.CreateDirectory(sourceDirectory);
|
||||||
|
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||||
|
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||||
|
if (files.Count > 0)
|
||||||
|
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||||
|
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(httpClient, host, page) ?? throw new Exception();
|
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||||
windows.ConstructProgressBar(collection.Count, nameof(Verify));
|
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||||
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata);
|
||||||
VerifyParallelFor(appSettings, windows, httpClient, collection[i], messages));
|
else
|
||||||
httpClient.Dispose();
|
results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
|
||||||
foreach (string message in messages)
|
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||||
logger?.LogWarning("{message}", message);
|
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
|
||||||
|
{
|
||||||
|
List<FirstPass> results = [];
|
||||||
|
int index = -1;
|
||||||
|
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
|
||||||
|
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
||||||
|
keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||||
|
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
|
||||||
|
}
|
||||||
|
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||||
|
{
|
||||||
|
if (keyValuePair.Value.Count > 2)
|
||||||
|
throw new NotSupportedException("Too many sidecar files!");
|
||||||
|
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
|
||||||
|
}
|
||||||
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<NginxFileSystem> GetRecursiveCollection(string host, string page)
|
private static ReadOnlyCollection<NginxFileSystem> GetRecursiveCollection(string host, string page)
|
||||||
@ -270,7 +320,7 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
{
|
{
|
||||||
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
continue;
|
continue;
|
||||||
if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
if (appSettings.ResultSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||||
continue;
|
continue;
|
||||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result);
|
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result);
|
||||||
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||||
@ -285,7 +335,7 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath);
|
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.ResultSettings, httpClient, filePath);
|
||||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result);
|
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result);
|
||||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||||
}
|
}
|
||||||
@ -310,7 +360,7 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||||
}
|
}
|
||||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||||
results.Add(firstPass);
|
results.Add(firstPass);
|
||||||
@ -318,27 +368,6 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<FirstPass> WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
|
|
||||||
{
|
|
||||||
List<FirstPass> results = [];
|
|
||||||
int index = -1;
|
|
||||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
|
|
||||||
if (string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
|
||||||
keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReadOnlyCollection<NginxFileSystem> collection = GetRecursiveCollection(appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
|
||||||
keyValuePairs = IMetadata.GetKeyValuePairs(collection);
|
|
||||||
}
|
|
||||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
|
||||||
{
|
|
||||||
if (keyValuePair.Value.Count > 2)
|
|
||||||
throw new NotSupportedException("Too many sidecar files!");
|
|
||||||
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
|
|
||||||
}
|
|
||||||
return results.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
|
private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
|
||||||
{
|
{
|
||||||
List<FirstPass> results = [];
|
List<FirstPass> results = [];
|
||||||
@ -346,12 +375,12 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
List<string> distinct = [];
|
List<string> distinct = [];
|
||||||
List<MetadataGroup> metadataGroups = [];
|
List<MetadataGroup> metadataGroups = [];
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups));
|
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, metadata, distinct, metadataGroups));
|
||||||
if (_ProgressBar?.CurrentTick != results.Count)
|
if (_ProgressBar?.CurrentTick != results.Count)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||||
{
|
{
|
||||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.ResultSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||||
else
|
else
|
||||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||||
@ -360,36 +389,4 @@ public partial class Windows : IWindows, IDisposable
|
|||||||
return results.AsReadOnly();
|
return results.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks, string sourceDirectory)
|
|
||||||
{
|
|
||||||
ReadOnlyCollection<FirstPass> results;
|
|
||||||
if (!Directory.Exists(sourceDirectory))
|
|
||||||
_ = Directory.CreateDirectory(sourceDirectory);
|
|
||||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
|
||||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
|
||||||
if (files.Count > 0)
|
|
||||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
|
||||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
|
||||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
|
||||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
|
||||||
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
|
||||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
|
||||||
results = WindowsSynchronousWork(logger, appSettings, windows, files, metadata);
|
|
||||||
else
|
|
||||||
results = WindowsAsynchronousWork(appSettings, windows, files, metadata, appSettingsMaxDegreeOfParallelism);
|
|
||||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
|
||||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WindowsWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, long ticks)
|
|
||||||
{
|
|
||||||
if (appSettings.WindowsSettings.VerifyOnly && !string.IsNullOrEmpty(appSettings.WindowsSettings.Host) && !string.IsNullOrEmpty(appSettings.WindowsSettings.Page))
|
|
||||||
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
|
||||||
WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user