您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
sol/bsc to gmgn
当前为
// ==UserScript== // @name Twitter sol/bsc to gmgn // @namespace http://tampermonkey.net/ // @version 0.7 // @description sol/bsc to gmgn // @author mqtt // @match https://x.com/* // @match https://twitter.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=twitter.com // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; const solAddressRegex = /\b(?![^<]*>|[^<>]*<\/)([1-9A-HJ-NP-Za-km-z]{32,44})(?![a-zA-Z0-9])\b/g; const evmAddressRegex = /\b(?![^<]*>|[^<>]*<\/)(0x[a-fA-F0-9]{40})(?![a-zA-Z0-9])\b/g; const TWEET_TEXT_SELECTORS = [ '[data-testid="tweetText"]', 'div[data-testid="card.wrapper"] div[lang]', 'div[data-testid="cellInnerDiv"] div[lang]' ].join(', '); const SOL_LINK_CLASS = 'sol-address-link'; const EVM_LINK_CLASS = 'evm-address-link'; const processedNodes = new WeakSet(); let processQueue = []; let processTimer = null; GM_addStyle(` a.${ SOL_LINK_CLASS } { color: red !important; text-decoration: underline !important; position: relative; z-index: 100; transition: all 0.2s ease; } a.${ SOL_LINK_CLASS }:hover { filter: brightness(1.2); transform: translateY(-1px); } a.${ EVM_LINK_CLASS } { color: red !important; text-decoration: underline !important; position: relative; z-index: 100; transition: all 0.2s ease; } a.${ EVM_LINK_CLASS }:hover { filter: brightness(1.2); transform: translateY(-1px); } `); function debounce(func, wait) { let timeout; return function () { const context = this; const args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } function processAddresses() { if (document.readyState !== 'complete') { return; } const nodesToProcess = [...processQueue]; processQueue = []; nodesToProcess.forEach(element => { if (processedNodes.has(element)) { return; } const textNodes = []; const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, { acceptNode: element_1 => { if (element_1.parentElement.closest('script, style, noscript, template, a') || processedNodes.has(element_1.parentElement)) { return NodeFilter.FILTER_SKIP; } if (/\b([a-zA-Z0-9]{32,44}|0x[a-fA-F0-9]{40})\b/.test(element_1.textContent)) { return NodeFilter.FILTER_ACCEPT; } return NodeFilter.FILTER_SKIP; } }, false); while (walker.nextNode()) { textNodes.push(walker.currentNode); } textNodes.forEach(element_2 => { const parent = element_2.parentElement; if (processedNodes.has(parent)) { return; } const text = element_2.textContent; if (!solAddressRegex.test(text) && !evmAddressRegex.test(text)) { return; } const fragment = document.createDocumentFragment(); let lastIndex = 0; solAddressRegex.lastIndex = 0; evmAddressRegex.lastIndex = 0; const combinedMatches = []; let solMatch; while (solMatch = solAddressRegex.exec(text)) { combinedMatches.push({ index: solMatch.index, length: solMatch[0].length, type: 'sol', address: solMatch[1] }); } let evmMatch; while (evmMatch = evmAddressRegex.exec(text)) { combinedMatches.push({ index: evmMatch.index, length: evmMatch[0].length, type: 'evm', address: evmMatch[1] }); } combinedMatches.sort((a, b) => a.index - b.index); combinedMatches.forEach(element_3 => { if (element_3.index > lastIndex) { fragment.appendChild(document.createTextNode(text.substring(lastIndex, element_3.index))); } const link = document.createElement('a'); if (element_3.type === 'sol') { link.href = `https://gmgn.ai/sol/token/ufeXUTjX_${ element_3.address }?filter=All`; link.className = SOL_LINK_CLASS; } else { link.href = `https://gmgn.ai/bsc/token/${ element_3.address }`; link.className = EVM_LINK_CLASS; } link.target = '_blank'; link.rel = 'noopener noreferrer'; link.textContent = element_3.address; link.dataset[`${ element_3.type }Address`] = element_3.address; fragment.appendChild(link); lastIndex = element_3.index + element_3.length; }); if (lastIndex < text.length) { fragment.appendChild(document.createTextNode(text.substring(lastIndex))); } parent.replaceChild(fragment, element_2); processedNodes.add(parent); }); }); } function enqueueNodeProcessing(node) { if (!processedNodes.has(node) && node.textContent) { processQueue.push(node); if (!processTimer) { processTimer = setTimeout(() => { processAddresses(); processTimer = null; }, 100); } } } function setupObserver() { const targetNode = document.querySelector('[data-testid="primaryColumn"]') || document.body; const observer = new MutationObserver(element => { let hasRelevantChanges = false; for (const mutation of element) { if (mutation.type === 'childList') { for (const node of mutation.addedNodes) { if (node.nodeType !== 1) { continue; } if (node.matches(TWEET_TEXT_SELECTORS)) { enqueueNodeProcessing(node); hasRelevantChanges = true; } else { if (node.querySelector(TWEET_TEXT_SELECTORS)) { node.querySelectorAll(TWEET_TEXT_SELECTORS).forEach(element => { enqueueNodeProcessing(element); }); hasRelevantChanges = true; } } } } if (hasRelevantChanges) { break; } } }); observer.observe(targetNode, { childList: true, subtree: true, attributes: false, characterData: false }); } function initialize() { document.querySelectorAll(TWEET_TEXT_SELECTORS).forEach(element => { enqueueNodeProcessing(element); }); setupObserver(); window.addEventListener('focus', debounce(() => { document.querySelectorAll(TWEET_TEXT_SELECTORS).forEach(element => { enqueueNodeProcessing(element); }); }, 500)); window.addEventListener('scroll', debounce(() => { const visibleElements = document.querySelectorAll(TWEET_TEXT_SELECTORS); visibleElements.forEach(element => { const rect = element.getBoundingClientRect(); if (rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth)) { enqueueNodeProcessing(element); } }); }, 500)); } function waitForTwitterLoad() { const checkInterval = setInterval(() => { if (document.querySelector('[data-testid="primaryColumn"]')) { clearInterval(checkInterval); initialize(); } }, 500); } if (document.readyState === 'complete') { waitForTwitterLoad(); } else { window.addEventListener('load', waitForTwitterLoad); } }());