// ==UserScript==
// @name Amazon a Pesos Argentinos
// @namespace sharkiller-amazon-dolar-tarjeta
// @description Mostrar precios en dolar tarjeta
// @version 3.2
// @require http://code.jquery.com/jquery-latest.js
// @require https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.2.1/mustache.min.js
// @include *amazon.com/*
// @include *amazon.co.uk/*
// @include *amazon.ca/*
// @include *amazon.es/*
// @include *amazon.de/*
// @include *amazon.fr/*
// @include *amazon.it/*
// @connect amazon.com
// @connect amazon.co.uk
// @connect amazon.ca
// @connect amazon.es
// @connect amazon.de
// @connect amazon.fr
// @connect amazon.it
// @connect yahoo.com
// @connect europa.eu
// @connect mercadolibre.com
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @downloadURL none
// ==/UserScript==
(function() {
if( typeof jQuery === 'undefined' ){
return false;
}
GM_addStyle('.price-ars{color:green;display:inline-block;margin:0 8px;background:linear-gradient(to bottom,#add8e6,#fff,#add8e6);border-radius:8px;padding:0 6px}'+
'#sc-buy-box .price-ars{font-size:12px;display:block;padding:0;margin:0;background:0 0}div#sc-buy-box{margin-bottom:-14px}');
GM_addStyle('#snoop-icon{margin-left:4px;width:30px;height:20px}#snoop-placeholder{width:32px}div.snoop-loader{width:13px;height:13px}div.snoop-tooltip,div.snoop-tooltip-ml{display:none;font-size:13px;border-image:none;letter-spacing:0}'+
'div.snoop-tooltip div.entry,div.snoop-tooltip-ml div.entry{padding-top:5px}span.snoop-price{color:#900;font-size:1em;font-weight:700}span.snoop-warning{color:#C60!important}.snoop-not-found{text-decoration:line-through}'+
'span.snoop-on{color:#000;font-weight:400}div.snoop-credits{font-size:.75em;font-style:italic;text-align:center;margin-top:13px;font-weight:400;color:#666}span.back-link{line-height:0;margin-left:1px;top:-10px;position:relative}'+
'span.back-link>img{top:1;position:relative}span.back-link>a{font-size:1em;text-decoration:none!important}#snoop-icon-ml{margin-left:10px}');
String.prototype.endsWith = function (pattern) {
var d = this.length - pattern.length;
return d >= 0 && this.lastIndexOf(pattern) === d;
};
var amazonCurrencies = ["USD", "GBP", "CAD", "EUR"];
var currencyFrom;
var currencies = {
"USD" : {
symbol: "$",
priceRegex: /\$\s*([\d,.]+\d)/,
vat: false
},
"GBP" : {
symbol: "£",
priceRegex: /£\s*([\d,.]+\d)/,
vat: true
},
"CAD" : {
symbol: "CDN$ ",
priceRegex: /CDN\$\s*([\d,.]+\d)/,
vat: false
},
"EUR" : {
symbol: "EUR ",
priceRegex: /EUR\s*([\s\d,.]+\d)/,
vat: true
}
};
if (document.domain.endsWith("com")) {
currencyFrom = "USD";
} else if (document.domain.endsWith("co.uk")) {
currencyFrom = "GBP";
} else if (document.domain.endsWith("ca")) {
currencyFrom = "CAD";
} else if (
document.domain.endsWith("es") ||
document.domain.endsWith("de") ||
document.domain.endsWith("fr") ||
document.domain.endsWith("it")
) {
currencyFrom = "EUR";
} else {
return;
}
var LAST_RUN = "last_run_";
var CURRENCY_RATE = "currency_rate_";
var decimalPlaces = 2;
var prefixCurrencySymbol = true;
var taxPorcentage = 5;
var rounding = Math.pow(10, decimalPlaces);
var rate = GM_getValue(CURRENCY_RATE + currencyFrom);
var lastRun = GM_getValue(LAST_RUN + currencyFrom, "01/01/0001");
var currencyTo = 'ARS';
var todayDate = new Date();
var todayString = todayDate.getDate() + "/" + todayDate.getMonth() + "/" + todayDate.getFullYear();
var currencyToSymbol = 'ARS $';
function regularPriceParser(price, currency) {
price = price.replace(/\s/g, '');
var regex = /^[\d.]+,[\d]{2}$/;
var needProperPrice = regex.exec(price);
if(needProperPrice) {
price = price.replace(/\./g, '').replace(/,/, '.');
}else{
price = price.replace(/\,/g, '');
}
return parseFloat(price);
}
function fetchCurrencyData(coin, callback) {
GM_xmlhttpRequest({
method: "GET",
url: "http://download.finance.yahoo.com/d/quotes.csv?s=" + coin + currencyTo + "=X&f=l1&e=.csv",
onload: function(responseDetails) {
var rate = responseDetails.responseText.replace(/[\r\n]/g, "");
GM_setValue(CURRENCY_RATE + coin, rate);
GM_setValue(LAST_RUN + coin, todayString);
callback();
},
onerror: function(responseDetails) {
alert("Error fetching currency data for " + coin);
}
});
}
function appendConversionNoVAT(price, matched, offset, string) {
return appendConversion(price, matched, offset, string, true);
}
function appendConversion(price, matched, offset, string, novat) {
var originalPrice = regularPriceParser(matched, currencyFrom);
if (isNaN(originalPrice)) {
return price;
}
if(currencies[currencyFrom].vat && novat === undefined){
originalPrice /= 1.2;
}
var converted = formatCurrency(originalPrice * (rate * (taxPorcentage / 100 + 1)), rounding, currencyToSymbol, prefixCurrencySymbol);
if(currencies[currencyFrom].vat && novat === undefined){
originalPrice = formatCurrency(originalPrice, rounding, currencies[currencyFrom].symbol, prefixCurrencySymbol);
return '' + originalPrice + '' + converted + '
';
}else{
return price + '
' + converted + '
';
}
}
function formatCurrency(num, rounding, symbol, prefix) {
sign = (num == (num = Math.abs(num)));
num = Math.floor(num * rounding + 0.50000000001);
cents = num % rounding;
num = Math.floor(num / rounding).toString();
if (cents < 10) {
cents = "0" + cents;
}
for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {
num = num.substring(0, num.length - (4 * i + 3)) + ',' +
num.substring(num.length-(4*i+3));
}
if (prefix) {
return (symbol + ((sign)?'':'-') + num + '.' + cents);
} else {
return (((sign)?'':'-') + num + '.' + cents + symbol);
}
}
convertCurrency = function(carrito) {
switch(carrito){
case 1:
if( jQuery('.a-size-base.a-text-bold:contains(Order summary)').length === 0 &&
jQuery('.a-size-base.a-text-bold:contains(Récapitulatif de commande)').length === 0 &&
jQuery('.a-size-base.a-text-bold:contains(Riepilogo ordine)').length === 0 &&
jQuery('.a-size-base.a-text-bold:contains(Resumen del pedido)').length === 0 &&
jQuery('.a-size-base.a-text-bold:contains(Zusammenfassung der Bestellung)').length === 0 &&
jQuery('.ap_popover.ap_popover_sprited.snoop-tooltip').length === 0
){
return false;
}else{
if(jQuery('#sc-buy-box.price-ars-cart').length === 0){
jQuery('#sc-buy-box').addClass('price-ars-cart');
}else{
return false;
}
}
break;
case 2:
if( jQuery('.entry.snoop-price:not(.snoop-warning):not(.price-ars-cart)').length === 0 ){
return false;
}
break;
default:
break;
}
//console.log('Cambiando precios', carrito);
var currency = currencies[currencyFrom];
jQuery('.a-column.a-span3.a-text-right.a-span-last.sc-value').removeClass('a-span3').addClass('a-span4');
jQuery('.a-column.a-span9.sc-text').removeClass('a-span9').addClass('a-span8');
jQuery('a.a-popover-trigger.a-declarative:contains(Estimated)').html('Shipping & handling ');
if(carrito == 2){
jQuery('.entry.snoop-price:not(.snoop-warning)').each(function(){
var text = jQuery(this).text();
if( jQuery(this).children().length === 0 && text.indexOf(currency.symbol) != -1 && text.indexOf('ARS') == -1){
jQuery(this).addClass('price-ars-cart').html( text.replace(currency.priceRegex, appendConversion) );
}
});
}else{
jQuery('span:not(:has(*))').each(function(){
var text = jQuery(this).text();
if( jQuery(this).children().length === 0 && text.indexOf(currency.symbol) != -1 && text.indexOf('ARS') == -1){
if( jQuery(this).parents('#sc-buy-box').length == 1 ||
window.location.href.indexOf("/order-details") > -1 ||
window.location.href.indexOf("/order-history") > -1
){
jQuery(this).html( text.replace(currency.priceRegex, appendConversionNoVAT) );
}else{
jQuery(this).html( text.replace(currency.priceRegex, appendConversion) );
}
}
});
}
};
var running_convert_1 = false;
var running_convert_2 = false;
$( document ).ready(function(){
console.log('Page ready!');
if (rate === undefined || todayString !== lastRun) {
fetchCurrencyData(currencyFrom, function() {
rate = GM_getValue(CURRENCY_RATE + currencyFrom);
convertCurrency();
});
} else {
console.log('Currency rate: ', rate);
convertCurrency();
}
$('.a-fixed-right-grid-col.a-col-right').bind("DOMSubtreeModified",function(e){
if(running_convert_1 === false){
console.log('Auto 1');
running_convert_1 = true;
setTimeout(function(){convertCurrency(1); running_convert_1=false;}, 1000);
}
});
$('#priceblock_ourprice').bind("DOMSubtreeModified",function(e){
if(running_convert_2 === false){
console.log('Auto 2');
running_convert_2 = true;
setTimeout(function(){convertCurrency(2); running_convert_2=false;}, 1000);
}
});
/*
////////////////////////////////////////////////////////////////
PRECIOS DE OTRAS TIENDAS
////////////////////////////////////////////////////////////////
*/
var asin = $('#ASIN').val();
if (asin === undefined)
return;
snoop.initialize(asin);
});
})();
//Various currencies' rates to EUR
window.Rates = {
timestamp: new Date(),
'EUR': 1,
'USD': 0,
'GBP': 0
};
function refreshRates() {
var cachedRates = JSON.parse(localStorage.getItem("conversionRates"));
//console.log(cachedRates);
if (cachedRates !== null && cachedRates.timestamp !== undefined) {
cachedRates.timestamp = new Date(cachedRates.timestamp);
Rates = cachedRates;
var ageInHours = (new Date() - cachedRates.timestamp) / 1000 / 60 / 60;
if (ageInHours < 7)
return;
}
console.log('Refreshing conversion rates...');
GM_xmlhttpRequest({
method: "GET",
url: 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',
onload: function(responseDetails) {
var $document = $(responseDetails.responseText);
for (var rate in Rates) {
if (typeof rate !== 'string' || rate === 'EUR')
continue;
Rates[rate] = parseFloat($document.find('Cube[currency="' + rate + '"]').attr('rate'));
}
Rates.timestamp = new Date();
localStorage.conversionRates = JSON.stringify(Rates);
},
onerror: function(responseDetails) {
alert("Error fetching currency rates.");
}
});
}
var Money = function (amount, currency, currency_symbol, extraAmount) {
this.amount = amount;
this.extraAmount = extraAmount;
this.currency = currency;
this.currency_symbol = currency_symbol;
//console.log('Money', this);
};
Money.prototype.for = function (currency, currency_symbol) {
var rate = Rates[currency] / Rates[this.currency];
var convertedAmount = this.amount * rate;
var convertedExtraAmount = this.extraAmount !== undefined ? this.extraAmount * rate : undefined;
//console.log('Conversion\n', this.currency, '->', currency,
// '\n', Rates[this.currency], '->', Rates[currency],
// '\n', this.amount, '->', convertedAmount);
return new Money(convertedAmount, currency, currency_symbol, convertedExtraAmount);
};
Money.prototype.toString = function () {
if (this.extraAmount === undefined)
return this.currency_symbol+(this.amount.toFixed(2));
else
return this.currency_symbol+(this.amount.toFixed(2)) + ' - ' + this.currency_symbol+(this.extraAmount.toFixed(2));
};
var Shop = function (id, title, domain, base_url, currency, currency_symbol, seller) {
this.id = id;
this.title = title;
this.domain = domain;
this.base_url = base_url;
this.url = this.base_url;
this.currency = currency;
this.currency_symbol = currency_symbol;
this.seller = seller;
this.setAsin = function (asin) {
this.url = this.urlFor(asin);
};
this.urlFor = function (asin) {
return this.base_url.replace('{asin}', asin);
};
this.moneyFrom = function (amount) {
var culture = this.culture;
if (amount.indexOf('-') == -1) {
var sanitizedAmount = amount.replace(/[^\d^,^.]/g, '');
var regex = /^[\d.]+,[\d]{2}$/;
var needProperPrice = regex.exec(sanitizedAmount);
if(needProperPrice) {
sanitizedAmount = sanitizedAmount.replace(/\./g, '').replace(/,/, '.');
}else{
sanitizedAmount = sanitizedAmount.replace(/\,/g, '');
}
return new Money(sanitizedAmount, this.currency);
}
var sanitizedAmounts = amount.split('-').map(function (a) {
return a.replace(/[^\d^,^.]/g, '');
});
return new Money(sanitizedAmounts[0], this.currency, sanitizedAmounts[1]);
};
};
var Settings = function (asin) {
this.asin = asin;
this.shops = [
new Shop(1, 'amazon.co.uk', 'www.amazon.co.uk', 'https://www.amazon.co.uk/dp/{asin}?smid=A3P5ROKL5A1OLE&tag=r0f340c-21', 'GBP', '£', 'Dispatched from and sold by Amazon'),
new Shop(2, 'amazon.de', 'www.amazon.de', 'https://www.amazon.de/dp/{asin}?smid=A3JWKAKR8XB7XF&tag=r0f3409-21', 'EUR', 'EUR ', 'Dispatched from and sold by Amazon|Verkauf und Versand durch Amazon'),
new Shop(3, 'amazon.fr', 'www.amazon.fr', 'https://www.amazon.fr/dp/{asin}?smid=A1X6FK5RDHNB96&tag=r0f3405-21', 'EUR', 'EUR ', 'Expédié et vendu par Amazon'),
new Shop(4, 'amazon.es', 'www.amazon.es', 'https://www.amazon.es/dp/{asin}?smid=A1AT7YVPFBWXBL&tag=r0f34-21', 'EUR', 'EUR ', 'Vendido y enviado por Amazon'),
new Shop(5, 'amazon.it', 'www.amazon.it', 'https://www.amazon.it/dp/{asin}?smid=A11IL2PNWYJU7H&tag=r0f3401-21', 'EUR', 'EUR ', 'Venduto e spedito da Amazon'),
new Shop(6, 'amazon.com', 'www.amazon.com', 'https://www.amazon.com/dp/{asin}?smid=ATVPDKIKX0DER&tag=r0f34-20', 'USD', '$', 'Ships from and sold by Amazon.com')
];
this.shops.forEach(function (shop) {
shop.setAsin(asin);
});
this.currentShop = this.shops.filter(function (shop) {
return shop.domain == document.domain;
})[0];
this.desiredCurrency = this.currentShop.currency;
if (this.currentShop.currency != this.desiredCurrency) {
this.filteredShops = this.shops;
}
else {
this.filteredShops = this.shops.filter(function (shop) {
return shop.domain != document.domain;
});
}
this.shop = function (id) {
var shopById = this.shops.filter(function (shop) {
return shop.id == id;
});
if (shopById.length == 1)
return shopById[0];
return null;
};
};
var pageScraper = {
warning: {
networkError: 'Error al consultar',
unavailable: 'No disponible',
wrongSeller: 'No vendido por Amazon',
notFound: 'No encontrado',
multipleOptions: 'Opciones multiples'
},
getPriceOn: function (shop, displayPrice, displayWarning) {
var serverUrl = shop.url;
var sellerText = shop.seller;
GM_xmlhttpRequest({
method: "GET",
url: serverUrl,
onload: function(data) {
var regex = /[nb]\s*?id="priceblock_[\w]*?price".*?>(.*?)'+
'';
var page = {
addTooltipToPage: function (tooltipMarkup) {
var $placeholderMarkup = $('
');
var $imageMarkup = $('
');
var $imageMarkupMELI = $('
');
var $container = this.findAppropriateTooltipContainer();
var tooltipTemplateML = '';
$container.after($imageMarkupMELI);
$container.after(tooltipTemplateML);
$container.after($imageMarkup);
$container.after(tooltipMarkup);
tooltip.registerShowHideHandlers();
tooltipML.registerShowHideHandlers();
convertCurrency();
},
findAppropriateTooltipContainer: function () {
var $tries = [
$('table.product .priceLarge:first', $('#priceBlock')),
$('#priceblock_ourprice'),
$('#priceblock_saleprice'),
$('#availability_feature_div > #availability > .a-color-price'),
$('div.buying span.availGreen', $('#handleBuy')),
$('div.buying span.availRed:nth-child(2)', $('#handleBuy'))
];
for (var i = 0; i < $tries.length; i++) {
if ($tries[i].length > 0)
return $tries[i];
}
throw new Error('Unable to find the price section.');
},
displayPrice: function ($shopInfo, price) {
var convertedPrice = price.for(settings.currentShop.currency, settings.currentShop.currency_symbol);
$shopInfo.text(convertedPrice.toString());
convertCurrency();
},
displayWarning: function ($shopInfo, warning, addNotFoundClass) {
$shopInfo.text(warning).addClass('snoop-warning');
if (addNotFoundClass)
$shopInfo.parent().addClass('snoop-not-found');
},
registerInitializationHandler: function (shops) {
$('#snoop-icon').mouseover(function () {
if (window.snoop_tooltipInitialized !== undefined && window.snoop_tooltipInitialized !== false)
return;
window.snoop_tooltipInitialized = true;
$.each(shops, function (index, shop) {
var $shopInfo = $('#snoop-shop-' + shop.id);
pageScraper.getPriceOn(shop, function (price) {
page.displayPrice($shopInfo, shop.moneyFrom(price));
}, function (warning, addNotFoundClass) {
page.displayWarning($shopInfo, warning, addNotFoundClass);
});
});
});
$('#snoop-icon-ml').mouseover(function () {
if (window.snoopML_tooltipInitialized !== undefined && window.snoopML_tooltipInitialized !== false)
return;
window.snoopML_tooltipInitialized = true;
var productName = decodeURI(jQuery('#productTitle').html().replace(' ', ' ').replace(/[^\w\d\s\.]/g, ' ').trim());
meli.showPrices(productName);
});
}
};
var settings;
var snoop = {
tooltip: null,
asin: null,
_startMonitoringAsin: function () {
var observer = new MutationObserver(function (mutations) {
var asinHasProbablyChanged = mutations.some(function (mutation) {
return mutation.addedNodes.length > 0;
});
if (!asinHasProbablyChanged)
return;
var newAsin = $('#ASIN').val();
if (snoop.asin == newAsin)
return;
snoop.run(newAsin);
});
observer.observe($('#buybox_feature_div')[0], { attributes: true, subtree: true, childList: true, characterData: true });
},
initialize: function (asin) {
this.asin = asin;
this._startMonitoringAsin();
refreshRates();
settings = new Settings(asin);
snoop.tooltip = Mustache.to_html(tooltipTemplate, {
shops: settings.filteredShops,
from_shop: settings.currentShop.id,
from_asin: settings.asin,
loader_url: 'https://i.imgur.com/Dp92MjH.gif'
});
snoop.run(asin);
},
run: function (asin) {
this.asin = asin;
settings = new Settings(asin);
window.snoop_tooltipInitialized = false;
window.snoopML_tooltipInitialized = false;
var ensureTooltipHasBeenLoaded = function () {
if (snoop.tooltip === null) {
setTimeout(ensureTooltipHasBeenLoaded, 50);
}
else {
var tooltipMarkup = snoop.tooltip.replace(/{asin}/gm, settings.asin);
page.addTooltipToPage(tooltipMarkup);
page.registerInitializationHandler(settings.filteredShops);
}
};
ensureTooltipHasBeenLoaded();
}
};
Number.prototype.formatMoney = function(c, d, t){
var n = this;
c = isNaN(c = Math.abs(c)) ? 2 : c;
d = d === undefined ? "." : d;
t = t === undefined ? "," : t;
var s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};
var meli = {
showPrices: function(productName) {
meli.fetchApiData(productName, meli.showProducts);
},
showProducts: function (data){
var meliProducts = $('.snoop-tooltip-ml .tmm_popover');
meliProducts.html('Buscando por: '+data.query+'
');
//console.log(data);
if(data.results.length === 0){
meliProducts.append('No se encontraron productos en MercadoLibre con esta búsqueda.
');
}
data.results.forEach(function(product) {
meliProducts.append('ARS $'+product.price.formatMoney(2)+'
» '+product.title+' ');
});
},
fetchApiData: function (productName, callback) {
GM_xmlhttpRequest({
method: "GET",
url: "https://api.mercadolibre.com/sites/MLA/search?q=" + encodeURI(productName) + "&condition=new",
onload: function(responseDetails) {
var api = JSON.parse(responseDetails.responseText);
callback(api);
},
onerror: function(responseDetails) {
alert("Error fetching API from MELI");
}
});
}
};