diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index 4c3bd4442..254c8a075 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -30,44 +30,34 @@ namespace API.Controllers } [HttpGet("image")] - public async Task> GetImage(int chapterId, int page) + public async Task GetImage(int chapterId, int page) { - // Temp let's iterate the directory each call to get next image var chapter = await _cacheService.Ensure(chapterId); - if (chapter == null) return BadRequest("There was an issue finding image file for reading"); var (path, mangaFile) = await _cacheService.GetCachedPagePath(chapter, page); - if (string.IsNullOrEmpty(path)) return BadRequest($"No such image for page {page}"); - var file = await _directoryService.ReadImageAsync(path); - file.Page = page; - file.MangaFileName = mangaFile.FilePath; - file.NeedsSplitting = file.Width > file.Height; - - // TODO: Validate if sending page whole (not base64 encoded) fixes Tablet issue - //Response.Headers.Add("Transfer-Encoding", "gzip"); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {page}"); - return Ok(file); + var content = await _directoryService.ReadFileAsync(path); + var format = Path.GetExtension(path).Replace(".", ""); + + // Look into HttpContext.Cache so we can utilize a memorystream for Zip entries (want to limit response time by 300ms) + // Calculates SHA1 Hash for byte[] + using var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider(); + Response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(content).Select(x => x.ToString("X2")))); + Response.Headers.Add("Cache-Control", "private"); + + return File(content, "image/" + format); } - - [HttpGet("image2")] - public async Task GetImage2(int chapterId, int page) - { - // Temp let's iterate the directory each call to get next image - var chapter = await _cacheService.Ensure(chapterId); + [HttpGet("chapter-path")] + public async Task> GetImagePath(int chapterId) + { + var chapter = await _cacheService.Ensure(chapterId); if (chapter == null) return BadRequest("There was an issue finding image file for reading"); - var (path, mangaFile) = await _cacheService.GetCachedPagePath(chapter, page); - if (string.IsNullOrEmpty(path)) return BadRequest($"No such image for page {page}"); - var file = await _directoryService.ReadImageAsync(path); - file.Page = page; - file.MangaFileName = mangaFile.FilePath; - file.NeedsSplitting = file.Width > file.Height; - - // TODO: Validate if sending page whole (not base64 encoded) fixes Tablet issue - - return File(file.Content, "image/jpeg", mangaFile.FilePath); + var (path, mangaFile) = await _cacheService.GetCachedPagePath(chapter, 0); + return Ok(mangaFile.FilePath); } [HttpGet("get-bookmark")] diff --git a/API/Extensions/HttpExtensions.cs b/API/Extensions/HttpExtensions.cs index 468bac728..3d08cc94a 100644 --- a/API/Extensions/HttpExtensions.cs +++ b/API/Extensions/HttpExtensions.cs @@ -18,5 +18,6 @@ namespace API.Extensions response.Headers.Add("Pagination", JsonSerializer.Serialize(paginationHeader, options)); response.Headers.Add("Access-Control-Expose-Headers", "Pagination"); } + } } \ No newline at end of file diff --git a/API/Interfaces/Services/IDirectoryService.cs b/API/Interfaces/Services/IDirectoryService.cs index 93fbfd64f..c4b15b94b 100644 --- a/API/Interfaces/Services/IDirectoryService.cs +++ b/API/Interfaces/Services/IDirectoryService.cs @@ -13,8 +13,6 @@ namespace API.Interfaces.Services /// Absolute path of directory to scan. /// List of folder names IEnumerable ListDirectory(string rootPath); - - Task ReadImageAsync(string imagePath); /// /// Gets files in a directory. If searchPatternExpression is passed, will match the regex against for filtering. /// diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index cd1dead46..f1f4f5eb1 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -145,26 +145,6 @@ namespace API.Services return dirs; } - - public async Task ReadImageAsync(string imagePath) - { - if (!File.Exists(imagePath)) - { - _logger.LogError("Image does not exist on disk"); - return null; - } - using var image = Image.NewFromFile(imagePath); - - return new ImageDto - { - Content = await ReadFileAsync(imagePath), - Filename = Path.GetFileNameWithoutExtension(imagePath), - FullPath = Path.GetFullPath(imagePath), - Width = image.Width, - Height = image.Height, - Format = image.Format, - }; - } public async Task ReadFileAsync(string path) { diff --git a/API/Startup.cs b/API/Startup.cs index 8b59f2f12..4c3ce5de4 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -1,9 +1,12 @@ +using System.IO.Compression; +using System.Linq; using API.Extensions; using API.Middleware; using Hangfire; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -37,8 +40,20 @@ namespace API { c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" }); }); - - + // This doesn't seem to work. + // services.AddResponseCompression(options => + // { + // options.Providers.Add(); + // options.MimeTypes = + // ResponseCompressionDefaults.MimeTypes.Concat( + // new[] { "image/jpeg", "image/jpg" }); + // }); + // services.Configure(options => + // { + // options.Level = CompressionLevel.Fastest; + // }); + + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -62,6 +77,8 @@ namespace API { app.UseCors(policy => policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:4200")); } + + //app.UseResponseCaching(); app.UseAuthentication();