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.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
|
using API.Extensions;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
using API.Interfaces.Services;
|
using API.Interfaces.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -28,51 +29,33 @@ namespace API.Controllers
|
|||||||
[HttpGet("chapter-cover")]
|
[HttpGet("chapter-cover")]
|
||||||
public async Task<ActionResult> GetChapterCoverImage(int chapterId)
|
public async Task<ActionResult> GetChapterCoverImage(int chapterId)
|
||||||
{
|
{
|
||||||
// TODO: Write custom methods to just get the byte[] as fast as possible
|
var content = await _unitOfWork.VolumeRepository.GetChapterCoverImageAsync(chapterId);
|
||||||
var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId);
|
if (content == null) return BadRequest("No cover image");
|
||||||
var content = chapter.CoverImage;
|
const string format = "jpeg";
|
||||||
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");
|
|
||||||
|
|
||||||
|
Response.AddCacheHeader(content);
|
||||||
return File(content, "image/" + format);
|
return File(content, "image/" + format);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("volume-cover")]
|
[HttpGet("volume-cover")]
|
||||||
public async Task<ActionResult> GetVolumeCoverImage(int volumeId)
|
public async Task<ActionResult> GetVolumeCoverImage(int volumeId)
|
||||||
{
|
{
|
||||||
var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId);
|
var content = await _unitOfWork.SeriesRepository.GetVolumeCoverImageAsync(volumeId);
|
||||||
var content = volume.CoverImage;
|
if (content == null) return BadRequest("No cover image");
|
||||||
var format = "jpeg"; //Path.GetExtension("jpeg").Replace(".", "");
|
const string format = "jpeg";
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
|
Response.AddCacheHeader(content);
|
||||||
return File(content, "image/" + format);
|
return File(content, "image/" + format);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("series-cover")]
|
[HttpGet("series-cover")]
|
||||||
public async Task<ActionResult> GetSeriesCoverImage(int seriesId)
|
public async Task<ActionResult> GetSeriesCoverImage(int seriesId)
|
||||||
{
|
{
|
||||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
var content = await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId);
|
||||||
var content = series.CoverImage;
|
if (content == null) return BadRequest("No cover image");
|
||||||
var format = "jpeg"; //Path.GetExtension("jpeg").Replace(".", "");
|
const string format = "jpeg";
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
|
Response.AddCacheHeader(content);
|
||||||
return File(content, "image/" + format);
|
return File(content, "image/" + format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,28 +4,27 @@ namespace API.DTOs
|
|||||||
{
|
{
|
||||||
public class ChapterDto
|
public class ChapterDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2".
|
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Range { get; set; }
|
public string Range { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Smallest number of the Range.
|
/// Smallest number of the Range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Number { get; set; }
|
public string Number { get; init; }
|
||||||
//public byte[] CoverImage { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of pages in all MangaFiles
|
/// Total number of pages in all MangaFiles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Pages { get; set; }
|
public int Pages { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The files that represent this Chapter
|
/// The files that represent this Chapter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ICollection<MangaFileDto> Files { get; set; }
|
public ICollection<MangaFileDto> Files { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculated at API time. Number of pages read for this Chapter for logged in user.
|
/// Calculated at API time. Number of pages read for this Chapter for logged in user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PagesRead { get; set; }
|
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
|
public class CreateLibraryDto
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
public string Name { get; set; }
|
public string Name { get; init; }
|
||||||
[Required]
|
[Required]
|
||||||
public LibraryType Type { get; set; }
|
public LibraryType Type { get; init; }
|
||||||
[Required]
|
[Required]
|
||||||
[MinLength(1)]
|
[MinLength(1)]
|
||||||
public IEnumerable<string> Folders { get; set; }
|
public IEnumerable<string> Folders { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,14 +2,14 @@
|
|||||||
{
|
{
|
||||||
public class ImageDto
|
public class ImageDto
|
||||||
{
|
{
|
||||||
public int Page { get; set; }
|
public int Page { get; init; }
|
||||||
public string Filename { get; init; }
|
public string Filename { get; init; }
|
||||||
public string FullPath { get; init; }
|
public string FullPath { get; init; }
|
||||||
public int Width { get; init; }
|
public int Width { get; init; }
|
||||||
public int Height { get; init; }
|
public int Height { get; init; }
|
||||||
public string Format { get; init; }
|
public string Format { get; init; }
|
||||||
public byte[] Content { get; init; }
|
public byte[] Content { get; init; }
|
||||||
public string MangaFileName { get; set; }
|
public string MangaFileName { get; init; }
|
||||||
public bool NeedsSplitting { get; set; }
|
public bool NeedsSplitting { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,9 +6,9 @@ namespace API.DTOs
|
|||||||
public class LibraryDto
|
public class LibraryDto
|
||||||
{
|
{
|
||||||
public int Id { get; init; }
|
public int Id { get; init; }
|
||||||
public string Name { get; set; }
|
public string Name { get; init; }
|
||||||
public string CoverImage { get; set; }
|
public string CoverImage { get; init; }
|
||||||
public LibraryType Type { get; set; }
|
public LibraryType Type { get; init; }
|
||||||
public ICollection<string> Folders { get; set; }
|
public ICollection<string> Folders { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class LoginDto
|
public class LoginDto
|
||||||
{
|
{
|
||||||
public string Username { get; set; }
|
public string Username { get; init; }
|
||||||
public string Password { get; set; }
|
public string Password { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,9 +4,9 @@ namespace API.DTOs
|
|||||||
{
|
{
|
||||||
public class MangaFileDto
|
public class MangaFileDto
|
||||||
{
|
{
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; init; }
|
||||||
public int NumberOfPages { get; set; } // TODO: Refactor to Pages
|
public int NumberOfPages { get; init; }
|
||||||
public MangaFormat Format { get; set; }
|
public MangaFormat Format { get; init; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,6 @@
|
|||||||
{
|
{
|
||||||
public class MarkReadDto
|
public class MarkReadDto
|
||||||
{
|
{
|
||||||
public int SeriesId { get; set; }
|
public int SeriesId { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,11 +8,11 @@ namespace API.DTOs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MemberDto
|
public class MemberDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; init; }
|
||||||
public string Username { get; set; }
|
public string Username { get; init; }
|
||||||
public DateTime Created { get; set; }
|
public DateTime Created { get; init; }
|
||||||
public DateTime LastActive { get; set; }
|
public DateTime LastActive { get; init; }
|
||||||
public IEnumerable<LibraryDto> Libraries { get; set; }
|
public IEnumerable<LibraryDto> Libraries { get; init; }
|
||||||
public IEnumerable<string> Roles { get; set; }
|
public IEnumerable<string> Roles { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,10 +5,10 @@ namespace API.DTOs
|
|||||||
public class RegisterDto
|
public class RegisterDto
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
public string Username { get; set; }
|
public string Username { get; init; }
|
||||||
[Required]
|
[Required]
|
||||||
[StringLength(16, MinimumLength = 4)]
|
[StringLength(16, MinimumLength = 4)]
|
||||||
public string Password { get; set; }
|
public string Password { get; init; }
|
||||||
public bool IsAdmin { get; set; }
|
public bool IsAdmin { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,8 +6,8 @@
|
|||||||
public string Name { get; init; }
|
public string Name { get; init; }
|
||||||
public string OriginalName { get; init; }
|
public string OriginalName { get; init; }
|
||||||
public string SortName { 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
|
// Grouping information
|
||||||
public string LibraryName { get; set; }
|
public string LibraryName { get; set; }
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
public string LocalizedName { get; init; }
|
public string LocalizedName { get; init; }
|
||||||
public string SortName { get; init; }
|
public string SortName { get; init; }
|
||||||
public string Summary { get; init; }
|
public string Summary { get; init; }
|
||||||
public byte[] CoverImage { get; init; }
|
|
||||||
public int Pages { get; init; }
|
public int Pages { get; init; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sum of pages read from linked Volumes. Calculated at API-time.
|
/// 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 Id { get; set; }
|
||||||
public int Number { get; set; }
|
public int Number { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
//public byte[] CoverImage { get; set; }
|
|
||||||
public int Pages { get; set; }
|
public int Pages { get; set; }
|
||||||
public int PagesRead { get; set; }
|
public int PagesRead { get; set; }
|
||||||
public DateTime LastModified { get; set; }
|
public DateTime LastModified { get; set; }
|
||||||
|
@ -244,6 +244,25 @@ namespace API.Data
|
|||||||
s.UserReview = rating.Review;
|
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)
|
private async Task AddVolumeModifiers(int userId, List<VolumeDto> volumes)
|
||||||
{
|
{
|
||||||
var userProgress = await _context.AppUserProgresses
|
var userProgress = await _context.AppUserProgresses
|
||||||
|
@ -50,7 +50,21 @@ namespace API.Data
|
|||||||
.Where(c => c.VolumeId == volumeId)
|
.Where(c => c.VolumeId == volumeId)
|
||||||
.ToListAsync();
|
.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)
|
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 API.Helpers;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
@ -18,6 +19,23 @@ namespace API.Extensions
|
|||||||
response.Headers.Add("Pagination", JsonSerializer.Serialize(paginationHeader, options));
|
response.Headers.Add("Pagination", JsonSerializer.Serialize(paginationHeader, options));
|
||||||
response.Headers.Add("Access-Control-Expose-Headers", "Pagination");
|
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>
|
/// <param name="series"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task AddSeriesModifiers(int userId, List<SeriesDto> series);
|
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<ChapterDto> GetChapterDtoAsync(int chapterId);
|
||||||
Task<IList<MangaFile>> GetFilesForChapter(int chapterId);
|
Task<IList<MangaFile>> GetFilesForChapter(int chapterId);
|
||||||
Task<IList<Chapter>> GetChaptersAsync(int volumeId);
|
Task<IList<Chapter>> GetChaptersAsync(int volumeId);
|
||||||
|
Task<byte[]> GetChapterCoverImageAsync(int chapterId);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user