Manga Reader Fixes (#1925)

* Fixed up an issue where image might be cut off in fit to height

* Removed some calls to backend for translating age rating to a string

* Fixed an issue with sizing on page splitting right to left.

* Ensure all image access requires apikey

* Removed a TODO
This commit is contained in:
Joe Milazzo 2023-04-13 15:07:11 -05:00 committed by GitHub
parent ff18389954
commit 5c1e9c0521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 48 deletions

View file

@ -34,9 +34,10 @@ public class ImageController : BaseApiController
/// <param name="chapterId"></param>
/// <returns></returns>
[HttpGet("chapter-cover")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"chapterId"})]
public async Task<ActionResult> GetChapterCoverImage(int chapterId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"chapterId", "apiKey"})]
public async Task<ActionResult> GetChapterCoverImage(int chapterId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.ChapterRepository.GetChapterCoverImageAsync(chapterId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -50,9 +51,10 @@ public class ImageController : BaseApiController
/// <param name="libraryId"></param>
/// <returns></returns>
[HttpGet("library-cover")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"libraryId"})]
public async Task<ActionResult> GetLibraryCoverImage(int libraryId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"libraryId", "apiKey"})]
public async Task<ActionResult> GetLibraryCoverImage(int libraryId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.LibraryRepository.GetLibraryCoverImageAsync(libraryId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -66,9 +68,10 @@ public class ImageController : BaseApiController
/// <param name="volumeId"></param>
/// <returns></returns>
[HttpGet("volume-cover")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"volumeId"})]
public async Task<ActionResult> GetVolumeCoverImage(int volumeId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"volumeId", "apiKey"})]
public async Task<ActionResult> GetVolumeCoverImage(int volumeId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.VolumeRepository.GetVolumeCoverImageAsync(volumeId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -81,10 +84,11 @@ public class ImageController : BaseApiController
/// </summary>
/// <param name="seriesId">Id of Series</param>
/// <returns></returns>
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"seriesId"})]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"seriesId", "apiKey"})]
[HttpGet("series-cover")]
public async Task<ActionResult> GetSeriesCoverImage(int seriesId)
public async Task<ActionResult> GetSeriesCoverImage(int seriesId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -100,9 +104,10 @@ public class ImageController : BaseApiController
/// <param name="collectionTagId"></param>
/// <returns></returns>
[HttpGet("collection-cover")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"collectionTagId"})]
public async Task<ActionResult> GetCollectionCoverImage(int collectionTagId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"collectionTagId", "apiKey"})]
public async Task<ActionResult> GetCollectionCoverImage(int collectionTagId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.CollectionTagRepository.GetCoverImageAsync(collectionTagId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -116,9 +121,10 @@ public class ImageController : BaseApiController
/// <param name="readingListId"></param>
/// <returns></returns>
[HttpGet("readinglist-cover")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"readingListId"})]
public async Task<ActionResult> GetReadingListCoverImage(int readingListId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"readingListId", "apiKey"})]
public async Task<ActionResult> GetReadingListCoverImage(int readingListId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.ReadingListRepository.GetCoverImageAsync(readingListId));
if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image");
var format = _directoryService.FileSystem.Path.GetExtension(path);
@ -139,6 +145,7 @@ public class ImageController : BaseApiController
public async Task<ActionResult> GetBookmarkImage(int chapterId, int pageNum, string apiKey)
{
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
if (userId == 0) return BadRequest();
var bookmark = await _unitOfWork.UserRepository.GetBookmarkForPage(pageNum, chapterId, userId);
if (bookmark == null) return BadRequest("Bookmark does not exist");
@ -157,9 +164,10 @@ public class ImageController : BaseApiController
/// <returns></returns>
[Authorize(Policy="RequireAdminRole")]
[HttpGet("cover-upload")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"filename"})]
public ActionResult GetCoverUploadImage(string filename)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Images, VaryByQueryKeys = new []{"filename", "apiKey"})]
public async Task<ActionResult> GetCoverUploadImage(string filename, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
if (filename.Contains("..")) return BadRequest("Invalid Filename");
var path = Path.Join(_directoryService.TempDirectory, filename);

View file

@ -57,9 +57,10 @@ public class ReaderController : BaseApiController
/// <param name="chapterId"></param>
/// <returns></returns>
[HttpGet("pdf")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour)]
public async Task<ActionResult> GetPdf(int chapterId)
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId", "apiKey"})]
public async Task<ActionResult> GetPdf(int chapterId, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var chapter = await _cacheService.Ensure(chapterId);
if (chapter == null) return BadRequest("There was an issue finding pdf file for reading");
@ -89,14 +90,16 @@ public class ReaderController : BaseApiController
/// <remarks>This will cache the chapter images for reading</remarks>
/// <param name="chapterId">Chapter Id</param>
/// <param name="page">Page in question</param>
/// <param name="apiKey">User's API Key for authentication</param>
/// <param name="extractPdf">Should Kavita extract pdf into images. Defaults to false.</param>
/// <returns></returns>
[HttpGet("image")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour)]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId","page", "extractPdf", "apiKey"})]
[AllowAnonymous]
public async Task<ActionResult> GetImage(int chapterId, int page, bool extractPdf = false)
public async Task<ActionResult> GetImage(int chapterId, int page, string apiKey, bool extractPdf = false)
{
if (page < 0) page = 0;
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
if (chapter == null) return BadRequest("There was an issue finding image file for reading");
@ -116,10 +119,11 @@ public class ReaderController : BaseApiController
}
[HttpGet("thumbnail")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour)]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId", "pageNum", "apiKey"})]
[AllowAnonymous]
public async Task<ActionResult> GetThumbnail(int chapterId, int pageNum)
public async Task<ActionResult> GetThumbnail(int chapterId, int pageNum, string apiKey)
{
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
var chapter = await _cacheService.Ensure(chapterId, true);
if (chapter == null) return BadRequest("There was an issue extracting images from chapter");
var images = _cacheService.GetCachedPages(chapterId);
@ -138,12 +142,13 @@ public class ReaderController : BaseApiController
/// <remarks>We must use api key as bookmarks could be leaked to other users via the API</remarks>
/// <returns></returns>
[HttpGet("bookmark-image")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour)]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"seriesId", "page", "apiKey"})]
[AllowAnonymous]
public async Task<ActionResult> GetBookmarkImage(int seriesId, string apiKey, int page)
{
if (page < 0) page = 0;
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
if (userId == 0) return BadRequest();
var totalPages = await _cacheService.CacheBookmarkForSeries(userId, seriesId);
if (page > totalPages)
@ -750,6 +755,7 @@ public class ReaderController : BaseApiController
/// <param name="seriesId"></param>
/// <returns></returns>
[HttpGet("time-left")]
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new string[] { "seriesId"})]
public async Task<ActionResult<HourEstimateRangeDto>> GetEstimateToCompletion(int seriesId)
{
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());