async ValueTask <IReadOnlyList <DiscordEmbedBuilder> > CheckRssListUpdates <TRss, TLe, TL>( MalUser dbUser, User user, DateTimeOffset lastUpdateDateTime, Action <string, DateTimeOffset, MalUser> dbUpdateAction, CancellationToken ct) where TRss : struct, IRssFeedType where TLe : class, IListEntry where TL : struct, IListType <TLe> { var rssUpdates = await this._client.GetRecentRssUpdatesAsync <TRss>(user.Username, ct).ConfigureAwait(false); var type = new TRss().Type; var updates = rssUpdates.Where(update => update.PublishingDateTimeOffset > lastUpdateDateTime) .Select(item => item.ToRecentUpdate(type)).OrderByDescending(u => u.UpdateDateTime).ToArray(); if (!updates.Any()) { return(Array.Empty <DiscordEmbedBuilder>()); } var list = await this._client.GetLatestListUpdatesAsync <TLe, TL>(user.Username, ct).ConfigureAwait(false); foreach (var update in updates) { var latest = list.FirstOrDefault(entry => entry.Id == update.Id); if (latest == null) { continue; } else { dbUpdateAction(latest.GetHash().ToHashString(), update.UpdateDateTime, dbUser); break; } } return(updates.Select(update => list.First(entry => entry.Id == update.Id) .ToDiscordEmbedBuilder(user, update.UpdateDateTime, dbUser.Features)).ToArray()); }
private async Task <List <UserFeedEntryModel> > GetUserFeed(MalUser user) { try { var resp = await new FeedQuery(user.Name).GetRequestResponse(); var output = new List <UserFeedEntryModel>(); var xmlDoc = XElement.Parse(resp); var nodes = xmlDoc.Element("channel").Elements("item").Take(Settings.FeedsMaxEntries); foreach (var node in nodes) { var current = new UserFeedEntryModel(); current.Date = DateTime.Parse(node.Element("pubDate").Value); if (DateTime.UtcNow.Subtract(current.Date).TotalDays > Settings.FeedsMaxEntryAge) { continue; } current.User = user; current.Header = node.Element("title").Value; current.Link = node.Element("link").Value; current.Description = node.Element("description").Value; var linkParts = current.Link.Substring(10).Split('/'); current.Id = int.Parse(linkParts[2]); var pos = current.Header.LastIndexOf('-'); current.Title = current.Header.Substring(0, pos).Trim(); output.Add(current); } return(output); } catch (Exception) { return(null); } }
public void ResetStarredMessages(MalUser user) { if (_starredMessages.ContainsKey(user.Name.ToLower())) { _starredMessages.Remove(user.Name.ToLower()); _updated = true; } }
private void MemberDataTemplateFling(View view1, int i, MalUser arg3) { var img = view1.FindViewById <ImageViewAsync>(Resource.Id.ProfilePageGeneralTabFriendItemImage); if (img.IntoIfLoaded(arg3.ImgUrl)) { img.Visibility = ViewStates.Invisible; } }
public bool IsMessageStarred(string forumMessageId, MalUser poster) { var key = poster.Name.ToLower(); if (_starredMessages.ContainsKey(key)) { return(_starredMessages[key].Any(message => message.MessageId == forumMessageId)); } return(false); }
public static async Task <MalUser?> GetUser(bool setSettings = true) { try { string data = await GetApi("https://api.myanimelist.net/v2/users/@me"); if (data.IsClean()) { MalUser user = JsonConvert.DeserializeObject <MalUser>(data); if (user.picture.Contains("?t=")) { user.picture = user.picture[..user.picture.IndexOf("?")];
async Task <IReadOnlyList <DiscordEmbedBuilder> > CheckProfileListUpdatesAsync <TLe, TL>( MalUser dbUser, User user, int latestUpdateId, DateTimeOffset latestUpdateDateTime, Action <string, DateTimeOffset, MalUser> dbUpdateAction, CancellationToken ct) where TLe : class, IListEntry where TL : struct, IListType <TLe> { var listUpdates = await this._client.GetLatestListUpdatesAsync <TLe, TL>(user.Username, ct).ConfigureAwait(false); var lastListUpdate = listUpdates.First(u => u.Id == latestUpdateId); dbUpdateAction(lastListUpdate.GetHash().ToHashString(), latestUpdateDateTime, dbUser); return(new[] { lastListUpdate.ToDiscordEmbedBuilder(user, DateTimeOffset.Now, dbUser.Features) }); }
public void UnstarForumMessage(string messageId, MalUser poster) { var key = poster.Name.ToLower(); if (_starredMessages.ContainsKey(key)) { _starredMessages[key].RemoveAt( _starredMessages[key].FindIndex(message => message.MessageId == messageId)); if (!_starredMessages[key].Any()) { _starredMessages.Remove(key); } } _updated = true; }
public static async Task <List <MalUser> > GetMoreUsers(string clubId) { var output = new List <MalUser>(); try { var client = await ResourceLocator.MalHttpContextProvider.GetHttpContextAsync(); var response = await client.GetAsync($"/clubs.php?id={clubId}&action=view&t=members"); if (!response.IsSuccessStatusCode) { return(null); } var doc = new HtmlDocument(); doc.LoadHtml(await response.Content.ReadAsStringAsync()); foreach (var htmlNode in doc.DocumentNode.WhereOfDescendantsWithClass("td", "borderClass")) { var current = new MalUser(); current.Name = WebUtility.HtmlDecode(htmlNode.InnerText.Trim()); try { current.ImgUrl = htmlNode.Descendants("img").First().Attributes["src"].Value .Replace("/thumbs", "").Replace("_thumb", ""); } catch (Exception) { //picture } output.Add(current); } return(output); } catch (Exception) { return(null); } }
private View GetFriendTemplateDelegate(int i, MalUser malUser, View convertView) { var view = convertView; if (view == null) { view = Activity.LayoutInflater.Inflate(Resource.Layout.ProfilePageGeneralTabFriendItem, null); view.Click += FriendButtonOnClick; } var img = (view as FrameLayout).FindViewById <ImageViewAsync>(Resource.Id.ProfilePageGeneralTabFriendItemImage); img.Into(malUser.ImgUrl); view.Tag = malUser.Wrap(); return(view); }
private View GetTagItem(int i, MalUser s, View convertView) { var view = convertView; if (view == null) { view = MainActivity.CurrentContext.LayoutInflater.Inflate(Resource.Layout.PinnedUsersDialogItem, null); view.FindViewById <ImageButton>(Resource.Id.DeleteButton).Click += (sender, args) => { _dataStorageModule.StoredItems.Remove((sender as View).Tag.Unwrap <MalUser>()); if (ViewModelLocator.GeneralMain.CurrentMainPage == PageIndex.PageProfile) { ViewModelLocator.ProfilePage.RaisePropertyChanged("IsPinned"); } }; view.SetOnClickListener(new OnClickListener(v => { ViewModelLocator.NavMgr.ResetMainBackNav(); ViewModelLocator.NavMgr.RegisterBackNav(PageIndex.PageAnimeList, null); ViewModelLocator.GeneralMain.Navigate( PageIndex.PageProfile, new ProfilePageNavigationArgs { TargetUser = v.Tag.Unwrap <MalUser>().Name }); CleanupDialog(); })); } var tag = s.Wrap(); view.Tag = tag; view.FindViewById <ImageButton>(Resource.Id.DeleteButton).Tag = tag; view.FindViewById <TextView>(Resource.Id.Name).Text = s.Name; view.FindViewById <ImageViewAsync>(Resource.Id.ProfileImg).Into(s.ImgUrl, new CircleTransformation()); return(view); }
static void DbAnimeUpdateAction(string h, DateTimeOffset dto, MalUser u) { u.LastAnimeUpdateHash = h; u.LastUpdatedAnimeListTimestamp = dto; }
private void MemberDataTemplateFull(View view1, int i, MalUser arg3) { view1.FindViewById <ImageViewAsync>(Resource.Id.ProfilePageGeneralTabFriendItemImage).Into(arg3.ImgUrl); }
static void DbMangaUpdateAction(string h, DateTimeOffset dto, MalUser u) { u.LastMangaUpdateHash = h; u.LastUpdatedMangaListTimestamp = dto; }
public async Task <ProfileData> GetProfileData(bool force = false) { ProfileData possibleData = null; if (!force) { possibleData = await DataCache.RetrieveProfileData(_userName); } if (possibleData != null) { return(possibleData); } var raw = 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 FavCharacter(); 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.OriginatingShowName = 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 FavPerson(); 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 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()); int 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 try { var sideInfo = doc.FirstOfDescendantsWithClass("ul", "user-status border-top pb8 mb4").Descendants("li").ToList(); current.User.ImgUrl = doc.FirstOfDescendantsWithClass("div", "user-image mb8").Descendants("img").First().Attributes["src"] .Value; try { 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; } } catch (Exception) { //??? } #endregion #region Friends 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); } #endregion #region Comments 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()); current.Comments.Add(curr); } } catch (Exception) { //no comments } #endregion DataCache.SaveProfileData(_userName, current); return(current); }
public async Task <ProfileData> GetProfileData(bool force = false, bool updateFavsOnly = false) { try { ProfileData possibleData = null; if (!force) { possibleData = await DataCache.RetrieveProfileData(_userName); } if (possibleData != null) { possibleData.Cached = true; return(possibleData); } var raw = !updateFavsOnly ? await(await (await ResourceLocator.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 == "statistics-updates di-b w100 mb8")) { 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 == "favorites-list characters") .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 == "favorites-list manga") .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 == "favorites-list anime") .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 == "favorites-list people") .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(), NumberStyles.Any, CultureInfo.InvariantCulture); current.AnimeMean = float.Parse(generalStats.Last().InnerText.Substring(11).Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); 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(), NumberStyles.Any, CultureInfo.InvariantCulture); current.MangaMean = float.Parse(generalStats.Last().InnerText.Substring(11).Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); #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 e) { //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) { var left = WebUtility.HtmlDecode(htmlNode.FirstChild.InnerText); if (left == "Supporter") { continue; } current.Details.Add(new Tuple <string, string>(left, WebUtility.HtmlDecode(htmlNode.LastChild.InnerText))); } } catch (Exception) { } 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["data-bg"].Value; 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(); var imgNode = comment.Descendants("img").First(); if (imgNode.Attributes.Contains("srcset")) { curr.User.ImgUrl = imgNode.Attributes["srcset"].Value.Split(',').Last() .Replace("2x", "").Trim(); } else if (imgNode.Attributes.Contains("data-src")) { curr.User.ImgUrl = imgNode.Attributes["data-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(); } foreach (var img in comment.Descendants("img").Skip(1)) { if (img.Attributes.Contains("src")) { curr.Images.Add(img.Attributes["src"].Value); } } 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", "profile-about-user js-truncate-inner").OuterHtml; } catch (Exception) { // } if (_userName.Equals(Credentials.UserName, StringComparison.CurrentCultureIgnoreCase)) //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()); } current.IsFriend = doc.FirstOrDefaultOfDescendantsWithClass("a", "icon-user-function icon-remove js-user-function") != null; current.CanAddFriend = doc.FirstOrDefaultOfDescendantsWithClass("a", "icon-user-function icon-request js-user-function") != null; if (!updateFavsOnly) { DataCache.SaveProfileData(_userName, current); } return(current); } catch (Exception e) { ResourceLocator.TelemetryProvider.LogEvent($"Profile Query Crash: {_userName}, {e}"); ResourceLocator.MessageDialogProvider.ShowMessageDialog( "Hmm, you have encountered bug that'm hunting. I've just sent report to myself. If everything goes well it should be gone in next release :). Sorry for inconvenience!", "Ooopsies!"); } return(new ProfileData()); }
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) { var left = WebUtility.HtmlDecode(htmlNode.FirstChild.InnerText); if (left == "Supporter") { continue; } current.Details.Add(new Tuple <string, string>(left, WebUtility.HtmlDecode(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(); } foreach (var img in comment.Descendants("img").Skip(1)) { if (img.Attributes.Contains("src")) { curr.Images.Add(img.Attributes["src"].Value); } } 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); }
public static async Task <MalClubDetails> GetClubDetails(string clubId, bool justComments = false) { try { var output = new MalClubDetails { Id = clubId }; var client = await ResourceLocator.MalHttpContextProvider.GetHttpContextAsync(); var response = await client.GetAsync($"/clubs.php?cid={clubId}"); if (!response.IsSuccessStatusCode) { return(null); } var doc = new HtmlDocument(); doc.LoadHtml(await response.Content.ReadAsStringAsync()); var mainFrame = doc.DocumentNode.Descendants("table").First(); var rightBar = mainFrame.ChildNodes[1].ChildNodes[3].ChildNodes[1]; var rightDivs = rightBar.ChildNodes.Where(node => node.Name == "div" && node.Attributes.Contains("class") && (node.Attributes["class"].Value == "normal_header" || node.Attributes["class"].Value == "spaceit_pad" || node.Attributes["class"].Value == "borderClass")); var leftBar = mainFrame.ChildNodes[1].ChildNodes[1].ChildNodes[1]; var membersTable = leftBar.ChildNodes.First(node => node.Name == "table"); if (!justComments) { output.Name = WebUtility.HtmlDecode(doc.DocumentNode.Descendants("h1").First().InnerText); output.DescriptionHtml = doc.FirstOfDescendantsWithClassContaining("div", "club-information-header") .ParentNode.ChildNodes .First(node => node.Attributes.Contains("class") && node.Attributes["class"].Value == "clearfix").InnerHtml; try { output.ImgUrl = rightBar.Descendants("img") .First(node => node.Attributes.Contains("src") && node.Attributes["src"].Value.Contains("/clubs/")).Attributes["src"].Value; } catch (Exception) { //image magic tajm } int mode = 0; foreach (var rightDiv in rightDivs) { if (rightDiv.Attributes["class"].Value == "normal_header") { switch (WebUtility.HtmlDecode(rightDiv.InnerText.Trim())) { case "Club Stats": mode = 0; break; case "Club Officers": mode = 1; break; case "Anime Relations": mode = 2; break; case "Manga Relations": mode = 3; break; case "Character Relations": mode = 4; break; default: mode = -1; break; } continue; } string[] innerTextTokens; HtmlNode link = null; switch (mode) { case 0: if (rightDiv.InnerText.Contains("Pictures")) { continue; } innerTextTokens = WebUtility.HtmlDecode(rightDiv.InnerText.Trim()).Split(':'); output.GeneralInfo.Add((innerTextTokens[0], innerTextTokens[1])); break; case 1: link = rightDiv.Descendants("a").First(); var name = (WebUtility.HtmlDecode(link.InnerText.Trim())); string role = null; if (rightDiv.InnerText.Contains("(") && rightDiv.InnerText.Contains(")")) { role = rightDiv.InnerText.Replace(name, "").Replace("(", "").Replace(")", "") .Trim(); } output.Officers.Add((name, string.IsNullOrEmpty(role) ? "Officer" : role)); break; case 2: link = rightDiv.Descendants("a").First(); output.AnimeRelations.Add( (WebUtility.HtmlDecode(link.InnerText.Trim()), link.Attributes["href"].Value .Split('=') .Last())); break; case 3: link = rightDiv.Descendants("a").First(); output.MangaRelations.Add( (WebUtility.HtmlDecode(link.InnerText.Trim()), link.Attributes["href"].Value .Split('=') .Last())); break; case 4: link = rightDiv.Descendants("a").First(); output.CharacterRelations.Add( (WebUtility.HtmlDecode(link.InnerText.Trim()), link.Attributes["href"].Value .Split('=') .Last())); break; default: continue; } } output.IsPublic = !rightBar.InnerText.Contains("This is a private club."); output.Joined = rightBar.InnerText.Contains("Leave Club"); foreach (var member in membersTable.Descendants("td")) { var innerDivs = member.ChildNodes.Where(node => node.Name == "div").ToList(); var current = new MalUser(); current.Name = WebUtility.HtmlDecode(innerDivs[0].InnerText.Trim()); try { current.ImgUrl = member.Descendants("img").First().Attributes["src"].Value .Replace("/thumbs", "").Replace("_thumb", ""); } catch (Exception e) { //yes image again } output.MembersPeek.Add(current); } } foreach (var htmlNode in leftBar.WhereOfDescendantsWithPartialId("div", "comment")) { var current = new MalClubComment(); var tds = htmlNode.Descendants("td").Skip(1).First(); var firstDiv = WebUtility.HtmlDecode(tds.ChildNodes.FindFirst("div").InnerText.Trim()).Split('|') .Select(s => s.Trim()).ToList(); current.User.Name = firstDiv[0]; current.Date = firstDiv[1]; current.Content = WebUtility.HtmlDecode(tds.InnerText).Trim(); current.Content = current.Content.Replace(current.Date, ""); current.Content = current.Content.Substring(current.Content.IndexOf('|') + 1).Trim(); try { current.User.ImgUrl = htmlNode.FirstOfDescendantsWithClass("div", "picSurround") .Descendants("img").First().Attributes["src"].Value .Replace("/thumbs", "").Replace("_thumb", ""); } catch (Exception e) { //yes image again } var delComment = htmlNode.Descendants("small").LastOrDefault(); if (delComment != null && !delComment.InnerText.Contains("|")) { var txt = delComment.Descendants("a").First().Attributes.First(attribute => attribute.Value.Contains("delComment")).Value .Replace("delComment", ""); var pos = txt.IndexOf(','); current.Id = txt.Substring(0, pos - 1); current.Content = current.Content.Substring(0, current.Content.Length - 6); } try { foreach (var image in htmlNode.WhereOfDescendantsWithClass("img", "userimg")) { current.Images.Add(image.Attributes["src"].Value); } } catch (Exception) { //images strike } output.RecentComments.Add(current); } return(output); } catch (Exception) { //here we go again... meh... yes it's html you guessed right return(null); } }