Exemple #1
0
        public async Task<IAnime> GetAnime(int animeId, string username = "", string password = "")
        {
            var fullTrace = string.Empty;

            var anime = _animeFactory.CreateAnime();

            try
            {
                //Our first task is to retrieve the MAL anime - for now we cheat and grab it from our example data
                var doc = new HtmlDocument();

                var url = string.Format(_urlHelper.MalUrl, animeId);
                HttpClient webClient;

                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
                {
                    var handler = new HttpClientHandler {Credentials = new NetworkCredential(username, password)};
                    webClient = new HttpClient(handler);
                }
                else
                {
                    webClient = new HttpClient();
                }
                var data = await webClient.GetStreamAsync(new Uri(url));
                doc.Load(data, Encoding.UTF8);

                //Retrieve the MAL ID
                int aid;
                var idString =
                    doc.DocumentNode.SelectSingleNode("//input[@type='hidden' and @name='aid']").Attributes["value"]
                        .Value;
                int.TryParse(idString, out aid);
                anime.Id = aid;

                anime.Title =
                    doc.DocumentNode.SelectSingleNode("//h1").SelectSingleNode("//span[@itemprop='name']").InnerText;

                var synopsis = string.Empty;
                var synopsisNode = doc.DocumentNode.SelectSingleNode("//span[@itemprop='description']");
                if (synopsisNode != null)
                {
                    synopsis = doc.DocumentNode.SelectSingleNode("//span[@itemprop='description']").InnerText;
                }
                else
                {
                    var tableRows = doc.DocumentNode.SelectNodes("//td[@valign='top']");
                    foreach (var row in tableRows)
                    {
                        var header = row.ChildNodes["h2"];
                        if (header != null && header.InnerText.Contains("Synopsis"))
                        {
                            var synopsisData = row.ChildNodes.Where(t => t.Name == "#text").Select(t => t.InnerText).ToList();
                            synopsis = synopsisData[1];
                        }
                    }
                }

                synopsis = synopsis.TrimStart("\r\n".ToCharArray()).Trim();
                synopsis = HttpUtility.HtmlDecode(synopsis);
                anime.Synopsis = synopsis;

                //Retrieve Alternative titles
                var divNodes = doc.DocumentNode.SelectNodes("//div[@class='spaceit_pad']") ??
                               doc.DocumentNode.SelectNodes("//div");


                foreach (var node in divNodes)
                {
                    var lang = node.ChildNodes.Descendants().FirstOrDefault()?.InnerText.Trim(':');

                    switch (lang)
                    {
                        case "Japanese":
                            var jNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var jTitle in jNodes.Select(title => title.InnerText.Replace("\r\n", "").Trim()).Where(jTitle => !string.IsNullOrEmpty(jTitle)))
                            {
                                foreach (var innerjTitle in jTitle.Split(',').Select(t => t.Trim()))
                                {
                                    anime.JapaneseTitles.Add(@WebUtility.HtmlDecode(innerjTitle));
                                }
                            }
                            break;
                        case "English":
                            var eNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var eTitle in eNodes.Select(title => title.InnerText.Replace("\r\n", "").Trim()).Where(eTitle => !string.IsNullOrEmpty(eTitle)))
                            {
                                foreach (var innereTitle in eTitle.Split(',').Select(t => t.Trim()))
                                {
                                    anime.EnglishTitles.Add(@WebUtility.HtmlDecode(innereTitle));
                                }
                            }
                            break;
                        case "Synonyms":
                            var sNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var sTitle in sNodes.Select(title => title.InnerText.Replace("\r\n", "").Trim()).Where(sTitle => !string.IsNullOrEmpty(sTitle)))
                            {
                                foreach (var innersTitle in sTitle.Split(',').Select(t => t.Trim()))
                                {
                                    anime.SynonymousTitles.Add(@WebUtility.HtmlDecode(innersTitle))
                                    ;
                                }
                            }
                            break;
                    }
                }

                var img = doc.DocumentNode.SelectSingleNode("//img[@itemprop='image']")?.Attributes["data-src"]?.Value;
                if (string.IsNullOrEmpty(img))
                {
                    img = doc.DocumentNode.SelectSingleNode("//img[@itemprop='image']")?.Attributes["src"]?.Value;
                }

                //If we cannot find an image check if there is a na_series image
                if (string.IsNullOrEmpty(img))
                {
                    var noImg =
                        doc.DocumentNode.SelectSingleNode(
                            "//img[@src='http://cdn.myanimelist.net/images/qm_50.gif']")?.Attributes["src"].Value;
                    if (string.IsNullOrEmpty(noImg))
                    {
                        noImg = doc.DocumentNode.SelectSingleNode(
                            "//img[@src='http://cdn.myanimelist.net/images/na_series.gif']")?.Attributes["src"].Value;
                    }

                    if (!string.IsNullOrEmpty(noImg))
                    {
                        anime.ImageUrl = noImg;
                        anime.HighResImageUrl = noImg;
                    }
                    else
                    {
                        anime.ImageUrl = null;
                        //throw new Exception("Cannot find the image for this series and there is no na_series.gif");
                    }
                }
                else
                {
                    anime.ImageUrl = img;
                    anime.HighResImageUrl = img.Insert(img.Length - 4, "l");
                }


                foreach (var node in doc.DocumentNode.SelectNodes("//div"))
                {
                    var innerSpan = node.ChildNodes.Descendants().FirstOrDefault()?.InnerText.Trim(':');
                    switch (innerSpan)
                    {
                        case "Type":
                            var tNodes = node.ChildNodes.Where(t => t.Name == "a");
                            foreach (var innerNode in tNodes)
                            {
                                if (innerNode.Attributes["href"].Value.StartsWith("https://myanimelist.net/topanime.php?type="))
                                {
                                    var type = innerNode.InnerText.Replace("\r\n", "").Trim();
                                    anime.Type = type;
                                }
                            }
                            
                            //foreach (var type in tNodes.Select(item => item.InnerText.Replace("\r\n", "").Trim()).Where(type => !string.IsNullOrEmpty(type)))
                            //{
                            //    anime.Type = type;
                            //}
                            break;
                        case "Episodes":
                            var epString = node.ChildNodes["#text"].InnerText.TrimEnd("\n\t".ToCharArray()).Trim();
                            if (epString.ToLower() == "unknown")
                            {
                                anime.Episodes = -1;
                            }
                            else
                            {
                                int eps;
                                int.TryParse(epString, out eps);
                                if (eps == 0)
                                {
                                    epString = node.ChildNodes[2].InnerText.Replace("\r\n", "").Trim();
                                    int.TryParse(epString, out eps);
                                    anime.Episodes = eps;
                                }

                                if (eps == 0)
                                    anime.Episodes = null;
                                else
                                    anime.Episodes = eps;
                            }
                            break;
                        case "Status":
                            var stNode = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (
                                var stat in
                                    stNode.Select(t => t.InnerText.Replace("\r\n", "").Trim())
                                        .Where(type => !string.IsNullOrEmpty(type)))
                            {
                                anime.Status = stat;
                            }
                            break;
                        case "Aired":
                            var dateNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var item in dateNodes)
                            {
                                var dateString = item.InnerText.Replace("\r\n", "").Trim();
                                if (!string.IsNullOrEmpty(dateString))
                                {
                                    var dates = Regex.Split(dateString, " to ");
                                    var startDate = DateTime.MinValue;
                                    var endDate = DateTime.MinValue;
                                    if (dates.Any())
                                        DateTime.TryParse(dates[0], out startDate);
                                    if (dates.Count() > 1)
                                        DateTime.TryParse(dates[1], out endDate);
                                    anime.StartDate = startDate;
                                    anime.EndDate = endDate;
                                }
                            }     
                            break;
                        case "Rating":
                            var txt = node.InnerText.Replace("\r\n", "");
                            var cleanText = Regex.Split(txt, "                                    ").Last().Trim();
                            cleanText = cleanText.Replace("Rating:", "").Replace("Rating:", "").Trim(Environment.NewLine.ToCharArray()).Trim();
                            anime.Classification = cleanText;
                            break;
                        case "Ranked":
                            var rankNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var randNode in rankNodes)
                            {
                                var rankString = randNode.InnerText.Replace("\r\n", "").Trim().TrimStart('#');
                                if (!string.IsNullOrEmpty(rankString))
                                {
                                    int number;
                                    int.TryParse(rankString, out number);
                                    anime.Rank = number;
                                }
                            }
                            break;
                        case "Popularity":
                            var popNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach(var popItem in popNodes)
                            {
                                var pString = popItem.InnerText.Trim().TrimStart('#');
                                if (!string.IsNullOrEmpty(pString))
                                {
                                    int pNum;
                                    int.TryParse(pString, out pNum);
                                    anime.Popularity = pNum;
                                }
                            }
                            break;
                        case "Score":
                            string scoreString;
                            var scoreNode = node.SelectNodes("//span[@itemprop='ratingValue']");
                            if (scoreNode != null && scoreNode.Count >= 1)
                            {
                                scoreString = scoreNode[0].InnerText;
                            }
                            else
                            {
                                var sNode = node.ChildNodes["#text"].InnerText;
                                scoreString = sNode;
                            }
                            double scoreVal;
                            double.TryParse(scoreString, NumberStyles.Any, CultureInfo.InvariantCulture, out scoreVal);
                            anime.MemberScore = scoreVal;
                            break;
                        case "Members":
                            var memberNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var memberNode in memberNodes)
                            {
                                var memberString = memberNode.InnerText.Replace("\r\n", "").Trim().Replace(",", "");
                                if (!string.IsNullOrEmpty(memberString))
                                {
                                    int mVal;
                                    int.TryParse(memberString, out mVal);
                                    anime.MemberCount = mVal;
                                }
                            }                         
                            break;
                        case "Favorites":
                            var favNodes = node.ChildNodes.Where(t => t.Name == "#text");
                            foreach (var favNode in favNodes)
                            {
                                var favString = favNode.InnerText.Replace("\r\n", "").Trim();
                                if (!string.IsNullOrEmpty(favString))
                                {
                                    int fVal;
                                    int.TryParse(favString, NumberStyles.Any, CultureInfo.InvariantCulture, out fVal);
                                    anime.FavoriteCount = fVal;
                                }
                            }
                            break;
                        case "Genres":
                            var genreNodes = node.ChildNodes.Where(t => t.Name == "a");
                            if (genreNodes == null) break;
                            foreach (var g in genreNodes)
                            {
                                anime.Genres.Add(g.InnerText);
                            }
                            break;
                    }
                }

                //var tagNodes = doc.DocumentNode.SelectNodes("//div[@class='tags-inner']");

                //if (tagNodes != null)
                //{

                //    foreach (var tagNode in tagNodes)
                //    {
                //        foreach (var tag in tagNode.ChildNodes.Nodes())
                //        {
                //            if (tag.OriginalName == "#text" && !anime.Tags.Contains(tag.InnerText))
                //                anime.Tags.Add(tag.InnerText);
                //        }
                //    }
                //}

                GetInfoUrls(doc, anime);
                GetRelated(doc, anime);
                await GetCharacterAndSeiyuuInformation(anime, username, password);

                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
                {
                    foreach (var statusNode in doc.DocumentNode.SelectSingleNode("//select[@name='myinfo_status']").ChildNodes)
                    {
                        if (statusNode.GetAttributeValue("selected", "") != "selected") continue;
                        var status = statusNode.NextSibling.InnerText;
                        anime.UserWatchedStatus = status;
                    }

                    var epNode =
                        doc.DocumentNode.SelectSingleNode("//input[@type='text' and @name='myinfo_watchedeps']")
                            .Attributes["value"].Value;
                    int myScore;
                    int.TryParse(epNode, out myScore);
                    anime.UserWatchedEpisodes = myScore;

                    foreach (
                        var scoreNodes in doc.DocumentNode.SelectSingleNode("//select[@name='myinfo_score']").ChildNodes
                        )
                    {
                        if (scoreNodes.GetAttributeValue("selected", "") != "selected") continue;
                        var epWatched = scoreNodes.Attributes["value"].Value;
                        int usrScore;
                        int.TryParse(epWatched, out usrScore);
                        anime.UserScore = usrScore;
                    }
                }
            }
            catch (Exception ex)
            {
                anime.ErrorOccured = true;
                anime.ErrorMessage = ex.Message;
                Log.Error(ex, "Error occured while trying to retrieve {AnimeId}", animeId);
            }

            return anime;
        }