public async Task<List<AnimeCharacter>> GetMangaCharacters(bool force) //html is malformed { if (_animeMode) throw new InvalidOperationException("You fed constructor with anime, remember?"); var output = force ? new List<AnimeCharacter>() : await DataCache.RetrieveData<List<AnimeCharacter>>($"staff_{_animeId}", "MangaDetails", 7) ?? new List<AnimeCharacter>(); var raw = await GetRequestResponse(false); if (string.IsNullOrEmpty(raw)) return null; var doc = new HtmlDocument(); doc.LoadHtml(raw); try { var mainContainer = doc.FirstOfDescendantsWithClass("div", "js-scrollfix-bottom-rel"); var tables = mainContainer.ChildNodes.Where(node => node.Name == "table").ToList(); foreach (var table in tables) { try { var current = new AnimeCharacter(); var imgs = table.Descendants("img").ToList(); var infos = table.Descendants("td").ToList(); //character var img = imgs[0].Attributes["data-src"].Value; if (!img.Contains("questionmark")) { img = img.Replace("/r/46x64", ""); current.ImgUrl = img.Substring(0, img.IndexOf('?')); } current.FromAnime = _animeMode; current.ShowId = _animeId.ToString(); current.Name = WebUtility.HtmlDecode(imgs[0].Attributes["alt"].Value.Replace(",", "")); current.Id = infos[0].ChildNodes[1].ChildNodes[0].Attributes["href"].Value.Split('/')[2]; current.Notes = ""; //malformed html here TODO: Check if fixed //table.Descendants("small").First().InnerText; output.Add(current); } catch (Exception) { // } } } catch (Exception) { //html strikes again } return output; }
public async Task<List<AnimeCharacter>> GetSearchResults() { var output = new List<AnimeCharacter>(); var raw = await GetRequestResponse(false); if (string.IsNullOrEmpty(raw)) return null; var doc = new HtmlDocument(); doc.LoadHtml(raw); try { foreach (var row in doc.DocumentNode.Descendants("table").First().Descendants("tr").Skip(1)) { try { var character = new AnimeCharacter(); var tds = row.Descendants("td").ToList(); var link = tds[1].Descendants("a").First(); character.Id = link.Attributes["href"].Value.Split('/')[2]; character.Name = WebUtility.HtmlDecode(link.InnerText.Trim()); var smalls = tds[1].Descendants("small"); if (smalls.Any()) character.Notes = WebUtility.HtmlDecode(smalls.Last().InnerText); var img = tds[0].Descendants("img").First().Attributes["src"].Value; if (!img.Contains("questionmark")) { img = Regex.Replace(img, @"\/r\/\d+x\d+", ""); character.ImgUrl = img.Substring(0, img.IndexOf('?')); } output.Add(character); } catch (Exception) { // } } } catch (Exception) { // } return output; }
public async Task<StaffDetailsData> GetStaffDetails(bool force) { var possibleData = force ? null : await DataCache.RetrieveData<StaffDetailsData>(_id.ToString(), "staff_details", 30); if (possibleData != null) return possibleData; var output = new StaffDetailsData(); var raw = await GetRequestResponse(); if (string.IsNullOrEmpty(raw)) return output; var doc = new HtmlDocument(); doc.LoadHtml(raw); output.Id = _id; try { var columns = doc.DocumentNode.Descendants("table").First().ChildNodes[0].ChildNodes.Where( node => node.Name == "td").ToList(); var leftColumn = columns[0]; var image = leftColumn.Descendants("img").FirstOrDefault(); if (image != null && image.Attributes.Contains("alt")) output.ImgUrl = image.Attributes["src"].Value; output.Name = WebUtility.HtmlDecode(doc.DocumentNode.Descendants("h1").First().InnerText.Trim()); bool recording = false; var currentString = ""; int i = 0; foreach (var child in leftColumn.ChildNodes) { if (!recording) { if (child.Attributes.Contains("class") && child.Attributes["class"].Value.Trim() == "js-sns-icon-container icon-block") recording = true; else continue; } if (child.Attributes.Contains("class") && child.Attributes["class"].Value == "spaceit_pad") { output.Details.Add(WebUtility.HtmlDecode(child.InnerText.Trim())); currentString = ""; i = 0; } else if (!string.IsNullOrWhiteSpace(child.InnerText)) { currentString += WebUtility.HtmlDecode(child.InnerText.Trim()) + " "; i++; if (i == 2) { output.Details.Add(currentString); currentString = ""; i = 0; } } if (child.Name == "div" && !child.Attributes.Contains("class")) break; } foreach (var table in columns[1].Descendants("table").Take(2)) try { foreach (var row in table.Descendants("tr")) { var tds = row.Descendants("td").ToList(); if (tds.Count == 4) { var current = new ShowCharacterPair(); var show = new AnimeLightEntry(); var img = tds[0].Descendants("img").First().Attributes["data-src"].Value; if (!img.Contains("questionmark")) { img = Regex.Replace(img, @"\/r\/\d+x\d+", ""); show.ImgUrl = img.Substring(0, img.IndexOf('?')); } var link = tds[1].Descendants("a").First(); show.IsAnime = true; show.Id = int.Parse(link.Attributes["href"].Value.Split('/')[2]); show.Title = WebUtility.HtmlDecode(link.InnerText.Trim()); current.AnimeLightEntry = show; var character = new AnimeCharacter(); character.FromAnime = true; character.ShowId = show.Id.ToString(); link = tds[2].Descendants("a").First(); character.Id = link.Attributes["href"].Value.Split('/')[2]; character.Name = WebUtility.HtmlDecode(link.InnerText.Trim()); character.Notes = WebUtility.HtmlDecode(tds[2].Descendants("div").Last().InnerText); img = tds[3].Descendants("img").First().Attributes["data-src"].Value; if (!img.Contains("questionmark")) { img = Regex.Replace(img, @"\/r\/\d+x\d+", ""); character.ImgUrl = img.Substring(0, img.IndexOf('?')); } current.AnimeCharacter = character; output.ShowCharacterPairs.Add(current); } else { var show = new AnimeLightEntry(); var img = tds[0].Descendants("img").First().Attributes["data-src"].Value; if (!img.Contains("questionmark")) { img = Regex.Replace(img, @"\/r\/\d+x\d+", ""); show.ImgUrl = img.Substring(0, img.IndexOf('?')); } var link = tds[1].Descendants("a").First(); show.IsAnime = !link.Attributes["href"].Value.Contains("/manga/"); show.Id = int.Parse(link.Attributes["href"].Value.Split('/')[2]); show.Title = WebUtility.HtmlDecode(link.InnerText.Trim()); show.Notes = WebUtility.HtmlDecode( tds[1].Descendants("div").Last().InnerText.Replace("add", "").Trim()); output.StaffPositions.Add(show); } } } catch (Exception e) { //htaml } } catch (Exception) { //sorcery } DataCache.SaveData(output, _id.ToString(), "staff_details"); return output; }
public async Task<ProfileData> GetProfileData(bool force = false, bool updateFavsOnly = false) { ProfileData possibleData = null; if (!force) possibleData = await DataCache.RetrieveProfileData(_userName); if (possibleData != null) return possibleData; var raw = !updateFavsOnly ? await (await (await MalHttpContextProvider.GetHttpContextAsync()).GetAsync($"/profile/{_userName}")).Content.ReadAsStringAsync() : await GetRequestResponse(); var doc = new HtmlDocument(); doc.LoadHtml(raw); var current = new ProfileData { User = { Name = _userName } }; #region Recents try { var i = 1; foreach ( var recentNode in doc.DocumentNode.Descendants("div") .Where( node => node.Attributes.Contains("class") && node.Attributes["class"].Value == HtmlClassMgr.ClassDefs["#Profile:recentUpdateNode:class"])) { if (i <= 3) { current.RecentAnime.Add( int.Parse( recentNode.Descendants("a").First().Attributes["href"].Value.Substring(8).Split('/')[2])); } else { current.RecentManga.Add( int.Parse( recentNode.Descendants("a").First().Attributes["href"].Value.Substring(8).Split('/')[2])); } i++; } } catch (Exception) { //no recents } #endregion #region FavChar try { foreach ( var favCharNode in doc.DocumentNode.Descendants("ul") .First( node => node.Attributes.Contains("class") && node.Attributes["class"].Value == HtmlClassMgr.ClassDefs["#Profile:favCharacterNode:class"]) .Descendants("li")) { var curr = new AnimeCharacter(); var imgNode = favCharNode.Descendants("a").First(); var styleString = imgNode.Attributes["style"].Value.Substring(22); curr.ImgUrl = styleString.Replace("/r/80x120", ""); curr.ImgUrl = curr.ImgUrl.Substring(0, curr.ImgUrl.IndexOf('?')); var infoNode = favCharNode.Descendants("div").Skip(1).First(); var nameNode = infoNode.Descendants("a").First(); curr.Name = nameNode.InnerText.Trim(); curr.Id = nameNode.Attributes["href"].Value.Substring(9).Split('/')[2]; var originNode = infoNode.Descendants("a").Skip(1).First(); curr.Notes = originNode.InnerText.Trim(); curr.ShowId = originNode.Attributes["href"].Value.Split('/')[2]; curr.FromAnime = originNode.Attributes["href"].Value.Split('/')[1] == "anime"; current.FavouriteCharacters.Add(curr); } } catch (Exception) { //no favs } #endregion #region FavManga try { foreach ( var favMangaNode in doc.DocumentNode.Descendants("ul") .First( node => node.Attributes.Contains("class") && node.Attributes["class"].Value == HtmlClassMgr.ClassDefs["#Profile:favMangaNode:class"]) .Descendants("li")) { current.FavouriteManga.Add( int.Parse( favMangaNode.Descendants("a").First().Attributes["href"].Value.Substring(9).Split('/')[2 ])); } } catch (Exception) { //no favs } #endregion #region FavAnime try { foreach ( var favAnimeNode in doc.DocumentNode.Descendants("ul") .First( node => node.Attributes.Contains("class") && node.Attributes["class"].Value == HtmlClassMgr.ClassDefs["#Profile:favAnimeNode:class"]) .Descendants("li")) { current.FavouriteAnime.Add( int.Parse( favAnimeNode.Descendants("a").First().Attributes["href"].Value.Substring(9).Split('/')[2 ])); } } catch (Exception) { //no favs } #endregion #region FavPpl try { foreach ( var favPersonNode in doc.DocumentNode.Descendants("ul") .First( node => node.Attributes.Contains("class") && node.Attributes["class"].Value == HtmlClassMgr.ClassDefs["#Profile:favPeopleNode:class"]) .Descendants("li")) { var curr = new AnimeStaffPerson(); var aElems = favPersonNode.Descendants("a"); var styleString = aElems.First().Attributes["style"].Value.Substring(22); curr.ImgUrl = styleString.Replace("/r/80x120", ""); curr.ImgUrl = curr.ImgUrl.Substring(0, curr.ImgUrl.IndexOf('?')); curr.Name = aElems.Skip(1).First().InnerText.Trim(); curr.Id = aElems.Skip(1).First().Attributes["href"].Value.Substring(9).Split('/')[2]; current.FavouritePeople.Add(curr); } } catch (Exception) { //no favs } #endregion #region Stats if (!updateFavsOnly) try { var animeStats = doc.FirstOfDescendantsWithClass("div", "stats anime"); var generalStats = animeStats.Descendants("div").First().Descendants("div"); current.AnimeDays = float.Parse(generalStats.First().InnerText.Substring(5).Trim()); current.AnimeMean = float.Parse(generalStats.Last().InnerText.Substring(11).Trim()); var i = 0; #region AnimeStats foreach ( var htmlNode in animeStats.FirstOfDescendantsWithClass("ul", "stats-status fl-l").Descendants("li")) { switch (i) { case 0: current.AnimeWatching = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 1: current.AnimeCompleted = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 2: current.AnimeOnHold = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 3: current.AnimeDropped = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 4: current.AnimePlanned = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; } i++; } //left stats done now right i = 0; foreach ( var htmlNode in animeStats.FirstOfDescendantsWithClass("ul", "stats-data fl-r").Descendants("li")) { switch (i) { case 0: current.AnimeTotal = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; case 1: current.AnimeRewatched = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; case 2: current.AnimeEpisodes = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; } i++; } //we are done with anime #endregion i = 0; animeStats = doc.FirstOfDescendantsWithClass("div", "stats manga"); generalStats = animeStats.Descendants("div").First().Descendants("div"); current.MangaDays = float.Parse(generalStats.First().InnerText.Substring(5).Trim()); current.MangaMean = float.Parse(generalStats.Last().InnerText.Substring(11).Trim()); #region MangaStats foreach ( var htmlNode in animeStats.FirstOfDescendantsWithClass("ul", "stats-status fl-l").Descendants("li")) { switch (i) { case 0: current.MangaReading = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 1: current.MangaCompleted = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 2: current.MangaOnHold = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 3: current.MangaDropped = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; case 4: current.MangaPlanned = int.Parse(htmlNode.Descendants("span").First().InnerText.Trim().Replace(",", "")); break; } i++; } //left stats done now right i = 0; foreach ( var htmlNode in animeStats.FirstOfDescendantsWithClass("ul", "stats-data fl-r").Descendants("li")) { switch (i) { case 0: current.MangaTotal = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; case 1: current.MangaReread = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; case 2: current.MangaChapters = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; case 3: current.MangaVolumes = int.Parse(htmlNode.Descendants("span").Last().InnerText.Trim().Replace(",", "")); break; } i++; } //we are done with manga #endregion } catch (Exception) { //hatml } #endregion #region LeftSideBar if (!updateFavsOnly) try { var sideInfo = doc.FirstOfDescendantsWithClass("ul", "user-status border-top pb8 mb4").Descendants("li").ToList(); try { foreach (var htmlNode in sideInfo) { current.Details.Add(new Tuple<string, string>(htmlNode.FirstChild.InnerText, htmlNode.LastChild.InnerText)); } //current.LastOnline = sideInfo[0].LastChild.InnerText; //current.Gender = sideInfo[1].LastChild.InnerText; //current.Birthday = sideInfo[2].LastChild.InnerText; //current.Location = sideInfo[3].LastChild.InnerText; //current.Joined = sideInfo[4].LastChild.InnerText; } catch (Exception) { //current.LastOnline = sideInfo[0].LastChild.InnerText; //current.Joined = sideInfo[1].LastChild.InnerText; } current.User.ImgUrl = doc.FirstOfDescendantsWithClass("div", "user-image mb8").Descendants("img").First().Attributes["src" ] .Value; } catch (Exception) { //??? } #endregion #region Friends if (!updateFavsOnly) try { var friends = doc.FirstOfDescendantsWithClass("div", "user-friends pt4 pb12").Descendants("a"); foreach (var friend in friends) { var curr = new MalUser(); var styleString = friend.Attributes["style"].Value.Substring(22); curr.ImgUrl = styleString.Replace("/r/76x120", ""); curr.ImgUrl = curr.ImgUrl.Substring(0, curr.ImgUrl.IndexOf('?')); curr.Name = friend.InnerText; current.Friends.Add(curr); } } catch (Exception) { // } #endregion #region Comments if (!updateFavsOnly) try { var commentBox = doc.FirstOfDescendantsWithClass("div", "user-comments mt24 pt24"); foreach (var comment in commentBox.WhereOfDescendantsWithClass("div", "comment clearfix")) { var curr = new MalComment(); curr.User.ImgUrl = comment.Descendants("img").First().Attributes["src"].Value; var textBlock = comment.Descendants("div").First(); var header = textBlock.Descendants("div").First(); curr.User.Name = header.ChildNodes[1].InnerText; curr.Date = header.ChildNodes[3].InnerText; curr.Content = WebUtility.HtmlDecode(textBlock.Descendants("div").Skip(1).First().InnerText.Trim()); var postActionNodes = comment.WhereOfDescendantsWithClass("a", "ml8"); var convNode = postActionNodes.FirstOrDefault(node => node.InnerText.Trim() == "Conversation"); if (convNode != null) { curr.ComToCom = WebUtility.HtmlDecode(convNode.Attributes["href"].Value.Split('?').Last()); } var deleteNode = postActionNodes.FirstOrDefault(node => node.InnerText.Trim() == "Delete"); if(deleteNode != null) { curr.CanDelete = true; curr.Id = deleteNode.Attributes["onclick"].Value.Split(new char[] {'(', ')'}, StringSplitOptions.RemoveEmptyEntries).Last(); } current.Comments.Add(curr); } } catch (Exception e) { //no comments } #endregion try { current.ProfileMemId = doc.DocumentNode.Descendants("input") .First(node => node.Attributes.Contains("name") && node.Attributes["name"].Value == "profileMemId") .Attributes["value"].Value; } catch (Exception) { //restricted } try { current.HtmlContent = doc.FirstOfDescendantsWithClass("div", "word-break").OuterHtml; } catch (Exception) { // } if (_userName == Credentials.UserName) //umm why do we need someone's favs? { FavouritesManager.ForceNewSet(FavouriteType.Anime, current.FavouriteAnime.Select(i => i.ToString()).ToList()); FavouritesManager.ForceNewSet(FavouriteType.Manga, current.FavouriteManga.Select(i => i.ToString()).ToList()); FavouritesManager.ForceNewSet(FavouriteType.Character, current.FavouriteCharacters.Select(i => i.Id).ToList()); FavouritesManager.ForceNewSet(FavouriteType.Person, current.FavouritePeople.Select(i => i.Id).ToList()); } if (!updateFavsOnly) DataCache.SaveProfileData(_userName, current); return current; }
private async void NavigateCharacterWebPage(AnimeCharacter character) { ResourceLocator.SystemControlsLauncherService.LaunchUri(new Uri($"https://myanimelist.net/character/{character.Id}")); }
private void NavigateDetails(AnimeCharacter character) { ViewModelLocator.GeneralMain.Navigate(PageIndex.PageAnimeDetails, new AnimeDetailsPageNavigationArgs(int.Parse(character.ShowId), character.Notes, null, null) { Source = PageIndex.PageProfile, AnimeMode = character.FromAnime }); }