// idArticle - if not empty, article will be added to shopping cart only if it is matching the specified idArticle. used for searching for cheap deals by user // idLanguages - list of languages to check for. if all are OK, pass in either an empty list or a list with exactly one entry which is an empty string private void checkArticle(string idProduct, System.Collections.Generic.List <string> idLanguages, string minCondition, string isFoil, string isSigned, string isAltered, string isPlayset, string matchingArticle, float maxAllowedPrice, float shippingAddition, float percentBelowOthers, bool checkTrend) { var sUrl = "https://api.cardmarket.com/ws/v2.0/articles/" + idProduct + "?minCondition=" + minCondition + "&start=0&maxResults=50"; if (isFoil != "") { sUrl += "&isFoil=" + isFoil; } if (isSigned != "") { sUrl += "&isSigned=" + isSigned; } if (isAltered != "") { sUrl += "&isAltered=" + isAltered; } if (isPlayset != "") { sUrl += "&isPlayset=" + isPlayset; } if (idLanguages.Count == 1 && idLanguages[0] != "") // if there is exactly one language specified, fetch only articles in that one language, otherwise get all { sUrl += "&idLanguage=" + idLanguages[0]; } XmlDocument doc2; try { doc2 = MKMInteract.RequestHelper.MakeRequest(sUrl, "GET"); } catch (Exception eError) { MKMHelpers.LogError("checking article id " + idProduct, eError.Message, false, sUrl); return; } var node2 = doc2.GetElementsByTagName("article"); var counter = 0; var noBestPrice = true; var aPrices = new float[4]; var bestPriceArticle = ""; float bestPriceInternational = 0; foreach (XmlNode offer in node2) { /* * Want states: * Empty = n/a * true = yes * false = no */ if (offer["seller"]["address"]["country"].InnerText != MainView.Instance.Config.MyCountryCode && domesticCheck.Checked) { continue; } bool languageOk = true; if (idLanguages.Count > 1) // only some languages were specified, filter { languageOk = false; foreach (string lang in idLanguages) { if (lang == offer["language"]["idLanguage"].InnerText) { languageOk = true; break; } } } if (!languageOk) { continue; } // save cheapest price found anywhere float price = Convert.ToSingle(MKMHelpers.GetPriceFromXml(offer), CultureInfo.InvariantCulture); if (price < 0) { continue; } aPrices[counter] = price; if (noBestPrice) { bestPriceInternational = aPrices[counter]; noBestPrice = false; } if (aPrices[0] + shippingAddition > maxAllowedPrice) { //frm1.logBox.Invoke(new Form1.logboxAppendCallback(frm1.logBoxAppend), "Price higher than Max Price\n"); continue; } if (counter == 0) { bestPriceArticle = offer["idArticle"].InnerText; // if looking for matching article, no point to continue if it is not the cheapest - perhaps could be modified to pick things that are among matching? if (matchingArticle != "" && matchingArticle != bestPriceArticle) { break; } } counter++; if (counter == 3) { float factor = percentBelowOthers; factor = factor / 100 + 1; MainView.Instance.LogMainWindow("Price 1: " + aPrices[0] + " Price 2: " + aPrices[1]); MainView.Instance.LogMainWindow( "Factor Price 1: " + Math.Round(aPrices[0] * factor + shippingAddition, 2) + " Factor Price 2: " + Math.Round(aPrices[1] * factor + shippingAddition, 2)); //X% under others if ( (aPrices[0] * factor + shippingAddition < aPrices[1]) && (aPrices[0] * factor + shippingAddition < aPrices[2]) ) { float fTrendprice = 100000; // fictive price if (checkTrend) { //check Trend Price try { var doc3 = MKMInteract.RequestHelper.MakeRequest( "https://api.cardmarket.com/ws/v2.0/products/" + idProduct, "GET"); fTrendprice = Convert.ToSingle(doc3.GetElementsByTagName("TREND")[0].InnerText.Replace(".", ",")); MainView.Instance.LogMainWindow("Trend: " + fTrendprice); } catch (Exception eError) { MKMHelpers.LogError("checking trend price for " + offer["product"]["locName"].InnerText, eError.Message, false); } } //only relevant if we search domestic if (domesticCheck.Checked) { // is best price international (+/-5%)? if (!(aPrices[0] * 0.95 <= bestPriceInternational)) { break; } } // X% under TREND if (aPrices[0] * factor < fTrendprice) { MainView.Instance.LogMainWindow("Found cheap offer, ID " + bestPriceArticle); try { var sRequestXML = MKMInteract.RequestHelper.AddCartBody(bestPriceArticle); sRequestXML = MKMInteract.RequestHelper.GetRequestBody(sRequestXML); MKMInteract.RequestHelper.MakeRequest("https://api.cardmarket.com/ws/v2.0/shoppingcart", "PUT", sRequestXML); } catch (Exception eError) { MKMHelpers.LogError("adding article " + offer["product"]["locName"].InnerText + " to cart", eError.Message, false); } } } break; } } }
/// For actually performing the check for cheap deals from a given user, expected to be run in its separate thread. /// <param name="selectedExpansionID">Leave as empty string if all expansion should be checked.</param> private void checkUserRun(string user, string isFoil, string isSigned, string isAltered, string isPlayset, string minCondition, bool domesticOnly, float maxPrice, float shippingAddition, float percentBelowOthers, bool checkTrend, System.Collections.Generic.List <string> selectedLanguage, string selectedExpansionID = "") { MainView.Instance.LogMainWindow("Check for cheap deals from seller '" + user + "'..."); if (domesticOnly) { MainView.Instance.LogMainWindow("WARNING - domestics only is checked, if the specified seller is from a foreign country, no deals will be found."); } // Go through the stock of a specified user, checks for cheap deals and add them to the cart. int start = 0; while (true) { string sUrl = "https://api.cardmarket.com/ws/v2.0/users/" + user + "/articles?start=" + start + "&maxResults=1000"; XmlDocument doc2; try { // get the users stock, filtered by the selected parameters doc2 = MKMInteract.RequestHelper.MakeRequest(sUrl, "GET"); } catch (Exception eError) { MKMHelpers.LogError("looking for cheap deals from user " + user, eError.Message, false, sUrl); break; } var node2 = doc2.GetElementsByTagName("article"); foreach (XmlNode article in node2) { if (selectedExpansionID != "") // if we want only cards from a specified set, check if this product is from that set using local database { DataRow card = MKMDbManager.Instance.GetSingleCard( article[MKMDbManager.InventoryFields.ProductID].InnerText); if (card == null || card.Field <string>(MKMDbManager.InventoryFields.ExpansionID) != selectedExpansionID) { continue; } } float price = MKMHelpers.GetPriceFromXml(article); if (price < 0) { continue; } if ( // do as much filtering here as possible to reduce the number of API calls MKMHelpers.IsBetterOrSameCondition(article["condition"].InnerText, minCondition) && (!foilBox.Checked || article["isFoil"].InnerText == "true") && (!playsetBox.Checked || article["isPlayset"].InnerText == "true") && (selectedLanguage[0] == "" || article["language"]["idLanguage"].InnerText == selectedLanguage[0]) && (!signedBox.Checked || article["isSigned"].InnerText == "true") && (!signedBox.Checked || article["isAltered"].InnerText == "true") && (maxPrice >= price) ) { MainView.Instance.LogMainWindow("Checking product ID: " + article["idProduct"].InnerText); checkArticle(article["idProduct"].InnerText, selectedLanguage, minCondition, isFoil, isSigned, isAltered, isPlayset, article["idArticle"].InnerText, maxPrice, shippingAddition, percentBelowOthers, checkTrend); } } if (node2.Count != 1000) // there is no additional items to fetch { break; } start += 1000; } MainView.Instance.LogMainWindow("Check finished."); }