private IMovement GetMovement(HtmlNode nameCell, WebCharacter character) { var movement = default(IMovement); var rawNameCellText = nameCell.InnerText; if (!string.IsNullOrEmpty(rawNameCellText)) { string name = GetStatName(nameCell); var valueCell = nameCell.SelectSingleNode(ScrapingConstants.XPathTableCellValues); var rawValueText = valueCell.InnerText; string value; if (rawValueText.Contains("[")) { var checkRank = valueCell.InnerText.Split('['); value = checkRank[0]; } else { value = rawValueText; } movement = _scrapingServices.CreateMovement(); movement.Name = name; movement.Value = value; movement.Owner = character.Name; movement.OwnerId = character.OwnerId; movement.Game = character.SourceUrl.Contains("Ultimate") ? Games.Ultimate : Games.Smash4; } return(movement); }
private Pikmin GetUniqueAttributeForUltimate(HtmlNode row, WebCharacter character) { var uniqueData = GetUniqueAttributeCore(row, character); uniqueData.Game = Games.Ultimate; return(uniqueData); }
protected override IMove GetMove(HtmlNodeCollection cells, WebCharacter character) { var move = default(IMove); if (!string.IsNullOrEmpty(cells[0].InnerText) && cells.Count > 1) { string name = GetStatName(cells[0]); string faf = cells[2].InnerText; string angle = cells[4].InnerText; string bkbwbkb = cells[5].InnerText; string kbg = cells[6].InnerText; string landingLag = cells[7].InnerText; var autocancel = new CommonAutocancelParameterResolver().Resolve(cells[8]); move = ScrapingServices.CreateMove(); move = new CommonMoveParameterResolver(character.Game).Resolve(cells, move); move.Name = name; move.Angle = angle; move.BaseKnockBackSetKnockback = bkbwbkb; move.FirstActionableFrame = faf; move.KnockbackGrowth = kbg; move.LandingLag = landingLag; move.AutoCancel = autocancel; move.MoveType = MoveType.Aerial.GetEnumDescription(); move.Owner = character.Name; move.OwnerId = character.OwnerId; } return(move); }
private Vegetable GetUniqueAttributeForSmash4(HtmlNode row, WebCharacter character) { var uniqueData = GetUniqueAttributeCore(row, character); uniqueData.Game = Games.Smash4; return(uniqueData); }
protected override IMove GetMove(HtmlNodeCollection cells, WebCharacter character) { var move = default(IMove); if (!string.IsNullOrEmpty(cells[0].InnerText) && cells.Count > 1) { string name = GetStatName(cells[0]); //string hitboxActive = cells[1].InnerText; string faf = cells[2].InnerText; //string basedmg = cells[3].InnerText; string angle = cells[4].InnerText; string bkbwbkb = cells[5].InnerText; string kbg = cells[6].InnerText; move = ScrapingServices.CreateMove(); move = new CommonMoveParameterResolver(character.Game).Resolve(cells, move); move.Name = name; move.Angle = angle; //move.BaseDamage = basedmg; move.BaseKnockBackSetKnockback = bkbwbkb; move.FirstActionableFrame = faf; //move.HitboxActive = hitboxActive; move.KnockbackGrowth = kbg; move.MoveType = MoveType.Special.GetEnumDescription(); move.Owner = character.Name; move.OwnerId = character.OwnerId; //move.Game = character.SourceUrl.Contains("Ultimate") ? Games.Ultimate : Games.Smash4; } return(move); }
private MonadoArt GetUniqueAttributeForSmash4(HtmlNode row, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <MonadoArt>(); var monadoArtsCells = row.SelectNodes("td"); string name = CleanupValue(monadoArtsCells[0].InnerText); string damageTaken = CleanupValue(monadoArtsCells[1].InnerText); string damageDealt = CleanupValue(monadoArtsCells[2].InnerText); string knockbackTaken = CleanupValue(monadoArtsCells[3].InnerText); string knockbackDealt = CleanupValue(monadoArtsCells[4].InnerText); string jumpHeight = CleanupValue(monadoArtsCells[5].InnerText); string walkSpeed = CleanupValue(monadoArtsCells[6].InnerText); string airSpeed = CleanupValue(monadoArtsCells[7].InnerText); string fallSpeed = CleanupValue(monadoArtsCells[8].InnerText); string shieldHealth = CleanupValue(monadoArtsCells[9].InnerText); uniqueData.Name = name; uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.AirSpeed = airSpeed; uniqueData.DamageDealt = damageDealt; uniqueData.DamageTaken = damageTaken; uniqueData.FallSpeed = fallSpeed; uniqueData.JumpHeight = jumpHeight; uniqueData.KnockbackDealt = knockbackDealt; uniqueData.KnockbackTaken = knockbackTaken; uniqueData.ShieldHealth = shieldHealth; uniqueData.WalkSpeed = walkSpeed; uniqueData.Game = Games.Smash4; return(uniqueData); }
protected override IMove GetMove(HtmlNodeCollection cells, WebCharacter character) { if (!string.IsNullOrEmpty(cells[0].InnerText) && cells.Count > 1) { string name = GetStatName(cells[0]); IMove move = ScrapingServices.CreateMove(); move.Name = name; move.Owner = character.Name; move.OwnerId = character.OwnerId; move.MoveType = MoveType.Throw.GetEnumDescription(); if (name.IndexOf(ScrapingConstants.CommonMoveNames.Throw, StringComparison.OrdinalIgnoreCase) >= 0) { if (character.SourceUrl.Contains("Smash4")) //this value isn't present in Ultimate values on kh site yet. { bool isWeightDependent = TranslateYesNoToBool(cells[1].InnerText); move.IsWeightDependent = isWeightDependent; string baseDamage = new Smash4BaseDamageResolver().GetRawValue(cells[2]); move.BaseDamage = baseDamage; string angle = cells[3].InnerText; string baseKnockbackSetKnockback = cells[4].InnerText; string knockbackGrowth = cells[5].InnerText; move.Angle = angle; move.BaseKnockBackSetKnockback = baseKnockbackSetKnockback; move.KnockbackGrowth = knockbackGrowth; } else if (character.SourceUrl.Contains("Ultimate")) { string baseDamage = new UltimateBaseDamageResolver().GetRawValue(cells[1]); move.BaseDamage = baseDamage; string angle = cells[2].InnerText; string baseKnockbackSetKnockback = cells[3].InnerText; string knockbackGrowth = cells[4].InnerText; move.Angle = angle; move.BaseKnockBackSetKnockback = baseKnockbackSetKnockback; move.KnockbackGrowth = knockbackGrowth; move.Game = character.Game; } return(move); } else { return(default(IMove)); } } else { return(default(IMove)); } }
public void ExpectedCharacterWithSpaceInNameCanBeScraped_Ultimate(WebCharacter character) { _urlUnderTest = $"{Keys.KHSiteBaseUrl}{Keys.UltimateUrl}/"; _characterDataScraper = MakeCharacterDataScraper(); character = _characterDataScraper.PopulateCharacterFromWeb(character, _urlUnderTest); AssertCharacterDataIsValid(character); }
public void ScrapeAttributeRowData_AllCharacters_ReturnsValidData_Ultimate(WebCharacter character) { var sut = new AttributeScraper($"{Keys.KHSiteBaseUrl}{Keys.UltimateUrl}", _scrapingServices, AttributeScrapers.AirSpeed); var attributeRows = sut.Scrape(character).ToList(); AssertAttributeCollectionIsValid(sut, attributeRows); }
private Float GetUniqueAttribute(HtmlNodeCollection rows, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <Float>(); uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.DurationInFrames = GetValue("Duration (Frames)", rows); uniqueData.DurationInSeconds = GetValue("Duration (Seconds)", rows); return(uniqueData); }
public void GroundMoveScraperShouldIncludeGrabs(WebCharacter character) { const int expectedGrabCount = 3; character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var groundMoveScrapingService = new GroundMoveScraper(_scrapingServices); var groundMoves = groundMoveScrapingService.Scrape(character).ToList(); int actualNumberOfGrabMoves = groundMoves.Count(move => move.Name.EndsWith(ScrapingConstants.CommonMoveNames.Grab, StringComparison.OrdinalIgnoreCase)); Assert.That(actualNumberOfGrabMoves, Is.EqualTo(expectedGrabCount), $"{character.Name}"); }
private static void AssertMoveIsValid(IMove move, WebCharacter character) { Assert.That(move, Is.Not.Null); Assert.That(move.Name, Is.Not.Null); Assert.That(move.Angle, Is.Not.Null); Assert.That(move.BaseDamage, Is.Not.Null); Assert.That(move.BaseKnockBackSetKnockback, Is.Not.Null); Assert.That(move.FirstActionableFrame, Is.Not.Null); Assert.That(move.HitboxActive, Is.Not.Null); Assert.That(move.KnockbackGrowth, Is.Not.Null); Assert.That(move.Owner, Is.EqualTo(character.Name), $"{nameof(move.Owner)}"); }
private Aura GetUniqueAttributeForSmash4(HtmlNodeCollection rows, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <Aura>(); uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.MinPercentAuraMultiplier = GetValue("Min % Aura ×", rows); uniqueData.MaxPercentAuraMultiplier = GetValue("Max % Aura ×", rows); uniqueData.AuraBaselinePercent = GetValue("Aura Baseline %", rows); uniqueData.AuraCeilingPercent = GetValue("Aura Ceiling %", rows); return(uniqueData); }
public void GroundMoveScraperShouldExcludeRowHeaders(WebCharacter character) { var groundMoveScrapingService = new GroundMoveScraper(_scrapingServices); character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var groundMoves = groundMoveScrapingService.Scrape(character).ToList(); groundMoves.ForEach(move => { Assert.That(move.Name, Is.Not.EqualTo(ScrapingConstants.ExcludedRowHeaders.Grabs), $"{nameof(character.Name)}"); Assert.That(move.Name, Is.Not.EqualTo(ScrapingConstants.ExcludedRowHeaders.Throws), $"{nameof(character.Name)}"); Assert.That(move.Name, Is.Not.EqualTo(ScrapingConstants.ExcludedRowHeaders.Miscellaneous), $"{nameof(character.Name)}"); AssertMoveIsValid(move, character); }); }
private CommandSelection GetUniqueAttributeCore(HtmlNode row, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <CommandSelection>(); var commandSelectionCells = row.SelectNodes("td"); string name = row.SelectSingleNode("th")?.InnerText; string description = commandSelectionCells[0]?.InnerText; uniqueData.Game = Games.Smash4; uniqueData.Name = $"CommandSelection - {name}"; uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.Description = CleanupValue(description); return(uniqueData); }
private MonadoArt GetUniqueAttributeForUltimate(HtmlNode row, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <MonadoArt>(); var monadoArtsCells = row.SelectNodes("td"); string name = CleanupValue(monadoArtsCells[0].InnerText); string active = CleanupValue(monadoArtsCells[1].InnerText); string cooldown = CleanupValue(monadoArtsCells[2].InnerText); string damageTaken = CleanupValue(monadoArtsCells[3].InnerText); string damageDealt = CleanupValue(monadoArtsCells[4].InnerText); string knockbackTaken = CleanupValue(monadoArtsCells[5].InnerText); string knockbackDealt = CleanupValue(monadoArtsCells[6].InnerText); string jumpHeight = CleanupValue(monadoArtsCells[7].InnerText); string ledgeJumpHeight = CleanupValue(monadoArtsCells[8].InnerText); string airSlashHeight = CleanupValue(monadoArtsCells[9].InnerText); string initialDashSpeed = CleanupValue(monadoArtsCells[10].InnerText); string runSpeed = CleanupValue(monadoArtsCells[11].InnerText); string walkSpeed = CleanupValue(monadoArtsCells[12].InnerText); string airSpeed = CleanupValue(monadoArtsCells[13].InnerText); string gravity = CleanupValue(monadoArtsCells[14].InnerText); string fallSpeed = CleanupValue(monadoArtsCells[15].InnerText); string shieldHealth = CleanupValue(monadoArtsCells[16].InnerText); string shieldRegen = CleanupValue(monadoArtsCells[17].InnerText); uniqueData.Name = name; uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.Active = active; uniqueData.AirSlashHeight = airSlashHeight; uniqueData.AirSpeed = airSpeed; uniqueData.Cooldown = cooldown; uniqueData.DamageDealt = damageDealt; uniqueData.DamageTaken = damageTaken; uniqueData.FallSpeed = fallSpeed; uniqueData.Gravity = gravity; uniqueData.InitialDashSpeed = initialDashSpeed; uniqueData.JumpHeight = jumpHeight; uniqueData.KnockbackDealt = knockbackDealt; uniqueData.KnockbackTaken = knockbackTaken; uniqueData.LedgeJumpHeight = ledgeJumpHeight; uniqueData.RunSpeed = runSpeed; uniqueData.ShieldHealth = shieldHealth; uniqueData.ShieldRegen = shieldRegen; uniqueData.WalkSpeed = walkSpeed; uniqueData.Game = Games.Ultimate; return(uniqueData); }
public void ScrapeSpecialMovesForCharacter(WebCharacter character) { var specialMoveScrapingService = new SpecialMoveScraper(_scrapingServices); character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var specialMoves = specialMoveScrapingService.Scrape(character).ToList(); CollectionAssert.AllItemsAreNotNull(specialMoves); CollectionAssert.AllItemsAreUnique(specialMoves); CollectionAssert.IsNotEmpty(specialMoves); specialMoves.ForEach(move => { AssertMoveIsValid(move, character); }); }
public void GroundMoveScraperShouldExcludeThrowMoves(WebCharacter character) { character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var groundMoveScrapingService = new GroundMoveScraper(_scrapingServices); var groundMoves = groundMoveScrapingService.Scrape(character).ToList(); CollectionAssert.AllItemsAreNotNull(groundMoves); CollectionAssert.AllItemsAreUnique(groundMoves); CollectionAssert.IsNotEmpty(groundMoves); groundMoves.ForEach(move => { Assert.That(move.Name.IndexOf(ScrapingConstants.CommonMoveNames.Throw, StringComparison.OrdinalIgnoreCase) == -1, $"{nameof(IMove.Name)} should not contain {ScrapingConstants.CommonMoveNames.Throw}. This means the scraper might be pulling in throw moves."); }); }
public void ScrapeThrowMovesForCharacter(WebCharacter character) { var throwMoveScraper = new ThrowMoveScraper(_scrapingServices); character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var throwMoves = throwMoveScraper.Scrape(character).ToList(); CollectionAssert.IsNotEmpty(throwMoves); Assert.That(throwMoves.Count, Is.EqualTo(4)); //all chars have 4 throws. throwMoves.ForEach(move => { Assert.That(move, Is.Not.Null, "move should not be null."); Assert.That(move.Name.Contains(MoveType.Throw.GetEnumDescription()), $"{move.Name}"); Assert.That(move.MoveType, Is.EqualTo(MoveType.Throw.ToString().ToLower()), $"{move.Name}"); }); }
private void AssertCharacterDataIsValid(WebCharacter character) { Assert.That(character.FullUrl, Is.Not.Empty); Assert.That(character.ColorTheme, Is.Not.Empty); Assert.That(character.DisplayName, Is.Not.Empty); Assert.That(character.ThumbnailUrl, Is.Not.Null); Assert.That(character.MainImageUrl, Is.Not.Empty); Uri testUri; Assert.That(Uri.TryCreate(character.MainImageUrl, UriKind.Absolute, out testUri), $"Malformed main image url: '{character.MainImageUrl}'"); Assert.That(Uri.TryCreate(character.ThumbnailUrl, UriKind.Absolute, out testUri), $"Malformed thumbnail image url: '{character.ThumbnailUrl}'"); CollectionAssert.IsNotEmpty(character.Movements, $"Movements for character '{character.Name}' are empty."); CollectionAssert.IsNotEmpty(character.Moves, $"Moves for character '{character.Name}' are empty."); CollectionAssert.IsNotEmpty(character.AttributeRows, $"Attributes Rows for character '{character.Name}' are empty."); }
private Vegetable GetUniqueAttributeCore(HtmlNode row, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <Vegetable>(); var vegetableCells = row.SelectNodes("td"); string name = row.SelectSingleNode("th")?.InnerText; string chance = vegetableCells[0]?.InnerText; string damageDealt = vegetableCells[1]?.InnerText; uniqueData.Game = Games.Smash4; uniqueData.Name = $"Vegetable - {name}"; uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.Chance = CleanupValue(chance); uniqueData.DamageDealt = CleanupValue(damageDealt); return(uniqueData); }
public IEnumerable <IMovement> GetMovementsForCharacter(WebCharacter character) { var htmlParser = _scrapingServices.CreateParserFromSourceUrl(character.SourceUrl); //get movement table html string movementTableHtml = htmlParser.GetSingle(ScrapingConstants.XPathTableNodeMovementStats); var movementTableRows = HtmlNode.CreateNode(movementTableHtml)?.SelectNodes(ScrapingConstants.XPathTableRows); if (movementTableRows == null) { throw new Exception($"Error getting movement table data after attempting to scrape full table using xpath: '{ScrapingConstants.XPathTableRows};"); } return(movementTableRows.SelectMany( row => row.SelectNodes(ScrapingConstants.XPathMovementTableCellKeys), (row, statName) => GetMovement(statName, character)).Where(stat => stat != null)); }
public void ScrapeAerialMovesForCharacter(WebCharacter character) { var aerialMoveScrapingService = new AerialMoveScraper(_scrapingServices); character.SourceUrl = $"{Keys.KHSiteBaseUrl}{_game}{character.EscapedCharacterName}"; var aerialMoves = aerialMoveScrapingService.Scrape(character).ToList(); CollectionAssert.AllItemsAreNotNull(aerialMoves); CollectionAssert.AllItemsAreUnique(aerialMoves); CollectionAssert.IsNotEmpty(aerialMoves); aerialMoves.ForEach(move => { AssertMoveIsValid(move, character); Assert.That(move.LandingLag, Is.Not.Null); Assert.That(move.AutoCancel, Is.Not.Null); }); }
private Pikmin GetUniqueAttributeCore(HtmlNode row, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <Pikmin>(); var pikminCells = row.SelectNodes("td"); string name = pikminCells[0]?.InnerText; string attackThrow = CleanupValue(pikminCells[1]?.InnerText); string hp = CleanupValue(pikminCells[3]?.InnerText); int indexOfAttack = name.IndexOf("Attack"); uniqueData.Name = $"{name.Substring(0, indexOfAttack).TrimEnd()}"; //just the stuff before attack uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.Attack = attackThrow.Substring(0, 4); uniqueData.Throw = attackThrow.Substring(5, 4); uniqueData.HP = hp; return(uniqueData); }
private LimitBreak GetUniqueAttributeForSmash4(HtmlNodeCollection rows, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <LimitBreak>(); uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.FramesToCharge = GetValue("Frames to Charge", rows); uniqueData.PercentDealtToCharge = GetValue("% Dealt to Charge", rows); uniqueData.RunSpeed = GetValue("Run Speed", rows); uniqueData.WalkSpeed = GetValue("Walk Speed", rows); uniqueData.Gravity = GetValue("Gravity", rows); uniqueData.SHAirTime = GetValue("SH Air Time", rows); uniqueData.GainedPerFrame = GetValue("Gained per Frame", rows); uniqueData.PercentTakenToCharge = GetValue("% Taken to Charge", rows); uniqueData.AirSpeed = GetValue("Air Speed", rows); uniqueData.FallSpeed = GetValue("Fall Speed", rows); uniqueData.AirAcceleration = GetValue("Air Acceleration", rows); uniqueData.FHAirTime = GetValue("FH Air Time", rows); return(uniqueData); }
protected override IMove GetMove(HtmlNodeCollection cells, WebCharacter character) { var move = default(IMove); string name = GetStatName(cells[0]); //a throw move is not a ground move if (name.IndexOf(ScrapingConstants.CommonMoveNames.Throw, StringComparison.OrdinalIgnoreCase) >= 0) { return(default(IMove)); } if (!string.IsNullOrEmpty(cells[0].InnerText) && cells.Count > 1) { move = ScrapingServices.CreateMove(); move = new CommonMoveParameterResolver(character.Game).Resolve(cells, move); string faf = cells[2].InnerText; string angle = cells[4].InnerText; string bkbwbkb = cells[5].InnerText; string kbg = cells[6].InnerText; move.Name = name; move.Angle = angle; move.BaseKnockBackSetKnockback = bkbwbkb; move.FirstActionableFrame = faf; move.KnockbackGrowth = kbg; move.MoveType = MoveType.Ground.GetEnumDescription(); move.Owner = character.Name; move.OwnerId = character.OwnerId; } return(move); }
public void SeedCharacterData(WebCharacter character, ICharacterService characterService, IMovementService movementService, IMoveService moveService, ICharacterAttributeRowService characterAttributeRowService, IUniqueDataService uniqueDataService) { Guard.VerifyObjectNotNull(character, nameof(character)); Guard.VerifyObjectNotNull(characterService, nameof(characterService)); Guard.VerifyObjectNotNull(movementService, nameof(movementService)); Guard.VerifyObjectNotNull(moveService, nameof(moveService)); Guard.VerifyObjectNotNull(characterAttributeRowService, nameof(characterAttributeRowService)); Guard.VerifyObjectNotNull(uniqueDataService, nameof(uniqueDataService)); _characterDataScraper.PopulateCharacterFromWeb(character); var entityCharacter = Mapper.Map <Character>(character); characterService.Add(entityCharacter); movementService.AddMany(character.Movements); moveService.AddMany(character.Moves); characterAttributeRowService.AddMany(character.AttributeRows); uniqueDataService.AddMany(character.UniqueProperties); }
private OneWingedAngel GetUniqueAttribute(HtmlNodeCollection rows, WebCharacter character) { var uniqueData = _uniqueDataScrapingServices.Create <OneWingedAngel>(); uniqueData.Owner = character.Name; uniqueData.OwnerId = character.OwnerId; uniqueData.RunAcceleration = GetValue("Run Accel", rows); uniqueData.WalkAcceleration = GetValue("Walk Accel", rows); uniqueData.RunSpeed = GetValue("Run Speed", rows); uniqueData.WalkSpeed = GetValue("Walk Speed", rows); uniqueData.Gravity = GetValue("Gravity", rows); uniqueData.SHAirTime = GetValue("SH Air Time", rows); uniqueData.DamageDealt = GetValue("Damage Dealt", rows); uniqueData.MaxJumps = GetValue("Max Jumps", rows); uniqueData.AirSpeed = GetValue("Air Speed", rows); uniqueData.AirSpeedFriction = GetValue("Air Speed Friction", rows); uniqueData.FallSpeed = GetValue("Fall Speed", rows); uniqueData.FastFallSpeed = GetValue("Fast Fall Speed", rows); uniqueData.AirAcceleration = GetValue("Air Acceleration", rows); uniqueData.FHAirTime = GetValue("FH Air Time", rows); return(uniqueData); }
protected abstract IMove GetMove(HtmlNodeCollection cells, WebCharacter character);
public WebCharacter PopulateCharacter(WebCharacter character, string sourceBaseUrl) { var populatedCharacter = new WebCharacter(character.Name, character.EscapedCharacterName, character.UniqueScraperTypes, character.PotentialScrapingNames); if (populatedCharacter.OwnerId != CharacterIds.RosalinaLuma || (populatedCharacter.OwnerId == CharacterIds.RosalinaLuma && sourceBaseUrl.Contains("Smash4"))) { populatedCharacter.SourceUrl = sourceBaseUrl + populatedCharacter.EscapedCharacterName; } else if (populatedCharacter.OwnerId == CharacterIds.RosalinaLuma && sourceBaseUrl.Contains("Ultimate")) { populatedCharacter.SourceUrl = sourceBaseUrl + "Rosalina"; //hack, but having different names for same chars across games? come on. } populatedCharacter.CssKey = character.CssKey; const string srcAttributeKey = "src"; const string characterNameKey = "[charactername]"; var htmlParser = _webServices.CreateParserFromSourceUrl(populatedCharacter.SourceUrl); string displayNameHtml = htmlParser.GetSingle(ScrapingConstants.XPathFrameDataVersion); string displayName = GetCharacterDisplayName(displayNameHtml); if (displayName == "Rosalina") { displayName = "Rosalina & Luma"; //see previously mentioned hack comment } string thumbnailPreparedUrl = Regex.Replace(populatedCharacter.SourceUrl, "([^/]*)$", string.Empty); var thumbnailHtmlParser = _webServices.CreateParserFromSourceUrl(thumbnailPreparedUrl); string thumbnailHtml = thumbnailHtmlParser.GetSingle(ScrapingConstants.XPathThumbnailUrl.Replace(characterNameKey, character.DisplayName)); string thumbnailUrl = string.Empty; if (string.IsNullOrEmpty(thumbnailHtml)) { //try potential scraping names if there are any for the character foreach (string name in character.PotentialScrapingNames) { thumbnailHtml = thumbnailHtmlParser.GetSingle(ScrapingConstants.XPathThumbnailUrl.Replace(characterNameKey, name)); if (!string.IsNullOrEmpty(thumbnailHtml)) { thumbnailUrl = GetThumbnailUrl(srcAttributeKey, thumbnailHtml, populatedCharacter.SourceUrl); break; } } } else { thumbnailUrl = GetThumbnailUrl(srcAttributeKey, thumbnailHtml, populatedCharacter.SourceUrl); } //character details string mainImageUrl = htmlParser.GetAttributeFromSingleNavigable(srcAttributeKey, ScrapingConstants.XPathImageUrl); var sourceUri = new Uri(populatedCharacter.SourceUrl); string baseUri = sourceUri.GetLeftPart(UriPartial.Authority); if (!mainImageUrl.StartsWith(baseUri)) { mainImageUrl = baseUri + mainImageUrl; } //color hex string colorTheme = string.Empty; if (!string.IsNullOrEmpty(populatedCharacter.CssKey)) { colorTheme = _imageScrapingService.GetColorHexValue(populatedCharacter.CssKey).Result; } //movements var movements = _movementScraper.GetMovementsForCharacter(populatedCharacter); //moves var moves = _characterMoveScraper.ScrapeMoves(populatedCharacter); //attributes var attributeRows = new List <ICharacterAttributeRow>(); foreach (var attributeScraper in _attributeScrapers) { string attributeName = string.Empty; if (attributeScraper.AttributeName == "RunSpeed") { attributeName = "DashSpeed"; //grrr.. } else { attributeName = attributeScraper.AttributeName; } attributeScraper.SourceUrl = $"{sourceBaseUrl}{attributeName}"; try { var newAttributes = attributeScraper.Scrape(populatedCharacter); attributeRows.AddRange(newAttributes); } catch (PageNotFoundException ex) { Console.WriteLine($"Exception while running scraper: {attributeScraper.AttributeName} for '{character.Name}'{Environment.NewLine}{ex.Message}"); } } //unique data var uniqueData = new List <object>(); var uniqueDataScrapersForThisCharacter = GetUniqueDataScrapersForCharacter(populatedCharacter); foreach (var uniqueDataScraper in uniqueDataScrapersForThisCharacter) { uniqueData.AddRange(uniqueDataScraper.Scrape(populatedCharacter)); } populatedCharacter.InstanceId = _instanceIdGenerator.GenerateId(); populatedCharacter.FullUrl = populatedCharacter.SourceUrl; populatedCharacter.DisplayName = displayName; populatedCharacter.ThumbnailUrl = thumbnailUrl; populatedCharacter.MainImageUrl = mainImageUrl; populatedCharacter.ColorTheme = colorTheme; populatedCharacter.Movements = movements; populatedCharacter.Moves = moves; populatedCharacter.AttributeRows = attributeRows; populatedCharacter.UniqueProperties = uniqueData; populatedCharacter.Game = populatedCharacter.SourceUrl.Contains("Ultimate") ? Games.Ultimate : Games.Smash4; return(populatedCharacter); }