Inheritance: FavouriteBase
        public async Task<AnimeStaffData> GetCharStaffData(bool force = false)
        {
            if (!_animeMode)
                throw new InvalidOperationException("Umm you said it's going to be manga...");
            var output = force
                ? new AnimeStaffData()
                : await DataCache.RetrieveData<AnimeStaffData>($"staff_{_animeId}", "AnimeDetails", 7) ??
                  new AnimeStaffData();
            if (output.AnimeCharacterPairs.Count > 0 || output.AnimeStaff.Count > 0) return output;

            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();
                int i = 0;
                foreach (var table in tables.Take(tables.Count - 1))
                {
                    try
                    {
                        var current = new AnimeCharacterStaffModel();

                        var imgs = table.Descendants("img").ToList();
                        var infos = table.Descendants("td").ToList(); //2nd is character 4th is person

                        //character
                        var img = imgs[0].Attributes["data-src"].Value;
                        if (!img.Contains("questionmark"))
                        {
                            img = img.Replace("/r/46x64", "");
                            current.AnimeCharacter.ImgUrl = img.Substring(0, img.IndexOf('?'));
                        }

                        current.AnimeCharacter.FromAnime = _animeMode;
                        current.AnimeCharacter.ShowId = _animeId.ToString();
                        current.AnimeCharacter.Name =
                            WebUtility.HtmlDecode(imgs[0].Attributes["alt"].Value.Replace(",", ""));
                        current.AnimeCharacter.Id = infos[1].ChildNodes[1].Attributes["href"].Value.Split('/')[2];
                        current.AnimeCharacter.Notes = infos[1].ChildNodes[3].InnerText;

                        //voiceactor
                        try
                        {
                            img = imgs[1].Attributes["data-src"].Value;
                            if (!img.Contains("questionmark"))
                            {
                                img = img.Replace("/r/46x64", "");
                                current.AnimeStaffPerson.ImgUrl = img.Substring(0, img.IndexOf('?'));
                            }
                            current.AnimeStaffPerson.Name = WebUtility.HtmlDecode(imgs[1].Attributes["alt"].Value.Replace(",", ""));
                            current.AnimeStaffPerson.Id = infos[3].ChildNodes[1].Attributes["href"].Value.Split('/')[2];
                            current.AnimeStaffPerson.Notes = infos[3].ChildNodes[4].InnerText;
                        }
                        catch (Exception)
                        {
                            //no voice actor
                            current.AnimeStaffPerson.Name = "Unknown";
                            current.AnimeStaffPerson.IsUnknown = true;
                        }


                        output.AnimeCharacterPairs.Add(current);
                        if (i++ > 30)
                            break;
                    }
                    catch (Exception)
                    {
                        //oddities
                    }

                }
                i = 0;
                foreach (var staffRow in tables.Last().Descendants("tr"))
                {
                    try
                    {
                        var current = new AnimeStaffPerson();
                        var imgs = staffRow.Descendants("img").ToList();
                        var info = staffRow.Descendants("td").Last(); //we want last

                        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.Name = WebUtility.HtmlDecode(imgs[0].Attributes["alt"].Value.Replace(",", ""));
                        current.Id = info.ChildNodes[0].Attributes["href"].Value.Split('/')[2];
                        current.Notes = info.ChildNodes[3].InnerText;

                        output.AnimeStaff.Add(current);
                        if (i++ > 30)
                            break;
                    }
                    catch (Exception)
                    {
                        //what can I say?
                    }
                }
            }
            catch (Exception)
            {
                //mysteries of html
            }


            DataCache.SaveData(output,$"staff_{_animeId}","AnimeDetails");

            return output;
        }
 private async void NavigatePersonWebPage(AnimeStaffPerson person)
 {
     ResourceLocator.SystemControlsLauncherService.LaunchUri(new Uri($"https://myanimelist.net/people/{person.Id}"));
 }
