e-dostavka/e-dostavka.user.js
2019-07-22 23:58:30 +03:00

90 lines
4.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==UserScript==
// @name [e-dostavka.by, gipermall.by] price comparison
// @namespace http://tampermonkey.net/
// @version 2
// @description Show prices per kilo, compare between sites
// @author nomoreknights
// @match https://e-dostavka.by/*
// @match https://gipermall.by/*
// @grant unsafeWindow
// @grant GM.xmlHttpRequest
// @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js
// @require https://unpkg.com/ohm-js@0.14.0/dist/ohm.min.js
// ==/UserScript==
; (function ($) {
'use strict';
const price = (() => {
const priceGrammar = ohm.grammar(`Price {
Price = integer "р." integer "к." Price?
integer = digit+
}`)
const priceVal = priceGrammar.createSemantics().addOperation('val', {
Price: (rub, _1, kop, _2, _3) => rub.val() + kop.val() * 0.01,
integer: _ => parseInt(_.sourceString)
})
const weightGrammar = ohm.grammar(`Weight {
Exp = BS AnyWeight BS AnyWeight? BS
AnyWeight = MulWeight | Weight
Weight = float (Unit1 | Unit10 | Unit1000) "."*
MulWeight = float ("x" | "х" | "*") Weight
float = digit+ ("." digit+)? -- fl
Unit1 = "г" | "мл"
Unit10 = "см"
Unit1000 = "кг" | "л" | "м" | "шт"
BS = (~AnyWeight any)*
}`)
const weightVal = weightGrammar.createSemantics().addOperation('val', {
Exp: (_1, weight, _2, _3, _4) => weight.val(),
Weight: (n, u, _1) => n.val() * u.val(),
MulWeight: (d, _, w) => d.val() * w.val(),
Unit1: _ => 0.001,
Unit10: _ => 0.01,
Unit1000: _ => 1,
float: _ => parseFloat(_.sourceString)
})
const interpret = (grammar, semantics, text) => {
const match = grammar.match(text)
if (match.failed()) console.log(`Failed to parse [${text}] with ${match.message}`)
return semantics(match).val()
}
return (price, weight) => interpret(priceGrammar, priceVal, price) / interpret(weightGrammar, weightVal, weight)
})()
const template = $("<a/>").css({
'background-color': '#fbba00',
'color': 'black', // default is #cb4f2b
'padding': '2px',
'border-radius': '5px',
'font-size': '14px',
'font-family': 'MyriadProCondencedBoldItalic',
'position': 'absolute',
'right': '5px'
}).attr('target', '_blank')
$(document).arrive(".products_card", { existing: true }, div => {
try {
const normalizedPrice = price(
$(div).find('div > form > div.prices__wrapper > div > div.prices_block > div > div.price').text(),
$(div).find('a.fancy_ajax').text()
)
const link = template.clone()
$(div).find('a.fa').replaceWith(link)
link.text(normalizedPrice.toFixed(2))
const url = (R.test(/e-dostavka/, location.host) ? R.identity : R.flip)(R.replace)('e-dostavka', 'gipermall', $(div).find('a.fancy_ajax').attr('href'))
GM.xmlHttpRequest({
method: 'GET', url, onload: page => {
try {
const html = $($.parseHTML(page.responseText))
const competingPrice = price(
html.find('div.services_wrap:nth-child(3) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1)').text(),
html.find('.template_1_columns > h1:nth-child(2)').text()
)
const diff = (1 - competingPrice / normalizedPrice) * 100
link.text((_, text) => `${text} (${diff > 0 ? '>' : '<'}${Math.abs(diff).toFixed(0)}%)`)
.prop('href', url)
} catch (e) { console.log(`Failed to process page ${url}`, e) }
}
});
} catch (e) { console.log(`Failed to process product card with ${$(div).find('a.fancy_ajax').text()}`, e) }
});
})(unsafeWindow.jQuery); // somehow, when @including jquery, infinite scroll stops working.