xd2shuffle

Visual larp: Changes ARS to $ everywhere (bets, balance, everything) - keeps numbers the same

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         xd2shuffle
// @namespace    http://tampermonkey.net/
// @version      7.7.8.1
// @description  Visual larp: Changes ARS to $ everywhere (bets, balance, everything) - keeps numbers the same
// @author       fusi | @loficat on tg | codedfusi on github
// @match        *://*.shuffle.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    const processedTextNodes = new WeakSet();
    const processedImages = new WeakSet();

    // Force update a text node
    function updateTextNode(node) {
        if (node.nodeType !== 3 || !node.nodeValue) return false;
        
        let original = node.nodeValue;
        let newValue = original;
        let changed = false;

        // Replace ARS with $ (case insensitive just in case)
        if (newValue.includes("ARS")) {
            newValue = newValue.replace(/ARS/g, "$");
            changed = true;
        }
        
        // Replace lowercase "ars" if it appears
        if (newValue.includes("ars")) {
            newValue = newValue.replace(/ars/g, "$");
            changed = true;
        }

        // Remove space after the new $
        if (changed) {
            newValue = newValue.replace(/\$\s+/g, '$');
        }

        if (changed && newValue !== original) {
            node.nodeValue = newValue;
            return true;
        }
        return false;
    }

    function processTextNode(node) {
        if (node.nodeType === 3 && node.nodeValue && !processedTextNodes.has(node)) {
            if (updateTextNode(node)) {
                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 all text nodes
        const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
        let node;
        while ((node = walker.nextNode())) {
            processTextNode(node);
        }

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

    // More aggressive mutation handling
    function onMutation(mutations) {
        let needsFullScan = false;
        
        for (const mutation of mutations) {
            // If attributes changed (like a bet amount updating), scan the target
            if (mutation.type === 'attributes') {
                if (mutation.target.nodeType === 1) {
                    // Re-scan this element and its children
                    walkAndProcess(mutation.target);
                    // Also scan its parent in case the change bubbled
                    if (mutation.target.parentNode) {
                        walkAndProcess(mutation.target.parentNode);
                    }
                }
                needsFullScan = true;
            }
            
            // If child nodes were added, process them
            if (mutation.type === 'childList') {
                for (const addedNode of mutation.addedNodes) {
                    if (addedNode.nodeType === 1) {
                        walkAndProcess(addedNode);
                    } else if (addedNode.nodeType === 3) {
                        processTextNode(addedNode);
                    }
                }
                needsFullScan = true;
            }
            
            // If text itself changed (characterData mutation)
            if (mutation.type === 'characterData') {
                if (mutation.target.nodeType === 3) {
                    // Re-process this text node even if it was processed before
                    const node = mutation.target;
                    if (node.nodeValue && (node.nodeValue.includes("ARS") || node.nodeValue.includes("ars"))) {
                        updateTextNode(node);
                    }
                }
                needsFullScan = true;
            }
        }
        
        // Do a quick partial scan of the body periodically to catch anything missed
        if (needsFullScan) {
            setTimeout(() => {
                // Scan the whole body but skip nodes we've already processed to save performance
                const allTextNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
                let tn;
                while ((tn = allTextNodes.nextNode())) {
                    if (tn.nodeValue && (tn.nodeValue.includes("ARS") || tn.nodeValue.includes("ars"))) {
                        if (updateTextNode(tn)) {
                            processedTextNodes.add(tn);
                        }
                    }
                }
            }, 100);
        }
    }

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

        // Watch for attribute changes (like bet amounts), text changes, AND child lists
        const observer = new MutationObserver(onMutation);
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: true,      // <-- CRITICAL: catches bet amount updates
            attributeFilter: ['textContent', 'innerHTML', 'value'], // Focus on text-related attributes
            characterData: true    // <-- CRITICAL: catches direct text changes
        });
        
        // Also run every second as a backup (heavy but ensures bets get caught)
        setInterval(() => {
            const allTextNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
            let tn;
            while ((tn = allTextNodes.nextNode())) {
                if (tn.nodeValue && (tn.nodeValue.includes("ARS") || tn.nodeValue.includes("ars"))) {
                    updateTextNode(tn);
                }
            }
        }, 1000);
    });
})();