Beispiel #3
0
        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;
        }
        public async Task<CharacterDetailsData> GetCharacterDetails(bool force = false)
        {
            var possibleData = force ? null : await DataCache.RetrieveData<CharacterDetailsData>(_id.ToString(), "character_details", 30);
            if (possibleData != null)
                return possibleData;

            var output = new CharacterDetailsData();
            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[1].ChildNodes.Where(node => node.Name == "td").ToList();
                var leftColumn = columns[0];
                var tables = leftColumn.Descendants("table");
                foreach (var table in tables)
                {
                    foreach (var descendant in table.Descendants("tr"))
                    {
                        var links = descendant.Descendants("a").ToList();
                        if (links[0].Attributes["href"].Value.StartsWith("/anime"))
                        {
                            var curr = new AnimeLightEntry { IsAnime = true };
                            curr.Id = int.Parse(links[0].Attributes["href"].Value.Split('/')[2]);
                            var img = links[0].Descendants("img").First().Attributes["src"].Value;
                            if (!img.Contains("questionmark"))
                            {
                                img = Regex.Replace(img, @"\/r\/\d+x\d+", "");
                                curr.ImgUrl = img.Substring(0, img.IndexOf('?'));
                            }
                            curr.Title = WebUtility.HtmlDecode(links[1].InnerText.Trim());
                            output.Animeography.Add(curr);
                        }
                        else
                        {
                            var curr = new AnimeLightEntry { IsAnime = false };
                            curr.Id = int.Parse(links[0].Attributes["href"].Value.Split('/')[2]);
                            var img = links[0].Descendants("img").First().Attributes["src"].Value;
                            if (!img.Contains("questionmark"))
                            {
                                img = Regex.Replace(img, @"\/r\/\d+x\d+", "");
                                curr.ImgUrl = img.Substring(0, img.IndexOf('?'));
                            }
                            curr.Title = WebUtility.HtmlDecode(links[1].InnerText.Trim());
                            output.Mangaography.Add(curr);
                        }
                    }
                }               
                var image = leftColumn.Descendants("img").First();
                if (image.Attributes.Contains("alt"))
                {
                    output.ImgUrl = image.Attributes["src"].Value;
                }

                output.Name = WebUtility.HtmlDecode(doc.DocumentNode.Descendants("h1").First().InnerText).Trim().Replace("  "," "); //because mal tends to leave two spaces there and there's pretty hardcore guy on github who can spot such things... props ;d
                output.Content = output.SpoilerContent = "";
                output.Content += WebUtility.HtmlDecode(leftColumn.LastChild.InnerText.Trim()) + "\n\n";
                foreach (var node in columns[1].ChildNodes)
                {
                    if (node.Name == "#text")
                        output.Content += WebUtility.HtmlDecode(node.InnerText.Trim());
                    else if (node.Name == "br" && !output.Content.EndsWith("\n\n"))
                        output.Content += "\n";
                    else if (node.Name == "div" && node.Attributes.Contains("class") && node.Attributes["class"].Value == "spoiler")
                        output.SpoilerContent += WebUtility.HtmlDecode(node.InnerText.Trim()) + "\n\n";
                    else if (node.Name == "table")
                    {
                        foreach (var descendant in node.Descendants("tr"))
                        {
                            var current = new AnimeStaffPerson();
                            var img = descendant.Descendants("img").First();
                            var imgUrl = img.Attributes["src"].Value;
                            if (!imgUrl.Contains("questionmark"))
                            {
                                var pos = imgUrl.LastIndexOf("v");
                                if (pos != -1)
                                    imgUrl = imgUrl.Remove(pos, 1);

                            }
                            current.ImgUrl = imgUrl;
                            var info = descendant.Descendants("td").Last();
                            current.Id = info.ChildNodes[0].Attributes["href"].Value.Split('/')[2];
                            current.Name = WebUtility.HtmlDecode(info.ChildNodes[0].InnerText.Trim());
                            current.Notes = info.ChildNodes[2].InnerText;
                            output.VoiceActors.Add(current);
                        }
                    }
                }
                output.Content = output.Content.Trim();
                output.SpoilerContent = output.SpoilerContent.Trim();
            }
            catch (Exception)
            {
                //html
            }
            
            DataCache.SaveData(output, _id.ToString(), "character_details");

            return output;
        }