From 7cf7eb85d29fbf42ca170e918fcf30ccaaa542d7 Mon Sep 17 00:00:00 2001 From: Glax Date: Thu, 9 Jan 2025 01:33:30 +0100 Subject: [PATCH] Fix #307 Chapternumbers ChapterNumbers now can be sub-decimal, like version-numbers (x.y.z.a...) --- API/Schema/Chapter.cs | 24 +- API/Schema/ChapterNumber.cs | 305 ++++++++++++++++++++++ API/Schema/MangaConnectors/AsuraToon.cs | 4 +- API/Schema/MangaConnectors/Bato.cs | 6 +- API/Schema/MangaConnectors/MangaDex.cs | 16 +- API/Schema/MangaConnectors/MangaHere.cs | 6 +- API/Schema/MangaConnectors/MangaKatana.cs | 6 +- API/Schema/MangaConnectors/MangaLife.cs | 10 +- API/Schema/MangaConnectors/Manganato.cs | 8 +- API/Schema/MangaConnectors/Mangasee.cs | 6 +- API/Schema/MangaConnectors/Mangaworld.cs | 14 +- API/Schema/MangaConnectors/ManhuaPlus.cs | 4 +- API/Schema/MangaConnectors/WeebCentral.cs | 9 +- 13 files changed, 379 insertions(+), 39 deletions(-) create mode 100644 API/Schema/ChapterNumber.cs diff --git a/API/Schema/Chapter.cs b/API/Schema/Chapter.cs index 6c03c973..f236e89d 100644 --- a/API/Schema/Chapter.cs +++ b/API/Schema/Chapter.cs @@ -10,19 +10,26 @@ public class Chapter : IComparable { [MaxLength(64)] public string ChapterId { get; init; } = TokenGen.CreateToken(typeof(Chapter), 64); - public float? VolumeNumber { get; private set; } - public float ChapterNumber { get; private set; } + public int? VolumeNumber { get; private set; } + public ChapterNumber ChapterNumber { get; private set; } public string Url { get; internal set; } public string? Title { get; private set; } public string ArchiveFileName { get; private set; } public bool Downloaded { get; internal set; } = false; - public Manga ParentManga { get; init; } + public string ParentMangaId { get; internal set; } + public Manga? ParentManga { get; init; } - public Chapter(Manga parentManga, string url, float chapterNumber, - float? volumeNumber = null, string? title = null) + public Chapter(Manga parentManga, string url, ChapterNumber chapterNumber, int? volumeNumber = null, string? title = null) + : this(parentManga.MangaId, url, chapterNumber, volumeNumber, title) { this.ParentManga = parentManga; + } + + public Chapter(string parentMangaId, string url, ChapterNumber chapterNumber, + int? volumeNumber = null, string? title = null) + { + this.ParentMangaId = parentMangaId; this.Url = url; this.ChapterNumber = chapterNumber; this.VolumeNumber = volumeNumber; @@ -30,16 +37,13 @@ public Chapter(Manga parentManga, string url, float chapterNumber, this.ArchiveFileName = BuildArchiveFileName(); } - public Chapter(string url, float chapterNumber, float? volumeNumber = null, string? title = null) - : this(null, url, chapterNumber, volumeNumber, title){} - - public MoveFileOrFolderJob? UpdateChapterNumber(float chapterNumber) + public MoveFileOrFolderJob? UpdateChapterNumber(ChapterNumber chapterNumber) { this.ChapterNumber = chapterNumber; return UpdateArchiveFileName(); } - public MoveFileOrFolderJob? UpdateVolumeNumber(float? volumeNumber) + public MoveFileOrFolderJob? UpdateVolumeNumber(int? volumeNumber) { this.VolumeNumber = volumeNumber; return UpdateArchiveFileName(); diff --git a/API/Schema/ChapterNumber.cs b/API/Schema/ChapterNumber.cs new file mode 100644 index 00000000..240ff7cd --- /dev/null +++ b/API/Schema/ChapterNumber.cs @@ -0,0 +1,305 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Numerics; +using System.Text.RegularExpressions; + +namespace API.Schema; + +public readonly struct ChapterNumber : INumber +{ + private readonly uint[] _numbers; + private readonly bool _naN; + + private ChapterNumber(uint[] numbers, bool naN = false) + { + this._numbers = numbers; + this._naN = naN; + } + + public ChapterNumber(string number) + { + if (!CanParse(number)) + { + this._numbers = []; + this._naN = true; + } + this._numbers = number.Split('.').Select(uint.Parse).ToArray(); + } + + public ChapterNumber(float number) : this(number.ToString("F")) {} + + public ChapterNumber(double number) : this((float)number) {} + + public ChapterNumber(uint number) + { + this._numbers = [number]; + this._naN = false; + } + + public ChapterNumber(int number) + { + if (int.IsNegative(number)) + { + this._numbers = []; + this._naN = true; + } + this._numbers = [(uint)number]; + this._naN = false; + } + + public int CompareTo(ChapterNumber other) + { + byte index = 0; + do + { + if (this._numbers[index] < other._numbers[index]) + return -1; + else if (this._numbers[index] > other._numbers[index]) + return 1; + }while(index < this._numbers.Length && index < other._numbers.Length); + + if (index >= this._numbers.Length && index >= other._numbers.Length) + return 0; + else if (index >= this._numbers.Length) + return -1; + else if (index >= other._numbers.Length) + return 1; + throw new UnreachableException(); + } + + private static readonly Regex Pattern = new(@"[0-9]+(?:\.[0-9]+)*"); + public static bool CanParse(string? number) => number is not null && Pattern.Match(number).Length == number.Length && number.Length > 0; + + public bool Equals(ChapterNumber other) => CompareTo(other) == 0; + + public string ToString(string? format, IFormatProvider? formatProvider) + { + return string.Join('.', _numbers); + } + + public override bool Equals(object? obj) + { + return obj is ChapterNumber other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(_numbers, _naN); + } + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + public int CompareTo(object? obj) + { + if(obj is ChapterNumber other) + return CompareTo(other); + throw new ArgumentException(); + } + + public static ChapterNumber Parse(string s, IFormatProvider? provider) + { + if(!CanParse(s)) + throw new FormatException($"Invalid ChapterNumber-String: {s}"); + return new ChapterNumber(s); + } + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out ChapterNumber result) + { + result = new ChapterNumber([], true);; + if (!CanParse(s)) + return false; + if (s is null) + return false; + result = new ChapterNumber(s); + return true; + } + + public static ChapterNumber Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s.ToString(), provider); + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out ChapterNumber result) => TryParse(s.ToString(), provider, out result); + + public static ChapterNumber operator +(ChapterNumber left, ChapterNumber right) + { + if (IsNaN(left) || IsNaN(right)) + return new ChapterNumber([], true); + int size = left._numbers.Length > right._numbers.Length ? left._numbers.Length : right._numbers.Length; + uint[] numbers = new uint[size]; + for (int i = 0; i < size; i++) + { + if(left._numbers.Length < i) + numbers[i] = right._numbers[i]; + else if(right._numbers.Length < i) + numbers[i] = left._numbers[i]; + else + numbers[i] = left._numbers[i] + right._numbers[i]; + } + return new ChapterNumber(numbers); + } + + private static bool BothNotNaN(ChapterNumber left, ChapterNumber right) => !IsNaN(left) && !IsNaN(right); + + public static ChapterNumber AdditiveIdentity => Zero; + + public static bool operator ==(ChapterNumber left, ChapterNumber right) => BothNotNaN(left, right) && left.Equals(right); + + public static bool operator !=(ChapterNumber left, ChapterNumber right) => !(left == right); + + public static bool operator >(ChapterNumber left, ChapterNumber right) => BothNotNaN(left, right) && left.CompareTo(right) > 0; + + public static bool operator >=(ChapterNumber left, ChapterNumber right) => BothNotNaN(left, right) && left.CompareTo(right) >= 0; + + public static bool operator <(ChapterNumber left, ChapterNumber right) => BothNotNaN(left, right) && left.CompareTo(right) < 0; + + public static bool operator <=(ChapterNumber left, ChapterNumber right) => BothNotNaN(left, right) && left.CompareTo(right) <= 0; + + public static ChapterNumber operator %(ChapterNumber left, ChapterNumber right) => throw new ArithmeticException(); + + public static ChapterNumber operator +(ChapterNumber value) => throw new InvalidOperationException(); + + public static ChapterNumber operator --(ChapterNumber value) + { + if (IsNaN(value)) + return value; + uint[] numbers = value._numbers; + numbers[0]--; + return new ChapterNumber(numbers); + } + + public static ChapterNumber operator /(ChapterNumber left, ChapterNumber right) => throw new InvalidOperationException(); + + public static ChapterNumber operator ++(ChapterNumber value) + { + if (IsNaN(value)) + return value; + uint[] numbers = value._numbers; + numbers[0]++; + return new ChapterNumber(numbers); + } + + public static ChapterNumber MultiplicativeIdentity => One; + public static ChapterNumber operator *(ChapterNumber left, ChapterNumber right) => throw new InvalidOperationException(); + + public static ChapterNumber operator -(ChapterNumber left, ChapterNumber right) => throw new InvalidOperationException(); + + public static ChapterNumber operator -(ChapterNumber value) => throw new InvalidOperationException(); + + public static ChapterNumber Abs(ChapterNumber value) => value; + + public static bool IsCanonical(ChapterNumber value) => true; + + public static bool IsComplexNumber(ChapterNumber value) => false; + + public static bool IsEvenInteger(ChapterNumber value) => IsInteger(value) && uint.IsEvenInteger(value._numbers[0]); + + public static bool IsFinite(ChapterNumber value) => true; + + public static bool IsImaginaryNumber(ChapterNumber value) => false; + + public static bool IsInfinity(ChapterNumber value) => false; + + public static bool IsInteger(ChapterNumber value) => !IsNaN(value) && value._numbers.Length == 1; + + public static bool IsNaN(ChapterNumber value) => value._naN; + + public static bool IsNegative(ChapterNumber value) => false; + + public static bool IsNegativeInfinity(ChapterNumber value) => false; + + public static bool IsNormal(ChapterNumber value) => true; + + public static bool IsOddInteger(ChapterNumber value) => false; + + public static bool IsPositive(ChapterNumber value) => true; + + public static bool IsPositiveInfinity(ChapterNumber value) => false; + + public static bool IsRealNumber(ChapterNumber value) => false; + + public static bool IsSubnormal(ChapterNumber value) => false; + + public static bool IsZero(ChapterNumber value) => value._numbers.All(n => n == 0); + + public static ChapterNumber MaxMagnitude(ChapterNumber x, ChapterNumber y) + { + if(IsNaN(x)) + return new ChapterNumber([], true); + if (IsNaN(y)) + return new ChapterNumber([], true); + return x >= y ? x : y; + } + + public static ChapterNumber MaxMagnitudeNumber(ChapterNumber x, ChapterNumber y) + { + if (IsNaN(x)) + return y; + if (IsNaN(y)) + return x; + return x >= y ? x : y; + } + + public static ChapterNumber MinMagnitude(ChapterNumber x, ChapterNumber y) + { + if(IsNaN(x)) + return new ChapterNumber([], true); + if (IsNaN(y)) + return new ChapterNumber([], true); + return x <= y ? x : y; + } + + public static ChapterNumber MinMagnitudeNumber(ChapterNumber x, ChapterNumber y) + { + if (IsNaN(x)) + return y; + if (IsNaN(y)) + return x; + return x <= y ? x : y; + } + + public static ChapterNumber Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + + public static ChapterNumber Parse(string s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + + public static bool TryConvertFromChecked(TOther value, out ChapterNumber result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryConvertFromSaturating(TOther value, out ChapterNumber result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryConvertFromTruncating(TOther value, out ChapterNumber result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryConvertToChecked(ChapterNumber value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryConvertToSaturating(ChapterNumber value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryConvertToTruncating(ChapterNumber value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase + { + throw new NotImplementedException(); + } + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ChapterNumber result) + => TryParse(s.ToString(), style, provider, out result); + + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ChapterNumber result) + => TryParse(s, provider, out result); + + public static ChapterNumber One => new(1); + public static int Radix => 10; + public static ChapterNumber Zero => new(0); +} \ No newline at end of file diff --git a/API/Schema/MangaConnectors/AsuraToon.cs b/API/Schema/MangaConnectors/AsuraToon.cs index 5bdda6fb..4394200a 100644 --- a/API/Schema/MangaConnectors/AsuraToon.cs +++ b/API/Schema/MangaConnectors/AsuraToon.cs @@ -152,7 +152,9 @@ private List ParseChaptersFromHtml(Manga manga, string mangaUrl) string chapterUrl = chapterInfo.GetAttributeValue("href", ""); Match match = infoRex.Match(chapterInfo.InnerText); - float chapterNumber = float.Parse(match.Groups[1].Value); + if(!ChapterNumber.CanParse(match.Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(match.Groups[1].Value); string? chapterName = match.Groups[2].Success && match.Groups[2].Length > 1 ? match.Groups[2].Value : null; string url = $"https://asuracomic.net/series/{chapterUrl}"; try diff --git a/API/Schema/MangaConnectors/Bato.cs b/API/Schema/MangaConnectors/Bato.cs index 45d3f3c8..80e3e039 100644 --- a/API/Schema/MangaConnectors/Bato.cs +++ b/API/Schema/MangaConnectors/Bato.cs @@ -158,8 +158,10 @@ private List ParseChaptersFromHtml(Manga manga, string mangaUrl) Match match = numberRex.Match(chapterUrl); string id = match.Groups[1].Value; - float? volumeNumber = match.Groups[2].Success ? float.Parse(match.Groups[2].Value) : null; - float chapterNumber = float.Parse(match.Groups[3].Value); + int? volumeNumber = match.Groups[2].Success ? int.Parse(match.Groups[2].Value) : null; + if(ChapterNumber.CanParse(match.Groups[3].Value)) + continue; + ChapterNumber chapterNumber = new(match.Groups[3].Value); string url = $"https://bato.to{chapterUrl}?load=2"; try { diff --git a/API/Schema/MangaConnectors/MangaDex.cs b/API/Schema/MangaConnectors/MangaDex.cs index 833108bb..c4a4b426 100644 --- a/API/Schema/MangaConnectors/MangaDex.cs +++ b/API/Schema/MangaConnectors/MangaDex.cs @@ -221,13 +221,17 @@ public override Chapter[] GetChapters(Manga manga, string language="en") ? attributes["title"]!.GetValue() : null; - float? volume = attributes.ContainsKey("volume") && attributes["volume"] is not null - ? float.Parse(attributes["volume"]!.GetValue()) + int? volume = attributes.ContainsKey("volume") && attributes["volume"] is not null + ? int.Parse(attributes["volume"]!.GetValue()) : null; - float chapterNum = attributes.ContainsKey("chapter") && attributes["chapter"] is not null - ? float.Parse(attributes["chapter"]!.GetValue()) - : 0; + string? chapterNumStr = attributes.ContainsKey("chapter") && attributes["chapter"] is not null + ? attributes["chapter"]!.GetValue() + : null; + + if(chapterNumStr is null || ChapterNumber.CanParse(chapterNumStr)) + continue; + ChapterNumber chapterNumber = new(chapterNumStr); if (attributes.ContainsKey("pages") && attributes["pages"] is not null && @@ -238,7 +242,7 @@ public override Chapter[] GetChapters(Manga manga, string language="en") try { - Chapter newChapter = new Chapter(manga, url, chapterNum, volume, title); + Chapter newChapter = new Chapter(manga, url, chapterNumber, volume, title); if(!chapters.Contains(newChapter)) chapters.Add(newChapter); } diff --git a/API/Schema/MangaConnectors/MangaHere.cs b/API/Schema/MangaConnectors/MangaHere.cs index e6551e76..bf3ec40a 100644 --- a/API/Schema/MangaConnectors/MangaHere.cs +++ b/API/Schema/MangaConnectors/MangaHere.cs @@ -127,8 +127,10 @@ public override Chapter[] GetChapters(Manga manga, string language="en") { Match rexMatch = chapterRex.Match(url); - float? volumeNumber = rexMatch.Groups[1].Value == "TBD" ? null : float.Parse(rexMatch.Groups[1].Value); - float chapterNumber = float.Parse(rexMatch.Groups[2].Value); + int? volumeNumber = rexMatch.Groups[1].Value == "TBD" ? null : int.Parse(rexMatch.Groups[1].Value); + if(!ChapterNumber.CanParse(rexMatch.Groups[2].Value)) + continue; + ChapterNumber chapterNumber = new(rexMatch.Groups[2].Value); string fullUrl = $"https://www.mangahere.cc{url}"; try diff --git a/API/Schema/MangaConnectors/MangaKatana.cs b/API/Schema/MangaConnectors/MangaKatana.cs index b28bd3e8..75299888 100644 --- a/API/Schema/MangaConnectors/MangaKatana.cs +++ b/API/Schema/MangaConnectors/MangaKatana.cs @@ -184,8 +184,10 @@ private List ParseChaptersFromHtml(Manga manga, string mangaUrl) string url = chapterInfo.Descendants("a").First() .GetAttributeValue("href", ""); - float? volumeNumber = volumeRex.IsMatch(url) ? float.Parse(volumeRex.Match(url).Groups[1].Value) : null; - float chapterNumber = float.Parse(chapterNumRex.Match(url).Groups[1].Value); + int? volumeNumber = volumeRex.IsMatch(url) ? int.Parse(volumeRex.Match(url).Groups[1].Value) : null; + if(!ChapterNumber.CanParse(chapterNumRex.Match(url).Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(chapterNumRex.Match(url).Groups[1].Value); string chapterName = chapterNameRex.Match(fullString).Groups[1].Value; try { diff --git a/API/Schema/MangaConnectors/MangaLife.cs b/API/Schema/MangaConnectors/MangaLife.cs index 24a97a37..30d72c68 100644 --- a/API/Schema/MangaConnectors/MangaLife.cs +++ b/API/Schema/MangaConnectors/MangaLife.cs @@ -147,9 +147,13 @@ public override Chapter[] GetChapters(Manga manga, string language="en") { Match rexMatch = urlRex.Match(url); - float? volumeNumber = rexMatch.Groups[3].Success && rexMatch.Groups[3].Value.Length > 0 ? - float.Parse(rexMatch.Groups[3].Value) : null; - float chapterNumber = float.Parse(rexMatch.Groups[1].Value); + int? volumeNumber = rexMatch.Groups[3].Success && rexMatch.Groups[3].Value.Length > 0 + ? int.Parse(rexMatch.Groups[3].Value) + : null; + + if(!ChapterNumber.CanParse(rexMatch.Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(rexMatch.Groups[1].Value); string fullUrl = $"https://manga4life.com{url}"; fullUrl = fullUrl.Replace(Regex.Match(url,"(-page-[0-9])").Value,""); try diff --git a/API/Schema/MangaConnectors/Manganato.cs b/API/Schema/MangaConnectors/Manganato.cs index 4c72da3a..054dfc5b 100644 --- a/API/Schema/MangaConnectors/Manganato.cs +++ b/API/Schema/MangaConnectors/Manganato.cs @@ -178,8 +178,12 @@ private List ParseChaptersFromHtml(Manga manga, HtmlDocument document) string url = chapterInfo.Descendants("a").First(d => d.HasClass("chapter-name")) .GetAttributeValue("href", ""); - float? volumeNumber = volRex.IsMatch(fullString) ? float.Parse(volRex.Match(fullString).Groups[1].Value) : null; - float chapterNumber = float.Parse(chapterRex.Match(url).Groups[1].Value); + int? volumeNumber = volRex.IsMatch(fullString) + ? int.Parse(volRex.Match(fullString).Groups[1].Value) + : null; + if(!ChapterNumber.CanParse(chapterRex.Match(url).Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(chapterRex.Match(url).Groups[1].Value); string chapterName = nameRex.Match(fullString).Groups[3].Value; try { diff --git a/API/Schema/MangaConnectors/Mangasee.cs b/API/Schema/MangaConnectors/Mangasee.cs index 86e04cfc..67e2b0fd 100644 --- a/API/Schema/MangaConnectors/Mangasee.cs +++ b/API/Schema/MangaConnectors/Mangasee.cs @@ -171,8 +171,10 @@ public override Chapter[] GetChapters(Manga manga, string language="en") { string url = chapter.Descendants("link").First().Value; Match m = chVolRex.Match(url); - float? volumeNumber = m.Groups[2].Success ? float.Parse(m.Groups[2].Value) : null; - float chapterNumber = float.Parse(m.Groups[1].Value); + int? volumeNumber = m.Groups[2].Success ? int.Parse(m.Groups[2].Value) : null; + if(!ChapterNumber.CanParse(m.Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(m.Groups[1].Value); string chapterUrl = Regex.Replace(url, @"-page-[0-9]+(\.html)", ".html"); try diff --git a/API/Schema/MangaConnectors/Mangaworld.cs b/API/Schema/MangaConnectors/Mangaworld.cs index cf483e9f..7c6c5b2d 100644 --- a/API/Schema/MangaConnectors/Mangaworld.cs +++ b/API/Schema/MangaConnectors/Mangaworld.cs @@ -154,17 +154,19 @@ private List ParseChaptersFromHtml(Manga manga, HtmlDocument document) foreach (HtmlNode volNode in document.DocumentNode.SelectNodes("//div[contains(concat(' ',normalize-space(@class),' '),'volume-element')]")) { string volumeStr = volumeRex.Match(volNode.SelectNodes("div").First(node => node.HasClass("volume")).SelectSingleNode("p").InnerText).Groups[1].Value; - float volume = float.Parse(volumeStr); + int volume = int.Parse(volumeStr); foreach (HtmlNode chNode in volNode.SelectNodes("div").First(node => node.HasClass("volume-chapters")).SelectNodes("div")) { string numberStr = chapterRex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText).Groups[1].Value; - float chapter = float.Parse(numberStr); + if(!ChapterNumber.CanParse(numberStr)) + continue; + ChapterNumber chapterNumber = new(numberStr); string url = chNode.SelectSingleNode("a").GetAttributeValue("href", ""); string id = idRex.Match(chNode.SelectSingleNode("a").GetAttributeValue("href", "")).Groups[1].Value; try { - ret.Add(new Chapter(manga, url, chapter, volume, null)); + ret.Add(new Chapter(manga, url, chapterNumber, volume, null)); } catch (Exception e) { @@ -177,12 +179,14 @@ private List ParseChaptersFromHtml(Manga manga, HtmlDocument document) foreach (HtmlNode chNode in chaptersWrapper.SelectNodes("div").Where(node => node.HasClass("chapter"))) { string numberStr = chapterRex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText).Groups[1].Value; - float chapter = float.Parse(numberStr); + if(!ChapterNumber.CanParse(numberStr)) + continue; + ChapterNumber chapterNumber = new(numberStr); string url = chNode.SelectSingleNode("a").GetAttributeValue("href", ""); string id = idRex.Match(chNode.SelectSingleNode("a").GetAttributeValue("href", "")).Groups[1].Value; try { - ret.Add(new Chapter(manga, url, chapter, null, null)); + ret.Add(new Chapter(manga, url, chapterNumber, null, null)); } catch (Exception e) { diff --git a/API/Schema/MangaConnectors/ManhuaPlus.cs b/API/Schema/MangaConnectors/ManhuaPlus.cs index dc6e2d0a..03128672 100644 --- a/API/Schema/MangaConnectors/ManhuaPlus.cs +++ b/API/Schema/MangaConnectors/ManhuaPlus.cs @@ -148,7 +148,9 @@ public override Chapter[] GetChapters(Manga manga, string language="en") { Match rexMatch = urlRex.Match(url); - float chapterNumber = float.Parse(rexMatch.Groups[1].Value); + if(!ChapterNumber.CanParse(rexMatch.Groups[1].Value)) + continue; + ChapterNumber chapterNumber = new(rexMatch.Groups[1].Value); string fullUrl = url; try { diff --git a/API/Schema/MangaConnectors/WeebCentral.cs b/API/Schema/MangaConnectors/WeebCentral.cs index 53700cbe..75681884 100644 --- a/API/Schema/MangaConnectors/WeebCentral.cs +++ b/API/Schema/MangaConnectors/WeebCentral.cs @@ -182,7 +182,7 @@ private List ParseChaptersFromHtml(Manga manga, HtmlDocument document) var url = elem.GetAttributeValue("href", "") ?? "Undefined"; if (!url.StartsWith("https://") && !url.StartsWith("http://")) - return new Chapter(manga, "undefined", -1, null, null); + return new Chapter(manga, "undefined", new ChapterNumber(-1), null, null); var idMatch = idRex.Match(url); var id = idMatch.Success ? idMatch.Groups[1].Value : null; @@ -191,10 +191,13 @@ private List ParseChaptersFromHtml(Manga manga, HtmlDocument document) "Undefined"; var chapterNumberMatch = chapterRex.Match(chapterNode); - var chapterNumber = chapterNumberMatch.Success ? float.Parse(chapterNumberMatch.Groups[1].Value) : -1; + if(!chapterNumberMatch.Success || !ChapterNumber.CanParse(chapterNumberMatch.Groups[1].Value)) + return new Chapter(manga, "undefined", new ChapterNumber(-1), null, null); + ChapterNumber chapterNumber = new(chapterNumberMatch.Groups[1].Value); + return new Chapter(manga, url, chapterNumber, null, null); - }).Where(elem => elem.ChapterNumber < 0 && elem.Url != "undefined").ToList(); + }).Where(elem => elem.ChapterNumber < ChapterNumber.Zero && elem.Url != "undefined").ToList(); ret.Reverse(); return ret;