using MetadataExtractor; using System.Collections.ObjectModel; using System.Text.Json; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Metadata.Models; /// // Dictionary>> /// public class B_Metadata : IMetadata { private readonly bool _PropertiesChangedForMetadata; private readonly IPropertyConfiguration _PropertyConfiguration; private readonly bool _ForceMetadataLastWriteTimeToCreationTime; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; private readonly ReadOnlyDictionary> _FileGroups; public B_Metadata(IPropertyConfiguration propertyConfiguration) { _PropertiesChangedForMetadata = false; _PropertyConfiguration = propertyConfiguration; _ForceMetadataLastWriteTimeToCreationTime = false; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, null, [propertyConfiguration.ResultSingleton]); } public B_Metadata(IPropertyConfiguration propertyConfiguration, bool forceMetadataLastWriteTimeToCreationTime, bool propertiesChangedForMetadata, string bResultsFullGroupDirectory) { _PropertyConfiguration = propertyConfiguration; _PropertiesChangedForMetadata = propertiesChangedForMetadata; _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, bResultsFullGroupDirectory, [propertyConfiguration.ResultSingleton]); } public override string ToString() { string result = JsonSerializer.Serialize(this, _WriteIndentedJsonSerializerOptions); return result; } public ExifDirectory GetMetadataCollection(FilePath filePath, List> subFileTuples, List parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem) { ExifDirectory? result = null; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); (_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath); FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json")); if (_ForceMetadataLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) { File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); fileInfo.Refresh(); } if (_ForceMetadataLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) { File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); fileInfo.Refresh(); } if (_PropertiesChangedForMetadata) result = null; else if (!fileInfo.Exists) result = null; else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old")) throw new ArgumentException("must be a *.json file"); else if (dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime) result = null; else { string json = File.ReadAllText(fileInfo.FullName); try { result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory); if (result is null) throw new Exception(); subFileTuples.Add(new Tuple(nameof(B_Metadata), fileInfo.LastWriteTime)); } catch (Exception) { result = null; parseExceptions.Add(nameof(B_Metadata)); } } if (result is null) { result = Stateless.Methods.IMetadata.GetExifDirectory(filePath); string json = JsonSerializer.Serialize(result, ExifDirectorySourceGenerationContext.Default.ExifDirectory); bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { if (!_ForceMetadataLastWriteTimeToCreationTime) subFileTuples.Add(new Tuple(nameof(B_Metadata), DateTime.Now)); else { File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); fileInfo.Refresh(); subFileTuples.Add(new Tuple(nameof(B_Metadata), fileInfo.CreationTime)); } } } return result; } (DateTime?, DateTime?[]) IMetadata.GetDateTimes(FilePath filePath, IReadOnlyList directories) { List results = []; DateTime? result = null; DateTime? dateTime; DateTime checkDateTime; string dateTimeFormat = Property.Models.Stateless.IProperty.DateTimeFormat(); MetadataExtractor.Formats.Exif.ExifDirectoryBase? exifDirectoryBase = directories.OfType().FirstOrDefault(); results.Add(new DateTime(filePath.CreationTicks)); results.Add(new DateTime(filePath.LastWriteTicks)); if (exifDirectoryBase is not null) { if (exifDirectoryBase.TryGetDateTime(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime, out checkDateTime)) results.Add(checkDateTime); else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime)); if (dateTime is not null) results.Add(dateTime.Value); } if (exifDirectoryBase.TryGetDateTime(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized, out checkDateTime)) results.Add(checkDateTime); else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized)); if (dateTime is not null) results.Add(dateTime.Value); } if (exifDirectoryBase.TryGetDateTime(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal, out checkDateTime)) { result ??= checkDateTime; results.Add(checkDateTime); } else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, exifDirectoryBase.GetString(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal)); if (dateTime is not null) { result ??= dateTime.Value; results.Add(dateTime.Value); } } } MetadataExtractor.Formats.Avi.AviDirectory? aviDirectory = directories.OfType().FirstOrDefault(); if (aviDirectory is not null) { if (aviDirectory.TryGetDateTime(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal, out checkDateTime)) { result ??= checkDateTime; results.Add(checkDateTime); } else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal)); if (dateTime is not null) { result ??= dateTime.Value; results.Add(dateTime.Value); } } } MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory? quickTimeMovieHeaderDirectory = directories.OfType().FirstOrDefault(); if (quickTimeMovieHeaderDirectory is not null) { if (quickTimeMovieHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated, out checkDateTime)) { result ??= checkDateTime; results.Add(checkDateTime); } else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated)); if (dateTime is not null) { result ??= dateTime.Value; results.Add(dateTime.Value); } } } MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory? quickTimeTrackHeaderDirectory = directories.OfType().FirstOrDefault(); if (quickTimeTrackHeaderDirectory is not null) { if (quickTimeTrackHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated, out checkDateTime)) { result ??= checkDateTime; results.Add(checkDateTime); } else { dateTime = Property.Models.Stateless.IProperty.GetDateTime(dateTimeFormat, quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated)); if (dateTime is not null) { result ??= dateTime.Value; results.Add(dateTime.Value); } } } return new(result, [.. results]); } }