From 480cd94ab5b22ae4435c65654f5f6d95123307ae Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 26 Jan 2022 15:35:31 -0800 Subject: [PATCH] API for Tachiyomi Progress Sync (#996) * Added a stub for an api * Added code to Parser to get MaximumNumberFromRange. Added new API for Tachiyomi Progress tracking "mark-chapter-until-as-read" --- API.Tests/Parser/ParserTest.cs | 13 +++++++ API/Controllers/ReaderController.cs | 55 +++++++++++++++++++++++++++++ API/Parser/Parser.cs | 19 ++++++++++ 3 files changed, 87 insertions(+) diff --git a/API.Tests/Parser/ParserTest.cs b/API.Tests/Parser/ParserTest.cs index 1157fdab8..38637c10d 100644 --- a/API.Tests/Parser/ParserTest.cs +++ b/API.Tests/Parser/ParserTest.cs @@ -133,6 +133,19 @@ namespace API.Tests.Parser Assert.Equal(expected, MinimumNumberFromRange(input)); } + [Theory] + [InlineData("12-14", 14)] + [InlineData("24", 24)] + [InlineData("18-04", 18)] + [InlineData("18-04.5", 18)] + [InlineData("40", 40)] + [InlineData("40a-040b", 0)] + [InlineData("40.1_a", 0)] + public void MaximumNumberFromRangeTest(string input, float expected) + { + Assert.Equal(expected, MaximumNumberFromRange(input)); + } + [Theory] [InlineData("Darker Than Black", "darkerthanblack")] [InlineData("Darker Than Black - Something", "darkerthanblacksomething")] diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index fbcde4f3c..afc04c4e4 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -365,6 +365,7 @@ namespace API.Controllers public async Task> GetContinuePoint(int seriesId) { var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _readerService.GetContinuePoint(seriesId, userId)); } @@ -380,6 +381,60 @@ namespace API.Controllers return Ok(await _unitOfWork.AppUserProgressRepository.HasAnyProgressOnSeriesAsync(seriesId, userId)); } + /// + /// Marks every chapter that is sorted below the passed number as Read. This will not mark any specials as read. + /// + /// This is built for Tachiyomi and is not expected to be called by any other place + /// + [HttpPost("mark-chapter-until-as-read")] + public async Task> MarkChaptersUntilAsRead(int seriesId, float chapterNumber) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List() { 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); + } + + _unitOfWork.UserRepository.Update(user); + + if (!_unitOfWork.HasChanges()) return Ok(true); + if (await _unitOfWork.CommitAsync()) return Ok(true); + + await _unitOfWork.RollbackAsync(); + return Ok(false); + } + + /// + /// Marks every chapter that is sorted below the passed number as Read. This will not mark any specials as read. + /// + /// This is built for Tachiyomi and is not expected to be called by any other place + /// + [HttpPost("mark-chapter-until-as-read")] + public async Task> MarkChaptersUntilAsRead(int seriesId, float chapterNumber) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List() { 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); + } + + _unitOfWork.UserRepository.Update(user); + + if (!_unitOfWork.HasChanges()) return Ok(true); + if (await _unitOfWork.CommitAsync()) return Ok(true); + + await _unitOfWork.RollbackAsync(); + return Ok(false); + } + /// /// Returns a list of bookmarked pages for a given Chapter /// diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 742abe642..847b0b62b 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -926,6 +926,25 @@ namespace API.Parser return XmlRegex.IsMatch(Path.GetExtension(filePath)); } + + public static float MaximumNumberFromRange(string range) + { + try + { + if (!Regex.IsMatch(range, @"^[\d-.]+$")) + { + return (float) 0.0; + } + + var tokens = range.Replace("_", string.Empty).Split("-"); + return tokens.Max(float.Parse); + } + catch + { + return (float) 0.0; + } + } + public static float MinimumNumberFromRange(string range) { try