Пример #1
0
        private void UpdateGraphWithPricePoints()
        {
            MTGCard           curCard = DM.GetCurrentCard();
            List <PricePoint> curPP   = DM.GetCurrentPricePoints();

            if (curCard == null || curPP == null)
            {
                // This can be called at the start to update sources when card/PP are null.
                return;
            }

            foreach (Series cs in mtgPriceChart.Series)
            {
                cs.Points.Clear();
            }

            UpdateStatusLabel("Status: Applying data filters.");
            // Apply any filters that are selected
            FilterTypes tempDataFilters = new FilterTypes();

            this.PopulateFilterTypes(ref tempDataFilters);
            curPP = DM.ApplyFilters(curPP, tempDataFilters);
            UpdateStatusLabel("Status: Complete");

            foreach (PricePoint pp in curPP)
            {
                // Only add points for selected retailers
                if (mtgPriceChart.Series.IsUniqueName(pp.Retailer) == false)
                {
                    mtgPriceChart.Series[pp.Retailer].Points.AddXY(pp.Date, (double)pp.Price / 100);
                }
            }

            UpdateCardInfoWindow(curCard, curPP);
        }
Пример #2
0
        /* For saving the updated card list for a given set */
        public void UpdatePricePoints(List <PricePoint> PPsIn, MTGCard CardIn)
        {
            int sum = 0;

            try
            {
                SQLiteTransaction trn = MTGDB.BeginTransaction();
                foreach (PricePoint pp in PPsIn)
                {
                    using (SQLiteCommand cmd = new SQLiteCommand(MTGDB))
                    {
                        cmd.Parameters.Clear();
                        cmd.CommandText = "INSERT OR REPLACE INTO mtgPP (cardName, setName, price, retailer, priceDate) " +
                                          "VALUES (@CNAME, @SNAME, @PRICE, @RET, @PDATE)";
                        cmd.Parameters.AddWithValue("@CNAME", CardIn.CardName);
                        cmd.Parameters.AddWithValue("@SNAME", CardIn.SetName);
                        cmd.Parameters.AddWithValue("@PRICE", pp.Price);
                        cmd.Parameters.AddWithValue("@RET", pp.Retailer);
                        cmd.Parameters.AddWithValue("@PDATE", pp.Date);
                        sum += cmd.ExecuteNonQuery();
                    }
                }
                trn.Commit();
            }
            catch (Exception err)
            {
                log.Error("Insert/Update Error: ", err);
            }
        }
Пример #3
0
        /* Returns a List of the MTGCards from the DB for a given set */
        public List <MTGCard> GetCardList(string SetName)
        {
            List <MTGCard> retCards = new List <MTGCard>();

            try
            {
                using (SQLiteCommand cmd = new SQLiteCommand(MTGDB))
                {
                    cmd.CommandText = "SELECT * FROM mtgCards WHERE setName=@SNAME";
                    cmd.Parameters.AddWithValue("@SNAME", SetName);
                    SQLiteDataReader rdr = cmd.ExecuteReader();
                    while (rdr.Read())
                    {
                        UInt64  price = Convert.ToUInt64(rdr["price"]);
                        MTGCard card  = new MTGCard(rdr["cardName"].ToString(), rdr["setName"].ToString(), price);
                        card.LastPricePointUpdate = (DateTime)rdr["lastUpdate"];
                        card.URL          = rdr["url"].ToString();
                        card.FoilURL      = rdr["foilURL"].ToString();
                        card.CardImageURL = rdr["imageURL"].ToString();
                        retCards.Add(card);
                    }
                }
            }
            catch (Exception err)
            {
                log.Warn("GetCardList() for set " + SetName + " Err:", err);
            }
            return(retCards);
        }
Пример #4
0
        /* Price Point fetching/parsing for a particular card/set and list of retailers*/
        public List <PricePoint> GetPricePointsForCard(MTGCard CardIn, List <string> RetailerList)
        {
            if (CardIn == null)
            {
                log.Error("UpdatePricePoints supplied null MTGCard");
                return(null);
            }
            CurrentCard = CardIn;

            // Need to Update PricePoints
            if (CardIn.LastPricePointUpdate.CompareTo(DateTime.Today) < 0)
            {
                List <PricePoint> parsePP = new List <PricePoint>();
                URLFetcher        Fetcher = new URLFetcher(startURL + CardIn.URL);
                string            ret     = Fetcher.Fetch();

                parsePP = _MTGPriceParser.ParsePricePoints(ret, CardIn);

                CardIn.LastPricePointUpdate = DateTime.Today;

                _SQLWrapper.UpdatePricePoints(parsePP, CardIn);
                _SQLWrapper.UpdateCardLastUpdate(CardIn, CardIn.LastPricePointUpdate);
            }

            // Select from SQL for given retailers.
            List <PricePoint> retPP = _SQLWrapper.GetPricePoints(CardIn, RetailerList);

            CurrentPricePoints = retPP;
            return(retPP);
        }
Пример #5
0
        /* Returns a List of the PricePoints from the DB for a given Card for certain retailers retailers.*/
        public List <PricePoint> GetPricePoints(MTGCard CardIn, List <string> RetailerList)
        {
            if (CardIn == null)
            {
                log.Error("SQLWrapper::GetPricePoints was given a null CardIn.");
                return(null);
            }

            List <PricePoint> retPP = new List <PricePoint>();

            try
            {
                using (SQLiteCommand cmd = new SQLiteCommand(MTGDB))
                {
                    cmd.CommandText = "SELECT * FROM mtgPP WHERE cardName=@CNAME AND setName=@SNAME";
                    cmd.Parameters.AddWithValue("@SNAME", CardIn.SetName);
                    cmd.Parameters.AddWithValue("@CNAME", CardIn.CardName);
                    // If no retailers it will just select all, otherwise specify retailers.
                    if (RetailerList.Count > 0)
                    {
                        cmd.CommandText += " AND (";
                        for (int i = 0; i < RetailerList.Count; i++)
                        {
                            cmd.CommandText += "retailer = @RNAME" + i.ToString();
                            if (i < RetailerList.Count() - 1)
                            {
                                cmd.CommandText += " OR ";
                            }                                                               // Add OR for all statements except last one.
                            cmd.Parameters.AddWithValue("@RNAME" + i.ToString(), RetailerList[i]);
                        }
                        cmd.CommandText += ")";
                    }
                    cmd.CommandText += " ORDER BY priceDate DESC";
                    SQLiteDataReader rdr = cmd.ExecuteReader();
                    while (rdr.Read())
                    {
                        PricePoint PP = new PricePoint();
                        PP.Date     = (DateTime)rdr["priceDate"];
                        PP.Price    = Convert.ToUInt64(rdr["price"]);
                        PP.Retailer = rdr["retailer"].ToString();
                        retPP.Add(PP);
                    }
                }
            }
            catch (Exception err)
            {
                log.Warn("GetPricePoints() for card " + CardIn.CardName + " in set " + CardIn.SetName + " Err:", err);
            }

            return(retPP);
        }
Пример #6
0
        /*
         * Called to save the URL of the card image.
         * Format of:
         * <meta property = "og:image" content="http://s.mtgprice.com/sets/Magic_Origins/img/Jace, Vryn's Prodigy.full.jpg" />
         */
        private void ParseCardImage(string HTMLIn, MTGCard CardIn)
        {
            HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
            htmlDoc.LoadHtml(HTMLIn.ToString());
            HtmlAgilityPack.HtmlNode imageNode = htmlDoc.DocumentNode.SelectSingleNode("//meta[@property = 'og:image']");

            foreach (HtmlAgilityPack.HtmlAttribute att in imageNode.Attributes)
            {
                if (att.Name == "content")
                {
                    CardIn.CardImageURL = att.Value;
                }
            }
        }
Пример #7
0
        public DataManager()
        {
            _SQLWrapper       = new SQLWrapper();
            _MTGPriceParser   = new MTGPriceParser();
            _FormatParser     = new FormatParser();
            _DataFilter       = new DataFilter();
            _ApplicationState = new MTGUtils.AppState();

            log                = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            Sets               = _SQLWrapper.GetSetList();
            CurrentCard        = null;
            CurrentPricePoints = null;
            CurrentFormat      = null;
        }
Пример #8
0
        private void UpdateCardInfoWindow(MTGCard CardIn, List <PricePoint> PPsIn)
        {
            UInt64 min = 0, max = 0;

            DF.GetMinMax(PPsIn, ref min, ref max);

            lblCurrentPrice.Text = DF.GetPriceFromUInt64(CardIn.Price);
            lblLowPrice.Text     = DF.GetPriceFromUInt64(min);
            lblHighPrice.Text    = DF.GetPriceFromUInt64(max);

            UInt64 Avg = 0, Avg3Day = 0, Avg7Day = 0, Avg30Day = 0;

            DF.CalculateAverages(PPsIn, ref Avg, ref Avg3Day, ref Avg7Day, ref Avg30Day);
            lblAveragePrice.Text      = DF.GetPriceFromUInt64(Avg);
            lbl3DayAveragePrice.Text  = DF.GetPriceFromUInt64(Avg3Day);
            lbl7DayAveragePrice.Text  = DF.GetPriceFromUInt64(Avg7Day);
            lbl30DayAveragePrice.Text = DF.GetPriceFromUInt64(Avg30Day);
        }
