Show Price as Hours of your Life

Gets the price displayed on shopping sites and shows the equivalent hours of your life spent to earn that money.

As of 2019-10-08. See the latest version.

// ==UserScript==
// @name            Show Price as Hours of your Life
// @description     Gets the price displayed on shopping sites and shows the equivalent hours of your life spent to earn that money.
// @author          navchandar
// @version         1.0
// @run-at          document-end
// @copyright       2019, navchandar(https://github.com/navchandar)
// @license         MIT
// @grant           GM_addStyle
// @grant           GM_getValue
// @grant           GM_setValue
// @include         https://play.google.com/store/*
// @include         https://play.google.com/store*
// @include         http://play.google.com/store*
// @include         http://www.amazon.com
// @include         https://www.amazon.com
// @include         http://www.amazon.in
// @match           https://www.amazon.in/*
// @include         https://www.flipkart.com*
// @include         http://www.flipkart.com*
// @include         https://paytm.com*
// @include         http://paytm.com*
// @include         https://paytmmall.com*
// @include         http://paytmmall.com*
// @namespace https://greasyfork.org/users/302262
// ==/UserScript==

function updateValuesINR() {
  var approxHourlySalary = Number(GM_getValue("approxAnnualSalary", "")) / (9 * 22 * 12);
  if (!approxHourlySalary) {
    console.log("Error calculating approxHourlySalary.")
  }

  if (approxHourlySalary > 0) {
    var items, separator;
    // These xpaths cover most of the price elements shown. Feel free to comment/fork to update if required.
    var amazonINRxpath = "//span[contains(@class, 'CurrencyINR')]//following-sibling::span" + " | " +
      "//span[@class='currencyINR']/parent::*" + " | " +
      "//*[contains(@class, 'rice')][contains(text(), '₹')]" + " | " +
      "//*[contains(@class, 'price')]//*[contains(text(), '₹')]" + " | " +
      "//*[contains(@class, 'price-whole')]" + " | " +
      "//h2/span[contains(text(), '₹')]";

    var amazonUSDxpath = "//*[@class='dealPrice']" + " | " +
      "//*[@class='buyingPrice']" + " | " +
      "//*[contains(@class,'-price-whole')]" + " | " +
      "(//span[@class='dv-conditional-linebreak']//following-sibling::text())[1]" + " | " +
      "(//span[@class='dv-conditional-linebreak']//following-sibling::text())[2]" + " | " +
      "//span[contains(@class, 'price')][contains(text(), '$')]" + " | " +
      "//h2[contains(@class, 'headline') and contains(text(), '₹')]" + " | " +
      "//a[@id='dealTitle']" + " | " + "//div[contains(@class, 'priceBlock')]";

    var flipkartINRxpath = "//*[contains(@title, '₹')]/div[3]" + " | " +
      "//div[contains(text(), '₹')]";

    var paytmINRxpath = "//span/span[contains(text(), 'Rs')]" + " | " +
      "//a//*[contains(@class, 'iconRupess')]//.." + " | " +
      "//*[contains(@class, 'iconRupess')]//..";

    var playStoreINRxpath = "//*[@class='display-price' and contains(text(), '₹')]" + " | " +
      "//button[@jsmodel]//span[contains(text(), '₹')]" + " | " +
      "//button[contains(text(), '₹')]//text()";

    var hostURL = window.location.href;
    if (hostURL.indexOf('amazon.in') >= 0) {
      items = document.evaluate(amazonINRxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = " ";
    }

    else if (hostURL.indexOf('amazon.com') >= 0) {
      items = document.evaluate(amazonUSDxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = " ";
    }

    else if (hostURL.indexOf('flipkart') >= 0) {
      items = document.evaluate(flipkartINRxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = " ";
    }

    else if (hostURL.indexOf('paytm') >= 0) {
      items = document.evaluate(paytmINRxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = "<br/>";
    }

    else if ((hostURL.indexOf('google') >= 0) && (hostURL.indexOf('details') >= 0)) {
      items = document.evaluate(playStoreINRxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = "&nbsp;";
    }

    else if ((hostURL.indexOf('google') >= 0) && (hostURL.indexOf('store') >= 0)) {
      items = document.evaluate(playStoreINRxpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      separator = "<br/>";
    }

    else {
      console.log("Show Price Hours script didnt match with the current site.");
    }

    if (!items) {
      console.log("No items found with the xpath in this page.");
    }
    else if (items.snapshotLength <= 0) {
      console.log("No items found with the xpath in this page.");
    }
    else {
      var passCount = 0;
      for (let i = 0; i < items.snapshotLength; i++) {
        var thisitem = items.snapshotItem(i);
        var txt = thisitem.innerText;
        var alreadyUpdated = false;
        try {
          if (txt.indexOf('hrs') >= 0  | txt.indexOf('days') >= 0 | txt.indexOf('month') >= 0) {
            alreadyUpdated = true;
          }
        }
        catch (err) {}
        try {
          if (thisitem.innerHTML.indexOf('hrs') >= 0 | thisitem.innerHTML.indexOf('days') >= 0 | thisitem.innerHTML.indexOf('month') >= 0) {
            alreadyUpdated = true;
          }
        }
        catch (err) {}

        if (!alreadyUpdated) {
          try {
            // to remove +10% offers from flipkart
            if (txt.indexOf('+') >= 0) {
              txt = txt.split('+')[0];
            }

            // to remove hidden text from paytm
            if (txt.indexOf('%') >= 0 && txt.indexOf('-') >= 0) {
              txt = txt.split('-')[0]
            }

            // to remove 100-200 range from amazon
            if (txt.indexOf('-') >= 0) {
              txt = txt.split('-')[1];
            }
            if (txt.indexOf('to') >= 0) {
              txt = txt.split('to')[1];
            }

            txt = (txt.replace(/\d+ Used/i, "").replace(/\d+ New/i, "")).replace(/\(\d+%\)/g, "");
            txt = txt.replace(/[a-z]/gi, "");

            // remove unneccessary text and convert to number.
            var amount = Number(txt.replace(",", "").replace("Rs.", "").replace("₹", "").replace("$", "").replace(".00", "").replace(" ", ""));
            if (!amount || amount <= 0) {
              amount = Number((txt.replace(".00", "").replace(/\.\d+/, "")).replace(/\D+/g, ""));
            }

            //console.log(amount, txt);

            if (amount > 0) {
              var calculated = (amount / approxHourlySalary).toFixed(2);
              if (calculated) {
                  if (calculated < 10){
                      thisitem.innerHTML += (separator + "<b>(" + calculated + " hrs)</b>");
                  }else if (calculated < 190){
                      thisitem.innerHTML += (separator + "<b>(" + (calculated/9).toFixed(2) + " days)</b>");
                  }else{
                      thisitem.innerHTML += (separator + "<b>(" + (calculated/198).toFixed(2) + " months)</b>");
                  }
                passCount++;
              }
              else {
                console.log("Error calculating amount : " + amount);
              }
            }
          }
          catch (err) {}
        }
      }
      console.log("Updated hours to " + passCount + " items.");
      items = "";
    }
  }
}

function ButtonClickAction(zEvent) {
  GM_setValue("approxAnnualSalary", "");
  var approxAnnualSalary = prompt('To calculate how many hours of your life, each item will cost, add an approximate Annual Salary/Wage Amount :', '');
  if (approxAnnualSalary) {
    GM_setValue("approxAnnualSalary", approxAnnualSalary);
    console.log("Stored approxAnnualSalary : " + approxAnnualSalary);
    GM_setValue("UserCancelledPrompt", false);
    self.location.assign(location);
  }
  else {
    GM_setValue("UserCancelledPrompt", true);
    console.log("User Cancelled prompt to update approxAnnualSalary.");
  }
}

function AddButton() {
  // Add a button element on div
  var zNode = document.createElement('div');
  zNode.innerHTML = '<button id="myButton" title="To update your stored wage/salary, Click me" type="button">Reset</button>';
  zNode.setAttribute('id', 'myContainer');
  document.body.appendChild(zNode);

  //--- Activate the newly added button.
  document.getElementById("myButton").addEventListener("click", ButtonClickAction, false);

  //--- Style our newly added element using CSS.
  GM_addStyle(`
#myContainer {
position:               fixed;
bottom:                 0;
left:                   0;
font-size:              11px;
margin:                 0px;
opacity:                0.75;
}
#myButton {
cursor:                 pointer;
background-color:       lightgrey;
color:                  black;
}
#myButton:hover {
background-color:       #555;
color:                  white;
box-shadow:             0 2px 6px 0 rgba(0,0,0,.24), 0 5px 10px 0 rgba(0,0,0,.19);
opacity:                1;
}
`);

}

(function () {
  'use strict';
  //GM_setValue("approxAnnualSalary", ""); // Reset here for test.
  var approxAnnualSalary = GM_getValue("approxAnnualSalary", "");
  var checkPriorCancellation = GM_getValue("UserCancelledPrompt");

  if ((approxAnnualSalary == "" || !approxAnnualSalary) && !checkPriorCancellation) {
    approxAnnualSalary = prompt('To calculate how many hours of your life, each item will cost, add an approximate Annual Salary/Wage Amount :', '');
    if (approxAnnualSalary) {
      GM_setValue("approxAnnualSalary", approxAnnualSalary);
      GM_setValue("UserCancelledPrompt", false);
      console.log("Stored approxAnnualSalary : " + approxAnnualSalary);
    }
    else {
      GM_setValue("UserCancelledPrompt", true);
      console.log("User Cancelled prompt to update approxAnnualSalary.");
    }
  }
  else {
    console.log("Retrieved approxAnnualSalary : " + approxAnnualSalary);
  }

  // call this function once
  AddButton();

  // call this every 2 seconds to update according to page load
  setInterval(function () {
    updateValuesINR();
  }, 2000);

})();