コード例 #1
0
 private static void VerifyConverterDecksAreEqual(ConverterDeck converterDeck, ConverterDeck otherConverterDeck)
 {
     for (int cs = 0; cs < converterDeck.ConverterSections.Count; cs++)
     {
         VerifyConverterSectionsAreIdentical(converterDeck.ConverterSections[cs], otherConverterDeck.ConverterSections[cs]);
     }
 }
コード例 #2
0
        /// <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;
        }
コード例 #3
0
        /// <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);
                }
            }
        }
コード例 #4
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));
            }
        }
コード例 #5
0
        /// <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);
        }
コード例 #6
0
        /// <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);
        }
コード例 #7
0
        /// <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);
        }
コード例 #8
0
        /// <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);
        }
コード例 #9
0
        /// <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);
        }
コード例 #10
0
        /// <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;
        }
コード例 #11
0
        /// <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);
        }
コード例 #12
0
        /// <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);
        }
コード例 #13
0
        /// <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);
        }
コード例 #14
0
        /// <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;
        }
コード例 #15
0
        /// <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);
        }
コード例 #16
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               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);
        }
コード例 #17
0
        /// <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);
        }
コード例 #18
0
        /// <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;
        }
コード例 #19
0
        /// <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);
        }
コード例 #20
0
        /// <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);
                }
            }
        }
コード例 #21
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);
        }
コード例 #22
0
ファイル: MW.cs プロジェクト: jlkatz/OCTGN.OCTGNDeckConverter
        /// <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));
            }
        }
コード例 #23
0
        /// <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&section=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;
        }
コード例 #24
0
        /// <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);
        }
コード例 #25
0
        /// <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;
        }
コード例 #26
0
        /// <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&section=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);
        }
コード例 #27
0
        /// <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);
        }