From f56f9db1612ace150a54d4e6754aa5d2adb5be6d Mon Sep 17 00:00:00 2001 From: Tobias Klika Date: Thu, 21 Mar 2024 13:34:35 +0100 Subject: [PATCH] add static media creator --- zero/Media/ImageDimensionReader.cs | 2 +- zero/Media/MediaCreator.cs | 4 +- zero/Media/Models/CachedMedia.cs | 70 ---------------------------- zero/Media/StaticMediaCreator.cs | 75 ++++++++++++++++++++++++++++++ zero/Media/ZeroMediaModule.cs | 2 +- 5 files changed, 79 insertions(+), 74 deletions(-) delete mode 100644 zero/Media/Models/CachedMedia.cs create mode 100644 zero/Media/StaticMediaCreator.cs diff --git a/zero/Media/ImageDimensionReader.cs b/zero/Media/ImageDimensionReader.cs index 263bd813..06ddf966 100644 --- a/zero/Media/ImageDimensionReader.cs +++ b/zero/Media/ImageDimensionReader.cs @@ -45,7 +45,7 @@ public class ImageDimensionReader : IImageDimensionReader MemoryCacheEntryOptions cacheEntryOptions = new(); cacheEntryOptions.AddExpirationToken(FileProvider.Watch(resolvedPath)); - //cacheEntryOptions.SetSize(value.Length * sizeof(char)); + cacheEntryOptions.SetSize(1); Cache.Set(path, value, cacheEntryOptions); return value; diff --git a/zero/Media/MediaCreator.cs b/zero/Media/MediaCreator.cs index 3a187e97..f8195c9b 100644 --- a/zero/Media/MediaCreator.cs +++ b/zero/Media/MediaCreator.cs @@ -22,7 +22,7 @@ public class MediaCreator : IMediaCreator /// - public async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) + public virtual async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) { string fileExtension = Path.GetExtension(filename); string normalizedFilename = Safenames.File(filename); @@ -92,7 +92,7 @@ public class MediaCreator : IMediaCreator /// - protected virtual MediaMetadata GetImageMetadata(Image image) + protected virtual MediaMetadata GetImageMetadata(IImageInfo image) { PngMetadata pngMetadata = image.Metadata.GetPngMetadata(); //WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata(); diff --git a/zero/Media/Models/CachedMedia.cs b/zero/Media/Models/CachedMedia.cs deleted file mode 100644 index 413d7173..00000000 --- a/zero/Media/Models/CachedMedia.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace zero.Media; - -/// -/// A cached media entity comes from the IMemoryCache -/// and is therefore reduced to only necessary properties -/// (Id, ParentId, Path, Metadata, AltText, Caption) -/// -public sealed class CachedMedia : Media -{ - internal static CachedMedia Create(MediaCacheEntry entry) - { - return new() - { - Id = entry.Id, - ParentId = entry.ParentId, - Path = entry.Path, - AltText = entry.AltText, - Caption = entry.Caption, - Metadata = entry.Metadata - }; - } -} - - -internal class MediaCacheEntry -{ - /// - /// Id of the entity - /// - public string Id { get; set; } - - /// - /// Id of the parent folder - /// - public string ParentId { get; set; } - - /// - /// Path of the media item - /// - public string Path { get; set; } - - /// - /// Alternative text which is used when the media can't be loaded - /// - public string AltText { get; set; } - - /// - /// Additional caption text - /// - public string Caption { get; set; } - - /// - /// Meta data for images/videos - /// - public MediaMetadata Metadata { get; set; } - - - internal static MediaCacheEntry Create(Media entry) - { - return new() - { - Id = entry.Id, - ParentId = entry.ParentId, - Path = entry.Path, - AltText = entry.AltText, - Caption = entry.Caption, - Metadata = entry.Metadata - }; - } -} \ No newline at end of file diff --git a/zero/Media/StaticMediaCreator.cs b/zero/Media/StaticMediaCreator.cs new file mode 100644 index 00000000..347627a2 --- /dev/null +++ b/zero/Media/StaticMediaCreator.cs @@ -0,0 +1,75 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.FileProviders; +using SixLabors.ImageSharp; +using System.IO; + +namespace zero.Media; + +public class StaticMediaCreator : MediaCreator, IStaticMediaCreator +{ + protected IMemoryCache Cache { get; set; } + + protected IFileProvider FileProvider { get; set; } + + + public StaticMediaCreator(IMediaFileSystem fileSystem, IZeroOptions options, IWebHostEnvironment hostingEnvironment, MediaMetadataCache cacheProvider) : base(fileSystem, options) + { + FileProvider = hostingEnvironment.WebRootFileProvider; + Cache = cacheProvider.Cache; + } + + + + /// + public virtual async Task> GetMedia(string path, CancellationToken cancellationToken = default) + { + if (Cache.TryGetValue(path, out Media media)) + { + return Result.Success(media); + } + + string filename = Path.GetFileName(path); + string fileExtension = Path.GetExtension(filename); + + bool isImage = Options.AllowedImageFileExtensions.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase); + bool isDocument = !isImage && Options.AllowedOtherFileExtensions.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase); + + if (!isImage && !isDocument) + { + return Result.Fail("This file type is not supported"); + } + + Media model = new(); + model.Name = filename; + model.Path = path; + model.IsFolder = false; + + // we need file metadata to get info about file size and the physical path for image modification + IFileMeta fileInfo = await FileSystem.GetFileInfo(model.Path, cancellationToken); + model.Size = fileInfo.Length; + + if (isImage) + { + IImageInfo info = await Image.IdentifyAsync(fileInfo.AbsolutePath, cancellationToken); + model.Metadata = GetImageMetadata(info); + } + + MemoryCacheEntryOptions cacheEntryOptions = new(); + cacheEntryOptions.AddExpirationToken(FileProvider.Watch(fileInfo.AbsolutePath)); + cacheEntryOptions.SetSize(1); + Cache.Set(path, model, cacheEntryOptions); + + return Result.Success(model); + } +} + + + +public interface IStaticMediaCreator +{ + /// + /// Builds a media file from a path + /// + Task> GetMedia(string path, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/zero/Media/ZeroMediaModule.cs b/zero/Media/ZeroMediaModule.cs index 48869e7a..fdb9571e 100644 --- a/zero/Media/ZeroMediaModule.cs +++ b/zero/Media/ZeroMediaModule.cs @@ -33,11 +33,11 @@ internal class ZeroMediaModule : ZeroModule { IOptions options = svc.GetRequiredService>(); IWebHostEnvironment env = svc.GetRequiredService(); - Console.WriteLine("media path: " + options.Value.FolderPath); return new(Path.Combine(env.WebRootPath, options.Value.FolderPath), options.Value.PublicPathPrefix + options.Value.FolderPath.EnsureStartsWith('/')); }); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton();