Steam Multi-currency Live Converter

Auto-detect and convert Steam prices to any currency with live exchange rates

// ==UserScript==
// @name         Steam Multi-currency Live Converter
// @name:ru      Steam Авто-конвертер валют с живыми курсами
// @name:de      Steam Auto-Währungsumrechner mit Live-Kursen
// @name:kk      Steam Авто-валюта конвертері тікелей бағамдармен
// @name:uk      Steam Авто-конвертер валют з живими курсами
// @namespace    http://tampermonkey.net/
// @version      4.2
// @description  Auto-detect and convert Steam prices to any currency with live exchange rates
// @description:ru Автоматически определяет и конвертирует цены Steam в любую валюту с живыми курсами
// @description:de Automatische Erkennung und Konvertierung von Steam-Preisen in jede Währung mit Live-Kursen
// @description:kk Steam бағаларын тікелей бағамдармен кез келген валютаға автоматты анықтау және конвертация
// @description:uk Автоматично визначає та конвертує ціни Steam у будь-яку валюту з живими курсами
// @author       Aze4ka
// @license      MIT
// @match        *://store.steampowered.com/*
// @match        *://steamcommunity.com/market/*
// @grant        GM_xmlhttpRequest
// @connect      cdn.jsdelivr.net
// ==/UserScript==
/*


               AAA                                                           444444444  kkkkkkkk
              A:::A                                                         4::::::::4  k::::::k
             A:::::A                                                       4:::::::::4  k::::::k
            A:::::::A                                                     4::::44::::4  k::::::k
           A:::::::::A           zzzzzzzzzzzzzzzzz    eeeeeeeeeeee       4::::4 4::::4   k:::::k    kkkkkkkaaaaaaaaaaaaa
          A:::::A:::::A          z:::::::::::::::z  ee::::::::::::ee    4::::4  4::::4   k:::::k   k:::::k a::::::::::::a
         A:::::A A:::::A         z::::::::::::::z  e::::::eeeee:::::ee 4::::4   4::::4   k:::::k  k:::::k  aaaaaaaaa:::::a
        A:::::A   A:::::A        zzzzzzzz::::::z  e::::::e     e:::::e4::::444444::::444 k:::::k k:::::k            a::::a
       A:::::A     A:::::A             z::::::z   e:::::::eeeee::::::e4::::::::::::::::4 k::::::k:::::k      aaaaaaa:::::a
      A:::::AAAAAAAAA:::::A           z::::::z    e:::::::::::::::::e 4444444444:::::444 k:::::::::::k     aa::::::::::::a
     A:::::::::::::::::::::A         z::::::z     e::::::eeeeeeeeeee            4::::4   k:::::::::::k    a::::aaaa::::::a
    A:::::AAAAAAAAAAAAA:::::A       z::::::z      e:::::::e                     4::::4   k::::::k:::::k  a::::a    a:::::a
   A:::::A             A:::::A     z::::::zzzzzzzze::::::::e                    4::::4  k::::::k k:::::k a::::a    a:::::a
  A:::::A               A:::::A   z::::::::::::::z e::::::::eeeeeeee          44::::::44k::::::k  k:::::ka:::::aaaa::::::a
 A:::::A                 A:::::A z:::::::::::::::z  ee:::::::::::::e          4::::::::4k::::::k   k:::::ka::::::::::aa:::a
AAAAAAA                   AAAAAAAzzzzzzzzzzzzzzzzz    eeeeeeeeeeeeee          4444444444kkkkkkkk    kkkkkkkaaaaaaaaaa  aaaa

*/

(function() {
    'use strict';

    const currencySymbols = {
        USD: '$', EUR: '€', CHF: 'CHF ', PLN: 'zł', CZK: 'Kč', GBP: '£',
        CAD: 'CA$', AUD: 'A$', JPY: '¥', KZT: '₸', HUF: 'Ft', RON: 'lei',
        CNY: '元', TRY: '₺', INR: '₹', UAH: '₴',
        BYN: 'Br', RUB: '₽', ARS: '$AR'
    };

    const ALL_CURRENCIES = [
        'USD','EUR','CHF','PLN','CZK','GBP',
        'CAD','AUD','JPY','KZT','HUF','RON','CNY',
        'TRY','INR','UAH','BYN','RUB','ARS'
    ];

    const PANEL_ID = 'uah-currency-panel';
    let originalCurrency = null;
    let priceElements = new Map();
    let currentRate = 1;

    function getUserCurrency() { return localStorage.getItem('uah_currency') || 'CHF'; }
    function setUserCurrency(v) { localStorage.setItem('uah_currency', v); }

    function addCurrencyPanel() {
        let panel = document.getElementById(PANEL_ID);
        if (panel) return panel;

        panel = document.createElement('div');
        panel.id = PANEL_ID;
        panel.style.position = 'fixed';
        panel.style.top = '18px';
        panel.style.right = '28px';
        panel.style.zIndex = 10000;
        panel.style.background = 'linear-gradient(90deg,#18e95b 20%, #63f177 80%)';
        panel.style.padding = '4px 10px 4px 10px';
        panel.style.borderRadius = '18px';
        panel.style.boxShadow = '0 0 10px 2px #11ff60dd,0 0 1px #222';
        panel.style.display = 'flex';
        panel.style.alignItems = 'center';

        const sel = document.createElement('select');
        sel.id = 'uah-currency-sel';
        sel.style.fontSize = '15px';
        sel.style.border = 'none';
        sel.style.outline = 'none';
        sel.style.background = 'transparent';
        sel.style.fontWeight = 'bold';
        sel.style.color = '#222';
        sel.style.cursor = 'pointer';
        sel.style.textShadow = '0 0 2px #fff, 0 0 1px #5fffaf';

        ALL_CURRENCIES.forEach((c) => {
            const o = document.createElement('option');
            o.value = c;
            o.textContent = c;
            if (getUserCurrency() === c) o.selected = true;
            sel.appendChild(o);
        });

        // Request rate only when currency is switched
        sel.onchange = async function() {
            const newCurrency = sel.value;
            setUserCurrency(newCurrency);

            console.log(`Currency changed to: ${newCurrency}`);

            // Reset conversion flags for all elements
            priceElements.forEach((data, element) => {
                if (element && element.parentNode) {
                    element.removeAttribute('data-price-converted');
                }
            });

            // Get rate only once when switching
            const fromCurrency = detectOriginalCurrency();
            currentRate = await getExchangeRate(fromCurrency, newCurrency);

            console.log(`Switching from ${fromCurrency} to ${newCurrency}, rate: ${currentRate}`);

            convertAllPrices();
        };

        panel.appendChild(sel);
        document.body.appendChild(panel);
        return panel;
    }

    // Detecting page currency
    function detectOriginalCurrency() {
        if (originalCurrency) return originalCurrency;

        const symbolToCode = {};
        Object.entries(currencySymbols).forEach(([code, sym]) => {
            if (sym && !/^[A-Za-z0-9 ]+$/.test(sym)) {
                symbolToCode[sym.trim()] = code;
            }
        });

        // Additional mappings for different formats
        symbolToCode['AR$'] = 'ARS';
        symbolToCode['руб.'] = 'RUB';
        symbolToCode['руб'] = 'RUB';
        symbolToCode['₽'] = 'RUB';
        symbolToCode['$'] = 'USD';
        symbolToCode['US$'] = 'USD';
        symbolToCode['USD'] = 'USD';
        symbolToCode['CA$'] = 'CAD';
        symbolToCode['CDN$'] = 'CAD';
        symbolToCode['A$'] = 'AUD';
        symbolToCode['zł'] = 'PLN';
        symbolToCode['Kč'] = 'CZK';
        symbolToCode['Ft'] = 'HUF';
        symbolToCode['lei'] = 'RON';
        symbolToCode['元'] = 'CNY';
        symbolToCode['₸'] = 'KZT';
        symbolToCode['Br'] = 'BYN';
        symbolToCode['CHF'] = 'CHF';
        symbolToCode['CHF '] = 'CHF';
        symbolToCode['£'] = 'GBP';
        symbolToCode['₹'] = 'INR';
        symbolToCode['¥'] = 'JPY';

        const priceSelectors = [
            '.discount_final_price',
            '.discount_original_price',
            '.game_purchase_price',
            '[class*="price"]',
            '.market_listing_price',
            '.price',
            '.discount_prices',
            '.game_purchase_action',
            '.discount_block'
        ];

        for (let selector of priceSelectors) {
            const elements = document.querySelectorAll(selector);
            for (let el of elements) {
                const text = el.textContent || '';

                // First check for exact matches of symbols
                for (let [symbol, code] of Object.entries(symbolToCode)) {
                    if (text.includes(symbol)) {
                        originalCurrency = code;
                        console.log(`Detected original currency: ${code} from symbol: ${symbol} in text: "${text}"`);
                        return originalCurrency;
                    }
                }

                // Check for currency code patterns (e.g., "10 USD", "15 EUR")
                const currencyCodePattern = /\d+\s*([A-Z]{3})/g;
                let match;
                while ((match = currencyCodePattern.exec(text)) !== null) {
                    const code = match[1];
                    if (ALL_CURRENCIES.includes(code)) {
                        originalCurrency = code;
                        console.log(`Detected original currency: ${code} from currency code pattern in text: "${text}"`);
                        return originalCurrency;
                    }
                }

                // Special check for USD - look for numbers ending with $ or starting with $
                if (/\$\s*\d+|\d+\s*\$/i.test(text)) {
                    originalCurrency = 'USD';
                    console.log(`Detected USD from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for CHF - look for numbers ending with CHF
                if (/CHF\s*\d+|\d+\s*CHF/i.test(text)) {
                    originalCurrency = 'CHF';
                    console.log(`Detected CHF from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for RUB - look for numbers ending with руб.
                if (/руб\.?\s*\d+|\d+\s*руб\.?/i.test(text)) {
                    originalCurrency = 'RUB';
                    console.log(`Detected RUB from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for GBP - look for numbers ending with £
                if (/£\s*\d+|\d+\s*£/i.test(text)) {
                    originalCurrency = 'GBP';
                    console.log(`Detected GBP from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for INR - look for numbers ending with ₹
                if (/₹\s*\d+|\d+\s*₹/i.test(text)) {
                    originalCurrency = 'INR';
                    console.log(`Detected INR from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for JPY - look for numbers ending with ¥
                if (/¥\s*\d+|\d+\s*¥/i.test(text)) {
                    originalCurrency = 'JPY';
                    console.log(`Detected JPY from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for CAD - look for numbers ending with CDN$
                if (/CDN\$\s*\d+|\d+\s*CDN\$/i.test(text)) {
                    originalCurrency = 'CAD';
                    console.log(`Detected CAD from price pattern: ${text}`);
                    return originalCurrency;
                }

                // Special check for AUD - look for numbers ending with A$
                if (/A\$\s*\d+|\d+\s*A\$/i.test(text)) {
                    originalCurrency = 'AUD';
                    console.log(`Detected AUD from price pattern: ${text}`);
                    return originalCurrency;
                }
            }
        }

        // Check entire page text for specific symbols
        const bodyText = document.body.innerText;

        // Check in order of priority (more specific first)
        if (bodyText.includes('₴')) {
            originalCurrency = 'UAH';
        } else if (bodyText.includes('₽') || bodyText.includes('руб.')) {
            originalCurrency = 'RUB';
        } else if (bodyText.includes('₺')) {
            originalCurrency = 'TRY';
        } else if (bodyText.includes('₹')) {
            originalCurrency = 'INR';
        } else if (bodyText.includes('¥')) {
            originalCurrency = 'JPY';
        } else if (bodyText.includes('£')) {
            originalCurrency = 'GBP';
        } else if (bodyText.includes('€')) {
            originalCurrency = 'EUR';
        } else if (bodyText.includes('₸')) {
            originalCurrency = 'KZT';
        } else if (bodyText.includes('Ft')) {
            originalCurrency = 'HUF';
        } else if (bodyText.includes('lei')) {
            originalCurrency = 'RON';
        } else if (bodyText.includes('元')) {
            originalCurrency = 'CNY';
        } else if (bodyText.includes('zł')) {
            originalCurrency = 'PLN';
        } else if (bodyText.includes('Kč')) {
            originalCurrency = 'CZK';
        } else if (bodyText.includes('Br')) {
            originalCurrency = 'BYN';
        } else if (bodyText.includes('CHF') || bodyText.includes('CHF ')) {
            originalCurrency = 'CHF';
        } else if (bodyText.includes('$AR') || bodyText.includes('AR$')) {
            originalCurrency = 'ARS';
        } else if (bodyText.includes('CA$')) {
            originalCurrency = 'CAD';
        } else if (bodyText.includes('A$')) {
            originalCurrency = 'AUD';
        } else if (bodyText.includes('$') || bodyText.includes('USD')) {
            originalCurrency = 'USD';
        } else {
            originalCurrency = 'USD'; // Default to USD
        }

        console.log(`Final detected currency: ${originalCurrency} from body text analysis`);
        return originalCurrency;
    }

    // Saving original HTML of elements
    function saveOriginalPrices() {
        const priceSelectors = [
            '.discount_final_price',
            '.discount_original_price',
            '.game_purchase_price',
            '[class*="price"]',
            '.market_listing_price',
            '.price',
            '.discount_prices',
            '.game_purchase_action',
            '.discount_block'
        ];

        priceSelectors.forEach(selector => {
            const elements = document.querySelectorAll(selector);
            elements.forEach(el => {
                // Check if element hasn't been processed yet
                if (!priceElements.has(el) && !el.hasAttribute('data-price-converted')) {
                    const originalHTML = el.innerHTML;
                    const originalText = el.textContent.trim();

                    // Check if element contains a price (numbers + currency symbol)
                    const hasPrice = /[\d.,]/.test(originalText) &&
                                   (originalText.includes('$') ||
                                    originalText.includes('€') ||
                                    originalText.includes('₽') ||
                                    originalText.includes('₴') ||
                                    originalText.includes('₺') ||
                                    originalText.includes('£') ||
                                    originalText.includes('¥') ||
                                    originalText.includes('CHF') ||
                                    originalText.includes('zł') ||
                                    originalText.includes('Kč') ||
                                    originalText.includes('Ft') ||
                                    originalText.includes('lei') ||
                                    originalText.includes('元') ||
                                    originalText.includes('₸') ||
                                    originalText.includes('Br') ||
                                    originalText.includes('₹') ||
                                    originalText.includes('CA$') ||
                                    originalText.includes('A$') ||
                                    originalText.includes('$AR') ||
                                    originalText.includes('AR$') ||
                                    originalText.includes('руб.') ||
                                    originalText.includes('руб') ||
                                    originalText.includes('CDN$') ||
                                    /\d+\s*[A-Z]{3}/i.test(originalText)); // For cases like "10 USD"

                    if (originalText && hasPrice) {
                        priceElements.set(el, {
                            originalHTML: originalHTML,
                            originalText: originalText,
                            originalCurrency: detectOriginalCurrency()
                        });
                        console.log(`Saved price element: ${originalText} (currency: ${detectOriginalCurrency()})`);
                    }
                }
            });
        });
    }

    // Getting currency rates (called only when switching)
    async function getExchangeRate(fromCurrency, toCurrency) {
        if (fromCurrency === toCurrency) return 1;

        try {
            console.log(`Fetching exchange rate ${fromCurrency} -> ${toCurrency}`);
            const response = await new Promise((resolve, reject) =>
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${fromCurrency.toLowerCase()}.json`,
                    onload: resolve,
                    onerror: reject,
                    timeout: 10000
                })
            );

            const data = JSON.parse(response.responseText);
            const rate = data[fromCurrency.toLowerCase()][toCurrency.toLowerCase()];
            console.log(`Exchange rate ${fromCurrency} -> ${toCurrency}: ${rate}`);
            return rate || 1;
        } catch (error) {
            console.error('Error fetching exchange rate:', error);
            return 1;
        }
    }

    // Converting price in text
    function convertPriceInText(text, rate, targetCurrency) {
        // Check if text already contains target currency (indicating it's already converted)
        const targetSymbol = currencySymbols[targetCurrency] || (targetCurrency + ' ');

        // More accurate check - look for target symbol followed by a number
        const targetCurrencyPattern = new RegExp(`${targetSymbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*[\\d\\s,.]`, 'i');
        if (targetCurrencyPattern.test(text)) {
            return text; // Already converted
        }

        // Find numbers preceding currency symbols in original currency
        const originalSymbol = currencySymbols[originalCurrency] || originalCurrency;

        // Special handling for different currencies
        let priceRegex;
        if (originalCurrency === 'USD') {
            // For USD, look for different variations: $10, 10$, $ 10, 10 $, 10 USD
            priceRegex = /(\$)\s*([\d\s,.]+)|([\d\s,.]+)\s*(\$)|([\d\s,.]+)\s*(USD)/gi;
        } else if (originalCurrency === 'RUB') {
            // For RUB, look for: 465 руб., 139 руб.
            priceRegex = /([\d\s,.]+)\s*(руб\.?)/gi;
        } else if (originalCurrency === 'GBP') {
            // For GBP, look for: £8.59, £3.43
            priceRegex = /(£)\s*([\d\s,.]+)/gi;
        } else if (originalCurrency === 'INR') {
            // For INR, look for: ₹ 499, ₹ 199
            priceRegex = /(₹)\s*([\d\s,.]+)/gi;
        } else if (originalCurrency === 'JPY') {
            // For JPY, look for: ¥ 1,320, ¥ 528
            priceRegex = /(¥)\s*([\d\s,.]+)/gi;
        } else if (originalCurrency === 'CAD') {
            // For CAD, look for: CDN$ 13.49, CDN$ 5.39
            priceRegex = /(CDN\$)\s*([\d\s,.]+)/gi;
        } else if (originalCurrency === 'AUD') {
            // For AUD, look for: A$ 14.95, A$ 5.98
            priceRegex = /(A\$)\s*([\d\s,.]+)/gi;
        } else {
            // For other currencies, use standard approach
            const escapedSymbol = originalSymbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            priceRegex = new RegExp(`([\\d\\s,.]+)\\s*${escapedSymbol}|([\\d\\s,.]+)\\s*(${originalCurrency})`, 'gi');
        }

        if (originalCurrency === 'USD') {
            let result = text.replace(priceRegex, (match, dollarBefore, amountBefore, amountAfter, dollarAfter, amountUSD, usdCode) => {
                const amount = amountBefore || amountAfter || amountUSD;
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });

            // Remove remaining USD and $ anywhere
            result = result.replace(/USD/gi, '').replace(/\$/g, '').replace(/\s+/g, ' ').trim();
            return result;
        } else if (originalCurrency === 'RUB') {
            const result = text.replace(priceRegex, (match, amount, rubSymbol) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining руб. anywhere
            const cleanedResult = result.replace(/руб\.?/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else if (originalCurrency === 'GBP') {
            const result = text.replace(priceRegex, (match, poundSymbol, amount) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining £ anywhere
            const cleanedResult = result.replace(/£/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else if (originalCurrency === 'INR') {
            const result = text.replace(priceRegex, (match, rupeeSymbol, amount) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining ₹ anywhere
            const cleanedResult = result.replace(/₹/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else if (originalCurrency === 'JPY') {
            const result = text.replace(priceRegex, (match, yenSymbol, amount) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining ¥ anywhere
            const cleanedResult = result.replace(/¥/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else if (originalCurrency === 'CAD') {
            const result = text.replace(priceRegex, (match, cadSymbol, amount) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining CDN$ anywhere
            const cleanedResult = result.replace(/CDN\$/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else if (originalCurrency === 'AUD') {
            const result = text.replace(priceRegex, (match, audSymbol, amount) => {
                const cleanNumber = amount.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });
            // Remove remaining A$ anywhere
            const cleanedResult = result.replace(/A\$/gi, '').replace(/\s+/g, ' ').trim();
            return cleanedResult;
        } else {
            let result = text.replace(priceRegex, (match, amount, symbol, amountCode, currencyCode) => {
                const amountValue = amount || amountCode;
                const cleanNumber = amountValue.replace(/[\s,]/g, '').replace(',', '.');
                const price = parseFloat(cleanNumber);

                if (!isNaN(price) && price > 0) {
                    const convertedPrice = (price * rate).toFixed(2);
                    return targetSymbol + convertedPrice;
                }
                return match;
            });

            // Remove remaining original currency symbol anywhere
            const escapedOriginalSymbol = originalSymbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            result = result.replace(new RegExp(`${escapedOriginalSymbol}`, 'gi'), '').replace(/\s+/g, ' ').trim();
            return result;
        }
    }

    // Converting all saved prices using current rate
    function convertAllPrices() {
        if (isConverting) return;
        isConverting = true;

        const targetCurrency = getUserCurrency();
        const fromCurrency = detectOriginalCurrency();

        console.log(`Converting prices using rate: ${currentRate}`);

        if (fromCurrency === targetCurrency || currentRate === 1) {
            // Restore original HTML
            priceElements.forEach((data, element) => {
                if (element && element.parentNode) {
                    element.innerHTML = data.originalHTML;
                    element.removeAttribute('title');
                    element.removeAttribute('data-price-converted');
                }
            });
        } else {
            // Convert prices in each element
            priceElements.forEach((data, element) => {
                if (element && element.parentNode) {
                    const tempDiv = document.createElement('div');
                    tempDiv.innerHTML = data.originalHTML;

                    // Special handling for discount cards
                    if (element.classList.contains('discount_prices') || element.closest('.discount_block')) {
                        // Process child elements with prices
                        const priceElements = tempDiv.querySelectorAll('.discount_original_price, .discount_final_price');
                        priceElements.forEach(priceEl => {
                            const originalText = priceEl.textContent;
                            if (/[\d.,]/.test(originalText)) {
                                // Check if it already contains target currency
                                const targetSymbol = currencySymbols[targetCurrency] || (targetCurrency + ' ');
                                if (!originalText.includes(targetSymbol)) {
                                    const convertedText = convertPriceInText(originalText, currentRate, targetCurrency);
                                    if (convertedText !== originalText) {
                                        priceEl.textContent = convertedText;
                                        priceEl.title = `Original: ${originalText}`;
                                    }
                                }
                            }
                        });
                    } else {
                        // Standard processing for regular elements
                        const walker = document.createTreeWalker(
                            tempDiv,
                            NodeFilter.SHOW_TEXT,
                            null,
                            false
                        );

                        let textNode;
                        while (textNode = walker.nextNode()) {
                            const originalText = textNode.textContent;
                            if (/[\d.,]/.test(originalText)) {
                                // Check if it already contains target currency
                                const targetSymbol = currencySymbols[targetCurrency] || (targetCurrency + ' ');
                                if (!originalText.includes(targetSymbol)) {
                                    const convertedText = convertPriceInText(originalText, currentRate, targetCurrency);
                                    if (convertedText !== originalText) {
                                        textNode.textContent = convertedText;
                                    }
                                }
                            }
                        }
                    }

                    element.innerHTML = tempDiv.innerHTML;
                    element.title = `Original: ${data.originalText}`;
                    element.setAttribute('data-price-converted', 'true');
                }
            });
        }

        setTimeout(() => { isConverting = false; }, 100);
    }

    let isConverting = false; // Flag to prevent recursion

    // Processing new elements
    function processNewElements() {
        if (isConverting) return; // Avoid recursion

        const oldSize = priceElements.size;
        saveOriginalPrices();
        const newSize = priceElements.size;

        // Convert only if new elements were added
        if (newSize > oldSize && getUserCurrency() !== detectOriginalCurrency() && currentRate !== 1) {
            isConverting = true;

            // Convert only new elements
            const newElements = Array.from(priceElements.entries()).slice(oldSize);
            newElements.forEach(([element, data]) => {
                if (element && element.parentNode && !element.hasAttribute('data-price-converted')) {
                    const tempDiv = document.createElement('div');
                    tempDiv.innerHTML = data.originalHTML;

                    // Special handling for discount cards
                    if (element.classList.contains('discount_prices') || element.closest('.discount_block')) {
                        const priceElements = tempDiv.querySelectorAll('.discount_original_price, .discount_final_price');
                        priceElements.forEach(priceEl => {
                            const originalText = priceEl.textContent;
                            if (/[\d.,]/.test(originalText)) {
                                // Check if it already contains target currency
                                const targetSymbol = currencySymbols[getUserCurrency()] || (getUserCurrency() + ' ');
                                if (!originalText.includes(targetSymbol)) {
                                    const convertedText = convertPriceInText(originalText, currentRate, getUserCurrency());
                                    if (convertedText !== originalText) {
                                        priceEl.textContent = convertedText;
                                        priceEl.title = `Original: ${originalText}`;
                                    }
                                }
                            }
                        });
                    } else {
                        // Standard processing for regular elements
                        const walker = document.createTreeWalker(
                            tempDiv,
                            NodeFilter.SHOW_TEXT,
                            null,
                            false
                        );

                        let textNode;
                        while (textNode = walker.nextNode()) {
                            const originalText = textNode.textContent;
                            if (/[\d.,]/.test(originalText)) {
                                // Check if it already contains target currency
                                const targetSymbol = currencySymbols[getUserCurrency()] || (getUserCurrency() + ' ');
                                if (!originalText.includes(targetSymbol)) {
                                    const convertedText = convertPriceInText(originalText, currentRate, getUserCurrency());
                                    if (convertedText !== originalText) {
                                        textNode.textContent = convertedText;
                                    }
                                }
                            }
                        }
                    }

                    element.innerHTML = tempDiv.innerHTML;
                    element.title = `Original: ${data.originalText}`;
                    element.setAttribute('data-price-converted', 'true');
                }
            });

            setTimeout(() => { isConverting = false; }, 100);
        }
    }

    // Initialization
    async function init() {
        console.log('Initializing currency converter...');

        // Reset currency detection on each initialization
        originalCurrency = null;
        priceElements.clear();

        detectOriginalCurrency();
        addCurrencyPanel();
        saveOriginalPrices();

        // Get initial rate if selected currency is different from original
        const targetCurrency = getUserCurrency();
        const detectedCurrency = detectOriginalCurrency();

        console.log(`Target currency: ${targetCurrency}, Detected currency: ${detectedCurrency}`);

        if (targetCurrency !== detectedCurrency) {
            currentRate = await getExchangeRate(detectedCurrency, targetCurrency);
            console.log(`Initial conversion rate: ${currentRate}`);
            convertAllPrices();
        } else {
            console.log('No conversion needed - currencies match');
        }
    }

    // Run after page load
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        setTimeout(init, 100);
    }

    // Tracking URL changes to handle region changes
    let lastUrl = location.href;
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            console.log('URL changed, re-initializing currency converter...');
            setTimeout(init, 500); // Small delay to allow new content to load
        }
    }).observe(document, {subtree: true, childList: true});

    // Observing new elements with protection against recursion
    let observerTimeout;
    const observer = new MutationObserver((mutations) => {
        // Ignore changes in our currency panel
        const relevantMutations = mutations.filter(mutation => {
            return !mutation.target.closest(`#${PANEL_ID}`) &&
                   mutation.target.id !== PANEL_ID &&
                   !isConverting;
        });

        if (relevantMutations.length === 0) return;

        clearTimeout(observerTimeout);
        observerTimeout = setTimeout(processNewElements, 500);
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: false // Do not track attribute changes
    });

})();