mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Bugfix/tachiyomi sync issue (#1002)
* Added extra unit cases for GetContinuePoint. Fixed a bug where if the series was just read chapters, the first chapter wouldn't be returned and would throw an error. * Wrote unit tests for MarkChaptersUntilAsRead for Tachiyomi and fixed a few cases where due to tracking on Tachiyomi, Volumes with a single 0 chapter would get marked as read.
This commit is contained in:
parent
c9bd1d1bfb
commit
567d475e46
@ -1007,6 +1007,282 @@ public class ReaderServiceTests
|
||||
Assert.Equal("1", nextChapter.Range);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetContinuePoint_ShouldReturnFirstChapter_WhenAllReadAndAllChapters()
|
||||
{
|
||||
_context.Series.Add(new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007"
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var fileSystem = new MockFileSystem();
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds));
|
||||
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>(), ds, cs);
|
||||
|
||||
// Save progress on first volume chapters and 1st of second volume
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 1,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 2,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 3,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var nextChapter = await readerService.GetContinuePoint(1, 1);
|
||||
|
||||
Assert.Equal("1", nextChapter.Range);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetContinuePoint_ShouldReturnFirstSpecial_WhenAllReadAndAllChapters()
|
||||
{
|
||||
_context.Series.Add(new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("Some Special Title", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007"
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var fileSystem = new MockFileSystem();
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds));
|
||||
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>(), ds, cs);
|
||||
|
||||
// Save progress on first volume chapters and 1st of second volume
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 1,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 2,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
await readerService.SaveReadingProgress(new ProgressDto()
|
||||
{
|
||||
PageNum = 1,
|
||||
ChapterId = 3,
|
||||
SeriesId = 1,
|
||||
VolumeId = 1
|
||||
}, 1);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var nextChapter = await readerService.GetContinuePoint(1, 1);
|
||||
|
||||
Assert.Equal("Some Special Title", nextChapter.Range);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MarkChaptersUntilAsRead
|
||||
|
||||
[Fact]
|
||||
public async Task MarkChaptersUntilAsRead_ShouldMarkAllChaptersAsRead()
|
||||
{
|
||||
_context.Series.Add(new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("Some Special Title", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007"
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var fileSystem = new MockFileSystem();
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds));
|
||||
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>(), ds, cs);
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
|
||||
await readerService.MarkChaptersUntilAsRead(user, 1, 5);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Validate correct chapters have read status
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1)).PagesRead);
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(2, 1)).PagesRead);
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(3, 1)).PagesRead);
|
||||
Assert.Null((await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(4, 1)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MarkChaptersUntilAsRead_ShouldMarkUptTillChapterNumberAsRead()
|
||||
{
|
||||
_context.Series.Add(new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("2.5", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("Some Special Title", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007"
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var fileSystem = new MockFileSystem();
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds));
|
||||
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>(), ds, cs);
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
|
||||
await readerService.MarkChaptersUntilAsRead(user, 1, 2.5f);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Validate correct chapters have read status
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1)).PagesRead);
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(2, 1)).PagesRead);
|
||||
Assert.Equal(1, (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(3, 1)).PagesRead);
|
||||
Assert.Null((await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(4, 1)));
|
||||
Assert.Null((await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(5, 1)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MarkChaptersUntilAsRead_ShouldNotReadOnlyVolumesWithChapter0()
|
||||
{
|
||||
_context.Series.Add(new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007"
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var fileSystem = new MockFileSystem();
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds));
|
||||
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>(), ds, cs);
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
|
||||
await readerService.MarkChaptersUntilAsRead(user, 1, 2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Validate correct chapters have read status
|
||||
Assert.False(await _unitOfWork.AppUserProgressRepository.UserHasProgress(LibraryType.Manga, 1));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
@ -392,12 +392,7 @@ namespace API.Controllers
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int>() { seriesId }, true);
|
||||
foreach (var volume in volumes.OrderBy(v => v.Number))
|
||||
{
|
||||
var chapters = volume.Chapters.OrderBy(c => float.Parse(c.Number)).Where(c => !c.IsSpecial && Parser.Parser.MaximumNumberFromRange(c.Range) <= chapterNumber);
|
||||
_readerService.MarkChaptersAsRead(user, volume.SeriesId, chapters);
|
||||
}
|
||||
await _readerService.MarkChaptersUntilAsRead(user, seriesId, chapterNumber);
|
||||
|
||||
_unitOfWork.UserRepository.Update(user);
|
||||
|
||||
|
@ -23,6 +23,7 @@ public interface IReaderService
|
||||
Task<int> GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId);
|
||||
Task<int> GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId);
|
||||
Task<ChapterDto> GetContinuePoint(int seriesId, int userId);
|
||||
Task MarkChaptersUntilAsRead(AppUser user, int seriesId, float chapterNumber);
|
||||
}
|
||||
|
||||
public class ReaderService : IReaderService
|
||||
@ -317,27 +318,22 @@ public class ReaderService : IReaderService
|
||||
.OrderBy(c => float.Parse(c.Number))
|
||||
.ToList();
|
||||
|
||||
|
||||
|
||||
var currentlyReadingChapter = nonSpecialChapters.FirstOrDefault(chapter => chapter.PagesRead < chapter.Pages);
|
||||
|
||||
|
||||
// Check if there are any specials
|
||||
if (currentlyReadingChapter == null)
|
||||
{
|
||||
var volume = volumes.SingleOrDefault(v => v.Number == 0);
|
||||
if (volume == null) return nonSpecialChapters.First();
|
||||
if (currentlyReadingChapter != null) return currentlyReadingChapter;
|
||||
|
||||
foreach (var chapter in volume.Chapters.OrderBy(c => float.Parse(c.Number)))
|
||||
{
|
||||
if (chapter.PagesRead < chapter.Pages)
|
||||
{
|
||||
return chapter;
|
||||
}
|
||||
}
|
||||
// Check if there are any specials
|
||||
var volume = volumes.SingleOrDefault(v => v.Number == 0);
|
||||
if (volume == null) return nonSpecialChapters.First();
|
||||
|
||||
var chapters = volume.Chapters.OrderBy(c => float.Parse(c.Number)).ToList();
|
||||
foreach (var chapter in chapters.Where(chapter => chapter.PagesRead < chapter.Pages))
|
||||
{
|
||||
return chapter;
|
||||
}
|
||||
|
||||
return currentlyReadingChapter ?? nonSpecialChapters.First();
|
||||
return chapters.First();
|
||||
}
|
||||
|
||||
|
||||
@ -357,5 +353,23 @@ public class ReaderService : IReaderService
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks every chapter that is sorted below the passed number as Read. This will not mark any specials as read or Volumes with a single 0 chapter.
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="seriesId"></param>
|
||||
/// <param name="chapterNumber"></param>
|
||||
public async Task MarkChaptersUntilAsRead(AppUser user, int seriesId, float chapterNumber)
|
||||
{
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int>() { seriesId }, true);
|
||||
foreach (var volume in volumes.OrderBy(v => v.Number))
|
||||
{
|
||||
var chapters = volume.Chapters
|
||||
.OrderBy(c => float.Parse(c.Number))
|
||||
.Where(c => !c.IsSpecial && Parser.Parser.MaximumNumberFromRange(c.Range) <= chapterNumber && Parser.Parser.MaximumNumberFromRange(c.Range) > 0.0);
|
||||
MarkChaptersAsRead(user, volume.SeriesId, chapters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user