mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
* Some performance refactoring around getting Library and avoid a byte[] copy for getting cover images for epubs. * Initial commit. Rewrote the main series scan loop to use chunks of data at a time. Not fully shaken out. * Hooked in the ability for the UI to react to series being added or removed from the DB. * Cleaned up the messaging in the scan loop to be more clear. * Metadata scan and scan work as expected and populate data to the UI. There is a slow down in speed for overall operation. Scan series and refresh series metadata does not work fully. * Fixed a bug where MangaFiles were not having LastModified Updated correctly, meaning they were opening archives every scan. * Modified the code to be more realistic to the underlying file * Updated ScanService to properly handle deleted files and not result in a higher-level scan. * Shuffled around volume related repo apis to the volume repo rather than being in series. * Rewrote scan series to be much cleaner and more concise on the flow. Fixed an issue in UpdateVolumes such that the debug code to log out removed volumes could throw an exception and actually break updating volumes. * Refactored the code to set MangaFile last modified timestamp into the MangaFile entity. * Added Series Name to ScanSeries event * Added additional checks in ScanSeries to ensure we never go outside the library folder. Added extra debug messages for when a metadata refresh doesn't actually make changes and for when we regen cover images. * More logging statements saying where they originate from. Fixed a critical bug which caused only 1 chunk to ever be processed. * Fixed a concurrency issue with natural sorter which could cause issues in ArchiveService.cs. * Log cleanups * Fixed an issue with logging out total time of a scan. * Only show added toastrs for admins. When kicking off a refresh metadata for series, make sure we regenerate all cover images. * Code smells on benchmark despite it being ignored
552 lines
21 KiB
C#
552 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using API.Data.Repositories;
|
|
using API.DTOs;
|
|
using API.DTOs.Reader;
|
|
using API.Entities;
|
|
using API.Extensions;
|
|
using API.Interfaces;
|
|
using API.Interfaces.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace API.Controllers
|
|
{
|
|
/// <summary>
|
|
/// For all things regarding reading, mainly focusing on non-Book related entities
|
|
/// </summary>
|
|
public class ReaderController : BaseApiController
|
|
{
|
|
private readonly ICacheService _cacheService;
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private readonly ILogger<ReaderController> _logger;
|
|
private readonly IReaderService _readerService;
|
|
|
|
/// <inheritdoc />
|
|
public ReaderController(ICacheService cacheService,
|
|
IUnitOfWork unitOfWork, ILogger<ReaderController> logger, IReaderService readerService)
|
|
{
|
|
_cacheService = cacheService;
|
|
_unitOfWork = unitOfWork;
|
|
_logger = logger;
|
|
_readerService = readerService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an image for a given chapter. Side effect: This will cache the chapter images for reading.
|
|
/// </summary>
|
|
/// <param name="chapterId"></param>
|
|
/// <param name="page"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("image")]
|
|
public async Task<ActionResult> GetImage(int chapterId, int page)
|
|
{
|
|
if (page < 0) page = 0;
|
|
var chapter = await _cacheService.Ensure(chapterId);
|
|
if (chapter == null) return BadRequest("There was an issue finding image file for reading");
|
|
|
|
try
|
|
{
|
|
var (path, _) = await _cacheService.GetCachedPagePath(chapter, page);
|
|
if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {page}");
|
|
var format = Path.GetExtension(path).Replace(".", "");
|
|
|
|
return PhysicalFile(path, "image/" + format, Path.GetFileName(path));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_cacheService.CleanupChapters(new []{ chapterId });
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns various information about a Chapter. Side effect: This will cache the chapter images for reading.
|
|
/// </summary>
|
|
/// <param name="chapterId"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("chapter-info")]
|
|
public async Task<ActionResult<ChapterInfoDto>> GetChapterInfo(int chapterId)
|
|
{
|
|
var chapter = await _cacheService.Ensure(chapterId);
|
|
if (chapter == null) return BadRequest("Could not find Chapter");
|
|
|
|
var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId);
|
|
var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId)).First();
|
|
|
|
return Ok(new ChapterInfoDto()
|
|
{
|
|
ChapterNumber = dto.ChapterNumber,
|
|
VolumeNumber = dto.VolumeNumber,
|
|
VolumeId = dto.VolumeId,
|
|
FileName = Path.GetFileName(mangaFile.FilePath),
|
|
SeriesName = dto.SeriesName,
|
|
SeriesFormat = dto.SeriesFormat,
|
|
SeriesId = dto.SeriesId,
|
|
LibraryId = dto.LibraryId,
|
|
IsSpecial = dto.IsSpecial,
|
|
Pages = dto.Pages,
|
|
});
|
|
}
|
|
|
|
|
|
[HttpPost("mark-read")]
|
|
public async Task<ActionResult> MarkRead(MarkReadDto markReadDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
var volumes = await _unitOfWork.VolumeRepository.GetVolumes(markReadDto.SeriesId);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
foreach (var volume in volumes)
|
|
{
|
|
_readerService.MarkChaptersAsRead(user, markReadDto.SeriesId, volume.Chapters);
|
|
}
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
|
|
return BadRequest("There was an issue saving progress");
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Marks a Series as Unread (progress)
|
|
/// </summary>
|
|
/// <param name="markReadDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-unread")]
|
|
public async Task<ActionResult> MarkUnread(MarkReadDto markReadDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
var volumes = await _unitOfWork.VolumeRepository.GetVolumes(markReadDto.SeriesId);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
foreach (var volume in volumes)
|
|
{
|
|
foreach (var chapter in volume.Chapters)
|
|
{
|
|
var userProgress = ReaderService.GetUserProgressForChapter(user, chapter);
|
|
|
|
if (userProgress == null) continue;
|
|
userProgress.PagesRead = 0;
|
|
userProgress.SeriesId = markReadDto.SeriesId;
|
|
userProgress.VolumeId = volume.Id;
|
|
}
|
|
}
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
|
|
return BadRequest("There was an issue saving progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a volume as unread
|
|
/// </summary>
|
|
/// <param name="markVolumeReadDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-volume-unread")]
|
|
public async Task<ActionResult> MarkVolumeAsUnread(MarkVolumeReadDto markVolumeReadDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
|
|
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
|
_readerService.MarkChaptersAsUnread(user, markVolumeReadDto.SeriesId, chapters);
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a volume as Read
|
|
/// </summary>
|
|
/// <param name="markVolumeReadDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-volume-read")]
|
|
public async Task<ActionResult> MarkVolumeAsRead(MarkVolumeReadDto markVolumeReadDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
|
|
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
|
_readerService.MarkChaptersAsRead(user, markVolumeReadDto.SeriesId, chapters);
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a list of volumes as Read. All volumes must belong to the same Series.
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-multiple-read")]
|
|
public async Task<ActionResult> MarkMultipleAsRead(MarkVolumesReadDto dto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
|
|
var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds);
|
|
foreach (var chapterId in dto.ChapterIds)
|
|
{
|
|
chapterIds.Add(chapterId);
|
|
}
|
|
var chapters = await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds);
|
|
_readerService.MarkChaptersAsRead(user, dto.SeriesId, chapters);
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a list of volumes as Unread. All volumes must belong to the same Series.
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-multiple-unread")]
|
|
public async Task<ActionResult> MarkMultipleAsUnread(MarkVolumesReadDto dto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
|
|
var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds);
|
|
foreach (var chapterId in dto.ChapterIds)
|
|
{
|
|
chapterIds.Add(chapterId);
|
|
}
|
|
var chapters = await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds);
|
|
_readerService.MarkChaptersAsUnread(user, dto.SeriesId, chapters);
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a list of series as Read.
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-multiple-series-read")]
|
|
public async Task<ActionResult> MarkMultipleSeriesAsRead(MarkMultipleSeriesAsReadDto dto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
|
|
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true);
|
|
foreach (var volume in volumes)
|
|
{
|
|
_readerService.MarkChaptersAsRead(user, volume.SeriesId, volume.Chapters);
|
|
}
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marks all chapters within a list of series as Unread.
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("mark-multiple-series-unread")]
|
|
public async Task<ActionResult> MarkMultipleSeriesAsUnread(MarkMultipleSeriesAsReadDto dto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
user.Progresses ??= new List<AppUserProgress>();
|
|
|
|
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true);
|
|
foreach (var volume in volumes)
|
|
{
|
|
_readerService.MarkChaptersAsUnread(user, volume.SeriesId, volume.Chapters);
|
|
}
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns Progress (page number) for a chapter for the logged in user
|
|
/// </summary>
|
|
/// <param name="chapterId"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("get-progress")]
|
|
public async Task<ActionResult<ProgressDto>> GetProgress(int chapterId)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
|
var progressBookmark = new ProgressDto()
|
|
{
|
|
PageNum = 0,
|
|
ChapterId = chapterId,
|
|
VolumeId = 0,
|
|
SeriesId = 0
|
|
};
|
|
if (user.Progresses == null) return Ok(progressBookmark);
|
|
var progress = user.Progresses.FirstOrDefault(x => x.AppUserId == user.Id && x.ChapterId == chapterId);
|
|
|
|
if (progress != null)
|
|
{
|
|
progressBookmark.SeriesId = progress.SeriesId;
|
|
progressBookmark.VolumeId = progress.VolumeId;
|
|
progressBookmark.PageNum = progress.PagesRead;
|
|
progressBookmark.BookScrollId = progress.BookScrollId;
|
|
}
|
|
return Ok(progressBookmark);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save page against Chapter for logged in user
|
|
/// </summary>
|
|
/// <param name="progressDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("progress")]
|
|
public async Task<ActionResult> BookmarkProgress(ProgressDto progressDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
|
|
|
if (await _readerService.SaveReadingProgress(progressDto, user.Id)) return Ok(true);
|
|
|
|
return BadRequest("Could not save progress");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a list of bookmarked pages for a given Chapter
|
|
/// </summary>
|
|
/// <param name="chapterId"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("get-bookmarks")]
|
|
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarks(int chapterId)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
|
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForChapter(user.Id, chapterId));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a list of all bookmarked pages for a User
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("get-all-bookmarks")]
|
|
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetAllBookmarks()
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
|
return Ok(await _unitOfWork.UserRepository.GetAllBookmarkDtos(user.Id));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all bookmarks for all chapters linked to a Series
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("remove-bookmarks")]
|
|
public async Task<ActionResult> RemoveBookmarks(RemoveBookmarkForSeriesDto dto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
if (user.Bookmarks == null) return Ok("Nothing to remove");
|
|
try
|
|
{
|
|
user.Bookmarks = user.Bookmarks.Where(bmk => bmk.SeriesId != dto.SeriesId).ToList();
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "There was an exception when trying to clear bookmarks");
|
|
await _unitOfWork.RollbackAsync();
|
|
}
|
|
|
|
return BadRequest("Could not clear bookmarks");
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns all bookmarked pages for a given volume
|
|
/// </summary>
|
|
/// <param name="volumeId"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("get-volume-bookmarks")]
|
|
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForVolume(int volumeId)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
|
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(user.Id, volumeId));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns all bookmarked pages for a given series
|
|
/// </summary>
|
|
/// <param name="seriesId"></param>
|
|
/// <returns></returns>
|
|
[HttpGet("get-series-bookmarks")]
|
|
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForSeries(int seriesId)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
|
|
|
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(user.Id, seriesId));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bookmarks a page against a Chapter
|
|
/// </summary>
|
|
/// <param name="bookmarkDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("bookmark")]
|
|
public async Task<ActionResult> BookmarkPage(BookmarkDto bookmarkDto)
|
|
{
|
|
// Don't let user save past total pages.
|
|
bookmarkDto.Page = await _readerService.CapPageToChapter(bookmarkDto.ChapterId, bookmarkDto.Page);
|
|
|
|
try
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
var userBookmark =
|
|
await _unitOfWork.UserRepository.GetBookmarkForPage(bookmarkDto.Page, bookmarkDto.ChapterId, user.Id);
|
|
|
|
if (userBookmark == null)
|
|
{
|
|
user.Bookmarks ??= new List<AppUserBookmark>();
|
|
user.Bookmarks.Add(new AppUserBookmark()
|
|
{
|
|
Page = bookmarkDto.Page,
|
|
VolumeId = bookmarkDto.VolumeId,
|
|
SeriesId = bookmarkDto.SeriesId,
|
|
ChapterId = bookmarkDto.ChapterId,
|
|
});
|
|
_unitOfWork.UserRepository.Update(user);
|
|
}
|
|
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
await _unitOfWork.RollbackAsync();
|
|
}
|
|
|
|
return BadRequest("Could not save bookmark");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a bookmarked page for a Chapter
|
|
/// </summary>
|
|
/// <param name="bookmarkDto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("unbookmark")]
|
|
public async Task<ActionResult> UnBookmarkPage(BookmarkDto bookmarkDto)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
|
|
|
if (user.Bookmarks == null) return Ok();
|
|
try {
|
|
user.Bookmarks = user.Bookmarks.Where(x =>
|
|
x.ChapterId == bookmarkDto.ChapterId
|
|
&& x.AppUserId == user.Id
|
|
&& x.Page != bookmarkDto.Page).ToList();
|
|
|
|
_unitOfWork.UserRepository.Update(user);
|
|
|
|
if (await _unitOfWork.CommitAsync())
|
|
{
|
|
return Ok();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
await _unitOfWork.RollbackAsync();
|
|
}
|
|
|
|
return BadRequest("Could not remove bookmark");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the next logical chapter from the series.
|
|
/// </summary>
|
|
/// <example>
|
|
/// V1 → V2 → V3 chapter 0 → V3 chapter 10 → SP 01 → SP 02
|
|
/// </example>
|
|
/// <param name="seriesId"></param>
|
|
/// <param name="volumeId"></param>
|
|
/// <param name="currentChapterId"></param>
|
|
/// <returns>chapter id for next manga</returns>
|
|
[HttpGet("next-chapter")]
|
|
public async Task<ActionResult<int>> GetNextChapter(int seriesId, int volumeId, int currentChapterId)
|
|
{
|
|
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
|
return await _readerService.GetNextChapterIdAsync(seriesId, volumeId, currentChapterId, userId);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns the previous logical chapter from the series.
|
|
/// </summary>
|
|
/// <example>
|
|
/// V1 ← V2 ← V3 chapter 0 ← V3 chapter 10 ← SP 01 ← SP 02
|
|
/// </example>
|
|
/// <param name="seriesId"></param>
|
|
/// <param name="volumeId"></param>
|
|
/// <param name="currentChapterId"></param>
|
|
/// <returns>chapter id for next manga</returns>
|
|
[HttpGet("prev-chapter")]
|
|
public async Task<ActionResult<int>> GetPreviousChapter(int seriesId, int volumeId, int currentChapterId)
|
|
{
|
|
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
|
return await _readerService.GetPrevChapterIdAsync(seriesId, volumeId, currentChapterId, userId);
|
|
}
|
|
|
|
}
|
|
}
|