Price Converter with Tax for Specific Websites

Convert price tags on websites

目前为 2023-05-21 提交的版本。查看 最新版本

// ==UserScript==
// @name         Price Converter with Tax for Specific Websites
// @namespace    http://tampermonkey.net/
// @version      0.7
// @description  Convert price tags on websites
// @author       Nears
// @match        *://*.newegg.ca/*
// @match        *://*.canadacomputers.com/*
// @match        *://*.amazon.ca/*
// @grant        none
// @license      MIT
// ==/UserScript==
(async function() {
	'use strict';
	// Define the tax rate
	const TAX_RATE = 0.14975;
	// Fetch the Euro conversion rate
	async function fetchExchangeRate() {
		const requestURL = 'https://api.exchangerate.host/convert?from=CAD&to=EUR';
		const response = await fetch(requestURL);
		const data = await response.json();
		return data.result;
	}
	const CAD_TO_EURO = await fetchExchangeRate();
	const euroFormatter = new Intl.NumberFormat('en-US', {
		style: 'currency',
		currency: 'EUR',
	});
	// Define the websites and their price tag selectors
	const websites = [{
		domain: 'newegg.ca',
		css: `
        .tax-included {
          color: #bd0000;
        }
        .price-note-euro {
          color: #bd0000;
          font-weight: 700;
        }
        .product-price .price-current {
          margin: 0 !important;
        }
      `,
		selectors: ['li.price-current', '.goods-price-current'],
		updatePrice: (element) => {
			const strongElement = element.querySelector('strong');
			const supElement = element.querySelector('sup');
			if(strongElement && supElement) {
				const price = parseFloat(`${strongElement.textContent.replace(',', '')}${supElement.textContent}`);
				const convertedPrice = convertPrice(price);
				const euroPrice = convertToEuros(convertedPrice);
				const priceParts = convertedPrice.toString().split(".");
				let taxedPriceEl = htmlToElement(`
            <li style="margin: 0">
              <span class="price-current tax-included">$<strong>${priceParts[0]}</strong><sup>.${priceParts[1]}</sup></span>
              <span class="price-note-label"> incl. tax</span>
              <span class="price-note-euro">(${euroFormatter.format(euroPrice)})</span>
            </li>`);
				insertAfter(taxedPriceEl, element);
			}
		}
	}, {
		domain: 'canadacomputers.com',
		css: `
        .tax-included {
          color: #bd0000;
          font-size: 2rem;
          font-weight: 400;
          display: inline-block;
          white-space: nowrap;
          line-height: 1;
        }
        .product-price .price-current {
          margin: 0 !important;
          white-space: nowrap;
        }
        .price-note-label {
          color: black;
          font-size: 0.5em;
          font-weight: normal;
          line-height: 1;
          white-space: nowrap;
        }
        .price-note-euro{
          color: #bd0000;
          font-size: 0.7em;
          font-weight: normal;
          margin-left: 4px;
          white-space: nowrap;
          line-height: 1;
        }
      `,
		selectors: ['.h2-big > strong:nth-child(1)', '.text-red d-block mb-0 pq-hdr-product_price line-height', '.d-block.mb-0.pq-hdr-product_price.line-height', '.text-danger h2 price', ],
		updatePrice: (element) => {
			const price = parseFloat(element.textContent.replace('$', '').replace(',', ''));
			const convertedPrice = convertPrice(price);
			const euroPrice = convertToEuros(convertedPrice);
			const priceParts = convertedPrice.toString().split(".");
			let taxedPriceEl = htmlToElement(`
          <div style="margin: 0;">
            <span class="price-current tax-included">
              $<strong>${priceParts[0]}</strong><sup>.${priceParts[1]}</sup>
              <span class="price-note-label"> incl. tax</span>
            </span>
            <span class="price-note-euro">(${euroFormatter.format(euroPrice)})</span>
          </div>
        `);
			insertAfter(taxedPriceEl, element);
		}
	}, {
		domain: 'amazon.ca',
        css: `
        .tax-included {
          color: #bd0000;
          font-size: 1.2em;
          font-weight: 700;
        }
        `,
		selectors: ['span.a-price', 'div.a-section.a-spacing-micro'],
		updatePrice: (element) => {
			const priceWholeElement = element.querySelector('.a-price-whole');
			const priceFractionElement = element.querySelector('.a-price-fraction');
			if (priceWholeElement && priceFractionElement) {
				const priceWhole = priceWholeElement.textContent.replace(',', '');
				const priceFraction = priceFractionElement.textContent;
				const price = parseFloat(`${priceWhole}.${priceFraction}`);
				const convertedPrice = convertPrice(price);
				const euroPrice = convertToEuros(convertedPrice);
				const priceParts = convertedPrice.toString().split(".");
				let taxedPriceEl = htmlToElement(`
				  <div class="a-row a-size-base a-color-base">
					<span class="price-current tax-included">
					  $<strong>${priceParts[0]}</strong>.${priceParts[1]}
					  <span class="price-note-label"> incl. tax</span>
					</span>
					<span class="price-note-euro">(${euroFormatter.format(euroPrice)})</span>
				  </div>
				`);
				insertAfter(taxedPriceEl, element);
			}
		}
	}];


	function htmlToElement(html) {
		var template = document.createElement('template');
		html = html.trim(); // Never return a text node of whitespace as the result
		template.innerHTML = html;
		return template.content.firstChild;
	}

	function insertAfter(newNode, existingNode) {
		existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
	}
	// Function to convert the price with tax
	function convertPrice(price) {
		const priceWithTax = price * (1 + TAX_RATE);
		return priceWithTax.toFixed(2);
	}
	// Function to convert the price to Euros
	function convertToEuros(price) {
		const priceInEuros = price * CAD_TO_EURO;
		return priceInEuros.toFixed(2);
	}
	// Function to update price tags on the website
	function updatePriceTags(website) {
		website.selectors.forEach(selector => {
			const elements = document.querySelectorAll(selector);
			elements.forEach(element => {
				website.updatePrice(element);
			});
		});
	}
	// Get the current hostname
	const hostname = window.location.hostname;
	// Update price tags for the matching website
	websites.forEach(website => {
		if(hostname.includes(website.domain)) {
			const styleElement = document.createElement('style');
			styleElement.textContent = website.css;
			document.head.appendChild(styleElement);
			updatePriceTags(website);
		}
	});
})();