Пример #9
0
 public void UpdateCardLastUpdate(MTGCard CardIn, DateTime LastPPUpdate)
 {
     try
     {
         SQLiteTransaction trn = MTGDB.BeginTransaction();
         using (SQLiteCommand cmd = new SQLiteCommand(MTGDB))
         {
             cmd.CommandText = "UPDATE mtgCards SET lastUpdate=@DATE, imageURL=@IURL WHERE setname=@SNAME AND cardname=@CNAME";
             cmd.Parameters.AddWithValue("@SNAME", CardIn.SetName);
             cmd.Parameters.AddWithValue("@CNAME", CardIn.CardName);
             cmd.Parameters.AddWithValue("@DATE", LastPPUpdate);
             cmd.Parameters.AddWithValue("@IURL", CardIn.CardImageURL);
             cmd.ExecuteNonQuery();
         }
         trn.Commit();
     }
     catch (Exception err)
     {
         log.Error("UpdateCardLastUpdate error: ", err);
     }
 }
Пример #10
0
        /* Information stored in <script> and specific line has "$scope.setList" */
        public List <MTGCard> ParseCardURLs(string HTMLIn, string SetName)
        {
            List <MTGCard> retCards = new List <MTGCard>();

            HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
            htmlDoc.LoadHtml(HTMLIn.ToString());
            string result = htmlDoc.DocumentNode.OuterHtml;

            /* As they use a script to display card names/urls/etc no easy way to get the specified line. So big giant string with entire HTML doc inside. */

            int listLocation = result.IndexOf("$scope.setList");
            int startOfList  = result.IndexOf("[{", listLocation);
            int endOfList    = result.IndexOf("}];", startOfList);

            // Off by 2 to remove the '[{'
            string listOfCards = result.Substring(startOfList + 2, (endOfList - startOfList - 2));

            /* Now we have listOfCards which is of the format:
             *
             * {"cardId":"AEtherlingDragons_MazefalseNM-M","name":"AEtherling","quantity":0,"countForTrade":0,"isFoil":false,"url":"/sets/Dragons_Maze/AEtherling",
             * "setUrl":"/spoiler_lists/Dragons_Maze","fair_price":0.39,"setName":"Dragons Maze","absoluteChangeSinceYesterday":0.0,"absoluteChangeSinceOneWeekAgo":0.0,
             * "percentageChangeSinceYesterday":0.0,"percentageChangeSinceOneWeekAgo":0.0,"color":"U","rarity":"R","manna":"4UU","bestVendorBuylist":"UNDEFINED",
             * "bestVendorBuylistPrice":"0","lowestPrice":"0.33","lowestPriceVendor":"HotSauce Games",
             * "fullImageUrl":"http://s.mtgprice.com/sets/Dragons_Maze/img/AEtherling.full.jpg"},{},{}
             */

            string[] stringSeperator = new string[] { "},{" };
            listOfCards = listOfCards.Replace("\\u0027", "'");
            string[] cardStrings = listOfCards.Split(stringSeperator, StringSplitOptions.None);

            // Now we have each card {INFO} in a string

            foreach (string cardString in cardStrings)
            {
                // Now to break it up into "Tag":"Value" pairs. The value can be numerical as well.
                string[] infoStringSeperator = new string[] { "\",\"", ",\"" };
                string[] infoStrings = cardString.Split(infoStringSeperator, StringSplitOptions.None);
                string   cardName = null, setURL = null, price = null;

                foreach (string infoString in infoStrings)
                {
                    // Now in the format of "TAG":"VALUE"
                    string[] cleanStringSeperator = new string[] { "\":" };
                    string[] tagStrings           = infoString.Split(cleanStringSeperator, StringSplitOptions.None);
                    if (tagStrings.Count() != 2)
                    {
                        continue;
                    }
                    if (tagStrings[0] == "name")
                    {
                        cardName = tagStrings[1].Trim('"');
                    }
                    else if (tagStrings[0] == "url")
                    {
                        setURL = tagStrings[1].Trim('"');
                    }
                    else if (tagStrings[0] == "fair_price")
                    {
                        price = tagStrings[1].Trim('"');
                        if (price.Contains('.'))
                        {
                            if (price.Length - price.LastIndexOf('.') == 2) // Adjust "1.X" to "1.X0"
                            {
                                price += "0";
                            }
                            else if (price.Length - price.LastIndexOf('.') > 3) // Adjust "1.XXxxxxxx" to "1.XX"
                            {
                                price = price.Substring(0, price.LastIndexOf('.') + 3);
                            }
                            price = price.Replace(".", string.Empty);
                        }
                        else
                        {
                            price = price + "00"; // Adjust "X" to "X00"
                        }
                    }
                }

                MTGCard tempCard = new MTGCard(cardName, SetName, Convert.ToUInt64(price));
                tempCard.URL = setURL;
                retCards.Add(tempCard);
            }

            return(retCards);
        }
