xd2shuffle

ARS to USD converter for shuffle.com (text + numbers)

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         xd2shuffle
// @namespace    http://tampermonkey.net/
// @version      7.7.7.8
// @description  ARS to USD converter for shuffle.com (text + numbers)
// @author       fusi | @loficat on tg | codedfusi on github | Modified by user
// @match        *://*.shuffle.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    // ==========================================
    // SET THE EXCHANGE RATE HERE
    // Example: 1 USD = 1400 ARS
    // ==========================================
    const USD_RATE = 1400;  // <-- CHANGE THIS NUMBER to the current rate

    // Store modified nodes to avoid double processing
    const processedTextNodes = new WeakSet();
    const processedImages = new WeakSet();

    // Helper: Convert ARS number string to USD formatted string
    function convertARStextToUSD(text) {
        // Match numbers that could be ARS amounts (including commas and decimals)
        // This looks for patterns like: 1,234,567.89 or 1.234.567,89 or just 1234
        const arsNumberPattern = /(\b[\d,]+(?:\.\d+)?\b)|(\b[\d.]+(?:,\d+)?\b)/g;

        return text.replace(arsNumberPattern, (match) => {
            // Clean the match: remove commas (for US style) or dots (for EU style)
            let cleanNumber = match.replace(/,/g, '');
            // If it has a dot and then exactly 2 digits at the end, it might be decimal
            // For EU style like 1.234,56 -> replace dot with empty and comma with dot
            if (cleanNumber.includes('.') && cleanNumber.includes(',')) {
                cleanNumber = cleanNumber.replace(/\./g, '').replace(/,/, '.');
            } else if (cleanNumber.includes(',')) {
                // If only commas, treat as decimal separator (EU)
                cleanNumber = cleanNumber.replace(/,/, '.');
            }

            const arsValue = parseFloat(cleanNumber);
            if (isNaN(arsValue)) return match;

            const usdValue = arsValue / USD_RATE;
            // Format USD with 2 decimal places, using US notation
            return usdValue.toLocaleString('en-US', {
                minimumFractionDigits: 2,
                maximumFractionDigits: 2
            });
        });
    }

    function processTextNode(node) {
        if (node.nodeType === 3 && node.nodeValue && !processedTextNodes.has(node)) {
            let original = node.nodeValue;
            let modified = false;
            let newValue = original;

            // Replace ARS symbol with $
            if (newValue.includes("ARS")) {
                newValue = newValue.replace(/ARS/g, "$");
                modified = true;
            }

            // Convert ARS numbers to USD (if text contains numbers)
            if (/\d/.test(newValue)) {
                const converted = convertARStextToUSD(newValue);
                if (converted !== newValue) {
                    newValue = converted;
                    modified = true;
                }
            }

            if (modified) {
                node.nodeValue = newValue;
                processedTextNodes.add(node);
            }
        }
    }

    function processImageElement(el) {
        if (el.nodeType === 1 && el.hasAttribute("src") && !processedImages.has(el)) {
            const src = el.getAttribute("src");
            if (src && src.includes("/icons/fiat/ARS.svg")) {
                el.setAttribute("src", src.replace("/icons/fiat/ARS.svg", "/icons/fiat/USD.svg"));
                processedImages.add(el);
            }
        }
    }

    function walkAndProcess(root) {
        if (!root) return;

        // Process text nodes
        const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
        let node;
        while ((node = walker.nextNode())) {
            processTextNode(node);
        }

        // Process image elements
        const images = root.querySelectorAll('img[src*="/icons/fiat/ARS.svg"]');
        images.forEach(img => processImageElement(img));
    }

    // MutationObserver callback to handle dynamically added content
    function onMutation(mutations) {
        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                for (const addedNode of mutation.addedNodes) {
                    if (addedNode.nodeType === 1) {
                        walkAndProcess(addedNode);
                    } else if (addedNode.nodeType === 3) {
                        processTextNode(addedNode);
                    }
                }
            }
        }
        // Also periodically re-check text nodes that might have changed value
        // (We use a weak set so we only reprocess if the node was garbage collected)
    }

    // Start the script once the DOM is ready
    document.addEventListener("DOMContentLoaded", () => {
        walkAndProcess(document.body);

        const observer = new MutationObserver(onMutation);
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
})();