ARS to USD converter for shuffle.com (text + numbers) - NO SPACE FIX
// ==UserScript==
// @name xd2shuffle
// @namespace http://tampermonkey.net/
// @version 7.7.7.9
// @description ARS to USD converter for shuffle.com (text + numbers) - NO SPACE FIX
// @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 (NO SPACE AFTER $)
function convertARStextToUSD(text) {
// Match numbers that could be ARS amounts (including commas and decimals)
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, '');
// 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
// toLocaleString can add spaces? No, but we'll force no space by joining directly.
// Use toFixed to avoid any automatic spacing issues.
let formattedUsd = usdValue.toFixed(2);
// Add commas for thousands separators manually (simple version)
// This adds commas but ensures NO SPACE.
let parts = formattedUsd.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join('.');
});
}
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 $ - ensure no space is added
if (newValue.includes("ARS")) {
// Replace ARS with $, and also remove any space that might be between the $ and the number
newValue = newValue.replace(/ARS\s*/g, "$");
modified = true;
}
// Convert ARS numbers to USD (if text contains numbers)
if (/\d/.test(newValue)) {
// Temporarily protect the $ so it doesn't get a space added
let protectedValue = newValue;
const converted = convertARStextToUSD(protectedValue);
if (converted !== protectedValue) {
// Now, ensure that if a $ is present, there is NO space after it
// This regex looks for $ followed by any whitespace and then a number
let finalConversion = converted.replace(/\$\s+(\d)/g, '$$$1');
newValue = finalConversion;
modified = true;
}
}
// Final cleanup: ensure no space after any $ sign
newValue = newValue.replace(/\$\s+/g, '$');
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);
}
}
}
}
}
// 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
});
});
})();