Greasy Fork is available in English.
Parse sbermarket for better product price indication.
// ==UserScript== // @name Instamart/Sbermarket price calculator // @namespace http://tampermonkey.net/ // @version 0.4 // @description Parse sbermarket for better product price indication. // @author Lunat1q // @include https://sbermarket.ru/metro/* // @include https://sbermarket.ru/auchan/* // @include https://instamart.ru/metro/* // @grant none // ==/UserScript== (function() { 'use strict'; var visitedProducts = []; var selector = "#wrap > div.body > div.products_with_filters_wrapper > div.products_container > div > ul"; var products = $.find(selector)[0]; if (products == undefined) { products = $.find("#wrap > div.body > div.key-content-wrapper.js-key-content-wrapper > div > div.products_container > div > ul")[0]; } var prevCount = 0; var priceDict = {}; var working = false; var prevSorted = 0; determineProductsPrice(); sortByPrice(); MutationObserver = window.MutationObserver || window.WebKitMutationObserver; var observer = new MutationObserver(function(mutations, observer) { determineProductsPrice(); setTimeout(function() {sortByPrice();}, 1000); }); observer.observe(products, { subtree: false, childList: true }); function determineProductsPrice() { let childElements = products.childElementCount; if (prevCount >= childElements) { return; } prevCount = childElements; let maxAmount = 0; let before = visitedProducts.length for (let i = 0; i < childElements; i++) { let product = products.children[i]; if (product.childElementCount > 0) { let prodLink = $(product).children("a"); let productPrice = prodLink.children("div.product__price"); let prodPriceTag = productPrice[0]; if (visitedProducts.includes(prodPriceTag)) { continue; } visitedProducts.push(prodPriceTag); let priceTag = productPrice.children("div").children("div.price-discount-sale").children("div.price.price--default"); // > div.product__price > div > div.price-discount-sale > div.price.price--default if (prodPriceTag == undefined) { priceDict[product.textContent] = 9999999999; continue; } if (priceTag.length == 0) { priceTag = productPrice.children("div"); } //#wrap > div.body > div.products_with_filters_wrapper > div.products_container > div > ul > li:nth-child(5) > a > div.product__price > div let money = getMoneyAmount(priceTag[0]); let parseResult = getVolumeAsKg(prodLink.children("p.product__volume")[0]) //#wrap > div.body > div.products_with_filters_wrapper > div.products_container > div > ul > li:nth-child(1) > a > p.product__volume let realPrice = money / parseResult.price; let realPriceTag = prodPriceTag.appendChild(document.createElement('p')) realPriceTag.innerText = realPrice.toFixed(1) + " ₽/" + parseResult.name; priceDict[product.textContent] = realPrice; } } console.log("Real price detected for: " + (visitedProducts.length - before) + "items"); } function sortByPrice() { if (prevSorted >= products.childElementCount) { return; } prevSorted = products.childElementCount; let arr = Array.from(products.getElementsByTagName("LI")); arr = arr.sort((a, b) => { let price1 = priceDict[a.textContent]; let price2 = priceDict[b.textContent]; return price1 > price2 ? 1 : -1; }); arr.forEach(li => products.appendChild(li)); working = false; } function getMoneyAmount(item) { if (item == undefined) { return 999999999; } return parseFloat(item.innerText.substring(0, item.innerText.length - 2).replace(" ", "").replace(",", ".")); } function getVolumeAsKg(item) { let volumeText = item.innerText; let multiplier = 1; let subStrLen = 0; let volumeName = ""; if (volumeText.includes("кг")) { multiplier = 1; subStrLen = 3; volumeName = "кг"; } else if (volumeText.includes("г")) { multiplier = 0.001; subStrLen = 2; volumeName = "кг"; } else if (volumeText.includes("мл")) { multiplier = 0.001; subStrLen = 3; volumeName = "л"; } else if (volumeText.includes("л")) { multiplier = 1; subStrLen = 2; volumeName = "л"; } else if (volumeText.includes("см")) { return { name: "шт", price: 1 }; } else if (volumeText.includes("шт")) { volumeName = "шт"; } let textToParse = item.innerText.substring(0, item.innerText.length - subStrLen).replace(",", "."); return { name: volumeName, price: parseFloat(textToParse) * multiplier }; } })();