Release Testing Day 1 (#1933)
* Enhance plugin/authenticate to allow RefreshToken to be returned as well. * When typing a series name, min, or max filter, press enter to apply metadata filter. * Cleaned up the documentation around MaxCount and TotalCount * Fixed a bug where PublicationStatus wasn't being correctly set due to some strange logic I coded. * Fixed bookmark mode not having access to critical page dimensions. Fetching bookmark info api now returns dimensions by default. * Fixed pagination scaling code for different fitting options * Fixed missing code to persist page split in manga reader * Removed unneeded prefetch of blank images in bookmark mode
This commit is contained in:
parent
f99a75c2d7
commit
e3467457ea
14 changed files with 119 additions and 40 deletions
|
|
@ -43,6 +43,7 @@ public class PluginController : BaseApiController
|
|||
{
|
||||
Username = user.UserName!,
|
||||
Token = await _tokenService.CreateToken(user),
|
||||
RefreshToken = await _tokenService.CreateRefreshToken(user),
|
||||
ApiKey = user.ApiKey,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ public class ReaderController : BaseApiController
|
|||
if (chapterId <= 0) return ArraySegment<FileDimensionDto>.Empty;
|
||||
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
|
||||
if (chapter == null) return BadRequest("Could not find Chapter");
|
||||
return Ok(_cacheService.GetCachedFileDimensions(chapterId));
|
||||
return Ok(_cacheService.GetCachedFileDimensions(_cacheService.GetCachePath(chapterId)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -228,7 +228,7 @@ public class ReaderController : BaseApiController
|
|||
|
||||
if (includeDimensions)
|
||||
{
|
||||
info.PageDimensions = _cacheService.GetCachedFileDimensions(chapterId);
|
||||
info.PageDimensions = _cacheService.GetCachedFileDimensions(_cacheService.GetCachePath(chapterId));
|
||||
info.DoublePairs = _readerService.GetPairs(info.PageDimensions);
|
||||
}
|
||||
|
||||
|
|
@ -260,21 +260,31 @@ public class ReaderController : BaseApiController
|
|||
/// Returns various information about all bookmark files for a Series. Side effect: This will cache the bookmark images for reading.
|
||||
/// </summary>
|
||||
/// <param name="seriesId">Series Id for all bookmarks</param>
|
||||
/// <param name="includeDimensions">Include file dimensions (extra I/O). Defaults to true.</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("bookmark-info")]
|
||||
public async Task<ActionResult<BookmarkInfoDto>> GetBookmarkInfo(int seriesId)
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"seriesId", "includeDimensions"})]
|
||||
public async Task<ActionResult<BookmarkInfoDto>> GetBookmarkInfo(int seriesId, bool includeDimensions = true)
|
||||
{
|
||||
var totalPages = await _cacheService.CacheBookmarkForSeries(User.GetUserId(), seriesId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId, SeriesIncludes.None);
|
||||
|
||||
return Ok(new BookmarkInfoDto()
|
||||
var info = new BookmarkInfoDto()
|
||||
{
|
||||
SeriesName = series!.Name,
|
||||
SeriesFormat = series.Format,
|
||||
SeriesId = series.Id,
|
||||
LibraryId = series.LibraryId,
|
||||
Pages = totalPages,
|
||||
});
|
||||
};
|
||||
|
||||
if (includeDimensions)
|
||||
{
|
||||
info.PageDimensions = _cacheService.GetCachedFileDimensions(_cacheService.GetBookmarkCachePath(seriesId));
|
||||
info.DoublePairs = _readerService.GetPairs(info.PageDimensions);
|
||||
}
|
||||
|
||||
return Ok(info);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -606,7 +616,7 @@ public class ReaderController : BaseApiController
|
|||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok("Nothing to remove");
|
||||
if (user.Bookmarks == null) return Ok("Nothing to remove");
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -643,7 +653,7 @@ public class ReaderController : BaseApiController
|
|||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(user.Id, volumeId));
|
||||
}
|
||||
|
||||
|
|
@ -657,7 +667,7 @@ public class ReaderController : BaseApiController
|
|||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(user.Id, seriesId));
|
||||
}
|
||||
|
|
@ -721,7 +731,7 @@ public class ReaderController : BaseApiController
|
|||
/// <param name="volumeId"></param>
|
||||
/// <param name="currentChapterId"></param>
|
||||
/// <returns>chapter id for next manga</returns>
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new string[] { "seriesId", "volumeId", "currentChapterId"})]
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new [] { "seriesId", "volumeId", "currentChapterId"})]
|
||||
[HttpGet("next-chapter")]
|
||||
public async Task<ActionResult<int>> GetNextChapter(int seriesId, int volumeId, int currentChapterId)
|
||||
{
|
||||
|
|
@ -740,7 +750,7 @@ public class ReaderController : BaseApiController
|
|||
/// <param name="volumeId"></param>
|
||||
/// <param name="currentChapterId"></param>
|
||||
/// <returns>chapter id for next manga</returns>
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new string[] { "seriesId", "volumeId", "currentChapterId"})]
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new [] { "seriesId", "volumeId", "currentChapterId"})]
|
||||
[HttpGet("prev-chapter")]
|
||||
public async Task<ActionResult<int>> GetPreviousChapter(int seriesId, int volumeId, int currentChapterId)
|
||||
{
|
||||
|
|
@ -755,7 +765,7 @@ public class ReaderController : BaseApiController
|
|||
/// <param name="seriesId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("time-left")]
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new string[] { "seriesId"})]
|
||||
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new [] { "seriesId"})]
|
||||
public async Task<ActionResult<HourEstimateRangeDto>> GetEstimateToCompletion(int seriesId)
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using API.Entities.Enums;
|
||||
using System.Collections.Generic;
|
||||
using API.Entities.Enums;
|
||||
|
||||
namespace API.DTOs.Reader;
|
||||
|
||||
|
|
@ -10,4 +11,14 @@ public class BookmarkInfoDto
|
|||
public int LibraryId { get; set; }
|
||||
public LibraryType LibraryType { get; set; }
|
||||
public int Pages { get; set; }
|
||||
/// <summary>
|
||||
/// List of all files with their inner archive structure maintained in filename and dimensions
|
||||
/// </summary>
|
||||
/// <remarks>This is optionally returned by includeDimensions</remarks>
|
||||
public IEnumerable<FileDimensionDto>? PageDimensions { get; set; }
|
||||
/// <summary>
|
||||
/// For Double Page reader, this will contain snap points to ensure the reader always resumes on correct page
|
||||
/// </summary>
|
||||
/// <remarks>This is optionally returned by includeDimensions</remarks>
|
||||
public IDictionary<int, int>? DoublePairs { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ public class ComicInfo
|
|||
return Math.Max(Count, (int) Math.Floor(float.Parse(Volume)));
|
||||
}
|
||||
|
||||
return Count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class SeriesMetadata : IHasConcurrencyToken
|
|||
/// </summary>
|
||||
public int TotalCount { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// Max number of issues/volumes in the series (Max of Volume/Issue field in ComicInfo)
|
||||
/// Max number of issues/volumes in the series (Max of Volume/Number field in ComicInfo)
|
||||
/// </summary>
|
||||
public int MaxCount { get; set; } = 0;
|
||||
public PublicationStatus PublicationStatus { get; set; }
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ public interface ICacheService
|
|||
void CleanupChapters(IEnumerable<int> chapterIds);
|
||||
void CleanupBookmarks(IEnumerable<int> seriesIds);
|
||||
string GetCachedPagePath(int chapterId, int page);
|
||||
string GetCachePath(int chapterId);
|
||||
string GetBookmarkCachePath(int seriesId);
|
||||
IEnumerable<string> GetCachedPages(int chapterId);
|
||||
IEnumerable<FileDimensionDto> GetCachedFileDimensions(int chapterId);
|
||||
IEnumerable<FileDimensionDto> GetCachedFileDimensions(string cachePath);
|
||||
string GetCachedBookmarkPagePath(int seriesId, int page);
|
||||
string GetCachedFile(Chapter chapter);
|
||||
public void ExtractChapterFiles(string extractPath, IReadOnlyList<MangaFile> files, bool extractPdfImages = false);
|
||||
|
|
@ -66,11 +68,15 @@ public class CacheService : ICacheService
|
|||
.OrderByNatural(Path.GetFileNameWithoutExtension);
|
||||
}
|
||||
|
||||
public IEnumerable<FileDimensionDto> GetCachedFileDimensions(int chapterId)
|
||||
/// <summary>
|
||||
/// For a given path, scan all files (in reading order) and generate File Dimensions for it. Path must exist
|
||||
/// </summary>
|
||||
/// <param name="cachePath"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<FileDimensionDto> GetCachedFileDimensions(string cachePath)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var path = GetCachePath(chapterId);
|
||||
var files = _directoryService.GetFilesWithExtension(path, Tasks.Scanner.Parser.Parser.ImageFileExtensions)
|
||||
var files = _directoryService.GetFilesWithExtension(cachePath, Tasks.Scanner.Parser.Parser.ImageFileExtensions)
|
||||
.OrderByNatural(Path.GetFileNameWithoutExtension)
|
||||
.ToArray();
|
||||
|
||||
|
|
@ -94,13 +100,13 @@ public class CacheService : ICacheService
|
|||
Height = image.Height,
|
||||
Width = image.Width,
|
||||
IsWide = image.Width > image.Height,
|
||||
FileName = file.Replace(path, string.Empty)
|
||||
FileName = file.Replace(cachePath, string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an error calculating image dimensions for {ChapterId}", chapterId);
|
||||
_logger.LogError(ex, "There was an error calculating image dimensions for {CachePath}", cachePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -259,12 +265,17 @@ public class CacheService : ICacheService
|
|||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <returns></returns>
|
||||
private string GetCachePath(int chapterId)
|
||||
public string GetCachePath(int chapterId)
|
||||
{
|
||||
return _directoryService.FileSystem.Path.GetFullPath(_directoryService.FileSystem.Path.Join(_directoryService.CacheDirectory, $"{chapterId}/"));
|
||||
}
|
||||
|
||||
private string GetBookmarkCachePath(int seriesId)
|
||||
/// <summary>
|
||||
/// Returns the cache path for a given series' bookmarks. Should be cacheDirectory/{seriesId_bookmarks}/
|
||||
/// </summary>
|
||||
/// <param name="seriesId"></param>
|
||||
/// <returns></returns>
|
||||
public string GetBookmarkCachePath(int seriesId)
|
||||
{
|
||||
return _directoryService.FileSystem.Path.GetFullPath(_directoryService.FileSystem.Path.Join(_directoryService.CacheDirectory, $"{seriesId}_bookmarks/"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,7 +276,9 @@ public class ProcessSeries : IProcessSeries
|
|||
// Set the AgeRating as highest in all the comicInfos
|
||||
if (!series.Metadata.AgeRatingLocked) series.Metadata.AgeRating = chapters.Max(chapter => chapter.AgeRating);
|
||||
|
||||
// Count (aka expected total number of chapters or volumes from metadata) across all chapters
|
||||
series.Metadata.TotalCount = chapters.Max(chapter => chapter.TotalCount);
|
||||
// The actual number of count's defined across all chapter's metadata
|
||||
series.Metadata.MaxCount = chapters.Max(chapter => chapter.Count);
|
||||
// To not have to rely completely on ComicInfo, try to parse out if the series is complete by checking parsed filenames as well.
|
||||
if (series.Metadata.MaxCount != series.Metadata.TotalCount)
|
||||
|
|
@ -294,7 +296,7 @@ public class ProcessSeries : IProcessSeries
|
|||
if (series.Metadata.MaxCount >= series.Metadata.TotalCount && series.Metadata.TotalCount > 0)
|
||||
{
|
||||
series.Metadata.PublicationStatus = PublicationStatus.Completed;
|
||||
} else if (series.Metadata.TotalCount > 0 && series.Metadata.MaxCount > 0)
|
||||
} else if (series.Metadata.TotalCount > 0)
|
||||
{
|
||||
series.Metadata.PublicationStatus = PublicationStatus.Ended;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue