mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Cleanup of lazy loading code. Made some DTOs use init rather than set to keep it clean.
This commit is contained in:
parent
33515ad865
commit
af35d8aad5
@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.DTOs;
|
||||
using API.Extensions;
|
||||
using API.Interfaces;
|
||||
using API.Interfaces.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -28,51 +29,33 @@ namespace API.Controllers
|
||||
[HttpGet("chapter-cover")]
|
||||
public async Task<ActionResult> GetChapterCoverImage(int chapterId)
|
||||
{
|
||||
// TODO: Write custom methods to just get the byte[] as fast as possible
|
||||
var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId);
|
||||
var content = chapter.CoverImage;
|
||||
var format = "jpeg"; //Path.GetExtension("jpeg").Replace(".", "");
|
||||
|
||||
// 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");
|
||||
var content = await _unitOfWork.VolumeRepository.GetChapterCoverImageAsync(chapterId);
|
||||
if (content == null) return BadRequest("No cover image");
|
||||
const string format = "jpeg";
|
||||
|
||||
Response.AddCacheHeader(content);
|
||||
return File(content, "image/" + format);
|
||||
}
|
||||
|
||||
[HttpGet("volume-cover")]
|
||||
public async Task<ActionResult> GetVolumeCoverImage(int volumeId)
|
||||
{
|
||||
var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId);
|
||||
var content = volume.CoverImage;
|
||||
var format = "jpeg"; //Path.GetExtension("jpeg").Replace(".", "");
|
||||
|
||||
// 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");
|
||||
var content = await _unitOfWork.SeriesRepository.GetVolumeCoverImageAsync(volumeId);
|
||||
if (content == null) return BadRequest("No cover image");
|
||||
const string format = "jpeg";
|
||||
|
||||
Response.AddCacheHeader(content);
|
||||
return File(content, "image/" + format);
|
||||
}
|
||||
|
||||
[HttpGet("series-cover")]
|
||||
public async Task<ActionResult> GetSeriesCoverImage(int seriesId)
|
||||
{
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
||||
var content = series.CoverImage;
|
||||
var format = "jpeg"; //Path.GetExtension("jpeg").Replace(".", "");
|
||||
|
||||
if (content.Length == 0)
|
||||
{
|
||||
// How do I handle?
|
||||
}
|
||||
|
||||
// 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");
|
||||
var content = await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId);
|
||||
if (content == null) return BadRequest("No cover image");
|
||||
const string format = "jpeg";
|
||||
|
||||
Response.AddCacheHeader(content);
|
||||
return File(content, "image/" + format);
|
||||
}
|
||||
}
|
||||
|
@ -4,28 +4,27 @@ namespace API.DTOs
|
||||
{
|
||||
public class ChapterDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Id { get; init; }
|
||||
/// <summary>
|
||||
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2".
|
||||
/// </summary>
|
||||
public string Range { get; set; }
|
||||
public string Range { get; init; }
|
||||
/// <summary>
|
||||
/// Smallest number of the Range.
|
||||
/// </summary>
|
||||
public string Number { get; set; }
|
||||
//public byte[] CoverImage { get; set; }
|
||||
public string Number { get; init; }
|
||||
/// <summary>
|
||||
/// Total number of pages in all MangaFiles
|
||||
/// </summary>
|
||||
public int Pages { get; set; }
|
||||
public int Pages { get; init; }
|
||||
/// <summary>
|
||||
/// The files that represent this Chapter
|
||||
/// </summary>
|
||||
public ICollection<MangaFileDto> Files { get; set; }
|
||||
public ICollection<MangaFileDto> Files { get; init; }
|
||||
/// <summary>
|
||||
/// Calculated at API time. Number of pages read for this Chapter for logged in user.
|
||||
/// </summary>
|
||||
public int PagesRead { get; set; }
|
||||
public int VolumeId { get; set; }
|
||||
public int VolumeId { get; init; }
|
||||
}
|
||||
}
|
@ -7,11 +7,11 @@ namespace API.DTOs
|
||||
public class CreateLibraryDto
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public string Name { get; init; }
|
||||
[Required]
|
||||
public LibraryType Type { get; set; }
|
||||
public LibraryType Type { get; init; }
|
||||
[Required]
|
||||
[MinLength(1)]
|
||||
public IEnumerable<string> Folders { get; set; }
|
||||
public IEnumerable<string> Folders { get; init; }
|
||||
}
|
||||
}
|
@ -2,14 +2,14 @@
|
||||
{
|
||||
public class ImageDto
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public int Page { get; init; }
|
||||
public string Filename { get; init; }
|
||||
public string FullPath { get; init; }
|
||||
public int Width { get; init; }
|
||||
public int Height { get; init; }
|
||||
public string Format { get; init; }
|
||||
public byte[] Content { get; init; }
|
||||
public string MangaFileName { get; set; }
|
||||
public bool NeedsSplitting { get; set; }
|
||||
public string MangaFileName { get; init; }
|
||||
public bool NeedsSplitting { get; init; }
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@ namespace API.DTOs
|
||||
public class LibraryDto
|
||||
{
|
||||
public int Id { get; init; }
|
||||
public string Name { get; set; }
|
||||
public string CoverImage { get; set; }
|
||||
public LibraryType Type { get; set; }
|
||||
public ICollection<string> Folders { get; set; }
|
||||
public string Name { get; init; }
|
||||
public string CoverImage { get; init; }
|
||||
public LibraryType Type { get; init; }
|
||||
public ICollection<string> Folders { get; init; }
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
public class LoginDto
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Username { get; init; }
|
||||
public string Password { get; init; }
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@ namespace API.DTOs
|
||||
{
|
||||
public class MangaFileDto
|
||||
{
|
||||
public string FilePath { get; set; }
|
||||
public int NumberOfPages { get; set; } // TODO: Refactor to Pages
|
||||
public MangaFormat Format { get; set; }
|
||||
public string FilePath { get; init; }
|
||||
public int NumberOfPages { get; init; }
|
||||
public MangaFormat Format { get; init; }
|
||||
|
||||
}
|
||||
}
|
@ -2,6 +2,6 @@
|
||||
{
|
||||
public class MarkReadDto
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
public int SeriesId { get; init; }
|
||||
}
|
||||
}
|
@ -8,11 +8,11 @@ namespace API.DTOs
|
||||
/// </summary>
|
||||
public class MemberDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Username { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public DateTime LastActive { get; set; }
|
||||
public IEnumerable<LibraryDto> Libraries { get; set; }
|
||||
public IEnumerable<string> Roles { get; set; }
|
||||
public int Id { get; init; }
|
||||
public string Username { get; init; }
|
||||
public DateTime Created { get; init; }
|
||||
public DateTime LastActive { get; init; }
|
||||
public IEnumerable<LibraryDto> Libraries { get; init; }
|
||||
public IEnumerable<string> Roles { get; init; }
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ namespace API.DTOs
|
||||
public class RegisterDto
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
public string Username { get; init; }
|
||||
[Required]
|
||||
[StringLength(16, MinimumLength = 4)]
|
||||
public string Password { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public string Password { get; init; }
|
||||
public bool IsAdmin { get; init; }
|
||||
}
|
||||
}
|
@ -6,8 +6,8 @@
|
||||
public string Name { get; init; }
|
||||
public string OriginalName { get; init; }
|
||||
public string SortName { get; init; }
|
||||
public byte[] CoverImage { get; init; } // This should be optional or a thumbImage (much smaller)
|
||||
|
||||
public byte[] CoverImage { get; init; } // This should be optional or a thumbImage (much smaller) // TODO: Refactor to lazy loading
|
||||
public string CoverImageUrl { get; init; }
|
||||
|
||||
// Grouping information
|
||||
public string LibraryName { get; set; }
|
||||
|
@ -8,7 +8,6 @@
|
||||
public string LocalizedName { get; init; }
|
||||
public string SortName { get; init; }
|
||||
public string Summary { get; init; }
|
||||
public byte[] CoverImage { get; init; }
|
||||
public int Pages { get; init; }
|
||||
/// <summary>
|
||||
/// Sum of pages read from linked Volumes. Calculated at API-time.
|
||||
|
@ -9,7 +9,6 @@ namespace API.DTOs
|
||||
public int Id { get; set; }
|
||||
public int Number { get; set; }
|
||||
public string Name { get; set; }
|
||||
//public byte[] CoverImage { get; set; }
|
||||
public int Pages { get; set; }
|
||||
public int PagesRead { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
|
@ -244,6 +244,25 @@ namespace API.Data
|
||||
s.UserReview = rating.Review;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetVolumeCoverImageAsync(int volumeId)
|
||||
{
|
||||
return await _context.Volume
|
||||
.Where(v => v.Id == volumeId)
|
||||
.Select(v => v.CoverImage)
|
||||
.AsNoTracking()
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetSeriesCoverImageAsync(int seriesId)
|
||||
{
|
||||
return await _context.Series
|
||||
.Where(s => s.Id == seriesId)
|
||||
.Select(s => s.CoverImage)
|
||||
.AsNoTracking()
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
private async Task AddVolumeModifiers(int userId, List<VolumeDto> volumes)
|
||||
{
|
||||
var userProgress = await _context.AppUserProgresses
|
||||
|
@ -50,7 +50,21 @@ namespace API.Data
|
||||
.Where(c => c.VolumeId == volumeId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cover image for a chapter id.
|
||||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<byte[]> GetChapterCoverImageAsync(int chapterId)
|
||||
{
|
||||
return await _context.Chapter
|
||||
.Where(c => c.Id == chapterId)
|
||||
.Select(c => c.CoverImage)
|
||||
.AsNoTracking()
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
||||
public async Task<ChapterDto> GetChapterDtoAsync(int chapterId)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using API.Helpers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
@ -18,6 +19,23 @@ namespace API.Extensions
|
||||
response.Headers.Add("Pagination", JsonSerializer.Serialize(paginationHeader, options));
|
||||
response.Headers.Add("Access-Control-Expose-Headers", "Pagination");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates SHA1 hash for a byte[] and sets as ETag. Ensures Cache-Control: private header is added.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="content"></param>
|
||||
public static void AddCacheHeader(this HttpResponse response, byte[] content)
|
||||
{
|
||||
// Calculates SHA1 Hash for byte[]
|
||||
if (content != null && content.Length > 0)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -52,5 +52,8 @@ namespace API.Interfaces
|
||||
/// <param name="series"></param>
|
||||
/// <returns></returns>
|
||||
Task AddSeriesModifiers(int userId, List<SeriesDto> series);
|
||||
|
||||
Task<byte[]> GetVolumeCoverImageAsync(int volumeId);
|
||||
Task<byte[]> GetSeriesCoverImageAsync(int seriesId);
|
||||
}
|
||||
}
|
@ -12,5 +12,6 @@ namespace API.Interfaces
|
||||
Task<ChapterDto> GetChapterDtoAsync(int chapterId);
|
||||
Task<IList<MangaFile>> GetFilesForChapter(int chapterId);
|
||||
Task<IList<Chapter>> GetChaptersAsync(int volumeId);
|
||||
Task<byte[]> GetChapterCoverImageAsync(int chapterId);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user