diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs index 1b2d4500b..e917bd6e8 100644 --- a/API.Tests/Parser/MangaParserTests.cs +++ b/API.Tests/Parser/MangaParserTests.cs @@ -60,6 +60,8 @@ namespace API.Tests.Parser [InlineData("NEEDLESS_Vol.4_-Simeon_6_v2[SugoiSugoi].rar", "4")] [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "1")] [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "4")] + [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "1")] + public void ParseVolumeTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseVolume(filename)); @@ -132,6 +134,7 @@ namespace API.Tests.Parser [InlineData("Kimetsu no Yaiba - Digital Colored Comics c162 Three Victorious Stars.cbz", "Kimetsu no Yaiba - Digital Colored Comics")] [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "Amaenaideyo MS")] [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "NEEDLESS")] + [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "Okusama wa Shougakusei")] public void ParseSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename)); @@ -191,6 +194,7 @@ namespace API.Tests.Parser [InlineData("Umineko no Naku Koro ni - Episode 1 - Legend of the Golden Witch #1", "1")] [InlineData("Kiss x Sis - Ch.00 - Let's Start from 0.cbz", "0")] [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "2")] + [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "3")] public void ParseChaptersTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseChapter(filename)); diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index 82dbe4e19..671a436b0 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -132,7 +132,7 @@ namespace API.Controllers var result = await _signInManager .CheckPasswordSignInAsync(user, loginDto.Password, false); - if (!result.Succeeded) return Unauthorized(); + if (!result.Succeeded) return Unauthorized("Your credentials are not correct."); // Update LastActive on account user.LastActive = DateTime.Now; diff --git a/API/Controllers/BookController.cs b/API/Controllers/BookController.cs index 9cc7bd65e..8626c8dcd 100644 --- a/API/Controllers/BookController.cs +++ b/API/Controllers/BookController.cs @@ -64,7 +64,7 @@ namespace API.Controllers var navItems = await book.GetNavigationAsync(); var chaptersList = new List(); - + foreach (var navigationItem in navItems) { if (navigationItem.NestedItems.Count > 0) @@ -116,6 +116,53 @@ namespace API.Controllers } } } + + if (chaptersList.Count == 0) + { + // Generate from TOC + var tocPage = book.Content.Html.Keys.FirstOrDefault(k => k.ToUpper().Contains("TOC")); + if (tocPage == null) return Ok(chaptersList); + + // Find all anchor tags, for each anchor we get inner text, to lower then titlecase on UI. Get href and generate page content + var doc = new HtmlDocument(); + var content = await book.Content.Html[tocPage].ReadContentAsync(); + doc.LoadHtml(content); + var anchors = doc.DocumentNode.SelectNodes("//a"); + if (anchors == null) return Ok(chaptersList); + + foreach (var anchor in anchors) + { + if (anchor.Attributes.Contains("href")) + { + var key = BookService.CleanContentKeys(anchor.Attributes["href"].Value).Split("#")[0]; + if (!mappings.ContainsKey(key)) + { + // Fallback to searching for key (bad epub metadata) + var correctedKey = book.Content.Html.Keys.SingleOrDefault(s => s.EndsWith(key)); + if (!string.IsNullOrEmpty(correctedKey)) + { + key = correctedKey; + } + } + if (!string.IsNullOrEmpty(key) && mappings.ContainsKey(key)) + { + var part = string.Empty; + if (anchor.Attributes["href"].Value.Contains("#")) + { + part = anchor.Attributes["href"].Value.Split("#")[1]; + } + chaptersList.Add(new BookChapterItem() + { + Title = anchor.InnerText, + Page = mappings[key], + Part = part, + Children = new List() + }); + } + } + } + + } return Ok(chaptersList); } diff --git a/API/Data/SeriesRepository.cs b/API/Data/SeriesRepository.cs index 9250d592a..6ada2e45f 100644 --- a/API/Data/SeriesRepository.cs +++ b/API/Data/SeriesRepository.cs @@ -332,26 +332,45 @@ namespace API.Data /// public async Task> GetInProgress(int userId, int libraryId, int limit) { - var series = await _context.Series + var series = _context.Series .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new { Series = s, PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id).Sum(s1 => s1.PagesRead), progress.AppUserId, LastModified = _context.AppUserProgresses.Where(p => p.Id == progress.Id).Max(p => p.LastModified) - }) - .Where(s => s.AppUserId == userId + }); + if (libraryId == 0) + { + var userLibraries = _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(user => user.Id == userId)) + .AsNoTracking() + .Select(library => library.Id) + .ToList(); + series = series.Where(s => s.AppUserId == userId + && s.PagesRead > 0 + && s.PagesRead < + s.Series.Pages - + 1 // - 1 because when reading, we start at 0 then go to pages - 1. But when summing, pages assumes starting at 1 + && userLibraries.Contains(s.Series.LibraryId)); + } + else + { + series = series.Where(s => s.AppUserId == userId && s.PagesRead > 0 - && s.PagesRead < (s.Series.Pages - 1) // - 1 because when reading, we start at 0 then go to pages - 1. But when summing, pages assumes starting at 1 - && (libraryId <= 0 || s.Series.LibraryId == libraryId)) - .Take(limit) + && s.PagesRead < + (s.Series.Pages - 1) // - 1 because when reading, we start at 0 then go to pages - 1. But when summing, pages assumes starting at 1 + && (s.Series.LibraryId == libraryId)); + } + var retSeries = await series.Take(limit) .OrderByDescending(s => s.LastModified) .Select(s => s.Series) .ProjectTo(_mapper.ConfigurationProvider) .AsNoTracking() .ToListAsync(); - return series.DistinctBy(s => s.Name); + return retSeries.DistinctBy(s => s.Name); } } } \ No newline at end of file diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index fbf5717e0..289982ad3 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -82,14 +82,14 @@ namespace API.Parser new Regex( @"(?.*)(?:, Chapter )(?\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Tonikaku Cawaii [Volume 11], Darling in the FranXX - Volume 01.cbz - new Regex( - @"(?.*)(?: _|-|\[|\() ?v", - RegexOptions.IgnoreCase | RegexOptions.Compiled), //Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans] new Regex( @"(?.*)(\bc\d+\b)", RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Tonikaku Cawaii [Volume 11], Darling in the FranXX - Volume 01.cbz + new Regex( + @"(?.*)(?: _|-|\[|\() ?v", + RegexOptions.IgnoreCase | RegexOptions.Compiled), // Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb) new Regex( @"(?.*) (\b|_|-)v",