public MangaObject ParseMangaObject(string Content) { HtmlDocument MangaObjectDocument = new HtmlDocument(); MangaObjectDocument.LoadHtml(Content); HtmlNode MangaNode = MangaObjectDocument.DocumentNode.SelectSingleNode(".//section[contains(@class, 'manga')]"); String Name = HtmlEntity.DeEntitize(MangaNode.SelectSingleNode(".//div/div[1]/h1/a").InnerText); Name = Name.Substring(0, Name.LastIndexOf(' ')); HtmlNode AlternateNamesNode = MangaNode.SelectSingleNode(".//div/table/tr/td[2]/table/tr[4]/td"); List <String> AlternateNames = (from AltName in HtmlEntity.DeEntitize(AlternateNamesNode.InnerText).Split(';') select AltName.Trim()).ToList(); List <String> Authors = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[5]/td/a") select HtmlEntity.DeEntitize(Node.InnerText)).ToList(); List <String> Artists = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[6]/td/a") select HtmlEntity.DeEntitize(Node.InnerText)).ToList(); List <String> Genres = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[7]/td/a") select HtmlEntity.DeEntitize(Node.InnerText)).ToList(); // Detect type MangaObjectType MangaType = MangaObjectType.Unknown; String mType = MangaNode.SelectSingleNode(".//div/table/tr/td[2]/table/tr[8]/td").InnerText.ToLower(); if (mType.Contains("japanese manga")) { MangaType = MangaObjectType.Manga; } else if (mType.Contains("korean manhwa")) { MangaType = MangaObjectType.Manhwa; } // Get description String Description = HtmlEntity.DeEntitize(MangaNode.SelectSingleNode(".//div/p").InnerText); // Chapters List <ChapterObject> Chapters = new List <ChapterObject>(); foreach (HtmlNode ChapterVersionNode in MangaNode.SelectNodes(".//*[@id='list']/div[starts-with(@id, 'stream_')]")) { foreach (HtmlNode VolumeNode in ChapterVersionNode.SelectNodes(".//div[contains(@class, 'volume')]")) { UInt32 Volume = 0; HtmlNode VolumeNameNode = VolumeNode.SelectSingleNode(".//h4"); if (!Equals(VolumeNameNode, null)) { String[] idParts = VolumeNameNode.GetAttributeValue("id", "v-1-").Split('-'); UInt32.TryParse(idParts[2], out Volume); } foreach (HtmlNode ChapterNode in ChapterVersionNode.SelectNodes(".//div/ul/li")) { HtmlNode InfoNode = ChapterNode.SelectSingleNode(".//a"); String ChapterName = HtmlEntity.DeEntitize(InfoNode.InnerText), Url = InfoNode.GetAttributeValue("href", null); UInt32 Chapter = 0, SubChapter = 0; Match match = Regex.Match(ChapterName, @"(vol\.(?<Volume>\d+)\s)?ch\.(?<Chapter>\d+)(\.(?<SubChapter>\d+))?"); if (match.Success) { if (match.Groups["Volume"].Success) { UInt32.TryParse(match.Groups["Volume"].Value, out Volume); } if (match.Groups["Chapter"].Success) { UInt32.TryParse(match.Groups["Chapter"].Value, out Chapter); } if (match.Groups["SubChapter"].Success) { UInt32.TryParse(match.Groups["SubChapter"].Value, out SubChapter); } } if (Equals(Url, null)) { continue; } Url = String.Format("{0}{1}", ExtensionDescriptionAttribute.RootUrl, Url); ChapterObject NewChapterObject = new ChapterObject() { Name = ChapterName, Volume = Volume, Chapter = Chapter, SubChapter = SubChapter, Locations = { new LocationObject() { Enabled = true, ExtensionName = ExtensionDescriptionAttribute.Name, ExtensionLanguage = ExtensionDescriptionAttribute.Language, Url = Url } } }; ChapterObject ExistingChapterObject = Chapters.FirstOrDefault(o => { if (!Int32.Equals(o.Chapter, NewChapterObject.Chapter)) { return(false); } if (!Int32.Equals(o.SubChapter, NewChapterObject.SubChapter)) { return(false); } return(true); }); if (Equals(ExistingChapterObject, null)) { Chapters.Add(NewChapterObject); } else { ExistingChapterObject.Merge(NewChapterObject); } } } } Chapters = Chapters.OrderBy(c => c.Chapter).ThenBy(c => c.SubChapter).ThenBy(c => c.Volume).ToList(); return(new MangaObject() { Name = Name, AlternateNames = AlternateNames, Description = Description, Authors = Authors, Artists = Artists, Genres = Genres, MangaType = MangaType, Chapters = Chapters }); }
public MangaObject ParseMangaObject(String content) { HtmlDocument MangaObjectDocument = new HtmlDocument(); MangaObjectDocument.LoadHtml(content); String MangaCoverPrime = MangaObjectDocument.GetElementbyId("mangaimg").SelectSingleNode(".//img").Attributes["src"].Value; Regex MangaCoverRegex = new Regex(@"(\d+)\.jpg"); Int32 MangaCoverInt = Int32.Parse(MangaCoverRegex.Match(MangaCoverPrime).Groups[1].Value); List <LocationObject> Covers = new List <LocationObject>(); for (Int32 mcI = 0; mcI <= MangaCoverInt; ++mcI) { Covers.Add(new LocationObject() { Url = MangaCoverRegex.Replace(MangaCoverPrime, String.Format("{0}.jpg", mcI)), ExtensionName = ExtensionDescriptionAttribute.Name, ExtensionLanguage = ExtensionDescriptionAttribute.Language }); } Covers.TrimExcess(); HtmlNode MangaProperties = MangaObjectDocument.GetElementbyId("mangaproperties").SelectSingleNode(".//table"), ChapterListing = MangaObjectDocument.GetElementbyId("listing"), MangaDesciption = MangaObjectDocument.GetElementbyId("readmangasum").SelectSingleNode(".//p"); String MangaName = HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[1]/td[2]/h2").InnerText), ReadDirection = MangaProperties.SelectSingleNode(".//tr[7]/td[2]").InnerText, ReleaseYear = Regex.Match(MangaProperties.SelectSingleNode(".//tr[3]/td[2]").InnerText, @"\d+").Value, Release = String.Format("01/01/{0}", String.IsNullOrWhiteSpace(ReleaseYear) ? "0001" : ReleaseYear), Desciption = MangaDesciption != null ? MangaDesciption.InnerText : String.Empty; MangaObjectType MangaType = MangaObjectType.Unknown; FlowDirection PageFlowDirection = FlowDirection.RightToLeft; switch (ReadDirection.ToLower()) { default: MangaType = MangaObjectType.Unknown; PageFlowDirection = FlowDirection.RightToLeft; break; case "right to left": MangaType = MangaObjectType.Manga; PageFlowDirection = FlowDirection.RightToLeft; break; case "left to right": MangaType = MangaObjectType.Manhwa; PageFlowDirection = FlowDirection.LeftToRight; break; } String[] AlternateNames = MangaProperties.SelectSingleNode(".//tr[2]/td[2]").InnerText.Split(new String[] { ", " }, StringSplitOptions.RemoveEmptyEntries), Authors = MangaProperties.SelectSingleNode(".//tr[5]/td[2]").InnerText.Split(new String[] { ", " }, StringSplitOptions.RemoveEmptyEntries), Artists = MangaProperties.SelectSingleNode(".//tr[6]/td[2]").InnerText.Split(new String[] { ", " }, StringSplitOptions.RemoveEmptyEntries), Genres = (from HtmlNode GenreNode in MangaProperties.SelectSingleNode(".//tr[8]/td[2]").SelectNodes(".//span[contains(@class,'genretags')]") select HtmlEntity.DeEntitize(GenreNode.InnerText)).ToArray(); ChapterObject[] Chapters = (from HtmlNode ChapterNode in ChapterListing.SelectNodes(".//tr[not(contains(@class,'table_head'))]") select new ChapterObject() { Name = HtmlEntity.DeEntitize(ChapterNode.SelectSingleNode(".//td[1]").LastChild.InnerText.Substring(3).Trim()), Chapter = UInt32.Parse(ChapterNode.SelectSingleNode(".//td[1]/a").InnerText.Substring(ChapterNode.SelectSingleNode(".//td[1]/a").InnerText.LastIndexOf(' ') + 1)), Locations = { new LocationObject() { ExtensionName = ExtensionDescriptionAttribute.Name, ExtensionLanguage = ExtensionDescriptionAttribute.Language, Url = String.Format("{0}{1}", ExtensionDescriptionAttribute.RootUrl, ChapterNode.SelectSingleNode(".//td[1]/a").Attributes["href"].Value) } }, Released = DateTime.Parse(ChapterNode.SelectSingleNode(".//td[2]").InnerText) }).ToArray(); return(new MangaObject() { Name = HtmlEntity.DeEntitize(MangaName), MangaType = MangaType, PageFlowDirection = PageFlowDirection, Description = HtmlEntity.DeEntitize(Desciption), AlternateNames = AlternateNames.ToList(), CoverLocations = Covers, Authors = (from Author in Authors select HtmlEntity.DeEntitize(Author)).ToList(), Artists = (from Artist in Artists select HtmlEntity.DeEntitize(Artist)).ToList(), Genres = Genres.ToList(), Released = DateTime.Parse(Release), Chapters = Chapters.ToList() }); }
public MangaObject ParseMangaObject(string content) { HtmlDocument MangaObjectDocument = new HtmlDocument(); MangaObjectDocument.LoadHtml(content); HtmlNode InformationNode = MangaObjectDocument.DocumentNode.SelectSingleNode("//div[contains(@class,'ipsBox')]/div"); String Cover = InformationNode.SelectSingleNode(".//div[1]/img").Attributes["src"].Value; HtmlNode MangaProperties = InformationNode.SelectSingleNode(".//table[contains(@class,'ipb_table')]"), ChapterListing = MangaObjectDocument.DocumentNode.SelectSingleNode("//table[contains(@class,'chapters_list')]"); String MangaName = HtmlEntity.DeEntitize(MangaObjectDocument.DocumentNode.SelectSingleNode("//h1[contains(@class,'ipsType_pagetitle')]").InnerText.Trim()), MangaTypeProp = HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[5]/td[2]").InnerText), Desciption = HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[7]/td[2]").InnerText.Replace("<br>", "\n")); MangaObjectType MangaType = MangaObjectType.Unknown; FlowDirection PageFlowDirection = FlowDirection.RightToLeft; switch (MangaTypeProp.ToLower()) { default: MangaType = MangaObjectType.Unknown; PageFlowDirection = FlowDirection.RightToLeft; break; case "manga (japanese)": MangaType = MangaObjectType.Manga; PageFlowDirection = FlowDirection.RightToLeft; break; case "manhwa (korean)": MangaType = MangaObjectType.Manhwa; PageFlowDirection = FlowDirection.LeftToRight; break; case "manhua (chinese)": MangaType = MangaObjectType.Manhua; PageFlowDirection = FlowDirection.LeftToRight; break; } HtmlNodeCollection AlternateNameNodes = MangaProperties.SelectSingleNode(".//tr[1]/td[2]").SelectNodes(".//span"), GenreNodes = MangaProperties.SelectSingleNode(".//tr[4]/td[2]").SelectNodes(".//a/span"); String[] AlternateNames = { }, Authors = { HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[2]/td[2]/a").InnerText) }, Artists = { HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[3]/td[2]/a").InnerText) }, Genres = { }; if (AlternateNameNodes != null && AlternateNameNodes.Count > 0) { AlternateNames = (from HtmlNode AltNameNode in AlternateNameNodes select HtmlEntity.DeEntitize(AltNameNode.InnerText.Trim())).ToArray(); } if (GenreNodes != null && GenreNodes.Count > 0) { Genres = (from HtmlNode GenreNode in GenreNodes select HtmlEntity.DeEntitize(GenreNode.InnerText.Trim())).ToArray(); } List <ChapterObject> Chapters = new List <ChapterObject>(); HtmlNodeCollection ChapterNodes = ChapterListing.SelectNodes(String.Format(".//tr[contains(@class,'lang_{0} chapter_row')]", ExtensionDescriptionAttribute.Language)); if (ChapterNodes != null && ChapterNodes.Count > 0) { foreach (HtmlNode ChapterNode in ChapterNodes) { HtmlNode VolChapNameNode = ChapterNode.SelectSingleNode("td[1]/a"); Match VolChapMatch = Regex.Match(VolChapNameNode.InnerText, @"(Vol\.(?<Volume>\d+)\s)?(Ch\.(?<Chapter>\d+))(\.(?<SubChapter>\d+))?"); String ChapterName = VolChapNameNode.InnerText.Substring(VolChapMatch.Length + 2).Trim(), ReleaseData = ReleaseData = ChapterNode.SelectSingleNode("td[5]").InnerText; ChapterObject PrevChapter = Chapters.LastOrDefault(); UInt32 Volume = 0, Chapter = 0, SubChapter = 0; if (VolChapMatch.Groups["Volume"].Success) { UInt32.TryParse(VolChapMatch.Groups["Volume"].Value, out Volume); } if (VolChapMatch.Groups["Chapter"].Success) { UInt32.TryParse(VolChapMatch.Groups["Chapter"].Value, out Chapter); } if (VolChapMatch.Groups["SubChapter"].Success) { UInt32.TryParse(VolChapMatch.Groups["SubChapter"].Value, out SubChapter); } DateTime Released = DateTime.Now; if (ReleaseData.Contains("-")) { ReleaseData = ReleaseData.Split(new String[] { " - " }, StringSplitOptions.RemoveEmptyEntries)[0]; DateTime.TryParseExact(ReleaseData, "dd MMMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out Released); } else if (ReleaseData.EndsWith("ago")) { String[] ReleaseDataParts = ReleaseData.Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Double Offset = 1; if (!Double.TryParse(ReleaseDataParts[0], out Offset)) { Offset = 1; } Offset *= -1; switch (ReleaseDataParts[1].ToLower()) { default: case "seconds": Released = Released.AddSeconds(Offset); break; case "minutes": Released = Released.AddMinutes(Offset); break; case "hours": Released = Released.AddHours(Offset); break; case "days": Released = Released.AddDays(Offset); break; case "weeks": Released = Released.AddDays(7 * Offset); break; } } String ChapterUrl = VolChapNameNode.Attributes["href"].Value; String ChapterHash = ChapterUrl.Split('#').Last().Split('_').First(); ChapterUrl = String.Format("https://bato.to/areader?id={0}&p=1&supress_webtoon=t", ChapterHash); ChapterObject chapterObject = new ChapterObject() { Name = HtmlEntity.DeEntitize(ChapterName), Volume = Volume, Chapter = Chapter, SubChapter = SubChapter, Released = Released, Locations = { new LocationObject() { ExtensionName = ExtensionDescriptionAttribute.Name, ExtensionLanguage = ExtensionDescriptionAttribute.Language, Url = ChapterUrl } } }; if (!Chapters.Any(o => o.Chapter == chapterObject.Chapter && ((Int32)o.SubChapter - chapterObject.SubChapter).InRange(-4, 4))) { Chapters.Add(chapterObject); } else { Chapters.Find(o => o.Chapter == chapterObject.Chapter && ((Int32)o.SubChapter - chapterObject.SubChapter).InRange(-4, 4)).Merge(chapterObject); } } } Chapters.Reverse(); Double Rating = -1; try { HtmlNode RatingNode = MangaObjectDocument.DocumentNode.SelectSingleNode("//div[contains(@class,'rating')]"); String RatingText = new String(RatingNode.InnerText.Trim().Substring(1, 4).Where(IsValidRatingChar).ToArray()); Double.TryParse(RatingText, out Rating); } catch { } return(new MangaObject() { Name = MangaName, MangaType = MangaType, PageFlowDirection = PageFlowDirection, Description = HtmlEntity.DeEntitize(Desciption), AlternateNames = AlternateNames.ToList(), CoverLocations = { new LocationObject() { Url = Cover, ExtensionName = ExtensionDescriptionAttribute.Name, ExtensionLanguage = ExtensionDescriptionAttribute.Language } }, Authors = Authors.ToList(), Artists = Artists.ToList(), Genres = Genres.ToList(), Released = (Chapters.FirstOrDefault() ?? new ChapterObject()).Released, Chapters = Chapters, Rating = Rating }); }