Пример #11
0
        /*
         * JavaScript is used to populate the tbody, and the formatting on the data is odd,
         * so pretty much just have to search for data and parse manually.
         * Ignore all zero priced data as it's useless.
         */
        public List <PricePoint> ParsePricePoints(string HTMLIn, MTGCard CardIn)
        {
            List <PricePoint> retPP = new List <PricePoint>();

            // Double check formatting
            if (HTMLIn.Contains("var results = [") == false || HTMLIn.Contains("var sellPriceData = [") == false)
            {
                log.Error("MTGPrice.com PricePoints formatting has been changed. Need to update the application.");
                return(null);
            }

            if (CardIn.CardImageURL == null || CardIn.CardImageURL == "")
            {
                ParseCardImage(HTMLIn, CardIn);
            }

            int start = HTMLIn.IndexOf("var results = [");
            int end   = HTMLIn.IndexOf("var sellPriceData = [");

            if (start == -1 || end == -1)
            {
                log.Error("MTGPrice.com PricePoints formatting has been changed. Need to update the application. (start = " + start + " end = " + end + ")");
                return(null);
            }

            /*
             *  Formatting Example:
             *  {
             *      "color": "rgb(140,172,198)",
             *      "label": "HotSauce Games - $19.99",
             *      "lines": { "show": true, "fill": true },
             *      "data": [[1379804931252,29.99],[1379964574414,29.99]]
             *   },
             *
             * The above group repeats per Retailer
             */

            string relevantData = HTMLIn.Substring(start, (end - start));

            // Keep going until a '"label":' is not found.

            string labelString = "\"label\": ";
            string dataString  = "\"data\": ";

            while (true)
            {
                int labelIndex = relevantData.IndexOf(labelString);
                if (labelIndex < 0)
                {
                    // No more retailers, done!
                    break;
                }

                int    commaIndex   = relevantData.IndexOf(',', labelIndex);
                string retailerName = relevantData.Substring((labelIndex + labelString.Length), commaIndex - labelIndex - labelString.Length);

                // Format is now '"<NAME>" - $<PRICE>', remove quotes, and everything after name.
                retailerName = retailerName.Substring(1, retailerName.IndexOf(" -") - 1);

                int dataIndex = relevantData.IndexOf(dataString);
                // Start at Index 1, as the 2nd-Xth strings will be "}DATA"
                int endIndex = relevantData.IndexOf('}', dataIndex);

                // Put just the price points into [DATE,PRICE],[DATE,PRICE] format and
                // Trim the first/last '[' and ']'
                string pureData = relevantData.Substring(dataIndex + dataString.Length, endIndex - dataIndex - dataString.Length);
                pureData = pureData.Replace(" ", string.Empty);
                pureData = pureData.Replace("\r", string.Empty);
                pureData = pureData.Replace("\n", string.Empty);
                if (pureData != null && pureData != "[]" && retailerName != "Best BUYLIST Price")
                {
                    // Split based on delimiter "],[" and use "[[" and "]]" to remove first/last double brackets and then remove emptry entries
                    // The "[]" case takes care of empty brackets
                    string[] delim     = new string[] { "],[", "[[", "]]", "[]" };
                    string[] splitData = pureData.Split(delim, StringSplitOptions.RemoveEmptyEntries);
                    // Data is now formatted as '[DATE,PRICE]'
                    foreach (string point in splitData)
                    {
                        string[] splitPoint  = point.Split(',');
                        string   stringPrice = splitPoint[1];

                        if (stringPrice == "0.0" || stringPrice == "0") // Ignore zero prices.
                        {
                            continue;
                        }

                        if (stringPrice.Contains('.'))
                        {
                            if (stringPrice.Length - stringPrice.LastIndexOf('.') == 2) // Adjust "1.X" to "1.X0"
                            {
                                stringPrice += "0";
                            }
                            else if (stringPrice.Length - stringPrice.LastIndexOf('.') > 3) // Adjust "1.XXxxxxxx" to "1.XX"
                            {
                                stringPrice = stringPrice.Substring(0, stringPrice.LastIndexOf('.') + 3);
                            }
                            stringPrice = stringPrice.Replace(".", string.Empty);
                        }
                        else
                        {
                            stringPrice = stringPrice + "00"; // Adjust "X" to "X00"
                        }

                        UInt64 Price = Convert.ToUInt64(stringPrice);

                        if (Price == 0)
                        {
                            log.Error(Price + " from '" + stringPrice + "'");
                        }

                        PricePoint tempPP = new PricePoint();
                        tempPP.Retailer = retailerName;
                        // Convert from Milliseconds since Unix Epoch to DateTime
                        tempPP.Date  = new DateTime(1970, 1, 1, 0, 0, 0, 0);
                        tempPP.Date  = tempPP.Date.AddSeconds(Convert.ToDouble(splitPoint[0]) / 1000).ToLocalTime();
                        tempPP.Price = Price;
                        retPP.Add(tempPP);
                    }
                }

                relevantData = relevantData.Substring(endIndex);
            }

            return(retPP);
        }
