mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Lots of work for chapters. This code will be refactored in a chapter rewrite.
This commit is contained in:
parent
f430595d11
commit
a42e54a078
19
API.Tests/ChapterSortComparerTest.cs
Normal file
19
API.Tests/ChapterSortComparerTest.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using API.Comparators;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace API.Tests
|
||||||
|
{
|
||||||
|
public class ChapterSortComparerTest
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(new[] {1, 2, 0}, new[] {1, 2, 0})]
|
||||||
|
[InlineData(new[] {3, 1, 2}, new[] {1, 2, 3})]
|
||||||
|
[InlineData(new[] {1, 0, 0}, new[] {1, 0, 0})]
|
||||||
|
public void ChapterSortTest(int[] input, int[] expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, input.OrderBy(f => f, new ChapterSortComparer()).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
using API.Interfaces;
|
using System.Collections.Generic;
|
||||||
|
using API.Entities;
|
||||||
|
using API.Interfaces;
|
||||||
using API.Services;
|
using API.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
@ -8,7 +10,7 @@ namespace API.Tests.Services
|
|||||||
{
|
{
|
||||||
public class CacheServiceTests
|
public class CacheServiceTests
|
||||||
{
|
{
|
||||||
private readonly ICacheService _cacheService;
|
private readonly CacheService _cacheService;
|
||||||
private readonly ILogger<CacheService> _logger = Substitute.For<ILogger<CacheService>>();
|
private readonly ILogger<CacheService> _logger = Substitute.For<ILogger<CacheService>>();
|
||||||
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
|
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
|
||||||
private readonly IArchiveService _archiveService = Substitute.For<IArchiveService>();
|
private readonly IArchiveService _archiveService = Substitute.For<IArchiveService>();
|
||||||
@ -56,6 +58,42 @@ namespace API.Tests.Services
|
|||||||
// Assert.Equal(expected, _cacheService.GetCachedPagePath(volume, pageNum));
|
// Assert.Equal(expected, _cacheService.GetCachedPagePath(volume, pageNum));
|
||||||
Assert.True(true);
|
Assert.True(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetOrderedChaptersTest()
|
||||||
|
{
|
||||||
|
var files = new List<MangaFile>()
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 1
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 2
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var expected = new List<MangaFile>()
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 1
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 2
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Chapter = 0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Assert.NotStrictEqual(expected, _cacheService.GetOrderedChapters(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ namespace API.Tests.Services
|
|||||||
new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
|
new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
|
||||||
new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
|
new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
|
||||||
)]
|
)]
|
||||||
|
|
||||||
public void TestLogicalComparer(string[] input, string[] expected)
|
public void TestLogicalComparer(string[] input, string[] expected)
|
||||||
{
|
{
|
||||||
NumericComparer nc = new NumericComparer();
|
NumericComparer nc = new NumericComparer();
|
||||||
|
18
API/Comparators/ChapterSortComparer.cs
Normal file
18
API/Comparators/ChapterSortComparer.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace API.Comparators
|
||||||
|
{
|
||||||
|
public class ChapterSortComparer : IComparer<int>
|
||||||
|
{
|
||||||
|
public int Compare(int x, int y)
|
||||||
|
{
|
||||||
|
if (x == 0 && y == 0) return 0;
|
||||||
|
// if x is 0, it comes second
|
||||||
|
if (x == 0) return 1;
|
||||||
|
// if y is 0, it comes second
|
||||||
|
if (y == 0) return -1;
|
||||||
|
|
||||||
|
return x.CompareTo(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using API.DTOs;
|
|||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@ -17,14 +18,16 @@ namespace API.Controllers
|
|||||||
private readonly ICacheService _cacheService;
|
private readonly ICacheService _cacheService;
|
||||||
private readonly ILogger<ReaderController> _logger;
|
private readonly ILogger<ReaderController> _logger;
|
||||||
private readonly IUnitOfWork _unitOfWork;
|
private readonly IUnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
public ReaderController(IDirectoryService directoryService, ICacheService cacheService,
|
public ReaderController(IDirectoryService directoryService, ICacheService cacheService,
|
||||||
ILogger<ReaderController> logger, IUnitOfWork unitOfWork)
|
ILogger<ReaderController> logger, IUnitOfWork unitOfWork, IMapper mapper)
|
||||||
{
|
{
|
||||||
_directoryService = directoryService;
|
_directoryService = directoryService;
|
||||||
_cacheService = cacheService;
|
_cacheService = cacheService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_unitOfWork = unitOfWork;
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("image")]
|
[HttpGet("image")]
|
||||||
@ -33,9 +36,12 @@ namespace API.Controllers
|
|||||||
// Temp let's iterate the directory each call to get next image
|
// Temp let's iterate the directory each call to get next image
|
||||||
var volume = await _cacheService.Ensure(volumeId);
|
var volume = await _cacheService.Ensure(volumeId);
|
||||||
|
|
||||||
var path = _cacheService.GetCachedPagePath(volume, page);
|
var (path, mangaFile) = _cacheService.GetCachedPagePath(volume, page);
|
||||||
|
if (string.IsNullOrEmpty(path)) return BadRequest($"No such image for page {page}");
|
||||||
var file = await _directoryService.ReadImageAsync(path);
|
var file = await _directoryService.ReadImageAsync(path);
|
||||||
file.Page = page;
|
file.Page = page;
|
||||||
|
file.Chapter = mangaFile.Chapter;
|
||||||
|
file.MangaFileName = mangaFile.FilePath;
|
||||||
|
|
||||||
return Ok(file);
|
return Ok(file);
|
||||||
}
|
}
|
||||||
@ -57,6 +63,8 @@ namespace API.Controllers
|
|||||||
{
|
{
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||||
_logger.LogInformation($"Saving {user.UserName} progress for {bookmarkDto.VolumeId} to page {bookmarkDto.PageNum}");
|
_logger.LogInformation($"Saving {user.UserName} progress for {bookmarkDto.VolumeId} to page {bookmarkDto.PageNum}");
|
||||||
|
|
||||||
|
// TODO: Don't let user bookmark past total pages.
|
||||||
|
|
||||||
user.Progresses ??= new List<AppUserProgress>();
|
user.Progresses ??= new List<AppUserProgress>();
|
||||||
var userProgress = user.Progresses.SingleOrDefault(x => x.VolumeId == bookmarkDto.VolumeId && x.AppUserId == user.Id);
|
var userProgress = user.Progresses.SingleOrDefault(x => x.VolumeId == bookmarkDto.VolumeId && x.AppUserId == user.Id);
|
||||||
|
@ -9,5 +9,7 @@
|
|||||||
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 int Chapter { get; set; }
|
||||||
|
public string MangaFileName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,7 +27,7 @@ namespace API.Entities
|
|||||||
public DateTime LastModified { get; set; }
|
public DateTime LastModified { get; set; }
|
||||||
public byte[] CoverImage { get; set; }
|
public byte[] CoverImage { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sum of all Volume pages
|
/// Sum of all Volume page counts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Pages { get; set; }
|
public int Pages { get; set; }
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace API.Interfaces
|
|||||||
/// <param name="volume"></param>
|
/// <param name="volume"></param>
|
||||||
/// <param name="page">Page number to look for</param>
|
/// <param name="page">Page number to look for</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string GetCachedPagePath(Volume volume, int page);
|
(string path, MangaFile file) GetCachedPagePath(Volume volume, int page);
|
||||||
|
|
||||||
bool CacheDirectoryIsAccessible();
|
bool CacheDirectoryIsAccessible();
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ namespace API.Parser
|
|||||||
/// <param name="filePath"></param>
|
/// <param name="filePath"></param>
|
||||||
/// <param name="rootPath">Root folder</param>
|
/// <param name="rootPath">Root folder</param>
|
||||||
/// <returns><see cref="ParserInfo"/> or null if Series was empty</returns>
|
/// <returns><see cref="ParserInfo"/> or null if Series was empty</returns>
|
||||||
public static ParserInfo? Parse(string filePath, string rootPath)
|
public static ParserInfo Parse(string filePath, string rootPath)
|
||||||
{
|
{
|
||||||
var fileName = Path.GetFileName(filePath);
|
var fileName = Path.GetFileName(filePath);
|
||||||
var directoryName = (new FileInfo(filePath)).Directory?.Name;
|
var directoryName = (new FileInfo(filePath)).Directory?.Name;
|
||||||
|
@ -108,10 +108,12 @@ namespace API.Services
|
|||||||
|
|
||||||
public IEnumerable<MangaFile> GetOrderedChapters(ICollection<MangaFile> files)
|
public IEnumerable<MangaFile> GetOrderedChapters(ICollection<MangaFile> files)
|
||||||
{
|
{
|
||||||
return files.OrderBy(f => f.Chapter).Where(f => f.Chapter > 0 || f.Volume.Number != 0);
|
// BUG: This causes a problem because total pages on a volume assumes "specials" to be there
|
||||||
|
//return files.OrderBy(f => f.Chapter).Where(f => f.Chapter > 0 || f.Volume.Number != 0);
|
||||||
|
return files.OrderBy(f => f.Chapter, new ChapterSortComparer());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetCachedPagePath(Volume volume, int page)
|
public (string path, MangaFile file) GetCachedPagePath(Volume volume, int page)
|
||||||
{
|
{
|
||||||
// Calculate what chapter the page belongs to
|
// Calculate what chapter the page belongs to
|
||||||
var pagesSoFar = 0;
|
var pagesSoFar = 0;
|
||||||
@ -125,12 +127,12 @@ namespace API.Services
|
|||||||
var files = _directoryService.GetFiles(path);
|
var files = _directoryService.GetFiles(path);
|
||||||
Array.Sort(files, _numericComparer);
|
Array.Sort(files, _numericComparer);
|
||||||
|
|
||||||
return files.ElementAt(page - pagesSoFar);
|
return (files.ElementAt(page - pagesSoFar), mangaFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
pagesSoFar += mangaFile.NumberOfPages;
|
pagesSoFar += mangaFile.NumberOfPages;
|
||||||
}
|
}
|
||||||
return "";
|
return ("", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -61,7 +61,7 @@ namespace API.Services
|
|||||||
FullPath = Path.GetFullPath(imagePath),
|
FullPath = Path.GetFullPath(imagePath),
|
||||||
Width = image.Width,
|
Width = image.Width,
|
||||||
Height = image.Height,
|
Height = image.Height,
|
||||||
Format = image.Format
|
Format = image.Format,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user