/// <summary> /// Make sure the rate for provided currency is known. /// </summary> static void EnsureValidRate(Currency currency) { //Check if there is data in memory if (Rates.ContainsKey(currency)) { if (Rates[currency].Expires > DateTime.Now) { return; } else { Logger.Log(currency + $" rate has expired since {Rates[currency].Expires} @ Currencier"); Rates.Remove(currency); } } else { Logger.Log(currency + " rate is not defined @ Currencier"); } EnsureImportingMeansSetup(); //Extraction string rawHtml = null; try { //Extraction from Web rawHtml = fastWeb.Get($"search?hl=en&gl=en&q={currency}+to+{MainCurrency}"); } catch (FastWeb2Exception) { Logger.Log($"Cannot retrieve remote rate for {currency}. Reading all rates from file [{filePath}]"); //Extraction from file AttemptReadRatesFromFile(currency); return; } //Having remote page pulled down, continue extraction HtmlDocument document = new HtmlDocument(); document.LoadHtml(rawHtml); HtmlNode docNode = document.DocumentNode; string exValue = rateParser.ExtractSingle(docNode); decimal.TryParse(exValue, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal value); //Saving SetRate(currency, new ExpirableRate(value, DefaultExpiration)); //Storing WriteAllRates(); }
/// <summary> /// Call for starting parsing by the contained rules, using provided crude information html content string. /// </summary> public PageParseResult Parse(string relativeUri = null) { if (fastWeb == null) { fastWeb = new FastWeb2(Domain); } var rawHtml = fastWeb.Get(relativeUri); //PreprocessPlan string processedHtml = PagePreprocess == null ? rawHtml : rawHtml.Mold(PagePreprocess); //interpret as document node HtmlDocument document = new HtmlDocument(); document.LoadHtml(processedHtml); HtmlNode entireDocumentNode = document.DocumentNode; var pageParseResult = new PageParseResult { Title = Title.ExtractSingle(node: entireDocumentNode) }; if (Subtitle != null) { pageParseResult.Title += " " + Subtitle.ExtractSingleFromNode(node: entireDocumentNode); } if (Thumbnail != null) { pageParseResult.ThumbPath = Thumbnail.ExtractSingleFromNode(node: entireDocumentNode); } //Parsing Actual Options if (DefaultOptionMode != DefaultOptionMode.Single) { try { bool isRegex = OptionsList.SelectMethod == SelectMethod.Regex; IEnumerable <object> crudeOptions; if (isRegex) { crudeOptions = OptionsList.ExtractList(entireDocumentNode.InnerHtml); } else { crudeOptions = OptionsList.ExtractList(entireDocumentNode); } foreach (var entry in crudeOptions) { var optionParseResult = isRegex ? ActualOption.Parse(entry as string) : ActualOption.Parse(entry as HtmlNode); if (optionParseResult.Price.Amount == 0 && PriceMode != PriceMode.Add) { continue; } pageParseResult.OptionParseResults.Add(optionParseResult); } } catch (NullReferenceException nrex) when(DefaultOptionMode == DefaultOptionMode.Alongside || DefaultOptionMode == DefaultOptionMode.Alternative) { //swallow when actual options absence allowed Logger.Log(nrex.Message + " @ PageParsing of " + relativeUri); } } //Default Option Logic if (DefaultOptionMode != DefaultOptionMode.Ignore) { if (DefaultOptionMode == DefaultOptionMode.Single) { Logger.Log(Domain + " has 1 option per page setup. Add all options separately."); } OptionParseResult defaultOption; try { defaultOption = DefaultOption.Parse(entireDocumentNode); defaultOption.PropertyA = defaultOption.Code = DefaultOptionMode.ToString(); } catch (NullReferenceException nrex) { Logger.Log(nrex.Message + " @ PageParsing of " + relativeUri); throw; } //Prices correction according to Price Mode Setting if (PriceMode == PriceMode.Add) { foreach (OptionParseResult optParseRes in pageParseResult.OptionParseResults) { optParseRes.Price.Amount += defaultOption.Price.Amount; } } //Adding default option to the options list, if necessary if (DefaultOptionMode == DefaultOptionMode.Alongside || DefaultOptionMode == DefaultOptionMode.Single || (DefaultOptionMode == DefaultOptionMode.Alternative && pageParseResult.OptionParseResults.Count == 0)) { pageParseResult.OptionParseResults.Add(defaultOption); } } //Prices correction according to the Main Currency & Shop Ordering Rules foreach (OptionParseResult optParseRes in pageParseResult.OptionParseResults) { optParseRes.Price = optParseRes.Price.AsMainCurrency(); var value = optParseRes.Price.Amount; value /= 1 + OrderDeduction; if (OrderExtra != null && OrderLimit != null && OrderLimit.AsMainCurrency().Amount > 0) { decimal limitValue = OrderLimit.AsMainCurrency().Amount; decimal orderExtraValue = OrderExtra.AsMainCurrency().Amount; decimal piecesPerOrder = limitValue / value; decimal extraPerPiece = orderExtraValue / piecesPerOrder; value += extraPerPiece; } optParseRes.Price.Amount = value; } return(pageParseResult); }