private static void VerifyConverterDecksAreEqual(ConverterDeck converterDeck, ConverterDeck otherConverterDeck) { for (int cs = 0; cs < converterDeck.ConverterSections.Count; cs++) { VerifyConverterSectionsAreIdentical(converterDeck.ConverterSections[cs], otherConverterDeck.ConverterSections[cs]); } }
/// <summary> /// Reads each line in each section, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="sectionLines">A collection of deck sections with Item1 as Name, and Item2 as a collection of lines of text which are cards</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> internal static ConverterDeck ConvertDeckWithSeparateSections(Dictionary<string, IEnumerable<string>> sectionLines, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (KeyValuePair<string, IEnumerable<string>> section in sectionLines) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(section.Key, StringComparison.InvariantCultureIgnoreCase)); foreach (string line in section.Value) { // The line is the Deck Name? Record it. string potentialDeckName = TextConverter.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { ConverterMapping potentialCard = TextConverter.ParseLineForCardAndQuantity(line); if (potentialCard != null) { converterSection.AddConverterMapping(potentialCard); } else { converterSection.AddIncorrectlyFormattedLine(line); } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Parses and verifies the card count of the deck filename. The filename must match /// those found in /DeckFiles/ /// </summary> /// <param name="deckFileName">The filename of the deck to verify</param> /// <param name="scratchDirectory">The directory to create the deck file in</param> /// <param name="game">The Game that should be chosen in the Wizard</param> public static void VerifyDeckFile( string deckFileName, IEnumerable <ExpectedDeckSection> expectedSectionsStats, string scratchDirectory, Octgn.DataNew.Entities.Game game) { Assert.IsTrue(DeckFileResourceHelpers.CopyDeckFileResourceToDirectory( scratchDirectory, deckFileName)); ConverterDeck converterDeck = ConvertDeckFileUsingWizard(Path.Combine(scratchDirectory, deckFileName), game); foreach (ConverterSection converterSection in converterDeck.ConverterSections) { ExpectedDeckSection expectedSectionStats = expectedSectionsStats.First(eds => eds.SectionName == converterSection.SectionName); Assert.AreEqual(expectedSectionStats.TotalCardCount, converterSection.SectionCount); Assert.AreEqual(expectedSectionStats.UniqueCardCount, converterSection.SectionMappings.Count(sm => sm.PotentialOCTGNCards.Count > 0)); foreach (ConverterMapping converterMapping in converterSection.SectionMappings) { // At least one potential match should have been found Assert.IsTrue(converterMapping.PotentialOCTGNCards.Count() > 0); } } }
/// <summary> /// Adds a Mage Stats card to accompany the Mage card, since it is required in OCTGN /// </summary> private static void AddMageStatsCard(ConverterDeck converterDeck) { ConverterSection mageSection = converterDeck.ConverterSections.First(s => s.SectionName.Equals("Mage", StringComparison.InvariantCultureIgnoreCase)); if (mageSection.SectionMappings.Any(sm => sm.CardName.EndsWith(" Stats"))) { // The corresponding Stats card already appears to be added return; } ConverterMapping firstMage = mageSection.SectionMappings.FirstOrDefault(); if (firstMage != null) { string mageName = firstMage.CardName; if (MW.RegexMatch_WizardSubtype(mageName)) { // No matter what the subtype of Wizard is, it should have a 'Wizard Stats' card mageName = "Wizard"; } mageSection.AddConverterMapping(new ConverterMapping(mageName + " Stats", string.Empty, 1)); } }
/// <summary> /// Reads each line in each section, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="sectionLines">A collection of deck sections with Item1 as Name, and Item2 as a collection of lines of text which are cards</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> internal static ConverterDeck ConvertDeckWithSeparateSections(Dictionary <string, IEnumerable <string> > sectionLines, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (KeyValuePair <string, IEnumerable <string> > section in sectionLines) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(section.Key, StringComparison.InvariantCultureIgnoreCase)); foreach (string line in section.Value) { // The line is the Deck Name? Record it. string potentialDeckName = TextConverter.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { ConverterMapping potentialCard = TextConverter.ParseLineForCardAndQuantity(line); if (potentialCard != null) { converterSection.AddConverterMapping(potentialCard); } else { converterSection.AddIncorrectlyFormattedLine(line); } } } } converterDeck.ConversionSuccessful = true; return(converterDeck); }
/// <summary> /// Converts user input text into a ConverterDeck which has all ConverterMappings populated with potential cards from the ConverterGame /// </summary> /// <param name="sectionsText">A collection of section names (keys), and the user input text of all cards in the section (values)</param> /// <param name="converterGame">The ConverterGame instance that will be used for searching for matches</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets</returns> public ConverterDeck ConvertText(Dictionary <string, string> sectionsText, ConverterGame converterGame) { this.ThrowIfConverterGameDoesntMatch(converterGame); ConverterDeck converterDeck = this.ConvertText(sectionsText, converterGame.Sets, converterGame.DeckSectionNames); return(converterDeck); }
/// <summary> /// Converts a text file into a ConverterDeck which has all ConverterMappings populated with potential cards from the ConverterGame /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="converterGame">The ConverterGame instance that will be used for searching for matches</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings populated with potential OCTGN cards from the converterSets</returns> public ConverterDeck ConvertFile(string fullPathName, ConverterGame converterGame) { this.ThrowIfConverterGameDoesntMatch(converterGame); ConverterDeck converterDeck = this.ConvertFile(fullPathName, converterGame.DeckSectionNames); converterDeck.PopulateConverterMappings(converterGame.Sets); return(converterDeck); }
/// <summary> /// Converts a URL into a ConverterDeck which has all ConverterMappings populated with potential cards from the ConverterGame /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="converterGame">The ConverterGame instance that will be used for searching for matches</param> /// <returns>A ConverterDeck which represents the data that is converted using the contents of the file</returns> public ConverterDeck ConvertURL(string url, ConverterGame converterGame) { this.ThrowIfConverterGameDoesntMatch(converterGame); ConverterDeck converterDeck = this.ConvertURL(url, converterGame.DeckSectionNames); converterDeck.PopulateConverterMappings(converterGame.Sets); return(converterDeck); }
/// <summary> /// Reads the lines which has Sideboard cards denoted on each line, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> public static ConverterDeck ConvertMTGDeckWithSideBoardCardsListedEachLine(IEnumerable <string> lines, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); ConverterSection mtgMainDeckConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Main", StringComparison.InvariantCultureIgnoreCase)); ConverterSection mtgSideboardConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Sideboard", StringComparison.InvariantCultureIgnoreCase)); foreach (string line in lines) { // The line is the Deck Name? Record it. string potentialDeckName = TextConverter.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { // Ordering: The most specific pattern is listed first, and each more generalized pattern follows if (RegexMatch_MWSSideBoardCard(line) != null) { // The line is a MWS sideboard "SB: Quantity [SET] Card" entry mtgSideboardConverterSection.AddConverterMapping(RegexMatch_MWSSideBoardCard(line)); } else if (RegexMatch_MWSMainDeckCard(line) != null) { // The line is a MWS main deck "Quantity [SET] Card" entry mtgMainDeckConverterSection.AddConverterMapping(RegexMatch_MWSMainDeckCard(line)); } else if (RegexMatch_RegularMTGSideBoardCard(line) != null) { // The line is a regular sideboard "Quantity Card" entry, without any Set info mtgSideboardConverterSection.AddConverterMapping(RegexMatch_RegularMTGSideBoardCard(line)); } else { ConverterMapping potentialCard = TextConverter.ParseLineForCardAndQuantity(line); if (potentialCard != null) { mtgMainDeckConverterSection.AddConverterMapping(potentialCard); } else { // The line is not a valid card entry } } } } converterDeck.ConversionSuccessful = true; return(converterDeck); }
/// <summary> /// Reads the lines which has Sideboard cards denoted on each line, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> public static ConverterDeck ConvertMTGDeckWithSideBoardCardsListedEachLine(IEnumerable<string> lines, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); ConverterSection mtgMainDeckConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Main", StringComparison.InvariantCultureIgnoreCase)); ConverterSection mtgSideboardConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Sideboard", StringComparison.InvariantCultureIgnoreCase)); foreach (string line in lines) { // The line is the Deck Name? Record it. string potentialDeckName = TextConverter.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { // Ordering: The most specific pattern is listed first, and each more generalized pattern follows if (RegexMatch_MWSSideBoardCard(line) != null) { // The line is a MWS sideboard "SB: Quantity [SET] Card" entry mtgSideboardConverterSection.AddConverterMapping(RegexMatch_MWSSideBoardCard(line)); } else if (RegexMatch_MWSMainDeckCard(line) != null) { // The line is a MWS main deck "Quantity [SET] Card" entry mtgMainDeckConverterSection.AddConverterMapping(RegexMatch_MWSMainDeckCard(line)); } else if (RegexMatch_RegularMTGSideBoardCard(line) != null) { // The line is a regular sideboard "Quantity Card" entry, without any Set info mtgSideboardConverterSection.AddConverterMapping(RegexMatch_RegularMTGSideBoardCard(line)); } else { ConverterMapping potentialCard = TextConverter.ParseLineForCardAndQuantity(line); if (potentialCard != null) { mtgMainDeckConverterSection.AddConverterMapping(potentialCard); } else { // The line is not a valid card entry } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Reads the lines of text which is in the SpellBookBuilder Text format, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="lines">The lines of text of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> public ConverterDeck Convert(IEnumerable <string> lines, IEnumerable <string> deckSectionNames) { string deckName = lines.FirstOrDefault(l => SpellBookBuilderText.RegexMatch_DeckName(l) != null); string mage; try { mage = (from l in lines select SpellBookBuilderText.RegexMatch_Mage(l)).First(m => m != null); } catch (Exception e) { e.Data.Add("Description", "Could not find a Mage in this deck."); throw; } List <ParsedCard> cards = new List <ParsedCard>(); foreach (string line in lines) { ParsedCard potentialCard = SpellBookBuilderText.RegexMatch_SBBTCard(line); if (potentialCard != null) { cards.Add(potentialCard); } } ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); // Insert the Deck Name if (deckName != null) { converterDeck.DeckName = deckName; } // Add the Mage with quantity of 1 ConverterSection mageSection = converterDeck.ConverterSections.First(s => s.SectionName.Equals("Mage", StringComparison.InvariantCultureIgnoreCase)); mageSection.AddConverterMapping(new ConverterMapping(mage, string.Empty, 1)); // Add each other card with quantity to the corresponding Section foreach (ParsedCard card in cards) { ConverterSection correspondingSection = converterDeck.ConverterSections.First(s => s.SectionName.Equals(card.Section, StringComparison.InvariantCultureIgnoreCase)); correspondingSection.AddConverterMapping(new ConverterMapping(card.Name, string.Empty, card.Quantity)); } return(converterDeck); }
/// <summary> /// Converts user input text into a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets /// </summary> /// <param name="sectionsText">A collection of section names (keys), and the user input text of all cards in the section (values)</param> /// <param name="converterSets">List of all ConverterSets. Only those with flag IncludeInSearches will be used.</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets</returns> public static ConverterDeck ConvertText(Dictionary <string, string> sectionsText, Dictionary <Guid, ConverterSet> converterSets, IEnumerable <string> deckSectionNames) { Dictionary <string, IEnumerable <string> > sectionsLines = new Dictionary <string, IEnumerable <string> >(); // Key = Section Name // Value = Section card lines as a blob of text foreach (KeyValuePair <string, string> section in sectionsText) { sectionsLines.Add(section.Key, TextConverter.SplitLines(section.Value)); } ConverterDeck converterDeck = TextConverter.ConvertDeckWithSeparateSections(sectionsLines, deckSectionNames); converterDeck.PopulateConverterMappings(converterSets); return(converterDeck); }
/// <summary> /// Downloads a URL which is a download link to a text file or equivalent, then parses it to return a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck which is a download link to a text file or equivalent</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> protected static ConverterDeck ConvertDownloadURL(string url, IEnumerable <string> deckSectionNames, Func <IEnumerable <string>, IEnumerable <string>, ConverterDeck> convertGenericFileFunc) { // Get the file and content Tuple <string, IEnumerable <string> > nameAndLines = WebpageConverter.ReadURLFileToLines(url); // Convert as SideBoardCardsListedEachLine ConverterDeck converterDeck = convertGenericFileFunc(nameAndLines.Item2, deckSectionNames); // If no Deck Name was given, use the filename if (string.IsNullOrWhiteSpace(converterDeck.DeckName)) { converterDeck.DeckName = nameAndLines.Item1; } return(converterDeck); }
/// <summary> /// Reads the lines of text which is in the SpellBookBuilder Text format, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="lines">The lines of text of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> public ConverterDeck Convert(IEnumerable<string> lines, IEnumerable<string> deckSectionNames) { string deckName = lines.FirstOrDefault(l => SpellBookBuilderText.RegexMatch_DeckName(l) != null); string mage; try { mage = (from l in lines select SpellBookBuilderText.RegexMatch_Mage(l)).First(m => m != null); } catch (Exception e) { e.Data.Add("Description", "Could not find a Mage in this deck."); throw; } List<ParsedCard> cards = new List<ParsedCard>(); foreach (string line in lines) { ParsedCard potentialCard = SpellBookBuilderText.RegexMatch_SBBTCard(line); if (potentialCard != null) { cards.Add(potentialCard); } } ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); // Insert the Deck Name if (deckName != null) { converterDeck.DeckName = deckName; } // Add the Mage with quantity of 1 ConverterSection mageSection = converterDeck.ConverterSections.First(s => s.SectionName.Equals("Mage", StringComparison.InvariantCultureIgnoreCase)); mageSection.AddConverterMapping(new ConverterMapping(mage, string.Empty, 1)); // Add each other card with quantity to the corresponding Section foreach (ParsedCard card in cards) { ConverterSection correspondingSection = converterDeck.ConverterSections.First(s => s.SectionName.Equals(card.Section, StringComparison.InvariantCultureIgnoreCase)); correspondingSection.AddConverterMapping(new ConverterMapping(card.Name, string.Empty, card.Quantity)); } return converterDeck; }
/// <summary> /// Converts a URL that is known to match this Game into a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings defined, but not yet populated with potential matching OCTGN cards</returns> protected override ConverterDeck ConvertURL(string url, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = null; // Try to find a pre-defined WebpageConverter to handle ConvertFile Webpage.WebpageConverter webpageConverter = this.FindMatchingWebpageConverter(url); if (webpageConverter != null) { converterDeck = webpageConverter.Convert(url, deckSectionNames, null); } else { throw new InvalidOperationException("There was a problem importing the deck from the given url, or the website has not been implemented yet"); } return(converterDeck); }
/// <summary> /// Converts a text file that is known to match this Game into a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings defined, but not yet populated with potential matching OCTGN cards</returns> protected override ConverterDeck ConvertFile(string fullPathName, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = null; string contents = System.IO.File.ReadAllText(fullPathName); IEnumerable <string> lines = TextConverter.SplitLines(contents); if (File.SpellBookBuilderText.DoesFileMatchSpellBookBuilderTextDeckFormat(lines)) { File.SpellBookBuilderText spellBookBuilderTextConverter = this.CompatibleFileConverters.First() as File.SpellBookBuilderText; converterDeck = spellBookBuilderTextConverter.Convert(lines, deckSectionNames); } else { // The file format didn't match any known MW format, so just try the generic format converterDeck = MW.ConvertGenericFile(lines, deckSectionNames); } MW.AddMageStatsCard(converterDeck); return(converterDeck); }
/// <summary> /// Reads the OCTGN format file, and returns a ConverterDeck which is populated with all cards. /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> /// <remarks>This will purposely ignore the Guids, which may help importing from OCTGN2 or other unofficial sets</remarks> public override ConverterDeck Convert(string fullPathName, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); using (XmlTextReader reader = new XmlTextReader(fullPathName)) { reader.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xd = new XmlDocument(); xd.Load(reader); XmlNode xnodDE = xd.DocumentElement; if (xnodDE.Name != "deck") { throw new InvalidOperationException("File is not a Octgn Deck"); } foreach (XmlNode child in xnodDE.ChildNodes) { if (child.Name.Equals("section", StringComparison.InvariantCultureIgnoreCase)) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(child.Attributes.GetNamedItem("name").Value, StringComparison.InvariantCultureIgnoreCase)); foreach (XmlNode cardXmlNode in child.ChildNodes) { converterSection.AddConverterMapping ( new ConverterMapping ( cardXmlNode.InnerText, string.Empty, int.Parse(cardXmlNode.Attributes.GetNamedItem("qty").Value) ) ); } } } } converterDeck.ConversionSuccessful = true; return(converterDeck); }
/// <summary> /// Reads the OCTGN format file, and returns a ConverterDeck which is populated with all cards. /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> /// <remarks>This will purposely ignore the Guids, which may help importing from OCTGN2 or other unofficial sets</remarks> public override ConverterDeck Convert(string fullPathName, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); using (XmlTextReader reader = new XmlTextReader(fullPathName)) { reader.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xd = new XmlDocument(); xd.Load(reader); XmlNode xnodDE = xd.DocumentElement; if (xnodDE.Name != "deck") { throw new InvalidOperationException("File is not a Octgn Deck"); } foreach (XmlNode child in xnodDE.ChildNodes) { if (child.Name.Equals("section", StringComparison.InvariantCultureIgnoreCase)) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(child.Attributes.GetNamedItem("name").Value, StringComparison.InvariantCultureIgnoreCase)); foreach (XmlNode cardXmlNode in child.ChildNodes) { converterSection.AddConverterMapping ( new ConverterMapping ( cardXmlNode.InnerText, string.Empty, int.Parse(cardXmlNode.Attributes.GetNamedItem("qty").Value) ) ); } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Converts user input text that is known to match this Game into a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets /// </summary> /// <param name="sectionsText">A collection of section names (keys), and the user input text of all cards in the section (values)</param> /// <param name="converterSets">List of all ConverterSets. Only those with flag IncludeInSearches will be used.</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets</returns> protected override ConverterDeck ConvertText(Dictionary <string, string> sectionsText, Dictionary <Guid, ConverterSet> converterSets, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = null; // If the text is in SpellBookBuilderText format, convert it with that. Otherwise, convert using normal text format IEnumerable <string> lines = sectionsText.SelectMany(st => TextConverter.SplitLines(st.Value)); if (File.SpellBookBuilderText.DoesFileMatchSpellBookBuilderTextDeckFormat(lines)) { File.SpellBookBuilderText spellBookBuilderTextConverter = this.CompatibleFileConverters.First() as File.SpellBookBuilderText; converterDeck = spellBookBuilderTextConverter.Convert(lines, deckSectionNames); converterDeck.PopulateConverterMappings(converterSets); } else { converterDeck = TextConverter.ConvertText(sectionsText, converterSets, deckSectionNames); } MW.AddMageStatsCard(converterDeck); return(converterDeck); }
/// <summary> /// Parses and verifies the card count of the deck URL. /// </summary> /// <param name="deckURL">The URL of the deck to verify</param> /// <param name="scratchDirectory">The directory to create the deck file in</param> /// <param name="game">The Game that should be chosen in the Wizard</param> public static void VerifyURL( string deckURL, IEnumerable <ExpectedDeckSection> expectedSectionsStats, Octgn.DataNew.Entities.Game game) { ConverterDeck converterDeck = ConvertURLUsingWizard(deckURL, game); foreach (ConverterSection converterSection in converterDeck.ConverterSections) { ExpectedDeckSection expectedSectionStats = expectedSectionsStats.First(eds => eds.SectionName == converterSection.SectionName); Assert.AreEqual(expectedSectionStats.TotalCardCount, converterSection.SectionCount); Assert.AreEqual(expectedSectionStats.UniqueCardCount, converterSection.SectionMappings.Count(sm => sm.PotentialOCTGNCards.Count > 0)); foreach (ConverterMapping converterMapping in converterSection.SectionMappings) { // At least one potential match should have been found Assert.IsTrue(converterMapping.PotentialOCTGNCards.Count() > 0); } } }
/// <summary> /// Converts a text file that is known to match this Game into a ConverterDeck which has all ConverterMappings populated with potential cards from the converterSets /// </summary> /// <param name="fullPathName">The full path name of the Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>Returns a ConverterDeck which has all ConverterMappings defined, but not yet populated with potential matching OCTGN cards</returns> protected override ConverterDeck ConvertFile(string fullPathName, IEnumerable <string> deckSectionNames) { ConverterDeck converterDeck = null; string extension = System.IO.Path.GetExtension(fullPathName); // Try to find a pre-defined FileConverter to handle ConvertFile File.FileConverter fileConverter = this.FindMatchingFileConverter(extension); if (fileConverter != null) { converterDeck = fileConverter.Convert(fullPathName, deckSectionNames); } else { // No pre-defined FileConverter was found, so the file is in another format, probably '.txt' string contents = System.IO.File.ReadAllText(fullPathName); string[] lines = TextConverter.SplitLines(contents); converterDeck = MTG.ConvertGenericFile(lines, deckSectionNames); } return(converterDeck); }
/// <summary> /// Converts a LoTR URL from cardgamedb.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> public override ConverterDeck Convert( string url, IEnumerable<string> deckSectionNames, Func<IEnumerable<string>, IEnumerable<string>, ConverterDeck> convertGenericFileFunc) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); // Find the block of javascript that contains the variable 'viewType' object rawDeckJavascriptNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//script[contains(text(), 'var viewType =')]"); string rawDeckJavascriptText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(rawDeckJavascriptNode); string[] rawDeckJavascriptLines = rawDeckJavascriptText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); dynamic rawDeckJSON = null; string viewTypeLine = rawDeckJavascriptLines.FirstOrDefault(l => l.Contains("var viewType =")); if (viewTypeLine == null) { throw new InvalidOperationException("Could not find the javascript variable 'viewType'"); } else if (viewTypeLine.Contains("submitted")) { // Since viewType is 'submitted', the deck is published. In this case, the JSON data the deck is embedded on this page in the javascript variable 'rawdeck' string rawDeckLine = rawDeckJavascriptLines.First(l => l.Contains("var rawdeck =")); // Trim everything except the JSON int openingCurlyBraceIndex = rawDeckLine.IndexOf('{'); int closingCurlyBraceIndex = rawDeckLine.LastIndexOf('}'); string rawDeckJSONString = rawDeckLine.Substring(openingCurlyBraceIndex, closingCurlyBraceIndex - openingCurlyBraceIndex + 1); rawDeckJSON = JsonConvert.DeserializeObject(rawDeckJSONString); } else if (viewTypeLine.Contains("share")) { // Since viewType is 'share', the deck is personal. In this case, the JSON is not embedded on this page and must be fetched via a form POST Dictionary<string, string> urlParams = WebpageConverter.GetParams(url); // Find the block of javascript that contains the 'ipb.vars' dictionary variable object rawIPBVarsJavascriptNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//script[contains(text(), 'ipb.vars[')]"); string rawIPBVarsJavascriptText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(rawIPBVarsJavascriptNode); string[] rawIPBVarsJavascriptLines = rawIPBVarsJavascriptText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); // Extract the 'secure_hash' value from IPBVar string secureHashLine = rawIPBVarsJavascriptLines.First(l => l.Contains(@"ipb.vars['secure_hash']")); string secure_hash = secureHashLine.Substring(0, secureHashLine.LastIndexOf('\'')); secure_hash = secure_hash.Substring(secure_hash.LastIndexOf('\'') + 1); // Extract the 'secure_hash' value from IPBVar string baseURLLine = rawIPBVarsJavascriptLines.First(l => l.Contains(@"ipb.vars['base_url']")); string base_url = baseURLLine.Substring(0, baseURLLine.LastIndexOf('\'')); base_url = base_url.Substring(base_url.LastIndexOf('\'') + 1); // These variables are all submitted with the form. They are added via javascript in lotrdecksection.js System.Collections.Specialized.NameValueCollection outgoingQueryString = System.Web.HttpUtility.ParseQueryString(String.Empty); outgoingQueryString.Add("dguid", urlParams["deck"]); outgoingQueryString.Add("fPage", "deckshare"); outgoingQueryString.Add("fgame", "lordoftherings"); outgoingQueryString.Add("md5check", secure_hash); outgoingQueryString.Add("pid", urlParams["p"]); string postData = outgoingQueryString.ToString(); ASCIIEncoding ascii = new ASCIIEncoding(); byte[] postBytes = ascii.GetBytes(postData.ToString()); string requestString = base_url + "app=ccs&module=ajax§ion=lotrdeckbuilder&do=share"; System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(requestString); request.Method = "POST"; request.Accept = "application/json"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postBytes.Length; request.Host = "www.cardgamedb.com"; request.Referer = url; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0"; // add post data to request System.IO.Stream postStream = request.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); System.Net.WebResponse response = request.GetResponse(); System.IO.Stream dataStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(dataStream); string responseFromServer = System.Web.HttpUtility.HtmlDecode(reader.ReadToEnd()); reader.Close(); response.Close(); rawDeckJSON = JsonConvert.DeserializeObject(responseFromServer); // When JSON is retrieved this way, the deck contents is stored in a sub-variable rawDeckJSON = rawDeckJSON.deckContents; } else { throw new InvalidOperationException("The javascript variable 'viewType' was not an expected value (" + viewTypeLine + ")"); } ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (dynamic card in rawDeckJSON.hero) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("hero", StringComparison.InvariantCultureIgnoreCase)); ConverterMapping converterMapping = new ConverterMapping( (string)card.name, (string)card.setname, int.Parse((string)card.quantity)); converterSection.AddConverterMapping(converterMapping); } foreach (dynamic card in rawDeckJSON.cards) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals((string)card.type, StringComparison.InvariantCultureIgnoreCase)); ConverterMapping converterMapping = new ConverterMapping( (string)card.name, (string)card.setname, int.Parse((string)card.quantity)); converterSection.AddConverterMapping(converterMapping); } return converterDeck; }
/// <summary> /// Converts a MW URL from arcanewonders.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> public override ConverterDeck Convert( string url, IEnumerable <string> deckSectionNames, Func <IEnumerable <string>, IEnumerable <string>, ConverterDeck> convertGenericFileFunc) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); // Find the div with id 'spellbook' because all deck data is contained inside it object spellbookDiv = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//div[@id='spellbook']"); if (spellbookDiv == null) { throw new InvalidOperationException("Could not find the html div 'spellbook', are you sure this webpage has a deck?"); } // Insert the Deck Name if available object spellbooknameSpan = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(spellbookDiv, "//span[@id='spellbookname']"); if (spellbooknameSpan != null) { converterDeck.DeckName = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(spellbooknameSpan); } // Convert the Mage card object firstMageSpan = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(spellbookDiv, "//span[@id='mage']").FirstOrDefault(); if (firstMageSpan != null) { ConverterSection mageSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Mage", StringComparison.InvariantCultureIgnoreCase)); mageSection.AddConverterMapping(new ConverterMapping( HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(firstMageSpan), string.Empty, 1)); } // The div 'spells' contains all the cards, grouped by spell class object spellsDiv = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(spellbookDiv, "//div[@id='spells']"); // Get a collection of all the span nodes inside the 'spells' div IEnumerable <object> cardAndSectionSpans = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(spellsDiv, "span"); ConverterSection currentConverterSection = null; foreach (object cardOrSectionSpan in cardAndSectionSpans) { // get the class name of the span IEnumerable <object> attributes = HtmlAgilityPackWrapper.HtmlNode_GetProperty_Attributes(cardOrSectionSpan); string className = string.Empty; foreach (object attribute in attributes) { if (HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attribute).Equals("class", StringComparison.InvariantCultureIgnoreCase)) { className = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(attribute); break; } } // If the class name of the span is 'spellClass', then it denotes a Deck Section. Find the corresponding ConverterSection if (className.Equals("spellClass", StringComparison.InvariantCultureIgnoreCase)) { string currentSpellClass = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(cardOrSectionSpan); currentConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(currentSpellClass, StringComparison.InvariantCultureIgnoreCase)); } else { // This span contains a card and quantity, so parse it string quantityAndCardString = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(cardOrSectionSpan); ConverterMapping converterMapping = TextConverter.RegexMatch_RegularCard(quantityAndCardString); currentConverterSection.AddConverterMapping(converterMapping); } } return(converterDeck); }
/// <summary> /// Converts a MW URL from arcanewonders.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> public override ConverterDeck Convert( string url, IEnumerable<string> deckSectionNames, Func<IEnumerable<string>, IEnumerable<string>, ConverterDeck> convertGenericFileFunc) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); // Find the div with id 'spellbook' because all deck data is contained inside it object spellbookDiv = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//div[@id='spellbook']"); if (spellbookDiv == null) { throw new InvalidOperationException("Could not find the html div 'spellbook', are you sure this webpage has a deck?"); } // Insert the Deck Name if available object spellbooknameSpan = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(spellbookDiv, "//span[@id='spellbookname']"); if (spellbooknameSpan != null) { converterDeck.DeckName = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(spellbooknameSpan); } // Convert the Mage card object firstMageSpan = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(spellbookDiv, "//span[@id='mage']").FirstOrDefault(); if (firstMageSpan != null) { ConverterSection mageSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Mage", StringComparison.InvariantCultureIgnoreCase)); mageSection.AddConverterMapping(new ConverterMapping( HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(firstMageSpan), string.Empty, 1)); } // The div 'spells' contains all the cards, grouped by spell class object spellsDiv = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(spellbookDiv, "//div[@id='spells']"); // Get a collection of all the span nodes inside the 'spells' div IEnumerable<object> cardAndSectionSpans = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(spellsDiv, "span"); ConverterSection currentConverterSection = null; foreach (object cardOrSectionSpan in cardAndSectionSpans) { // get the class name of the span IEnumerable<object> attributes = HtmlAgilityPackWrapper.HtmlNode_GetProperty_Attributes(cardOrSectionSpan); string className = string.Empty; foreach (object attribute in attributes) { if (HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attribute).Equals("class", StringComparison.InvariantCultureIgnoreCase)) { className = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(attribute); break; } } // If the class name of the span is 'spellClass', then it denotes a Deck Section. Find the corresponding ConverterSection if (className.Equals("spellClass", StringComparison.InvariantCultureIgnoreCase)) { string currentSpellClass = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(cardOrSectionSpan); currentConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(currentSpellClass, StringComparison.InvariantCultureIgnoreCase)); } else { // This span contains a card and quantity, so parse it string quantityAndCardString = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(cardOrSectionSpan); ConverterMapping converterMapping = TextConverter.RegexMatch_RegularCard(quantityAndCardString); currentConverterSection.AddConverterMapping(converterMapping); } } return converterDeck; }
/// <summary> /// Converts a LoTR URL from cardgamedb.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> public override ConverterDeck Convert( string url, IEnumerable <string> deckSectionNames, Func <IEnumerable <string>, IEnumerable <string>, ConverterDeck> convertGenericFileFunc) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); // Find the block of javascript that contains the variable 'viewType' object rawDeckJavascriptNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//script[contains(text(), 'var viewType =')]"); string rawDeckJavascriptText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(rawDeckJavascriptNode); string[] rawDeckJavascriptLines = rawDeckJavascriptText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); dynamic rawDeckJSON = null; string viewTypeLine = rawDeckJavascriptLines.FirstOrDefault(l => l.Contains("var viewType =")); if (viewTypeLine == null) { throw new InvalidOperationException("Could not find the javascript variable 'viewType'"); } else if (viewTypeLine.Contains("submitted")) { // Since viewType is 'submitted', the deck is published. In this case, the JSON data the deck is embedded on this page in the javascript variable 'rawdeck' string rawDeckLine = rawDeckJavascriptLines.First(l => l.Contains("var rawdeck =")); // Trim everything except the JSON int openingCurlyBraceIndex = rawDeckLine.IndexOf('{'); int closingCurlyBraceIndex = rawDeckLine.LastIndexOf('}'); string rawDeckJSONString = rawDeckLine.Substring(openingCurlyBraceIndex, closingCurlyBraceIndex - openingCurlyBraceIndex + 1); rawDeckJSON = JsonConvert.DeserializeObject(rawDeckJSONString); } else if (viewTypeLine.Contains("share")) { // Since viewType is 'share', the deck is personal. In this case, the JSON is not embedded on this page and must be fetched via a form POST Dictionary <string, string> urlParams = WebpageConverter.GetParams(url); // Find the block of javascript that contains the 'ipb.vars' dictionary variable object rawIPBVarsJavascriptNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//script[contains(text(), 'ipb.vars[')]"); string rawIPBVarsJavascriptText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(rawIPBVarsJavascriptNode); string[] rawIPBVarsJavascriptLines = rawIPBVarsJavascriptText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); // Extract the 'secure_hash' value from IPBVar string secureHashLine = rawIPBVarsJavascriptLines.First(l => l.Contains(@"ipb.vars['secure_hash']")); string secure_hash = secureHashLine.Substring(0, secureHashLine.LastIndexOf('\'')); secure_hash = secure_hash.Substring(secure_hash.LastIndexOf('\'') + 1); // Extract the 'secure_hash' value from IPBVar string baseURLLine = rawIPBVarsJavascriptLines.First(l => l.Contains(@"ipb.vars['base_url']")); string base_url = baseURLLine.Substring(0, baseURLLine.LastIndexOf('\'')); base_url = base_url.Substring(base_url.LastIndexOf('\'') + 1); // These variables are all submitted with the form. They are added via javascript in lotrdecksection.js System.Collections.Specialized.NameValueCollection outgoingQueryString = System.Web.HttpUtility.ParseQueryString(String.Empty); outgoingQueryString.Add("dguid", urlParams["deck"]); outgoingQueryString.Add("fPage", "deckshare"); outgoingQueryString.Add("fgame", "lordoftherings"); outgoingQueryString.Add("md5check", secure_hash); outgoingQueryString.Add("pid", urlParams["p"]); string postData = outgoingQueryString.ToString(); ASCIIEncoding ascii = new ASCIIEncoding(); byte[] postBytes = ascii.GetBytes(postData.ToString()); string requestString = base_url + "app=ccs&module=ajax§ion=lotrdeckbuilder&do=share"; System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(requestString); request.Method = "POST"; request.Accept = "application/json"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postBytes.Length; request.Host = "www.cardgamedb.com"; request.Referer = url; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0"; // add post data to request System.IO.Stream postStream = request.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); System.Net.WebResponse response = request.GetResponse(); System.IO.Stream dataStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(dataStream); string responseFromServer = System.Web.HttpUtility.HtmlDecode(reader.ReadToEnd()); reader.Close(); response.Close(); rawDeckJSON = JsonConvert.DeserializeObject(responseFromServer); // When JSON is retrieved this way, the deck contents is stored in a sub-variable rawDeckJSON = rawDeckJSON.deckContents; } else { throw new InvalidOperationException("The javascript variable 'viewType' was not an expected value (" + viewTypeLine + ")"); } ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (dynamic card in rawDeckJSON.hero) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("hero", StringComparison.InvariantCultureIgnoreCase)); ConverterMapping converterMapping = new ConverterMapping( (string)card.name, (string)card.setname, int.Parse((string)card.quantity)); converterSection.AddConverterMapping(converterMapping); } foreach (dynamic card in rawDeckJSON.cards) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals((string)card.type, StringComparison.InvariantCultureIgnoreCase)); ConverterMapping converterMapping = new ConverterMapping( (string)card.name, (string)card.setname, int.Parse((string)card.quantity)); converterSection.AddConverterMapping(converterMapping); } return(converterDeck); }
/// <summary> /// Converts a URL from mtgvault.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <param name="convertGenericFileFunc"> /// Function to convert a collection of lines from a deck file into a ConverterDeck. /// Used when downloading a Deck File from a webpage instead of scraping. /// </param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> public override ConverterDeck Convert( string url, IEnumerable <string> deckSectionNames, Func <IEnumerable <string>, IEnumerable <string>, ConverterDeck> convertGenericFileFunc) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); // Extract the '__VIEWSTATE' and '__EVENTVALIDATION' input values string viewstateValue = null; string eventValidationValue = null; // Get a collection of all the input nodes IEnumerable <object> aspnetFormInputNodes = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(htmlDocument_DocumentNode, "//input"); foreach (object inputNode in aspnetFormInputNodes) { // get the name of the input IEnumerable <object> attributes = HtmlAgilityPackWrapper.HtmlNode_GetProperty_Attributes(inputNode); string name = string.Empty; foreach (object attribute in attributes) { if (HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attribute).Equals("name", StringComparison.InvariantCultureIgnoreCase)) { name = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(attribute); break; } } if (name.Equals(@"__VIEWSTATE", StringComparison.InvariantCultureIgnoreCase)) { foreach (object attribute in attributes) { if (HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attribute).Equals("value", StringComparison.InvariantCultureIgnoreCase)) { viewstateValue = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(attribute); break; } } } else if (name.Equals(@"__EVENTVALIDATION", StringComparison.InvariantCultureIgnoreCase)) { foreach (object attribute in attributes) { if (HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attribute).Equals("value", StringComparison.InvariantCultureIgnoreCase)) { eventValidationValue = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(attribute); break; } } } } System.Collections.Specialized.NameValueCollection outgoingQueryString = System.Web.HttpUtility.ParseQueryString(String.Empty); outgoingQueryString.Add(@"__EVENTTARGET", @"ctl00$ContentPlaceHolder1$LinkButton1"); outgoingQueryString.Add(@"__EVENTARGUMENT", string.Empty); outgoingQueryString.Add(@"__VIEWSTATE", viewstateValue); outgoingQueryString.Add(@"__EVENTVALIDATION", eventValidationValue); outgoingQueryString.Add(@"ctl00$ContentPlaceHolder1$TextBox_AutoCompleteSideBoard", string.Empty); outgoingQueryString.Add(@"ctl00$ContentPlaceHolder1$TextBox_QuantitySideBoard", string.Empty); outgoingQueryString.Add(@"ctl00$ContentPlaceHolder1$TextBox_BulkImportSideBoard", string.Empty); outgoingQueryString.Add(@"ctl00$Login1$TextBox_Username", string.Empty); outgoingQueryString.Add(@"ctl00$Login1$TextBox_Password", string.Empty); string postData = outgoingQueryString.ToString(); ASCIIEncoding ascii = new ASCIIEncoding(); byte[] postBytes = ascii.GetBytes(postData.ToString()); System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); request.Method = "POST"; request.Accept = "text/html,application/xhtml+xml,application/xml"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postBytes.Length; request.Host = "www.mtgvault.com"; request.Referer = url; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0"; // add post data to request System.IO.Stream postStream = request.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); System.Net.WebResponse response = request.GetResponse(); string filename = response.Headers["content-disposition"]; System.IO.Stream dataStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(dataStream); string responseFromServer = System.Web.HttpUtility.HtmlDecode(reader.ReadToEnd()); reader.Close(); response.Close(); filename = filename.Replace(@"attachment;", string.Empty); filename = filename.Replace(@".txt", string.Empty); ConverterDeck converterDeck = convertGenericFileFunc(TextConverter.SplitLines(responseFromServer), deckSectionNames); converterDeck.DeckName = filename; return(converterDeck); }