Lots of work for chapters. This code will be refactored in a chapter rewrite.

This commit is contained in:
Joseph Milazzo 2021-01-27 14:14:16 -06:00
parent f430595d11
commit a42e54a078
11 changed files with 99 additions and 13 deletions

View 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());
}
}
}

View File

@ -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));
}
} }

View File

@ -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();

View 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);
}
}
}

View File

@ -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);

View File

@ -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; }
} }
} }

View File

@ -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; }

View File

@ -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();
} }

View File

@ -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;

View File

@ -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);
} }
} }
} }

View File

@ -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,
}; };
} }