Epub Annotation System (#4008)

Co-authored-by: Fesaa <77553571+Fesaa@users.noreply.github.com>
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
Joe Milazzo
2025-08-30 14:01:00 -05:00
committed by GitHub
parent 3b883b178f
commit b141613d60
170 changed files with 15837 additions and 3158 deletions
+23 -7
View File
@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using API.Constants;
using API.Data;
using API.DTOs.Reader;
using API.Entities.Enums;
@@ -34,33 +35,41 @@ public class BookController : BaseApiController
}
/// <summary>
/// Retrieves information for the PDF and Epub reader
/// Retrieves information for the PDF and Epub reader. This will cache the file.
/// </summary>
/// <remarks>This only applies to Epub or PDF files</remarks>
/// <param name="chapterId"></param>
/// <returns></returns>
[HttpGet("{chapterId}/book-info")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId"])]
public async Task<ActionResult<BookInfoDto>> GetBookInfo(int chapterId)
{
var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId);
if (dto == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
var bookTitle = string.Empty;
switch (dto.SeriesFormat)
{
case MangaFormat.Epub:
{
var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId))[0];
using var book = await EpubReader.OpenBookAsync(mangaFile.FilePath, BookService.LenientBookReaderOptions);
await _cacheService.Ensure(chapterId);
var file = _cacheService.GetCachedFile(chapterId, mangaFile.FilePath);
using var book = await EpubReader.OpenBookAsync(file, BookService.LenientBookReaderOptions);
bookTitle = book.Title;
break;
}
case MangaFormat.Pdf:
{
var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId))[0];
await _cacheService.Ensure(chapterId);
var file = _cacheService.GetCachedFile(chapterId, mangaFile.FilePath);
if (string.IsNullOrEmpty(bookTitle))
{
// Override with filename
bookTitle = Path.GetFileNameWithoutExtension(mangaFile.FilePath);
bookTitle = Path.GetFileNameWithoutExtension(file);
}
break;
@@ -72,9 +81,9 @@ public class BookController : BaseApiController
break;
}
return Ok(new BookInfoDto()
var info = new BookInfoDto()
{
ChapterNumber = dto.ChapterNumber,
ChapterNumber = dto.ChapterNumber,
VolumeNumber = dto.VolumeNumber,
VolumeId = dto.VolumeId,
BookTitle = bookTitle,
@@ -84,7 +93,10 @@ public class BookController : BaseApiController
LibraryId = dto.LibraryId,
IsSpecial = dto.IsSpecial,
Pages = dto.Pages,
});
};
return Ok(info);
}
/// <summary>
@@ -157,7 +169,11 @@ public class BookController : BaseApiController
try
{
return Ok(await _bookService.GetBookPage(page, chapterId, path, baseUrl));
var ptocBookmarks =
await _unitOfWork.UserTableOfContentRepository.GetPersonalToCForPage(User.GetUserId(), chapterId, page);
var annotations = await _unitOfWork.UserRepository.GetAnnotationsByPage(User.GetUserId(), chapter.Id, page);
return Ok(await _bookService.GetBookPage(page, chapterId, path, baseUrl, ptocBookmarks, annotations));
}
catch (KavitaException ex)
{