// ==UserScript==
// @name eshop EUR prices with API
// @namespace Violentmonkey Scripts
// @include https://deathangels.shop*
// @include https://www.blue-tomato.com*
// @include https://doomer.shop*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @version 3.2
// @license MIT
// @author KraXen72
// @description 9/11/2022, 4:27:46 PM
// @icon https://cdn.shopify.com/s/files/1/0569/8407/6311/files/23.png?crop=center&height=32&v=1660122641&width=32
// ==/UserScript==
function injectCSS(css) {
const styleTag = document.createElement("style")
styleTag.innerHTML = css
document.head.appendChild(styleTag)
}
function prependText(text, pelem, parent) {
const elem = document.createElement("span")
elem.textContent = text
parent.insertBefore(elem, pelem)
}
function checkNumber(num) {
return typeof num === 'number' && !isNaN(num)
}
function sameDay(d1, d2) {
// console.log("sameday", d1, d2, {year: [d1.getFullYear(), d2.getFullYear()], month: [d1.getUTCMonth(), d2.getUTCMonth()], date: [d1.getUTCDate(), d2.getUTCDate()]})
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
}
let thisDate = new Date(Date.now())
let lastDate = new Date(GM_getValue("lastDate", new Date().setDate(new Date().getDate() - 1)))
const defaultPriceRegex = /\d*[,.]*\d{1,}/gi
let conversionTableEURto = {}
if (!(typeof lastDate.getMonth === 'function')) lastDate = new Date(lastDate)
function getStuffFromApi() {
console.log("getting stuff from api")
const apiKey = GM_getValue("apiKey", false)
if (!apiKey) throw "set API key for exchangerate-api.com in values"
const req = GM_xmlhttpRequest({
url: `https://v6.exchangerate-api.com/v6/${apiKey}/latest/EUR`,
method: "GET",
responseType: "json",
onload: (responseBody) => {
const data = JSON.parse(responseBody.responseText)
console.log("!!!got api response", thisDate, lastDate, data)
GM_setValue("lastDate", thisDate.toDateString())
GM_setValue("conversionJSON",data["conversion_rates"])
window.location.reload()
}
})
}
if (GM_getValue("conversionJSON", false) !== false) {
console.log("getvalue", GM_getValue("conversionJSON", false), sameDay(thisDate, lastDate))
if (sameDay(thisDate, lastDate)) {
conversionTableEURto = GM_getValue("conversionJSON",{})
console.log("had cached stuff:", conversionTableEURto)
} else {
getStuffFromApi()
}
} else {
getStuffFromApi()
}
// console.log("date sanity check", thisDate, lastDate, sameDay(lastDate, thisDate), GM_getValue("lastDate"))
function applyPrice(conversionConstant, initialPrice, element, mode = "normal", parentElem = element.parentElement) {
if (initialPrice === null) return
const eurPrice = (initialPrice / conversionConstant).toFixed(2)
// console.log({ eurPrice, initialPrice, conversionConstant})
element.title = `${eurPrice}€`
element.innerHTML += ` = ${eurPrice}€`
}
function getPrice(element, regex = defaultPriceRegex, deleteComma = true, debug = false) {
const text = element.innerText.trim()
let res = text.match(regex)
if (res === null) return res
if (checkNumber(res)) return res
if (Array.isArray(res)) res = res[0]
if (typeof res === "string" && res.includes(",")) {
if (deleteComma) {
res = res.replaceAll(",", "")
} else {
res = res.replaceAll(",", ".")
}
}
if (debug) console.log("[regex]", text, res);
if (!isNaN(parseInt(res))) {
if (res.includes(".")) {
return parseFloat(res)
} else {
return parseInt(res)
}
} else {
console.warn(`failed to parse ${res} as a number. it's ${parseInt(res)} on text "${text}"`, element)
return res
}
}
if (window.location.hostname === "deathangels.shop") {
const prices = [...document.querySelectorAll(".price__regular .price-item.price-item--regular, .cart-item .price.price--end")]
prices.forEach(priceElem => {
const price = getPrice(priceElem)
applyPrice(conversionTableEURto["JPY"], price, priceElem)
})
} else if (window.location.hostname === "www.blue-tomato.com") {
const prices = [... document.querySelectorAll(".productdesc .price")]
prices.forEach(priceElem => {
// console.log(priceElem, priceElem.children.length)
let price = getPrice(priceElem)
applyPrice(conversionTableEURto["GBP"], price, priceElem)
})
if (document.querySelector(".js-price > .c-details-box__price-current") !== null) {
console.log("detail view found")
const detailHolder =document.querySelector(".js-price > .c-details-box__price-current").parentElement
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type === 'childList') {
console.log('mo: childList modification. refreshing', mutation);
observer.disconnect();
[...document.querySelectorAll(".js-price > .c-details-box__price-current")].forEach(priceElem => {
const price = getPrice(priceElem)
applyPrice(conversionTableEURto["GBP"], price, priceElem)
})
}
}
};
const config = { attributes: false, childList: true, subtree: true };
const priceObserver = new MutationObserver(callback);
priceObserver.observe(detailHolder, config);
} else {
console.log("no detail view found")
}
} else if (window.location.hostname === "doomer.shop") {
const prices = [...document.querySelectorAll(".price-item.price-item--regular")]
prices.forEach(priceElem => {
const price = getPrice(priceElem)
if (price !== "") {
applyPrice(conversionTableEURto["USD"], price, priceElem)
}
})
}