xd2shuffle

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

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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
        });
    });
})();