您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
把转发按钮替换成复制按钮,一键复制推文内容,点击后显示打勾图标
// ==UserScript== // @name 推特一键复制 // @namespace http://tampermonkey.net/ // @version 2.3 // @description 把转发按钮替换成复制按钮,一键复制推文内容,点击后显示打勾图标 // @author chengdu // @match https://twitter.com/* // @match https://x.com/* // @grant none // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; console.log('推特复制脚本 v2.3 启动啦~'); function copyToClipboard(text, buttonElement) { navigator.clipboard.writeText(text).then(() => { changeIconToCheck(buttonElement); }).catch(err => { console.error('复制失败 Copy Failed:', err); const textArea = document.createElement('textarea'); textArea.value = text; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); changeIconToCheck(buttonElement); }); } // 把图标改为打勾 Change Icon to Checkmark function changeIconToCheck(buttonElement) { const iconSvg = buttonElement.querySelector('svg'); if (iconSvg) { iconSvg.innerHTML = ` <path d="M9 16.2l-3.5-3.5-1.4 1.4L9 19 20 8l-1.4-1.4z" fill="currentColor"/> `; iconSvg.style.transition = 'all 0.3s ease'; iconSvg.style.color = '#1d9bf0'; // 2秒后恢复原始图标 Restore Original Icon After 2s setTimeout(() => { iconSvg.innerHTML = ` <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" fill="currentColor"/> `; iconSvg.style.color = '#536471'; }, 2000); } } function extractTweetContent(tweetElement) { const textElement = tweetElement.querySelector('[data-testid="tweetText"]'); let tweetText = textElement ? textElement.innerText : ''; const userNameElement = tweetElement.querySelector('[data-testid="User-Name"]'); const userName = userNameElement ? userNameElement.innerText.split('@')[0] : ''; const timeElement = tweetElement.querySelector('time'); const timeText = timeElement ? timeElement.getAttribute('datetime') : ''; let copyContent = ''; if (userName) copyContent += `👤 ${userName}\n`; if (tweetText) copyContent += `📝 ${tweetText}\n`; if (timeText) copyContent += `🕐 ${new Date(timeText).toLocaleString()}\n`; copyContent += `🔗 ${window.location.href}`; return copyContent || 'Failed to get tweet content'; } function hideRetweetCounts() { const copyButtons = document.querySelectorAll('[data-testid="copy-tweet"]'); copyButtons.forEach(button => { const countContainer = button.querySelector('span[data-testid="app-text-transition-container"]'); if (countContainer && !countContainer.getAttribute('data-moe-hidden')) { countContainer.style.display = 'none'; countContainer.setAttribute('data-moe-hidden', 'true'); } const allSpans = button.querySelectorAll('span'); allSpans.forEach(span => { if (span.textContent.match(/^\d+$/) && !span.getAttribute('data-moe-hidden')) { span.style.display = 'none'; span.setAttribute('data-moe-hidden', 'true'); } }); }); } function replaceRetweetButtons() { const retweetButtons = document.querySelectorAll('[data-testid="retweet"]'); retweetButtons.forEach(button => { if (button.getAttribute('data-moe-replaced') === 'true') return; const tweetElement = button.closest('[data-testid="tweet"]'); if (!tweetElement) return; const copyButton = button.cloneNode(true); copyButton.setAttribute('data-moe-replaced', 'true'); copyButton.setAttribute('data-testid', 'copy-tweet'); const iconSvg = copyButton.querySelector('svg'); if (iconSvg) { iconSvg.innerHTML = ` <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" fill="currentColor"/> `; iconSvg.style.color = '#536471'; } copyButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const content = extractTweetContent(tweetElement); copyToClipboard(content, copyButton); copyButton.style.transform = 'scale(0.95)'; setTimeout(() => { copyButton.style.transform = 'scale(1)'; }, 150); }); copyButton.addEventListener('mouseenter', () => { copyButton.style.transition = 'all 0.2s ease'; copyButton.style.transform = 'scale(1.05)'; }); copyButton.addEventListener('mouseleave', () => { copyButton.style.transform = 'scale(1)'; }); button.parentNode.replaceChild(copyButton, button); }); hideRetweetCounts(); } const observer = new MutationObserver((mutations) => { let shouldUpdate = false; mutations.forEach((mutation) => { if (mutation.type === 'childList') { const hasNewTweets = Array.from(mutation.addedNodes).some(node => node.nodeType === 1 && (node.querySelector && node.querySelector('[data-testid="retweet"]')) ); if (hasNewTweets) shouldUpdate = true; } }); if (shouldUpdate) { setTimeout(replaceRetweetButtons, 100); } }); function init() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { setTimeout(startObserving, 1000); }); } else { setTimeout(startObserving, 1000); } } function startObserving() { replaceRetweetButtons(); observer.observe(document.body, { childList: true, subtree: true }); console.log('系统启动完成~开始监听推文变化!'); setInterval(() => { replaceRetweetButtons(); }, 2000); } init(); })();