Ready to test DownloadFile
DirectoryDictionary Add http file .7-Question JustMediaDate CombinedEnumAndIndex
This commit is contained in:
parent
ef4672aaf0
commit
c15c854481
2
.gitignore
vendored
2
.gitignore
vendored
@ -475,4 +475,4 @@ Rename/.vscode/.UserSecrets/secrets.json
|
||||
Rename/.vscode/.UserSecretsOld/rename.json
|
||||
Rename/.vscode/.UserSecretsOld/secrets.json
|
||||
Windows/.vscode/.UserSecrets/secrets.json
|
||||
Windows/.vscode/.iCloudPhotos2025
|
||||
Windows/.vscode/.7-Question
|
@ -20,16 +20,16 @@ public record AppSettings(ResultSettings ResultSettings,
|
||||
|
||||
private static void Verify(AppSettings appSettings)
|
||||
{
|
||||
if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeDaysDeltaTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDaysDeltaTolerance));
|
||||
if (appSettings.DistanceSettings.RangeDistanceTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeDistanceTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeDistanceTolerance));
|
||||
if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeFaceAreaTolerance.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceAreaTolerance));
|
||||
if (appSettings.DistanceSettings.RangeFaceConfidence.Length != 3)
|
||||
if (appSettings.DistanceSettings.RangeFaceConfidence.Length is not 3 and not 6)
|
||||
throw new NullReferenceException(nameof(appSettings.DistanceSettings.RangeFaceConfidence));
|
||||
_ = DateTime.Now.AddDays(-appSettings.DistanceSettings.RangeDaysDeltaTolerance[1]);
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Length > 0)
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && appSettings.PeopleSettings.JLinks.Where(l => !string.IsNullOrEmpty(l)).Any())
|
||||
throw new Exception("Settings has SaveSortingWithoutPerson and JLinks!");
|
||||
if (appSettings.DistanceSettings.SaveSortingWithoutPerson && !string.IsNullOrEmpty(appSettings.DistanceSettings.FocusModel))
|
||||
throw new Exception("Settings has SaveSortingWithoutPerson and FocusModel!");
|
||||
|
@ -72,16 +72,16 @@ internal static class FilterLogicD
|
||||
internal static string GetResizeContentDirectory(ResultSettings resultSettings, string cContentDirectory, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(cContentDirectory, directoryName);
|
||||
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;
|
||||
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension);
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ public class A_Metadata
|
||||
|
||||
private readonly ResultSettings _ResultSettings;
|
||||
private readonly MetadataSettings _MetadataSettings;
|
||||
private readonly ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> _FileGroups;
|
||||
private readonly ReadOnlyDictionary<int, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> _ResultSingletonFileGroups;
|
||||
|
||||
public A_Metadata(ResultSettings resultSettings, MetadataSettings metadataSettings)
|
||||
{
|
||||
@ -23,16 +23,28 @@ public class A_Metadata
|
||||
includeResizeGroup: false,
|
||||
includeModel: false,
|
||||
includePredictorModel: false);
|
||||
_FileGroups = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]);
|
||||
Dictionary<int, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs = IPath.GetKeyValuePairs(resultSettings, aResultsFullGroupDirectory, [resultSettings.ResultSingleton]);
|
||||
foreach (KeyValuePair<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValue in keyValuePair.Value)
|
||||
{
|
||||
if (keyValue.Key == resultSettings.ResultSingleton)
|
||||
results.Add(keyValuePair.Key, keyValue.Value);
|
||||
else
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
_ResultSingletonFileGroups = new(results);
|
||||
}
|
||||
|
||||
private MinimumYearAndPathCombined GetMinimumYearAndPathCombined(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
MinimumYearAndPathCombined result;
|
||||
(_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
DateTime minimumDateTime = new(filePath.CreationTicks < filePath.LastWriteTicks ? filePath.CreationTicks : filePath.LastWriteTicks);
|
||||
int minimumYear = minimumDateTime.Year < resultSettings.EpicYear ? resultSettings.EpicYear : minimumDateTime.Year;
|
||||
result = new(minimumYear, Path.Combine(_FileGroups[minimumYear][_ResultSettings.ResultSingleton][directoryIndex], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"));
|
||||
result = new(minimumYear, Path.Combine(_ResultSingletonFileGroups[minimumYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -42,9 +54,9 @@ public class A_Metadata
|
||||
DateTime? dateTime;
|
||||
dateTime = IDate.GetDateTimeOriginal(exifDirectory);
|
||||
dateTime ??= IDate.GetMinimum(exifDirectory);
|
||||
(_, int directoryIndex) = IPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
int exifYear = dateTime.Value.Year < resultSettings.EpicYear ? resultSettings.EpicYear : dateTime.Value.Year;
|
||||
result = Path.Combine(_FileGroups[exifYear][_ResultSettings.ResultSingleton][directoryIndex], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json");
|
||||
result = Path.Combine(_ResultSingletonFileGroups[exifYear][cei.Enum][cei.Index], $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}.json");
|
||||
return new(exifYear, result);
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,14 @@ namespace View_by_Distance.Rename.Models;
|
||||
|
||||
public record RenameSettings(string Company,
|
||||
string DefaultMaker,
|
||||
Dictionary<string, string?> DirectoryDictionary,
|
||||
string? FirstPassFile,
|
||||
bool ForceNewId,
|
||||
string[] IgnoreExtensions,
|
||||
bool InPlace,
|
||||
bool InPlaceMoveDirectory,
|
||||
bool InPlaceWithOriginalName,
|
||||
bool JustMediaDate,
|
||||
int MaxDegreeOfParallelism,
|
||||
int MaxMilliSecondsPerCall,
|
||||
bool OnlySaveIdentifiersToDisk,
|
||||
|
242
Rename/Rename.cs
242
Rename/Rename.cs
@ -176,7 +176,7 @@ public partial class Rename : IRename, IDisposable
|
||||
JsonFile: minimumYearAndPathCombined.PathCombined);
|
||||
toDoCollection.AddRange(GetSidecarFiles(appSettings, record, [], checkDirectory, paddedId));
|
||||
}
|
||||
_ = RenameFilesInDirectories(appSettings.RenameSettings, rename, new(toDoCollection));
|
||||
_ = RenameFilesInDirectories(appSettings.RenameSettings, rename, toDoCollection.AsReadOnly());
|
||||
string jsonFile = Path.Combine(checkDirectory, $"{paddedId}{checkFileExtension}.json");
|
||||
File.Move(minimumYearAndPathCombined.PathCombined, jsonFile, overwrite: true);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName && ids.Count > 0)
|
||||
@ -189,12 +189,37 @@ public partial class Rename : IRename, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private List<FirstPass> GetFirstPassCollection(ILogger<Program>? logger, AppSettings appSettings, IRename rename, long ticks, ReadOnlyCollection<int> ids, IEnumerable<string> files, A_Metadata metadata)
|
||||
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)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
FilePath filePath;
|
||||
TimeSpan timeSpan;
|
||||
FirstPass firstPass;
|
||||
string directoryName;
|
||||
ExifDirectory exifDirectory;
|
||||
@ -204,7 +229,66 @@ public partial class Rename : IRename, IDisposable
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs = IMetadata.GetKeyValuePairs(files);
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (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;
|
||||
@ -217,57 +301,7 @@ public partial class Rename : IRename, IDisposable
|
||||
}
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.RenameSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.RenameSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (appSettings.RenameSettings.SkipIdFiles && filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (!appSettings.RenameSettings.ForceNewId && filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (appSettings.RenameSettings.InPlaceWithOriginalName || (appSettings.RenameSettings.InPlace && directoryName.EndsWith(filePath.Id.Value.ToString())))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = rename.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.RenameSettings, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? rename.GetDeterministicHashCode(filePath) : rename.GetDeterministicHashCode(fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (appSettings.RenameSettings.InPlace || appSettings.RenameSettings.InPlaceWithOriginalName)
|
||||
NonParallelismAndInPlace(appSettings, rename, ids, exifDirectory, minimumYearAndPathCombined, fastForwardMovingPictureExpertsGroupUsed, sidecarFiles.ToArray());
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.RenameSettings.InPlaceMoveDirectory && appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
SetFirstPassCollection(logger, appSettings, rename, ids, metadata, index, keyValuePair, results);
|
||||
timeSpan = new(DateTime.Now.Ticks - ticks);
|
||||
if (timeSpan.TotalMilliseconds > appSettings.RenameSettings.MaxMilliSecondsPerCall)
|
||||
break;
|
||||
@ -302,49 +336,61 @@ public partial class Rename : IRename, IDisposable
|
||||
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)
|
||||
{
|
||||
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;
|
||||
FirstPass firstPass;
|
||||
List<FirstPass> collection;
|
||||
string? checkFile = string.IsNullOrEmpty(appSettings.RenameSettings.FirstPassFile) ? null : Path.Combine(sourceDirectory, appSettings.RenameSettings.FirstPassFile);
|
||||
if (!string.IsNullOrEmpty(checkFile) && File.Exists(checkFile))
|
||||
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
|
||||
{
|
||||
collection = [];
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.RenameSettings.MaxDegreeOfParallelism;
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
rename.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
collection.AddRange(GetFirstPassCollection(logger, appSettings, rename, ticks, ids, files, metadata));
|
||||
else
|
||||
{
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(rename, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.RenameSettings, metadata, distinct, metadataGroups));
|
||||
Thread.Sleep(500);
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.RenameSettings.InPlaceMoveDirectory || !appSettings.RenameSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
collection.Add(firstPass);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(checkFile))
|
||||
{
|
||||
string json = JsonSerializer.Serialize(collection, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
}
|
||||
}
|
||||
results = GetRecordCollection(appSettings, collection);
|
||||
results = GetRecordCollection(appSettings, collection);
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -381,6 +427,7 @@ public partial class Rename : IRename, IDisposable
|
||||
{
|
||||
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;
|
||||
@ -389,7 +436,14 @@ public partial class Rename : IRename, IDisposable
|
||||
string? splat = checkDirectoryName.Length > 3 && checkDirectoryName[^3..][1] == '!' ? checkDirectoryName[^3..] : null;
|
||||
string contains = record.ExifDirectory.FilePath.Id is null || ids.Contains(record.ExifDirectory.FilePath.Id.Value) ? "_ Exists _" : "_ New-Destination _";
|
||||
string makerSplit = string.IsNullOrEmpty(maker) ? string.IsNullOrEmpty(appSettings.RenameSettings.DefaultMaker) ? string.Empty : appSettings.RenameSettings.DefaultMaker : $" {maker.Split(' ')[0]}";
|
||||
string directoryName = GetDirectoryName(year, tfw, segments[0], splat, seasonValue, seasonName, makerSplit);
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -460,9 +514,9 @@ public partial class Rename : IRename, IDisposable
|
||||
string checkFile;
|
||||
FilePath filePath;
|
||||
FileInfo[] matches;
|
||||
string directoryName;
|
||||
FileHolder fileHolder;
|
||||
string? checkDirectory;
|
||||
CombinedEnumAndIndex cei;
|
||||
const string jpg = ".jpg";
|
||||
string checkFileExtension;
|
||||
List<string> distinct = [];
|
||||
@ -493,8 +547,8 @@ public partial class Rename : IRename, IDisposable
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
}
|
||||
(directoryName, _) = IPath.GetDirectoryNameAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath);
|
||||
jsonFile = Path.Combine(jsonFileSubDirectory, directoryName, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json");
|
||||
cei = IPath.GetCombinedEnumAndIndex(appSettings.ResultSettings, record.ExifDirectory.FilePath);
|
||||
jsonFile = Path.Combine(jsonFileSubDirectory, cei.Combined, $"{record.ExifDirectory.FilePath.Id.Value}{checkFileExtension}.json");
|
||||
if (record.JsonFile != jsonFile)
|
||||
{
|
||||
fileHolder = FileHolder.Get(record.JsonFile);
|
||||
|
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
23
Shared/Models/CombinedEnumAndIndex.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models;
|
||||
|
||||
public record CombinedEnumAndIndex(string Combined,
|
||||
byte Enum,
|
||||
int Index)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, CombinedEnumAndIndexSourceGenerationContext.Default.CombinedEnumAndIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(CombinedEnumAndIndex))]
|
||||
internal partial class CombinedEnumAndIndexSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -61,14 +61,14 @@ public interface IPath
|
||||
static string GetDirectory(string sourceDirectory, int level, string directoryName) =>
|
||||
XPath.GetDirectory(sourceDirectory, level, directoryName);
|
||||
|
||||
(string, int) TestStatic_GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
XPath.GetDirectoryNameAndIndex(resultSettings, filePath);
|
||||
CombinedEnumAndIndex TestStatic_GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath) =>
|
||||
XPath.GetCombinedEnumAndIndex(resultSettings, filePath);
|
||||
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> TestStatic_GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups) =>
|
||||
XPath.GetKeyValuePairs(resultSettings, resultsFullGroupDirectory, jsonGroups);
|
||||
|
||||
}
|
@ -82,13 +82,15 @@ internal abstract class XDate
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
check = Path.GetDirectoryName(check);
|
||||
if (string.IsNullOrEmpty(check) || check == directoryInfo.FullName)
|
||||
if (string.IsNullOrEmpty(check))
|
||||
break;
|
||||
directoryName = Path.GetFileName(check);
|
||||
directorySegments = directoryName.Split(' ');
|
||||
(result, results) = IsWrongYear(directorySegments, year);
|
||||
if (result is not null)
|
||||
break;
|
||||
if (check == directoryInfo.FullName)
|
||||
break;
|
||||
}
|
||||
if (result is not null && !result.Value)
|
||||
break;
|
||||
|
@ -265,40 +265,64 @@ internal abstract class XPath
|
||||
}
|
||||
}
|
||||
|
||||
private static (string, int) GetDirectoryNameAndIndex(int resultAllInOneSubdirectoryLength, string fileNameWithoutExtension)
|
||||
private static byte GetEnum(bool? ik, bool? dto)
|
||||
{
|
||||
byte result;
|
||||
if (ik is not null && ik.Value && dto is not null && dto.Value)
|
||||
result = 11;
|
||||
else if (ik is not null && ik.Value && dto is not null && !dto.Value)
|
||||
result = 15;
|
||||
else if (ik is not null && ik.Value && dto is null)
|
||||
result = 19;
|
||||
else if (ik is not null && !ik.Value && dto is not null && dto.Value)
|
||||
result = 51;
|
||||
else if (ik is not null && !ik.Value && dto is not null && !dto.Value)
|
||||
result = 55;
|
||||
else if (ik is not null && !ik.Value && dto is null)
|
||||
result = 59;
|
||||
else if (ik is null && dto is not null && dto.Value)
|
||||
result = 91;
|
||||
else if (ik is null && dto is not null && !dto.Value)
|
||||
result = 95;
|
||||
else if (ik is null && dto is null)
|
||||
result = 99;
|
||||
else
|
||||
throw new Exception();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CombinedEnumAndIndex GetCombinedEnumAndIndex(int resultAllInOneSubdirectoryLength, FilePath filePath, string fileNameWithoutExtension)
|
||||
{
|
||||
CombinedEnumAndIndex result;
|
||||
int converted;
|
||||
string result;
|
||||
string combined;
|
||||
string fileNameBeforeFirst = fileNameWithoutExtension.Split('.')[0];
|
||||
string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ? new('-', resultAllInOneSubdirectoryLength) : fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..];
|
||||
byte @enum = GetEnum(filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal);
|
||||
string check = fileNameBeforeFirst.Length < resultAllInOneSubdirectoryLength ?
|
||||
new('-', resultAllInOneSubdirectoryLength) :
|
||||
fileNameBeforeFirst[^resultAllInOneSubdirectoryLength..];
|
||||
if (check.Any(l => !char.IsNumber(l)))
|
||||
{
|
||||
result = new('-', resultAllInOneSubdirectoryLength);
|
||||
combined = $"{@enum}{new('-', resultAllInOneSubdirectoryLength)}";
|
||||
converted = int.Parse($"1{new string('0', resultAllInOneSubdirectoryLength)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = check;
|
||||
combined = $"{@enum}{check}";
|
||||
converted = int.Parse(check);
|
||||
}
|
||||
return new(result, converted);
|
||||
result = new(combined, @enum, converted);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, int id)
|
||||
internal static CombinedEnumAndIndex GetCombinedEnumAndIndex(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
(string result, int converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, id.ToString());
|
||||
return new(result, converted);
|
||||
}
|
||||
|
||||
internal static (string, int) GetDirectoryNameAndIndex(ResultSettings resultSettings, FilePath filePath)
|
||||
{
|
||||
string result;
|
||||
int converted;
|
||||
CombinedEnumAndIndex result;
|
||||
if (filePath.Id is not null)
|
||||
(result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.Id.Value.ToString());
|
||||
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.Id.Value.ToString());
|
||||
else
|
||||
(result, converted) = GetDirectoryNameAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath.NameWithoutExtension);
|
||||
return new(result, converted);
|
||||
result = GetCombinedEnumAndIndex(resultSettings.ResultAllInOneSubdirectoryLength, filePath, filePath.NameWithoutExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetYears(ResultSettings resultSettings)
|
||||
@ -310,62 +334,121 @@ internal abstract class XPath
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> Convert(Dictionary<int, Dictionary<string, string[]>> collection)
|
||||
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<int, ReadOnlyDictionary<string, string[]>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<string, string[]>> keyValuePair in collection)
|
||||
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
||||
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<string, string[]>> GetKeyValuePairs(ResultSettings resultSettings, string? resultsFullGroupDirectory, string[]? jsonGroups)
|
||||
private static ReadOnlyDictionary<byte, ReadOnlyCollection<string>> Convert(List<CombinedEnumAndIndex> collection)
|
||||
{
|
||||
Dictionary<int, Dictionary<string, string[]>> results = [];
|
||||
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)
|
||||
{
|
||||
Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> results = [];
|
||||
int plusOne;
|
||||
string directory;
|
||||
string checkDirectory;
|
||||
Dictionary<string, string[]>? keyValuePairs;
|
||||
ReadOnlyCollection<int> years = GetYears(resultSettings);
|
||||
CombinedEnumAndIndex cei;
|
||||
byte[] bytes = GetBytes();
|
||||
List<CombinedEnumAndIndex> collection = [];
|
||||
ReadOnlyDictionary<byte, ReadOnlyCollection<string>> keyValuePairs;
|
||||
int converted = int.Parse($"1{new string('0', resultSettings.ResultAllInOneSubdirectoryLength)}");
|
||||
int plusOne = converted + 1;
|
||||
List<string> collection = [];
|
||||
foreach (int year in years)
|
||||
if (jsonGroups is not null)
|
||||
{
|
||||
results.Add(year, []);
|
||||
if (!results.TryGetValue(year, out keyValuePairs))
|
||||
throw new NullReferenceException(nameof(keyValuePairs));
|
||||
if (jsonGroups is not null)
|
||||
plusOne = converted + 1;
|
||||
foreach (string jsonGroup in jsonGroups)
|
||||
{
|
||||
foreach (string jsonGroup in jsonGroups)
|
||||
if (resultsFullGroupDirectory is null)
|
||||
continue;
|
||||
foreach (byte @enum in bytes)
|
||||
{
|
||||
if (resultsFullGroupDirectory is null)
|
||||
continue;
|
||||
collection.Clear();
|
||||
for (int i = 0; i < plusOne; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonGroup))
|
||||
{
|
||||
if (i == converted)
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, new('-', resultSettings.ResultAllInOneSubdirectoryLength)));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}"));
|
||||
else
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(resultsFullGroupDirectory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
directory = Path.Combine(resultsFullGroupDirectory, jsonGroup);
|
||||
if (i == converted)
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, new('-', resultSettings.ResultAllInOneSubdirectoryLength)));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{new('-', resultSettings.ResultAllInOneSubdirectoryLength)}"));
|
||||
else
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')));
|
||||
checkDirectory = Path.GetFullPath(Path.Combine(directory, $"{@enum}{i.ToString().PadLeft(resultSettings.ResultAllInOneSubdirectoryLength, '0')}"));
|
||||
}
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
collection.Add(checkDirectory);
|
||||
cei = new(Combined: checkDirectory, Enum: @enum, Index: -1);
|
||||
collection.Add(cei);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(jsonGroup))
|
||||
keyValuePairs.Add(jsonGroup, collection.ToArray());
|
||||
else
|
||||
keyValuePairs.Add(year.ToString(), collection.ToArray());
|
||||
}
|
||||
keyValuePairs = Convert(collection);
|
||||
if (!string.IsNullOrEmpty(jsonGroup))
|
||||
results.Add(jsonGroup, keyValuePairs);
|
||||
else
|
||||
results.Add(dateTime.Ticks.ToString(), keyValuePairs);
|
||||
}
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> Convert(Dictionary<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> results = [];
|
||||
foreach (KeyValuePair<int, Dictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static 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);
|
||||
|
5
Windows/.vscode/11.http
vendored
Normal file
5
Windows/.vscode/11.http
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
@host = http://192.168.0.11:8080
|
||||
|
||||
GET {{host}}/iCloud%20Photos%202025
|
||||
|
||||
###
|
5
Windows/.vscode/mklink.md
vendored
Normal file
5
Windows/.vscode/mklink.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# mklink
|
||||
|
||||
```bash 1741014465915 = 638766112659150000 = 2025-0.Winter = Mon Mar 03 2025 08:07:45 GMT-0700 (Mountain Standard Time)
|
||||
mklink /J "L:\Git\AA\Windows\.vscode\.7-Question" "V:\7-Question"
|
||||
````
|
@ -50,6 +50,15 @@ public partial class Windows : IWindows, IDisposable
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private static void DownloadFile(HttpClient httpClient, FilePath filePath)
|
||||
{
|
||||
FileStream fileStream = new(filePath.FullName, FileMode.Truncate);
|
||||
Task<HttpResponseMessage> httpResponseMessage = httpClient.GetAsync(filePath.FullName);
|
||||
httpResponseMessage.Wait();
|
||||
Task task = httpResponseMessage.Result.Content.CopyToAsync(fileStream);
|
||||
task.Wait();
|
||||
}
|
||||
|
||||
ReadOnlyCollection<string> IWindows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(IWindowsSettings WindowsSettings, HttpClient? httpClient, FilePath filePath)
|
||||
{
|
||||
List<string> results = [];
|
||||
@ -57,6 +66,8 @@ public partial class Windows : IWindows, IDisposable
|
||||
if (isValidVideoFormatExtensions)
|
||||
{
|
||||
bool check;
|
||||
if (httpClient is not null)
|
||||
DownloadFile(httpClient, filePath);
|
||||
try
|
||||
{
|
||||
CommandTask<CommandResult> commandTask = Cli.Wrap("L:/Git/ffmpeg-2024-10-02-git-358fdf3083-full_build/bin/ffmpeg.exe")
|
||||
@ -240,10 +251,10 @@ public partial class Windows : IWindows, IDisposable
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<FirstPass> GetCollection(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, IEnumerable<string> files, A_Metadata metadata)
|
||||
private static int WindowsSynchronousWork(ILogger<Program>? logger, AppSettings appSettings, IWindows windows, A_Metadata metadata, List<FirstPass> results, int index, KeyValuePair<string, List<FileHolder>> keyValuePair)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
int index = -1;
|
||||
int result = index + 1;
|
||||
windows.Tick();
|
||||
FilePath filePath;
|
||||
FirstPass firstPass;
|
||||
string directoryName;
|
||||
@ -253,9 +264,65 @@ public partial class Windows : IWindows, IDisposable
|
||||
bool fastForwardMovingPictureExpertsGroupUsed;
|
||||
MinimumYearAndPathCombined minimumYearAndPathCombined;
|
||||
FilePath? fastForwardMovingPictureExpertsGroupFilePath;
|
||||
ReadOnlyDictionary<string, List<FileHolder>> keyValuePairs;
|
||||
ReadOnlyCollection<string>? fastForwardMovingPictureExpertsGroupFiles;
|
||||
HttpClient? httpClient = string.IsNullOrEmpty(appSettings.WindowsSettings.Host) || string.IsNullOrEmpty(appSettings.WindowsSettings.Page) ? null : new();
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, result);
|
||||
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (directoryName.EndsWith(filePath.Id.Value.ToString()))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), result);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
return 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
|
||||
@ -265,61 +332,53 @@ public partial class Windows : IWindows, IDisposable
|
||||
}
|
||||
foreach (KeyValuePair<string, List<FileHolder>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
index += 1;
|
||||
windows.Tick();
|
||||
if (keyValuePair.Value.Count > 2)
|
||||
throw new NotSupportedException("Too many sidecar files!");
|
||||
foreach (FileHolder fileHolder in keyValuePair.Value)
|
||||
{
|
||||
if (appSettings.WindowsSettings.SidecarExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
if (appSettings.WindowsSettings.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
|
||||
continue;
|
||||
filePath = FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, fileHolder, index);
|
||||
if (filePath.Id is not null && (filePath.IsIntelligentIdFormat || filePath.SortOrder is not null))
|
||||
continue;
|
||||
if (filePath.Id is not null)
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = null;
|
||||
deterministicHashCode = new(null, filePath.Id, null);
|
||||
directoryName = Path.GetFileName(filePath.DirectoryFullPath);
|
||||
if (directoryName.EndsWith(filePath.Id.Value.ToString()))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fastForwardMovingPictureExpertsGroupFiles = windows.ConvertAndGetFastForwardMovingPictureExpertsGroupFiles(appSettings.WindowsSettings, httpClient, filePath);
|
||||
fastForwardMovingPictureExpertsGroupFilePath = fastForwardMovingPictureExpertsGroupFiles.Count == 0 ? null : FilePath.Get(appSettings.ResultSettings, appSettings.MetadataSettings, FileHolder.Get(fastForwardMovingPictureExpertsGroupFiles[0]), index);
|
||||
deterministicHashCode = fastForwardMovingPictureExpertsGroupFilePath is null ? windows.GetDeterministicHashCode(httpClient, filePath) : windows.GetDeterministicHashCode(httpClient, fastForwardMovingPictureExpertsGroupFilePath);
|
||||
}
|
||||
sidecarFiles = [];
|
||||
filePath = FilePath.Get(filePath, deterministicHashCode);
|
||||
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
||||
{
|
||||
if (keyValuePair.Value[i].ExtensionLowered == fileHolder.ExtensionLowered)
|
||||
continue;
|
||||
sidecarFiles.Add(keyValuePair.Value[i]);
|
||||
}
|
||||
try
|
||||
{ (minimumYearAndPathCombined, exifDirectory) = metadata.GetMetadataCollection(appSettings.ResultSettings, appSettings.MetadataSettings, httpClient, filePath); }
|
||||
catch (Exception)
|
||||
{
|
||||
logger?.LogWarning("<{filePath}>", filePath.FullName);
|
||||
continue;
|
||||
}
|
||||
fastForwardMovingPictureExpertsGroupUsed = fastForwardMovingPictureExpertsGroupFiles is not null && fastForwardMovingPictureExpertsGroupFiles.Count > 0;
|
||||
if (fastForwardMovingPictureExpertsGroupUsed && fastForwardMovingPictureExpertsGroupFiles is not null)
|
||||
{
|
||||
foreach (string fastForwardMovingPictureExpertsGroupFile in fastForwardMovingPictureExpertsGroupFiles)
|
||||
File.Delete(fastForwardMovingPictureExpertsGroupFile);
|
||||
}
|
||||
if (!fastForwardMovingPictureExpertsGroupUsed && appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered))
|
||||
fastForwardMovingPictureExpertsGroupUsed = true;
|
||||
firstPass = new(exifDirectory, fastForwardMovingPictureExpertsGroupUsed, minimumYearAndPathCombined, sidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
index = WindowsSynchronousWork(logger, appSettings, windows, metadata, results, index, keyValuePair);
|
||||
}
|
||||
return results;
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private ReadOnlyCollection<FirstPass> WindowsAsynchronousWork(AppSettings appSettings, IWindows windows, ReadOnlyCollection<string> files, A_Metadata metadata, int appSettingsMaxDegreeOfParallelism)
|
||||
{
|
||||
List<FirstPass> results = [];
|
||||
FirstPass firstPass;
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups));
|
||||
if (_ProgressBar?.CurrentTick != results.Count)
|
||||
throw new NotSupportedException();
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
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)
|
||||
@ -328,40 +387,8 @@ public partial class Windows : IWindows, IDisposable
|
||||
Verify(logger, appSettings, windows, appSettings.WindowsSettings.Host, appSettings.WindowsSettings.Page);
|
||||
else
|
||||
{
|
||||
FirstPass firstPass;
|
||||
List<FirstPass> results = [];
|
||||
string sourceDirectory = Path.GetFullPath(appSettings.ResultSettings.RootDirectory);
|
||||
if (!Directory.Exists(sourceDirectory))
|
||||
_ = Directory.CreateDirectory(sourceDirectory);
|
||||
logger?.LogInformation("{Ticks} {RootDirectory}", ticks, sourceDirectory);
|
||||
ReadOnlyCollection<string> files = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray().AsReadOnly();
|
||||
if (files.Count > 0)
|
||||
_ = IPath.DeleteEmptyDirectories(appSettings.ResultSettings.RootDirectory);
|
||||
A_Metadata metadata = new(appSettings.ResultSettings, appSettings.MetadataSettings);
|
||||
int appSettingsMaxDegreeOfParallelism = appSettings.WindowsSettings.MaxDegreeOfParallelism;
|
||||
int filesCount = appSettingsMaxDegreeOfParallelism == 1 ? files.Count : 123000;
|
||||
windows.ConstructProgressBar(filesCount, "EnumerateFiles load");
|
||||
if (appSettingsMaxDegreeOfParallelism == 1)
|
||||
results.AddRange(GetCollection(logger, appSettings, windows, files, metadata));
|
||||
else
|
||||
{
|
||||
List<string> distinct = [];
|
||||
List<MetadataGroup> metadataGroups = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = appSettingsMaxDegreeOfParallelism };
|
||||
files.AsParallel().ForAll(IMetadata.SetExifDirectoryCollection(windows, appSettings.ResultSettings, appSettings.MetadataSettings, appSettings.WindowsSettings, metadata, distinct, metadataGroups));
|
||||
if (_ProgressBar?.CurrentTick != results.Count)
|
||||
throw new NotSupportedException();
|
||||
foreach (MetadataGroup metadataGroup in metadataGroups)
|
||||
{
|
||||
if (metadataGroup.FastForwardMovingPictureExpertsGroupUsed || !appSettings.WindowsSettings.ValidVideoFormatExtensions.Contains(metadataGroup.FilePath.ExtensionLowered))
|
||||
firstPass = new(metadataGroup.ExifDirectory, metadataGroup.FastForwardMovingPictureExpertsGroupUsed, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
else
|
||||
firstPass = new(metadataGroup.ExifDirectory, FastForwardMovingPictureExpertsGroupUsed: true, metadataGroup.MinimumYearAndPathCombined, metadataGroup.SidecarFiles.ToArray());
|
||||
results.Add(firstPass);
|
||||
}
|
||||
}
|
||||
string json = JsonSerializer.Serialize(results, FirstPassCollectionSourceGenerationContext.Default.ListFirstPass);
|
||||
File.WriteAllText(Path.Combine(sourceDirectory, $"{ticks}.json"), json);
|
||||
WindowsWork(logger, appSettings, windows, ticks, sourceDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user