Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

79 rindas
3.8KB

  1. // ==UserScript==
  2. // @name [e-dostavka.by, gipermall.by] price comparison
  3. // @namespace http://tampermonkey.net/
  4. // @version 2
  5. // @description Show prices per kilo, compare between sites
  6. // @author nomoreknights
  7. // @match https://e-dostavka.by/*
  8. // @match https://gipermall.by/*
  9. // @grant unsafeWindow
  10. // @grant GM.xmlHttpRequest
  11. // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js
  13. // @require https://unpkg.com/ohm-js@0.14.0/dist/ohm.min.js
  14. // ==/UserScript==
  15. (function () {
  16. 'use strict';
  17. const price = (() => {
  18. const float = n => parseFloat(n.sourceString)
  19. const priceG = ohm.grammar(`Price { Price = digit+ "р." digit+ "к." Price? }`)
  20. const priceS = priceG.createSemantics().addOperation('val', {
  21. Price: (rub, _2, kop, _4, _5) => float(rub) * 100 + float(kop),
  22. })
  23. const weightG = ohm.grammar(`Weight {
  24. Exp = BS* AnyWeight BS* AnyWeight? BS*
  25. AnyWeight = MulWeight | Weight
  26. Weight = float (OneUnit | ThUnit)
  27. OneUnit = Dot<"г"> | Dot<"мл"> | Dot<"шт"> | Dot<"см">
  28. ThUnit = Dot<"кг"> | Dot<"л"> | Dot<"м">
  29. Dot<R> = R "."*
  30. MulWeight = float ("x" | "х" | "*") Weight
  31. BS = ~AnyWeight any
  32. float = (digit digit* "." digit) -- fl
  33. | digit+
  34. }`)
  35. const weightS = weightG.createSemantics().addOperation('val', {
  36. Exp: (_, weight, __, ___, _____) => weight.val(),
  37. Weight: (n, u) => float(n) * u.val(),
  38. OneUnit: _ => 1, ThUnit: _ => 1000,
  39. MulWeight: (d, _, w) => float(d) * w.val(),
  40. })
  41. const interpret = (g, s) => (text) => s(g.match(text))
  42. return (price, weight) => (interpret(priceG, priceS)(price).val() / interpret(weightG, weightS)(weight).val() / 100 * 1000)
  43. })()
  44. const $ = unsafeWindow.jQuery; // somehow, when @including jquery, infinite scroll stops working.
  45. const template = $("<a/>").css({
  46. 'background-color': '#fbba00',
  47. 'color': 'black', // default is #cb4f2b
  48. 'padding': '2px',
  49. 'border-radius': '5px',
  50. 'font-size': '14px',
  51. 'font-family': 'MyriadProCondencedBoldItalic',
  52. 'position': 'absolute',
  53. 'right': '5px'
  54. }).attr('target', '_blank')
  55. $(document).arrive(".products_card", { existing: true }, div => {
  56. const normalizedPrice = price(
  57. $(div).find('div > form > div.prices__wrapper > div > div.prices_block > div > div.price').text(),
  58. $(div).find('a.fancy_ajax').text()
  59. )
  60. const button = template.clone()
  61. const url = (R.test(/e-dostavka/, location.host) ? R.identity : R.flip)(R.replace)('e-dostavka', 'gipermall', $(div).find('a.fancy_ajax').attr('href'))
  62. $(div).find('a.fa').replaceWith(button)
  63. button.text(normalizedPrice.toFixed(2))
  64. GM.xmlHttpRequest({
  65. method: 'GET', url, onload: page => {
  66. try {
  67. const html = $($.parseHTML(page.responseText))
  68. const competingPrice = price(
  69. html.find('div.services_wrap:nth-child(3) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1)').text(),
  70. html.find('.template_1_columns > h1:nth-child(2)').text()
  71. )
  72. const difference = Math.abs(1 - competingPrice / normalizedPrice) * 100
  73. button.text((i, _) => `${_} (${competingPrice >= normalizedPrice ? '>' : '<'}${difference.toFixed(0)}%)`).prop('href', url)
  74. } catch (e) { }
  75. }
  76. });
  77. });
  78. })();