From 6e85fe8c0ae13ba7e33020e6b01be82098d88f7c Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Sun, 3 Oct 2021 13:30:31 -0700 Subject: [PATCH] Interlude/Half Volumes (#626) * Refactored Parser to handle parts * Fixed a bug where marking multiple entities as unread would actually make them look read on the UI * Implemented the ability to have float volume numbers * Removed two unit test cases * Code smells --- API.Tests/Parser/MangaParserTests.cs | 13 +--- API/Controllers/ReadingListController.cs | 2 +- API/Entities/Volume.cs | 3 + API/Parser/Parser.cs | 79 +++++++++------------- UI/Web/src/app/_services/action.service.ts | 6 +- 5 files changed, 41 insertions(+), 62 deletions(-) diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs index 917d1f467..7fb204ca7 100644 --- a/API.Tests/Parser/MangaParserTests.cs +++ b/API.Tests/Parser/MangaParserTests.cs @@ -67,6 +67,7 @@ namespace API.Tests.Parser [InlineData("X-Men v1 #201 (September 2007).cbz", "1")] [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "6")] [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "3")] + [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03.5 Ch. 023.5 - Volume 3 Extras.cbz", "3.5")] public void ParseVolumeTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseVolume(filename)); @@ -291,18 +292,6 @@ namespace API.Tests.Parser Assert.Equal(expected, API.Parser.Parser.ParseMangaSpecial(inputFile)); } -/* - private static ParserInfo CreateParserInfo(string series, string chapter, string volume, bool isSpecial = false) - { - return new ParserInfo() - { - Chapters = chapter, - Volumes = volume, - IsSpecial = isSpecial, - Series = series, - }; - } -*/ [Theory] [InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", "Btooom!~1~1")] diff --git a/API/Controllers/ReadingListController.cs b/API/Controllers/ReadingListController.cs index 1f22263c7..03a8d7c9d 100644 --- a/API/Controllers/ReadingListController.cs +++ b/API/Controllers/ReadingListController.cs @@ -437,7 +437,7 @@ namespace API.Controllers var existingChapterExists = readingList.Items.Select(rli => rli.ChapterId).ToHashSet(); var chaptersForSeries = (await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds)) - .OrderBy(c => int.Parse(c.Volume.Name)) + .OrderBy(c => float.Parse(c.Volume.Name)) .ThenBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting); var index = lastOrder + 1; diff --git a/API/Entities/Volume.cs b/API/Entities/Volume.cs index 3be7a4d6a..f4f0076db 100644 --- a/API/Entities/Volume.cs +++ b/API/Entities/Volume.cs @@ -8,6 +8,9 @@ namespace API.Entities public class Volume : IEntityDate { public int Id { get; set; } + /// + /// A String representation of the volume number. Allows for floats + /// public string Name { get; set; } public int Number { get; set; } public IList Chapters { get; set; } diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 84a6bcb43..5c9c22f83 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -70,19 +70,19 @@ namespace API.Parser @"(?.*)(\b|_)(?!\[)v(?\d+(-\d+)?)(?!\])", MatchOptions, RegexTimeout), - // Kodomo no Jikan vol. 10 + // Kodomo no Jikan vol. 10, [dmntsf.net] One Piece - Digital Colored Comics Vol. 20.5-21.5 Ch. 177 new Regex( - @"(?.*)(\b|_)(vol\.? ?)(?\d+(-\d+)?)", + @"(?.*)(\b|_)(vol\.? ?)(?\d+(\.\d)?(-\d+)?(\.\d)?)", MatchOptions, RegexTimeout), // Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb) new Regex( - @"(vol\.? ?)(?\d+)", + @"(vol\.? ?)(?\d+(\.\d)?)", MatchOptions, RegexTimeout), // Tonikaku Cawaii [Volume 11].cbz new Regex( - @"(volume )(?\d+)", + @"(volume )(?\d+(\.\d)?)", MatchOptions, RegexTimeout), // Tower Of God S01 014 (CBT) (digital).cbz @@ -92,7 +92,7 @@ namespace API.Parser RegexTimeout), // vol_001-1.cbz for MangaPy default naming convention new Regex( - @"(vol_)(?\d+)", + @"(vol_)(?\d+(\.\d)?)", MatchOptions, RegexTimeout), }; @@ -480,7 +480,7 @@ namespace API.Parser RegexTimeout), // Beelzebub_01_[Noodles].zip, Beelzebub_153b_RHS.zip new Regex( - @"^((?!v|vo|vol|Volume).)*(\s|_)(?\.?\d+(?:.\d+|-\d+)?)(?b)?(\s|_|\[|\()", + @"^((?!v|vo|vol|Volume).)*(\s|_)(?\.?\d+(?:.\d+|-\d+)?)(?b)?(\s|_|\[|\()", MatchOptions, RegexTimeout), // Yumekui-Merry_DKThias_Chapter21.zip @@ -810,12 +810,8 @@ namespace API.Parser if (!match.Groups["Volume"].Success || match.Groups["Volume"] == Match.Empty) continue; var value = match.Groups["Volume"].Value; - if (!value.Contains("-")) return RemoveLeadingZeroes(match.Groups["Volume"].Value); - var tokens = value.Split("-"); - var from = RemoveLeadingZeroes(tokens[0]); - var to = RemoveLeadingZeroes(tokens[1]); - return $"{@from}-{to}"; - + var hasPart = match.Groups["Part"].Success; + return FormatValue(value, hasPart); } } @@ -832,18 +828,32 @@ namespace API.Parser if (!match.Groups["Volume"].Success || match.Groups["Volume"] == Match.Empty) continue; var value = match.Groups["Volume"].Value; - if (!value.Contains("-")) return RemoveLeadingZeroes(match.Groups["Volume"].Value); - var tokens = value.Split("-"); - var from = RemoveLeadingZeroes(tokens[0]); - var to = RemoveLeadingZeroes(tokens[1]); - return $"{@from}-{to}"; - + var hasPart = match.Groups["Part"].Success; + return FormatValue(value, hasPart); } } return DefaultVolume; } + private static string FormatValue(string value, bool hasPart) + { + if (!value.Contains("-")) + { + return RemoveLeadingZeroes(hasPart ? AddChapterPart(value) : value); + } + + var tokens = value.Split("-"); + var from = RemoveLeadingZeroes(tokens[0]); + if (tokens.Length == 2) + { + var to = RemoveLeadingZeroes(hasPart ? AddChapterPart(tokens[1]) : tokens[1]); + return $"{@from}-{to}"; + } + + return @from; + } + public static string ParseChapter(string filename) { foreach (var regex in MangaChapterRegex) @@ -854,24 +864,9 @@ namespace API.Parser if (!match.Groups["Chapter"].Success || match.Groups["Chapter"] == Match.Empty) continue; var value = match.Groups["Chapter"].Value; - var hasChapterPart = match.Groups["ChapterPart"].Success; - - if (!value.Contains("-")) - { - return RemoveLeadingZeroes(hasChapterPart ? AddChapterPart(value) : value); - } - - var tokens = value.Split("-"); - var from = RemoveLeadingZeroes(tokens[0]); - if (tokens.Length == 2) - { - var to = RemoveLeadingZeroes(hasChapterPart ? AddChapterPart(tokens[1]) : tokens[1]); - return $"{@from}-{to}"; - } - - return from; - + var hasPart = match.Groups["Part"].Success; + return FormatValue(value, hasPart); } } @@ -898,16 +893,8 @@ namespace API.Parser if (match.Groups["Chapter"].Success && match.Groups["Chapter"] != Match.Empty) { var value = match.Groups["Chapter"].Value; - - if (value.Contains("-")) - { - var tokens = value.Split("-"); - var from = RemoveLeadingZeroes(tokens[0]); - var to = RemoveLeadingZeroes(tokens[1]); - return $"{from}-{to}"; - } - - return RemoveLeadingZeroes(match.Groups["Chapter"].Value); + var hasPart = match.Groups["Part"].Success; + return FormatValue(value, hasPart); } } @@ -1026,7 +1013,7 @@ namespace API.Parser private static string PerformPadding(string number) { - var num = Int32.Parse(number); + var num = int.Parse(number); return num switch { < 10 => "00" + num, diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 867e2e0f8..3d654108f 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -245,10 +245,10 @@ export class ActionService implements OnDestroy { markMultipleAsUnread(seriesId: number, volumes: Array, chapters?: Array, callback?: VoidActionCallback) { this.readerService.markMultipleUnread(seriesId, volumes.map(v => v.id), chapters?.map(c => c.id)).pipe(take(1)).subscribe(() => { volumes.forEach(volume => { - volume.pagesRead = volume.pages; - volume.chapters?.forEach(c => c.pagesRead = c.pages); + volume.pagesRead = 0; + volume.chapters?.forEach(c => c.pagesRead = 0); }); - chapters?.forEach(c => c.pagesRead = c.pages); + chapters?.forEach(c => c.pagesRead = 0); this.toastr.success('Marked as Read'); if (callback) {