Amazon Seller Product Price Loader

Optimized version to load Amazon product prices with customizable settings, minimized RAM usage, and UI.

目前為 2024-11-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Amazon Seller Product Price Loader
// @namespace    http://tampermonkey.net/
// @version      4.7
// @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==

// ==UserScript==
// @name         Amazon Seller Product Price Loader (Optimized and Debugged)
// @namespace    http://tampermonkey.net/
// @version      4.6
// @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.in/*
// @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';

    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 CSS
    GM_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 RGB
            const 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 values
            const invR = 255 - r;
            const invG = 255 - g;
            const invB = 255 - b;

            // Convert the inverted RGB values back to hex
            return `#${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'};
        }
        .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'};
        }
        .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'};
        }
        .loading {
            opacity: 0.5;
            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 exists
        if (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 down
        settingsContainer.style.right = '70px'; // Adjust the value to move the menu left or right

        settingsContainer.appendChild(title);

        // Display Settings
        const 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 functionality
        const 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 Settings
        const 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 Settings
        const 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 memory
            addCustomStyle();
        };
        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.1;
        glowIntensityInput.value = options.glowIntensity;
        glowIntensityInput.className = 'w-full';
        glowIntensityInput.onchange = (e) => {
            options.glowIntensity = parseFloat(e.target.value);
            GM_setValue('glowIntensity', options.glowIntensity); // Save to memory
            addCustomStyle();
        };

        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 = 'Save';
        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 color
            options.glowIntensity = GM_getValue('glowIntensity', 0.5); // Default glow intensity
            options.isBold = GM_getValue('isBold', false); // Default bold setting (false = not bold)
            options.fontColor = GM_getValue('fontColor', '#000000'); // Default font color


            Object.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 transparent
        document.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 ? `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 settings
    GM_registerMenuCommand('Amazon Price Loader Settings', createSettingsUI);

    // MutationObserver to monitor changes on the page
    const observer = new MutationObserver(setupPriceAndRatingDisplay);
    observer.observe(document.body, { childList: true, subtree: true });
})();