Greasy Fork is available in English.
Optimized version to load Amazon product prices with customizable settings, minimized RAM usage, and UI.
// ==UserScript==// @name Amazon Seller Product Price Loader// @namespace http://tampermonkey.net/// @version 4.8// @description Optimized version to load Amazon product prices with customizable settings, minimized RAM usage, and UI.// @license MIT https://opensource.org/licenses/MIT// @match https://sellercentral.amazon.com/*// @match https://sellercentral.amazon.co.uk/*// @match https://sellercentral.amazon.de/*// @match https://sellercentral.amazon.fr/*// @match https://sellercentral.amazon.it/*// @match https://sellercentral.amazon.es/*// @match https://sellercentral.amazon.ca/*// @match https://sellercentral.amazon.com.mx/*// @match https://sellercentral.amazon.com.br/*// @match https://sellercentral.amazon.co.jp/*// @match https://sellercentral.Amazon.com.br/*// @match https://sellercentral.amazon.com.au/*// @grant GM_getValue// @grant GM_setValue// @grant GM_registerMenuCommand// @grant GM_addStyle// @grant GM_getResourceText// @grant GM_xmlhttpRequest// @resource IMPORTED_CSS https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css// @run-at document-end// ==/UserScript==(function () {'use strict';function applySettings() {// Apply font size, font family, and bold settingsdocument.body.style.fontSize = `${options.fontSize}px`;document.body.style.fontFamily = options.fontFamily;document.body.style.fontWeight = options.fontBold ? 'bold' : 'normal';// Apply font colordocument.body.style.color = options.fontColor || 'initial';// Apply glow settings if enabledif (options.glowEnabled) {document.body.style.textShadow = `0px 0px 5px ${options.glowColor}`;} else {document.body.style.textShadow = 'none';}}document.addEventListener('DOMContentLoaded', () => {// Load saved options from GM_setValueoptions.fontSize = GM_getValue('fontSize', 14); // Default to 14px if not setoptions.fontFamily = GM_getValue('fontFamily', 'Arial'); // Default to Arial if not setoptions.fontBold = GM_getValue('fontBold', false); // Default to false if not setoptions.fontColor = GM_getValue('fontColor', '#000000'); // Default to black if not setoptions.glowEnabled = GM_getValue('glowEnabled', false); // Default to false if not setoptions.glowColor = GM_getValue('glowColor', '#ffffff'); // Default to white if not set// Apply loaded settingsapplySettings();// Create font color input and add event listenerconst fontColorInput = document.createElement('input');fontColorInput.type = 'color';fontColorInput.value = options.fontColor; // Set the current font colorfontColorInput.addEventListener('change', (e) => {options.fontColor = e.target.value;GM_setValue('fontColor', options.fontColor);applySettings(); // Reapply settings to update font color immediately});// Add the font color input to the settings UI (for example, adding to a settings container)document.body.appendChild(fontColorInput); // Adjust where you want it placed in your UI});const defaultOptions = {fontSize: '12px',fontFamily: 'Arial, sans-serif',textColor: '#0066c0',priceColor: '#0066c0',reviewsColor: '#008800',sellerColor: '#cc5500',glowColor: '#ff00ff',showFrame: true,frameColor: '#cccccc',loadDelay: 10,currency: 'default',enableNotifications: false};let options = Object.keys(defaultOptions).reduce((acc, key) => {acc[key] = GM_getValue(key, defaultOptions[key]);return acc;}, {});const MAX_RETRIES = 2;const RETRY_DELAY = 40;// Add Tailwind CSSGM_addStyle(GM_getResourceText("IMPORTED_CSS"));function addCustomStyle() {let styles = [];if (options.fontBold) {styles.push('font-bold');}if (options.glowIntensity > 0) {styles.push(`text-shadow: 0 0 ${options.glowIntensity * 20}px ${options.glowColor}`);}styles.push(`color: ${options.priceColor}`);styles.push(`font-family: ${options.fontFamily}`);styles.push(`font-size: ${options.fontSize}`);const glowBlurRadius = options.glowIntensity * 10;const glowSpreadRadius = options.glowIntensity * 5;styles.push(`text-shadow: 0 0 ${glowBlurRadius}px ${options.glowColor}, 0 0 ${glowSpreadRadius}px ${options.glowColor}`);styles.push(`color: ${options.priceColor}`);styles.push(`font-family: ${options.fontFamily}`);styles.push(`font-size: ${options.fontSize}`);const customStyle = styles.join('; ');document.documentElement.style.setProperty('--custom-style', customStyle);if (options.glowIntensity > 0) {styles.push(`text-shadow: 0 0 ${options.glowIntensity * 20}px ${options.glowColor}`);}styles.push(`color: ${options.priceColor}`);styles.push(`font-family: ${options.fontFamily}`);styles.push(`font-size: ${options.fontSize}`);const isDarkMode = document.body.classList.contains('dark');function getInvertedColor(color) {// Convert the hex color to RGBconst r = parseInt(color.slice(1, 3), 16);const g = parseInt(color.slice(3, 5), 16);const b = parseInt(color.slice(5, 7), 16);// Invert the RGB valuesconst invR = 255 - r;const invG = 255 - g;const invB = 255 - b;// Convert the inverted RGB values back to hexreturn `#${invR.toString(16).padStart(2, '0')}${invG.toString(16).padStart(2, '0')}${invB.toString(16).padStart(2, '0')}`;}GM_addStyle(`.price-display-container {display: block;margin-top: 4px;}.price-display {display: block;font-size: ${options.fontSize};font-family: ${options.fontFamily};color: ${isDarkMode ? getInvertedColor(options.priceColor) : options.priceColor};text-shadow: 0 0 ${glowBlurRadius}px ${options.glowColor}, 0 0 ${glowSpreadRadius}px ${options.glowColor};font-weight: ${options.fontBold ? 'bold' : 'normal'};-webkit-text-stroke: 2px var(--glow-color);}.rating-display {display: block;font-size: ${options.fontSize};font-family: ${options.fontFamily};color: ${isDarkMode ? getInvertedColor(options.reviewsColor) : options.reviewsColor};text-shadow: 0 0 ${glowBlurRadius}px ${options.glowColor}, 0 0 ${glowSpreadRadius}px ${options.glowColor};font-weight: ${options.fontBold ? 'bold' : 'normal'};-webkit-text-stroke: 2px var(--glow-color);}.seller-display {display: block;font-size: ${options.fontSize};font-family: ${options.fontFamily};color: ${isDarkMode ? getInvertedColor(options.sellerColor) : options.sellerColor};text-shadow: 0 0 ${glowBlurRadius}px ${options.glowColor}, 0 0 ${glowSpreadRadius}px ${options.glowColor};font-weight: ${options.fontBold ? 'bold' : 'normal'};-webkit-text-stroke: 2px var(--glow-color);}.loading {opacity: 0.9;padding: 1px 8px;border: 1px solid ${options.frameColor};display: inline-block;}#amazon-price-loader-settings {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 10000;background: #f9f9f9;padding: 15px;border-radius: 8px;box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);max-width: 400px;width: 90%;overflow: hidden;border: 1px solid #ccc;display: flex;flex-wrap: wrap;justify-content: space-between;}.settings-overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, 0.5);z-index: 9999;}.tooltip {position: absolute;background: white;border: 1px solid black;padding: 10px;z-index: 1000;}.setting-row {display: flex;flex-direction: column;width: 48%;margin-bottom: 10px;}.setting-label {font-weight: bold;color: #333;margin-bottom: 5px;}.setting-button {background-color: #007bff;color: white;border: none;border-radius: 5px;padding: 5px 10px;cursor: pointer;transition: background-color 0.3s;font-size: 14px;width: 100%;margin-top: 10px;}.setting-button:hover {background-color: #0056b3;}.color-picker {width: 100%;height: 30px;border: none;padding: 0;cursor: pointer;}.font-picker {width: 100%;padding: 5px;border: 1px solid #ccc;border-radius: 5px;}.font-size-input {width: 100%;padding: 5px;border: 1px solid #ccc;border-radius: 5px;}`);}function createSettingsUI() {// Check if the settings overlay already existsif (document.querySelector('.settings-overlay')) {return; // Exit the function if the overlay is already present}const settingsContainer = document.createElement('div');settingsContainer.className = 'settings-container bg-white shadow-md rounded-lg p-2 w-48';const title = document.createElement('h2');title.textContent = 'Settings';title.classList.add('text-xs', 'font-bold', 'mb-2');settingsContainer.style.position = 'fixed';settingsContainer.style.top = '0px'; // Adjust the value to move the menu up or downsettingsContainer.style.right = '70px'; // Adjust the value to move the menu left or rightsettingsContainer.appendChild(title);// Display Settingsconst displaySettings = document.createElement('div');displaySettings.classList.add('mb-2');const fontSizeRow = document.createElement('div');fontSizeRow.classList.add('flex', 'items-center', 'justify-between');const fontSizeLabel = document.createElement('label');fontSizeLabel.textContent = 'Size';fontSizeLabel.classList.add('text-xxs', 'font-medium');const fontSizeInput = document.createElement('input');fontSizeInput.type = 'number';fontSizeInput.value = options.fontSize.replace('px', '');fontSizeInput.min = 8;fontSizeInput.max = 36;fontSizeInput.className = 'w-10 px-1 py-0.5 border rounded text-xxs';fontSizeInput.onchange = (e) => {options.fontSize = `${e.target.value}px`;addCustomStyle();};fontSizeRow.appendChild(fontSizeLabel);fontSizeRow.appendChild(fontSizeInput);displaySettings.appendChild(fontSizeRow);const fontFamilyRow = document.createElement('div');fontFamilyRow.classList.add('flex', 'items-center', 'justify-between');const fontFamilyLabel = document.createElement('label');fontFamilyLabel.textContent = 'Font';fontFamilyLabel.classList.add('text-xxs', 'font-medium');const fontFamilyInput = document.createElement('select');fontFamilyInput.className = 'w-full px-1 py-0.5 border rounded text-xxs';fontFamilyInput.onchange = (e) => {options.fontFamily = e.target.value;addCustomStyle();};const fonts = ['Arial, sans-serif','Times New Roman, serif','Verdana, sans-serif','Georgia, serif','Courier New, monospace','Roboto, sans-serif','Open Sans, sans-serif','Lato, sans-serif','Montserrat, sans-serif','Poppins, sans-serif'];fonts.forEach(font => {const option = document.createElement('option');option.value = font;option.textContent = font;option.selected = options.fontFamily === font;fontFamilyInput.appendChild(option);});// Bold functionalityconst fontBoldRow = document.createElement('div');fontBoldRow.classList.add('flex', 'items-center', 'justify-between');const fontBoldLabel = document.createElement('label');fontBoldLabel.textContent = 'Bold';fontBoldLabel.classList.add('text-xxs', 'font-medium');const fontBoldCheckbox = document.createElement('input');fontBoldCheckbox.type = 'checkbox';fontBoldCheckbox.checked = options.fontBold;fontBoldCheckbox.className = 'w-4 h-4 border rounded';fontBoldCheckbox.onchange = (e) => {options.fontBold = e.target.checked;addCustomStyle();};fontBoldRow.appendChild(fontBoldLabel);fontBoldRow.appendChild(fontBoldCheckbox);displaySettings.appendChild(fontBoldRow);fontFamilyRow.appendChild(fontFamilyLabel);fontFamilyRow.appendChild(fontFamilyInput);displaySettings.appendChild(fontFamilyRow);displaySettings.appendChild(fontBoldCheckbox);displaySettings.appendChild(fontBoldLabel);settingsContainer.appendChild(displaySettings);// Color Settingsconst colorSettings = document.createElement('div');colorSettings.classList.add('mb-2');const priceColorRow = document.createElement('div');priceColorRow.classList.add('flex', 'items-center', 'justify-between');const priceColorLabel = document.createElement('label');priceColorLabel.textContent = 'Price';priceColorLabel.classList.add('text-xxs', 'font-medium');const priceColorInput = document.createElement('input');priceColorInput.type = 'color';priceColorInput.value = options.priceColor;priceColorInput.className = 'w-5 h-5 border rounded-full';priceColorInput.onchange = (e) => {options.priceColor = e.target.value;addCustomStyle();};priceColorRow.appendChild(priceColorLabel);priceColorRow.appendChild(priceColorInput);colorSettings.appendChild(priceColorRow);const reviewsColorRow = document.createElement('div');reviewsColorRow.classList.add('flex', 'items-center', 'justify-between');const reviewsColorLabel = document.createElement('label');reviewsColorLabel.textContent = 'Reviews';reviewsColorLabel.classList.add('text-xxs', 'font-medium');const reviewsColorInput = document.createElement('input');reviewsColorInput.type = 'color';reviewsColorInput.value = options.reviewsColor;reviewsColorInput.className = 'w-5 h-5 border rounded-full';reviewsColorInput.onchange = (e) => {options.reviewsColor = e.target.value;addCustomStyle();};reviewsColorRow.appendChild(reviewsColorLabel);reviewsColorRow.appendChild(reviewsColorInput);colorSettings.appendChild(reviewsColorRow);const sellerColorRow = document.createElement('div');sellerColorRow.classList.add('flex', 'items-center', 'justify-between');const sellerColorLabel = document.createElement('label');sellerColorLabel.textContent = 'Seller';sellerColorLabel.classList.add('text-xxs', 'font-medium');const sellerColorInput = document.createElement('input');sellerColorInput.type = 'color';sellerColorInput.value = options.sellerColor;sellerColorInput.className = 'w-5 h-5 border rounded-full';sellerColorInput.onchange = (e) => {options.sellerColor = e.target.value;addCustomStyle();};sellerColorRow.appendChild(sellerColorLabel);sellerColorRow.appendChild(sellerColorInput);colorSettings.appendChild(sellerColorRow);settingsContainer.appendChild(colorSettings);// Global Glow Settingsconst glowSettings = document.createElement('div');glowSettings.classList.add('mb-2');const glowColorRow = document.createElement('div');glowColorRow.classList.add('flex', 'items-center', 'justify-between');const glowColorLabel = document.createElement('label');glowColorLabel.textContent = 'Glow Color';glowColorLabel.classList.add('text-xxs', 'font-medium');const glowColorInput = document.createElement('input');glowColorInput.type = 'color';glowColorInput.value = options.glowColor;glowColorInput.className = 'w-5 h-5 border rounded-full';glowColorInput.onchange = (e) => {options.glowColor = e.target.value;GM_setValue('glowColor', options.glowColor); // Save to memoryaddCustomStyle();};const glowColor = options.glowColor || '#ff00ff';const glowIntensity = options.glowIntensity || 0.5;const isBold = options.isBold ? 'bold' : 'normal';const fontColor = options.fontColor || '#000000';const style = document.createElement('style');style.innerHTML = `.price-display, .rating-display, .seller-display {text-shadow: 0 0 ${glowIntensity * 10}px ${glowColor}; /* Apply glow */color: ${fontColor}; /* Apply font color */font-weight: ${isBold}; /* Apply bold if set */}`;document.head.appendChild(style);addCustomStyle();const glowIntensityInput = document.createElement('input');glowIntensityInput.type = 'range';glowIntensityInput.min = 0;glowIntensityInput.max = 1;glowIntensityInput.step = 0.01;glowIntensityInput.value = options.glowIntensity;glowIntensityInput.className = 'w-full';glowIntensityInput.onchange = (e) => {options.glowIntensity = parseFloat(e.target.value);GM_setValue('glowIntensity', options.glowIntensity); // Save to memoryaddCustomStyle();};const glowIntensityLabel = document.createElement('label');glowIntensityLabel.textContent = 'Glow Intensity';glowIntensityLabel.classList.add('text-xxs', 'font-medium');glowColorRow.appendChild(glowColorLabel);glowColorRow.appendChild(glowColorInput);glowSettings.appendChild(glowColorRow);glowSettings.appendChild(glowIntensityLabel);glowSettings.appendChild(glowIntensityInput);settingsContainer.appendChild(glowSettings);const buttonsContainer = document.createElement('div');buttonsContainer.classList.add('flex', 'justify-end', 'space-x-2');const saveButton = document.createElement('button');saveButton.className = 'bg-blue-500 hover:bg-blue-600 text-white font-medium py-0.5 px-2 rounded text-xxs';saveButton.textContent = 'Close';saveButton.onclick = () => {options.fontSize = `${fontSizeInput.value}px`;options.fontFamily = fontFamilyInput.value;options.fontBold = fontBoldCheckbox.checked;options.priceColor = priceColorInput.value;options.reviewsColor = reviewsColorInput.value;options.sellerColor = sellerColorInput.value;options.glowColor = GM_getValue('glowColor', '#ff00ff'); // Default glow coloroptions.glowIntensity = GM_getValue('glowIntensity', 0.5); // Default glow intensityoptions.isBold = GM_getValue('isBold', false); // Default bold setting (false = not bold)options.fontColor = GM_getValue('fontColor', '#000000'); // Default font colorObject.keys(options).forEach(key => {GM_setValue(key, options[key]);});addCustomStyle();document.body.removeChild(settingsOverlay);};buttonsContainer.appendChild(saveButton);settingsContainer.appendChild(buttonsContainer);const settingsOverlay = document.createElement('div');settingsOverlay.className = 'settings-overlay';settingsOverlay.appendChild(settingsContainer);settingsOverlay.style.backgroundColor = 'transparent'; // Ensure it's transparentdocument.body.appendChild(settingsOverlay);}function getCurrencySymbol(currency) {const symbols = {'USD': '$ ','EUR': '€ ','GBP': '£ ','NIS': '₪ ','JPY': '¥ '};return symbols[currency] || '';}async function fetchPriceAndRating(url, retries = 0) {try {const response = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method: 'GET',url: url,timeout: 5000,onload: resolve,onerror: reject,ontimeout: reject});});const parser = new DOMParser();const doc = parser.parseFromString(response.responseText, 'text/html');const priceElement = doc.querySelector('.a-price .a-offscreen');let price = priceElement ? priceElement.textContent.trim() : 'No price found';if (options.currency !== 'default') {price = `${getCurrencySymbol(options.currency)} ${price.replace(/[^\d.]/g, '')}`;}const ratingElement = doc.querySelector('.a-icon-alt');let rating = ratingElement ? ratingElement.textContent : 'No rating found';const numberOfRatingsElement = doc.querySelector('#acrCustomerReviewText');let numberOfRatings = numberOfRatingsElement ? numberOfRatingsElement.textContent : '0 ratings';return { price, rating, numberOfRatings };} catch (error) {if (retries < MAX_RETRIES) {await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));return fetchPriceAndRating(url, retries + 1);}return { price: 'Error fetching price', rating: 'Error fetching rating', numberOfRatings: 'Error fetching ratings' };}}async function fetchPriceRatingAndSeller(url, retries = 0) {try {const response = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method: 'GET',url: url,timeout: 5000,onload: resolve,onerror: reject,ontimeout: reject});});const parser = new DOMParser();const doc = parser.parseFromString(response.responseText, 'text/html');const priceElement = doc.querySelector('.a-price .a-offscreen');let price = priceElement ? priceElement.textContent.trim() : 'No price found';if (options.currency !== 'default') {price = `${getCurrencySymbol(options.currency)} ${price.replace(/[^\d.]/g, '')}`;}const ratingElement = doc.querySelector('.a-icon-alt');let rating = ratingElement ? ratingElement.textContent : 'No rating found';const numberOfRatingsElement = doc.querySelector('#acrCustomerReviewText');let numberOfRatings = numberOfRatingsElement ? numberOfRatingsElement.textContent : '0 ratings';const sellerElement = doc.querySelector('#sellerProfileTriggerId');let sellerName = sellerElement ? sellerElement.textContent.trim() : 'Seller info not available';return { price, rating, numberOfRatings, sellerName };} catch (error) {if (retries < MAX_RETRIES) {await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));return fetchPriceRatingAndSeller(url, retries + 1);}return { price: 'Error fetching price', rating: 'Error fetching rating', numberOfRatings: 'Error fetching ratings', sellerName: 'Error fetching seller' };}}async function displayPriceRatingAndSeller(link) {const existingDisplay = link.nextElementSibling;if (existingDisplay && existingDisplay.classList.contains('price-display-container')) return;const parentContainer = document.createElement('div');parentContainer.className = 'price-link-container';link.parentNode.insertBefore(parentContainer, link);parentContainer.appendChild(link);const container = document.createElement('div');container.className = 'price-display-container loading';container.style.border = options.showFrame ? `0.1px solid ${options.frameColor}` : 'none';container.style.padding = '0.1em';const priceDisplay = document.createElement('div');priceDisplay.className = 'price-display';priceDisplay.textContent = 'Loading price...';const ratingDisplay = document.createElement('div');ratingDisplay.className = 'rating-display';ratingDisplay.textContent = 'Loading rating...';const sellerDisplay = document.createElement('div');sellerDisplay.className = 'seller-display';sellerDisplay.textContent = 'Loading seller...';container.appendChild(priceDisplay);container.appendChild(ratingDisplay);container.appendChild(sellerDisplay);parentContainer.appendChild(container);try {await new Promise(resolve => setTimeout(resolve, options.loadDelay));const { price, rating, numberOfRatings, sellerName } = await fetchPriceRatingAndSeller(link.href);priceDisplay.textContent = price;ratingDisplay.textContent = `${rating} (${numberOfRatings})`;sellerDisplay.textContent = `Seller: ${sellerName}`;priceDisplay.classList.remove('loading');ratingDisplay.classList.remove('loading');sellerDisplay.classList.remove('loading');if (options.enableNotifications && price !== 'No price found' && price !== 'Error fetching price') {alert(`Price fetched: ${price}`);}} catch (error) {console.error('Failed to fetch price and rating', error);}}function setupPriceAndRatingDisplay() {const productLinks = document.querySelectorAll('a[href*="/dp/"]');productLinks.forEach(link => displayPriceRatingAndSeller(link));}addCustomStyle();setupPriceAndRatingDisplay();// Register the command for settingsGM_registerMenuCommand('Amazon Price Loader Settings', createSettingsUI);// MutationObserver to monitor changes on the pageconst observer = new MutationObserver(setupPriceAndRatingDisplay);observer.observe(document.body, { childList: true, subtree: true });})();