Пример #12
0
        /* Fetch PricePoints if needed, update chart variables */
        private void ApplyPricePointsToChart()
        {
            if (mtgCardsGraphListBox.SelectedItem == null)
            {
                return;
            }

            MTGCard curCard = (MTGCard)mtgCardsGraphListBox.SelectedItem;

            if (curCard == null)
            {
                return;
            }

            // Populate the List of Currently selected retailers.
            List <string> RetailerList = new List <string>();

            foreach (string retailer in mtgPriceSourceCheckListBox.CheckedItems)
            {
                RetailerList.Add(retailer);
            }

            // Update the Title
            mtgPriceChart.Titles.Clear();
            Title title = mtgPriceChart.Titles.Add(curCard.ToString());

            title.Font = new Font("Arial", 32);

            // Fetch the Price Points if required
            UpdateStatusLabel("Status: Fetching info for " + curCard.ToString());
            List <PricePoint> PricePoints = DM.GetPricePointsForCard(curCard, RetailerList);

            UpdateStatusLabel("Status: Complete");

            if (PricePoints != null)
            {
                UpdateGraphWithPricePoints();
            }
            else
            {
                UpdateStatusLabel("Status: Error retrieving price points for card " + curCard.ToString());
            }

            try
            {
                pictureBoxCard.Load(curCard.CardImageURL);
            }
            catch (System.Net.WebException ex)
            {
                if (ex.Response is System.Net.HttpWebResponse)
                {
                    System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)ex.Response;
                    log.Error("Failed to load image " + curCard.CardImageURL + " with status code " + response.StatusCode + " (" + response.StatusDescription + ")");
                }

                pictureBoxCard.Image = global::MTGUtils.Properties.Resources.MTG_Card_Back;
            }

            /* TODO: Add a toggle for this as it can be cluttered with older sets.
             * // Add the set release date markets to the chart
             * mtgPriceChart.ChartAreas["StripLines"].AxisX.StripLines.Clear();
             * foreach(MTGSet set in DM.GetSets())
             * {
             *  if(set.SetDate.CompareTo(PricePoints.First().Date) < 0 &&  set.SetDate.CompareTo(PricePoints.Last().Date) > 0)
             *  {
             *      StripLine stripLine = new StripLine();
             *      // stripLine.Text = set.SetName;
             *      stripLine.BackColor = Color.Magenta;
             *      stripLine.StripWidth = 0.1;
             *      stripLine.StripWidthType = DateTimeIntervalType.Days;
             *
             *      TimeSpan ts = set.SetDate - PricePoints.Last().Date;
             *
             *      stripLine.Interval = 100000; // Tried setting to 0 to be shown once, but then I see nothing.
             *      stripLine.IntervalOffset = ts.Days;
             *      stripLine.IntervalOffsetType = DateTimeIntervalType.Days;
             *
             *      mtgPriceChart.ChartAreas["StripLines"].AxisX.StripLines.Add(stripLine);
             *  }
             * }
             */
        }