From d3b42081cb86170d013d5e7cd1fed53eeb60ccfe Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Fri, 12 Mar 2021 10:37:42 -0600 Subject: [PATCH] Enable response compression (br and gzip) for images and static assets. After we scan a library, kick of a cleanup of cache to ensure if archives were changed, the cache is cleared too. --- API/Controllers/ReaderController.cs | 40 +++++++++++++++++++++++++++++ API/DTOs/MarkVolumeReadDto.cs | 8 ++++++ API/Data/VolumeRepository.cs | 15 ++++++++++- API/Interfaces/IVolumeRepository.cs | 1 + API/Services/TaskScheduler.cs | 2 ++ API/Startup.cs | 27 ++++++++++--------- API/appsettings.Development.json | 3 ++- 7 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 API/DTOs/MarkVolumeReadDto.cs diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index 254c8a075..c9e441cdb 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -152,6 +152,46 @@ namespace API.Controllers return BadRequest("There was an issue saving progress"); } + [HttpPost("mark-volume-read")] + public async Task MarkVolumeAsRead(MarkVolumeReadDto markVolumeReadDto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + _logger.LogDebug("Saving {UserName} progress for Volume {VolumeID} to read", user.UserName, markVolumeReadDto.VolumeId); + + var chapters = await _unitOfWork.VolumeRepository.GetChaptersAsync(markVolumeReadDto.VolumeId); + foreach (var chapter in chapters) + { + user.Progresses ??= new List(); + var userProgress = user.Progresses.SingleOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); + + if (userProgress == null) + { + user.Progresses.Add(new AppUserProgress + { + PagesRead = chapter.Pages, + VolumeId = markVolumeReadDto.VolumeId, + SeriesId = markVolumeReadDto.SeriesId, + ChapterId = chapter.Id + }); + } + else + { + userProgress.PagesRead = chapter.Pages; + userProgress.SeriesId = markVolumeReadDto.SeriesId; + userProgress.VolumeId = markVolumeReadDto.VolumeId; + } + } + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.Complete()) + { + return Ok(); + } + + return BadRequest("Could not save progress"); + } + [HttpPost("bookmark")] public async Task Bookmark(BookmarkDto bookmarkDto) { diff --git a/API/DTOs/MarkVolumeReadDto.cs b/API/DTOs/MarkVolumeReadDto.cs new file mode 100644 index 000000000..ffae155a2 --- /dev/null +++ b/API/DTOs/MarkVolumeReadDto.cs @@ -0,0 +1,8 @@ +namespace API.DTOs +{ + public class MarkVolumeReadDto + { + public int SeriesId { get; init; } + public int VolumeId { get; init; } + } +} \ No newline at end of file diff --git a/API/Data/VolumeRepository.cs b/API/Data/VolumeRepository.cs index ce8dd0eea..abfb672a8 100644 --- a/API/Data/VolumeRepository.cs +++ b/API/Data/VolumeRepository.cs @@ -35,9 +35,22 @@ namespace API.Data { return await _context.Chapter .Include(c => c.Files) - .AsNoTracking() .SingleOrDefaultAsync(c => c.Id == chapterId); } + + + /// + /// Returns Chapters for a volume id. + /// + /// + /// + public async Task> GetChaptersAsync(int volumeId) + { + return await _context.Chapter + .Where(c => c.VolumeId == volumeId) + .ToListAsync(); + } + public async Task GetChapterDtoAsync(int chapterId) { diff --git a/API/Interfaces/IVolumeRepository.cs b/API/Interfaces/IVolumeRepository.cs index 0bc28253b..727133d80 100644 --- a/API/Interfaces/IVolumeRepository.cs +++ b/API/Interfaces/IVolumeRepository.cs @@ -11,5 +11,6 @@ namespace API.Interfaces Task GetChapterAsync(int chapterId); Task GetChapterDtoAsync(int chapterId); Task> GetFilesForChapter(int chapterId); + Task> GetChaptersAsync(int volumeId); } } \ No newline at end of file diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index dd3f21150..42c45d465 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -78,6 +78,8 @@ namespace API.Services { _logger.LogInformation("Enqueuing library scan for: {LibraryId}", libraryId); BackgroundJob.Enqueue(() => _scannerService.ScanLibrary(libraryId, forceUpdate)); + BackgroundJob.Enqueue(() => _cleanupService.Cleanup()); // When we do a scan, force cache to re-unpack in case page numbers change + } public void CleanupChapters(int[] chapterIds) diff --git a/API/Startup.cs b/API/Startup.cs index 4c3ce5de4..029fe5f5c 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -41,17 +41,19 @@ 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; - // }); + services.AddResponseCompression(options => + { + options.Providers.Add(); + options.Providers.Add(); + options.MimeTypes = + ResponseCompressionDefaults.MimeTypes.Concat( + new[] { "image/jpeg", "image/jpg" }); + options.EnableForHttps = true; + }); + services.Configure(options => + { + options.Level = CompressionLevel.Fastest; + }); } @@ -67,6 +69,7 @@ namespace API app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1")); app.UseHangfireDashboard(); } + app.UseResponseCompression(); app.UseForwardedHeaders(); @@ -85,7 +88,7 @@ namespace API app.UseAuthorization(); app.UseDefaultFiles(); - + app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = new FileExtensionContentTypeProvider() diff --git a/API/appsettings.Development.json b/API/appsettings.Development.json index 67e0049ba..4dd015431 100644 --- a/API/appsettings.Development.json +++ b/API/appsettings.Development.json @@ -8,7 +8,8 @@ "Default": "Debug", "Microsoft": "Information", "Microsoft.Hosting.Lifetime": "Error", - "Hangfire": "Information" + "Hangfire": "Information", + "Microsoft.AspNetCore.Hosting.Internal.WebHost": "Information" }, "File": { "Path": "kavita.log",